9
0
Fork 0

Merge branch 'for-next/of'

Conflicts:
	arch/arm/boards/freescale-mx53-loco/board.c
	drivers/of/Makefile
This commit is contained in:
Sascha Hauer 2013-08-05 12:50:06 +02:00
commit fbf082b565
33 changed files with 885 additions and 102 deletions

View File

@ -0,0 +1,10 @@
barebox specific devicetree bindings
====================================
barebox uses some barebox specific devicetree bindings. All of these
are under the /chosen/ hierarchy in the devicetree.
The bindings have the form of a device with regular 'compatible' properties.
drivers matching these devices do not handle physical devices but instead
influence / configure certain behaviours of barebox like the place where to
find the persistent environment.

View File

@ -0,0 +1,25 @@
barebox environment
===================
This driver provides an environment for barebox from the devicetree.
Required properties:
- compatible: should be "barebox,environment"
- device-path: path to the environment
The device-path is a multistring property. The first string should be a
nodepath to the node containing the physical device of the environment.
The subsequent strings are of the form <type>:<options> to further describe
the path to the environment. Supported values for <type>:
partname:<partname> This describes a partition on a device. <partname> can
be the label for mtd partitions, the number for DOS
partitions (beginning with 0) or the name for GPT
partitions
Example:
environment@0 {
compatible = "barebox,environment";
device-path = &flash, "partname:barebox-environment";
};

View File

@ -0,0 +1,8 @@
Common leds properties.
- linux,default-trigger barebox,default-trigger: This parameter, if present, is a
string defining the trigger assigned to the LED. Current triggers are:
"heartbeat" - LED flashes at a constant rate
"panic" - LED turns on when barebox panics
"net" - LED indicates network activity

View File

@ -114,22 +114,6 @@ static int realq7_env_init(void)
BBU_HANDLER_FLAG_DEFAULT, NULL, 0, 0x00907000);
imx6_bbu_internal_mmc_register_handler("mmc", "/dev/mmc3.barebox",
0, NULL, 0, 0x00907000);
switch (bootsource_get()) {
case BOOTSOURCE_MMC:
device_detect_by_name("mmc3");
devfs_add_partition("mmc3", 0, SZ_1M, DEVFS_PARTITION_FIXED, "mmc3.barebox");
devfs_add_partition("mmc3", SZ_1M, SZ_1M, DEVFS_PARTITION_FIXED, "mmc3.bareboxenv");
default_environment_path = "/dev/mmc3.bareboxenv";
break;
default:
case BOOTSOURCE_SPI:
devfs_add_partition("m25p0", 0, SZ_256K, DEVFS_PARTITION_FIXED, "m25p0.barebox");
devfs_add_partition("m25p0", SZ_256K, SZ_256K, DEVFS_PARTITION_FIXED, "m25p0.bareboxenv");
default_environment_path = "/dev/m25p0.bareboxenv";
break;
}
return 0;
}
late_initcall(realq7_env_init);
@ -141,6 +125,16 @@ static int realq7_console_init(void)
imx6_init_lowlevel();
switch (bootsource_get()) {
case BOOTSOURCE_MMC:
of_device_enable_path("/chosen/environment-emmc");
break;
default:
case BOOTSOURCE_SPI:
of_device_enable_path("/chosen/environment-spi");
break;
}
return 0;
}
postcore_initcall(realq7_console_init);

View File

@ -210,6 +210,16 @@ static int efikamx_usb_init(void)
mxc_iomux_v3_setup_pad(MX51_PAD_EIM_A26__USBH2_STP);
}
switch (bootsource_get()) {
case BOOTSOURCE_MMC:
of_device_enable_path("/chosen/environment-sd");
break;
case BOOTSOURCE_SPI:
default:
of_device_enable_path("/chosen/environment-spi");
break;
}
return 0;
}
console_initcall(efikamx_usb_init);
@ -230,7 +240,6 @@ extern char flash_header_imx51_genesi_efikasb_end[];
static int efikamx_late_init(void)
{
enum bootsource bootsource;
int i;
if (!of_machine_is_compatible("genesi,imx51-sb"))
@ -255,24 +264,6 @@ static int efikamx_late_init(void)
armlinux_set_architecture(2370);
armlinux_set_revision(0x5100 | imx_silicon_revision());
bootsource = bootsource_get();
switch (bootsource) {
case BOOTSOURCE_MMC:
device_detect_by_name("mmc1");
devfs_add_partition("mmc1", 0x00000, 0x80000,
DEVFS_PARTITION_FIXED, "self0");
devfs_add_partition("mmc1", 0x80000, 0x80000,
DEVFS_PARTITION_FIXED, "env0");
break;
case BOOTSOURCE_SPI:
default:
devfs_add_partition("m25p0", 0x80000, 0x20000,
DEVFS_PARTITION_FIXED, "env0");
break;
}
return 0;
}
late_initcall(efikamx_late_init);

View File

@ -178,11 +178,6 @@ static int imx51_babbage_late_init(void)
BBU_HANDLER_FLAG_DEFAULT, (void *)flash_header_imx51_babbage_start,
flash_header_imx51_babbage_end - flash_header_imx51_babbage_start, 0);
device_detect_by_name("mmc0");
devfs_add_partition("mmc0", 0x00000, 0x40000, DEVFS_PARTITION_FIXED, "self0");
devfs_add_partition("mmc0", 0x40000, 0x20000, DEVFS_PARTITION_FIXED, "env0");
return 0;
}
late_initcall(imx51_babbage_late_init);

View File

@ -71,6 +71,7 @@ CONFIG_NET_NFS=y
CONFIG_NET_PING=y
CONFIG_NET_RESOLV=y
CONFIG_OFDEVICE=y
CONFIG_OF_BAREBOX_DRIVERS=y
CONFIG_DRIVER_NET_FEC_IMX=y
CONFIG_DRIVER_SPI_IMX=y
CONFIG_I2C=y

View File

@ -19,6 +19,11 @@
chosen {
linux,stdout-path = "/soc/aips@70000000/serial@73fbc000";
environment@0 {
compatible = "barebox,environment";
device-path = &esdhc1, "partname:barebox-environment";
};
};
memory {
@ -73,6 +78,13 @@
fsl,cd-controller;
fsl,wp-controller;
status = "okay";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "barebox-environment";
reg = <0x80000 0x20000>;
};
};
&esdhc2 {

View File

@ -18,6 +18,18 @@
chosen {
linux,stdout-path = "/soc/aips@70000000/serial@73fbc000";
environment-sd {
compatible = "barebox,environment";
device-path = &esdhc2, "partname:barebox-environment";
status = "disabled";
};
environment-spi {
compatible = "barebox,environment";
device-path = &flash, "partname:barebox-environment";
status = "disabled";
};
};
memory {
@ -178,6 +190,13 @@
cd-gpios = <&gpio1 8 0>;
wp-gpios = <&gpio1 7 0>;
status = "okay";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "barebox-environment";
reg = <0x80000 0x80000>;
};
};
&ecspi1 {
@ -290,6 +309,13 @@
compatible = "sst,sst25vf032b", "m25p80";
spi-max-frequency = <15000000>;
reg = <1>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "barebox-environment";
reg = <0x80000 0x80000>;
};
};
};

View File

@ -19,6 +19,11 @@
chosen {
linux,stdout-path = "/soc/aips@50000000/serial@53fbc000";
environment@0 {
compatible = "barebox,environment";
device-path = &esdhc1, "partname:barebox-environment";
};
};
memory {
@ -119,6 +124,13 @@
pinctrl-0 = <&pinctrl_esdhc1_1>;
cd-gpios = <&gpio3 13 0>;
status = "okay";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "barebox-environment";
reg = <0x80000 0x20000>;
};
};
&ssi2 {

View File

@ -19,6 +19,18 @@
chosen {
linux,stdout-path = "/soc/aips-bus@02100000/serial@021e8000";
environment-emmc {
compatible = "barebox,environment";
device-path = &usdhc4, "partname:barebox-environment";
status = "disabled";
};
environment-spi {
compatible = "barebox,environment";
device-path = &flash, "partname:barebox-environment";
status = "disabled";
};
};
aliases {
@ -87,6 +99,18 @@
compatible = "m25p80";
spi-max-frequency = <40000000>;
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "barebox";
reg = <0x0 0x80000>;
};
partition@1 {
label = "barebox-environment";
reg = <0x80000 0x20000>;
};
};
};
@ -351,4 +375,11 @@
non-removable;
bus-width = <8>;
status = "okay";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "barebox-environment";
reg = <0x0 0x80000>;
};
};

View File

@ -25,6 +25,7 @@
#include <init.h>
#include <asm/syslib.h>
#include <ns16550.h>
#include <linux/err.h>
/*
* These datas are from the MBR, created by the linker and filled by the
@ -43,6 +44,7 @@ extern uint8_t pers_env_drive;
static int devices_init(void)
{
int rc;
struct cdev *cdev;
/* extended memory only */
add_mem_device("ram0", 0x0, bios_get_memsize() << 10,
@ -51,11 +53,11 @@ static int devices_init(void)
NULL);
if (pers_env_size != PATCH_AREA_PERS_SIZE_UNUSED) {
rc = devfs_add_partition("biosdisk0",
cdev = devfs_add_partition("biosdisk0",
pers_env_storage * 512,
(unsigned)pers_env_size * 512,
DEVFS_PARTITION_FIXED, "env0");
printf("Partition: %d\n", rc);
printf("Partition: %d\n", IS_ERR(cdev) ? PTR_ERR(cdev) : 0);
} else
printf("No persistent storage defined\n");

View File

@ -35,6 +35,7 @@
#include <linux/stat.h>
#include <libgen.h>
#include <getopt.h>
#include <linux/err.h>
#define SIZE_REMAINING ((ulong)-1)
@ -48,7 +49,8 @@ static int mtd_part_do_parse_one(char *devname, const char *partstr,
char *end;
char buf[PATH_MAX] = {};
unsigned long flags = 0;
int ret;
int ret = 0;
struct cdev *cdev;
memset(buf, 0, PATH_MAX);
@ -99,9 +101,12 @@ static int mtd_part_do_parse_one(char *devname, const char *partstr,
*retsize = size;
ret = devfs_add_partition(devname, *offset, size, flags, buf);
if (ret)
cdev = devfs_add_partition(devname, *offset, size, flags, buf);
if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev);
printf("cannot create %s: %s\n", buf, strerror(-ret));
}
return ret;
}

View File

@ -379,7 +379,7 @@ out:
int envfs_register_partition(const char *devname, unsigned int partnr)
{
struct cdev *cdev;
struct cdev *cdev, *part;
char *partname;
if (!devname)
@ -398,8 +398,14 @@ int envfs_register_partition(const char *devname, unsigned int partnr)
return -ENODEV;
}
return devfs_add_partition(partname, 0, cdev->size,
part = devfs_add_partition(partname, 0, cdev->size,
DEVFS_PARTITION_FIXED, "env0");
if (part)
return 0;
free(partname);
return -EINVAL;
}
EXPORT_SYMBOL(envfs_register_partition);
#endif

View File

@ -29,6 +29,7 @@
#include <disks.h>
#include <filetype.h>
#include <dma.h>
#include <linux/err.h>
#include "partitions/parser.h"
@ -48,16 +49,19 @@ static int register_one_partition(struct block_device *blk,
int ret;
uint64_t start = part->first_sec * SECTOR_SIZE;
uint64_t size = part->size * SECTOR_SIZE;
struct cdev *cdev;
partition_name = asprintf("%s.%d", blk->cdev.name, no);
if (!partition_name)
return -ENOMEM;
dev_dbg(blk->dev, "Registering partition %s on drive %s\n",
partition_name, blk->cdev.name);
ret = devfs_add_partition(blk->cdev.name,
cdev = devfs_add_partition(blk->cdev.name,
start, size, 0, partition_name);
if (ret)
if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev);
goto out;
}
free(partition_name);
@ -70,10 +74,10 @@ static int register_one_partition(struct block_device *blk,
dev_dbg(blk->dev, "Registering partition %s on drive %s\n",
partition_name, blk->cdev.name);
ret = devfs_add_partition(blk->cdev.name,
cdev = devfs_add_partition(blk->cdev.name,
start, size, 0, partition_name);
if (ret)
if (IS_ERR(cdev))
dev_warn(blk->dev, "Registering partition %s on drive %s failed\n",
partition_name, blk->cdev.name);

View File

@ -24,5 +24,6 @@ source "drivers/dma/Kconfig"
source "drivers/gpio/Kconfig"
source "drivers/w1/Kconfig"
source "drivers/pinctrl/Kconfig"
source "drivers/bus/Kconfig"
endmenu

View File

@ -23,3 +23,4 @@ obj-y += gpio/
obj-$(CONFIG_OFTREE) += of/
obj-$(CONFIG_W1) += w1/
obj-y += pinctrl/
obj-y += bus/

7
drivers/bus/Kconfig Normal file
View File

@ -0,0 +1,7 @@
menu "Bus devices"
config IMX_WEIM
depends on ARCH_IMX
bool "i.MX WEIM driver"
endmenu

1
drivers/bus/Makefile Normal file
View File

@ -0,0 +1 @@
obj-$(CONFIG_IMX_WEIM) += imx-weim.o

171
drivers/bus/imx-weim.c Normal file
View File

@ -0,0 +1,171 @@
/*
* EIM driver for Freescale's i.MX chips
*
* Copyright (C) 2013 Freescale Semiconductor, Inc.
*
* 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 <common.h>
#include <driver.h>
#include <init.h>
#include <io.h>
#include <of.h>
struct imx_weim_devtype {
unsigned int cs_count;
unsigned int cs_regs_count;
unsigned int cs_stride;
};
static const struct imx_weim_devtype imx1_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 2,
.cs_stride = 0x08,
};
static const struct imx_weim_devtype imx27_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 3,
.cs_stride = 0x10,
};
static const struct imx_weim_devtype imx50_weim_devtype = {
.cs_count = 4,
.cs_regs_count = 6,
.cs_stride = 0x18,
};
static const struct imx_weim_devtype imx51_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 6,
.cs_stride = 0x18,
};
static struct of_device_id weim_id_table[] = {
{
/* i.MX1/21 */
.compatible = "fsl,imx1-weim",
.data = (unsigned long)&imx1_weim_devtype,
}, {
/* i.MX25/27/31/35 */
.compatible = "fsl,imx27-weim",
.data = (unsigned long)&imx27_weim_devtype,
}, {
/* i.MX50/53/6Q */
.compatible = "fsl,imx50-weim",
.data = (unsigned long)&imx50_weim_devtype,
}, {
/* i.MX51 */
.compatible = "fsl,imx51-weim",
.data = (unsigned long)&imx51_weim_devtype,
}, {
.compatible = "fsl,imx6q-weim",
.data = (unsigned long)&imx50_weim_devtype,
}, {
}
};
struct imx_weim {
struct device_d *dev;
void __iomem *base;
struct imx_weim_devtype *devtype;
};
/* Parse and set the timing for this device. */
static int
weim_timing_setup(struct imx_weim *weim, struct device_node *np)
{
struct imx_weim_devtype *devtype = weim->devtype;
u32 cs_idx, value[devtype->cs_regs_count];
int i, ret;
/* get the CS index from this child node's "reg" property. */
ret = of_property_read_u32(np, "reg", &cs_idx);
if (ret)
return ret;
if (cs_idx >= devtype->cs_count)
return -EINVAL;
ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
value, devtype->cs_regs_count);
if (ret)
return ret;
dev_dbg(weim->dev, "setting up cs for %s\n", np->name);
/* set the timing for WEIM */
for (i = 0; i < devtype->cs_regs_count; i++)
writel(value[i], weim->base + cs_idx * devtype->cs_stride + i * 4);
return 0;
}
static int weim_parse_dt(struct imx_weim *weim)
{
struct device_node *child;
int ret;
for_each_child_of_node(weim->dev->device_node, child) {
if (!child->name)
continue;
ret = weim_timing_setup(weim, child);
if (ret) {
dev_err(weim->dev, "%s set timing failed.\n",
child->full_name);
return ret;
}
}
ret = of_platform_populate(weim->dev->device_node, NULL, weim->dev);
if (ret)
dev_err(weim->dev, "%s fail to create devices.\n",
weim->dev->device_node->full_name);
return ret;
}
static int weim_probe(struct device_d *dev)
{
struct imx_weim_devtype *devtype;
struct imx_weim *weim;
int ret;
ret = dev_get_drvdata(dev, (unsigned long *)&devtype);
if (ret)
return ret;
weim = xzalloc(sizeof(*weim));
weim->dev = dev;
weim->devtype = devtype;
/* get the resource */
weim->base = dev_request_mem_region(dev, 0);
if (!weim->base) {
ret = -EBUSY;
goto weim_err;
}
/* parse the device node */
ret = weim_parse_dt(weim);
if (ret) {
goto weim_err;
}
dev_info(dev, "WEIM driver registered.\n");
return 0;
weim_err:
return ret;
}
static struct driver_d weim_driver = {
.name = "imx-weim",
.of_compatible = DRV_OF_COMPAT(weim_id_table),
.probe = weim_probe,
};
device_platform_driver(weim_driver);

View File

@ -7,6 +7,10 @@ config LED_GPIO
bool "gpio LED support"
depends on GENERIC_GPIO
config LED_GPIO_OF
bool "support parsing gpio LEDs from device tree"
depends on LED_GPIO && OFTREE
config LED_GPIO_RGB
bool "gpio rgb LED support"
depends on LED_GPIO

View File

@ -18,8 +18,10 @@
*
*/
#include <common.h>
#include <init.h>
#include <led.h>
#include <gpio.h>
#include <of_gpio.h>
static void led_gpio_set(struct led *led, unsigned int value)
{
@ -194,3 +196,79 @@ void led_gpio_rgb_unregister(struct gpio_led *led)
led_unregister(&led->led);
}
#endif /* CONFIG_LED_GPIO_RGB */
#ifdef CONFIG_LED_GPIO_OF
struct led_trg {
const char *str;
enum led_trigger trg;
};
static struct led_trg triggers[] = {
{ .str = "heartbeat", LED_TRIGGER_HEARTBEAT, },
{ .str = "panic", LED_TRIGGER_PANIC, },
{ .str = "net", LED_TRIGGER_NET_TXRX, },
};
static void led_of_parse_trigger(struct led *led, struct device_node *np)
{
const char *trigger;
int i;
trigger = of_get_property(np, "linux,default-trigger", NULL);
if (!trigger)
trigger = of_get_property(np, "barebox,default-trigger", NULL);
if (!trigger)
return;
for (i = 0; i < ARRAY_SIZE(triggers); i++) {
struct led_trg *trg = &triggers[i];
if (!strcmp(trg->str, trigger)) {
led_set_trigger(trg->trg, led);
return;
}
}
}
static int led_gpio_of_probe(struct device_d *dev)
{
struct device_node *child;
for_each_child_of_node(dev->device_node, child) {
struct gpio_led *gled;
enum of_gpio_flags flags;
int gpio;
gpio = of_get_named_gpio_flags(child, "gpios", 0, &flags);
if (gpio < 0)
continue;
gled = xzalloc(sizeof(*gled));
gled->led.name = xstrdup(child->name);
gled->gpio = gpio;
gled->active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
dev_dbg(dev, "register led %s on gpio%d, active_low = %d\n",
gled->led.name, gled->gpio, gled->active_low);
led_of_parse_trigger(&gled->led, child);
led_gpio_register(gled);
}
return 0;
}
static struct of_device_id led_gpio_of_ids[] = {
{ .compatible = "gpio-leds", },
{ }
};
static struct driver_d led_gpio_of_driver = {
.name = "gpio-leds",
.probe = led_gpio_of_probe,
.of_compatible = DRV_OF_COMPAT(led_gpio_of_ids),
};
device_platform_driver(led_gpio_of_driver);
#endif /* CONFIG LED_GPIO_OF */

View File

@ -406,7 +406,7 @@ static int mci_calc_blk_cnt(uint64_t cap, unsigned shift)
}
static void mci_part_add(struct mci *mci, uint64_t size,
unsigned int part_cfg, char *name, int idx, bool ro,
unsigned int part_cfg, char *name, char *partname, int idx, bool ro,
int area_type)
{
struct mci_part *part = &mci->part[mci->nr_parts];
@ -414,6 +414,7 @@ static void mci_part_add(struct mci *mci, uint64_t size,
part->mci = mci;
part->size = size;
part->blk.cdev.name = name;
part->blk.cdev.partname = partname;
part->blk.blockbits = SECTOR_SHIFT;
part->blk.num_blocks = mci_calc_blk_cnt(size, part->blk.blockbits);
part->area_type = area_type;
@ -482,13 +483,14 @@ static int mmc_change_freq(struct mci *mci)
unsigned int part_size;
for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) {
char *name;
char *name, *partname;
part_size = mci->ext_csd[EXT_CSD_BOOT_MULT] << 17;
name = asprintf("%s.boot%d", mci->cdevname, idx);
partname = asprintf("boot%d", idx);
name = asprintf("%s.%s", mci->cdevname, partname);
mci_part_add(mci, part_size,
EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx,
name, idx, true,
name, partname, idx, true,
MMC_BLK_DATA_AREA_BOOT);
}
@ -1104,7 +1106,7 @@ static int mci_startup(struct mci *mci)
err = mci_set_blocklen(mci, mci->read_bl_len);
mci_part_add(mci, mci->capacity, 0,
mci->cdevname, 0, true,
mci->cdevname, NULL, 0, true,
MMC_BLK_DATA_AREA_MAIN);
return err;
@ -1556,6 +1558,7 @@ static int mci_card_probe(struct mci *mci)
dev_warn(&mci->dev, "No partition table found\n");
rc = 0; /* it's not a failure */
}
of_parse_partitions(&part->blk.cdev, host->hw_dev->device_node);
}
if (IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS) &&

View File

@ -386,6 +386,7 @@ int add_mtd_device(struct mtd_info *mtd, char *devname)
}
devfs_create(&mtd->cdev);
of_parse_partitions(&mtd->cdev, mtd->parent->device_node);
list_for_each_entry(hook, &mtd_register_hooks, hook)
if (hook->add_mtd_device)

View File

@ -18,3 +18,12 @@ config OFDEVICE
config OF_NET
depends on NET
def_bool y
config OF_BAREBOX_DRIVERS
depends on OFDEVICE
bool "Enable barebox specific devicetree configuration drivers"
help
barebox supports being configured from devicetree. This enables
support for this feature. This currently allows to configure the
environment path from devicetree and to partition devices. See
Documentation/devicetree/bindings/barebox/ for more information.

View File

@ -4,3 +4,4 @@ obj-$(CONFIG_GPIOLIB) += of_gpio.o
obj-y += partition.o
obj-y += of_net.o
obj-$(CONFIG_MTD) += of_mtd.o
obj-$(CONFIG_OF_BAREBOX_DRIVERS) += barebox.o of_path.o

99
drivers/of/barebox.c Normal file
View File

@ -0,0 +1,99 @@
/*
* barebox.c
*
* Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* 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 <common.h>
#include <init.h>
#include <io.h>
#include <of.h>
#include <malloc.h>
#include <partition.h>
#include <envfs.h>
struct of_partition {
struct list_head list;
char *nodepath;
struct device_d *dev;
struct device_node *of_partitions;
};
static LIST_HEAD(of_partition_list);
struct device_d *of_find_device_by_node_path(const char *path)
{
struct device_d *dev;
for_each_device(dev) {
if (!dev->device_node)
continue;
if (!strcmp(path, dev->device_node->full_name))
return dev;
}
return NULL;
}
static int environment_probe(struct device_d *dev)
{
char *path;
int ret;
ret = of_find_path(dev->device_node, "device-path", &path);
if (ret)
return ret;
dev_info(dev, "setting default environment path to %s\n", path);
default_environment_path = path;
return 0;
}
static struct of_device_id environment_dt_ids[] = {
{
.compatible = "barebox,environment",
}, {
/* sentinel */
}
};
static struct driver_d environment_driver = {
.name = "barebox-environment",
.probe = environment_probe,
.of_compatible = environment_dt_ids,
};
static int barebox_of_driver_init(void)
{
struct device_node *node;
node = of_get_root_node();
if (!node)
return 0;
node = of_find_node_by_path("/chosen");
if (!node)
return 0;
of_platform_populate(node, of_default_bus_match_table, NULL);
platform_driver_register(&environment_driver);
return 0;
}
late_initcall(barebox_of_driver_init);

View File

@ -1755,3 +1755,68 @@ int of_add_initrd(struct device_node *root, resource_size_t start,
return 0;
}
/**
* of_device_enable - enable a devicenode device
* @node - the node to enable
*
* This deletes the status property of a devicenode effectively
* enabling the device.
*/
int of_device_enable(struct device_node *node)
{
struct property *pp;
pp = of_find_property(node, "status", NULL);
if (!pp)
return 0;
of_delete_property(pp);
return 0;
}
/**
* of_device_enable_path - enable a devicenode
* @path - the nodepath to enable
*
* wrapper around of_device_enable taking the nodepath as argument
*/
int of_device_enable_path(const char *path)
{
struct device_node *node;
node = of_find_node_by_path(path);
if (!node)
return -ENODEV;
return of_device_enable(node);
}
/**
* of_device_enable - disable a devicenode device
* @node - the node to disable
*
* This sets the status of a devicenode to "disabled"
*/
int of_device_disable(struct device_node *node)
{
return of_set_property(node, "status", "disabled", sizeof("disabled"), 1);
}
/**
* of_device_disable_path - disable a devicenode
* @path - the nodepath to disable
*
* wrapper around of_device_disable taking the nodepath as argument
*/
int of_device_disable_path(const char *path)
{
struct device_node *node;
node = of_find_node_by_path(path);
if (!node)
return -ENODEV;
return of_device_disable(node);
}

155
drivers/of/of_path.c Normal file
View File

@ -0,0 +1,155 @@
/*
* of_path.c
*
* Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* 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 <common.h>
#include <malloc.h>
#include <of.h>
struct of_path {
struct cdev *cdev;
struct device_d *dev;
};
struct of_path_type {
const char *name;
int (*parse)(struct of_path *op, const char *str);
};
/**
* of_path_type_partname - find a partition based on physical device and
* partition name
* @op: of_path context
* @name: the partition name to find
*/
static int of_path_type_partname(struct of_path *op, const char *name)
{
if (!op->dev)
return -EINVAL;
op->cdev = device_find_partition(op->dev, name);
if (op->cdev) {
pr_debug("%s: found part '%s'\n", __func__, name);
return 0;
} else {
pr_debug("%s: cannot find part '%s'\n", __func__, name);
return -ENODEV;
}
}
static struct of_path_type of_path_types[] = {
{
.name = "partname",
.parse = of_path_type_partname,
},
};
static int of_path_parse_one(struct of_path *op, const char *str)
{
int i, ret;
char *name, *desc;
pr_debug("parsing: %s\n", str);
name = xstrdup(str);
desc = strchr(name, ':');
if (!desc) {
free(name);
return -EINVAL;
}
*desc = 0;
desc++;
for (i = 0; i < ARRAY_SIZE(of_path_types); i++) {
if (!strcmp(of_path_types[i].name, name)) {
ret = of_path_types[i].parse(op, desc);
goto out;
}
}
ret = -EINVAL;
out:
free(name);
return ret;
}
/**
* of_find_path - translate a path description in the devicetree to a barebox
* path
*
* @node: the node containing the property with the path description
* @propname: the property name of the path description
* @outpath: if this function returns 0 outpath will contain the path belonging
* to the input path description. Must be freed with free().
*
* pathes in the devicetree have the form of a multistring property. The first
* string contains the full path to the physical device containing the path.
* The remaining strings have the form "<type>:<options>". Currently supported
* for <type> are:
*
* partname:<partname> - find a partition by its partition name. For mtd
* partitions this is the label. For DOS partitions
* this is the number beginning with 0.
*
* examples:
*
* device-path = &mmc0, "partname:0";
* device-path = &norflash, "partname:barebox-environment";
*/
int of_find_path(struct device_node *node, const char *propname, char **outpath)
{
struct of_path op = {};
struct device_node *rnode;
const char *path, *str;
int i, len, ret;
path = of_get_property(node, propname, &len);
if (!path)
return -EINVAL;
rnode = of_find_node_by_path(path);
if (!rnode)
return -ENODEV;
op.dev = of_find_device_by_node_path(rnode->full_name);
if (!op.dev)
return -ENODEV;
device_detect(op.dev);
i = 1;
while (1) {
ret = of_property_read_string_index(node, propname, i++, &str);
if (ret)
break;
ret = of_path_parse_one(&op, str);
if (ret)
return ret;
}
if (!op.cdev)
return -ENOENT;
*outpath = asprintf("/dev/%s", op.cdev->name);
return 0;
}

View File

@ -23,44 +23,58 @@
#include <linux/mtd/mtd.h>
#include <nand.h>
struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node)
{
const char *partname;
char *filename;
struct cdev *new;
const __be32 *reg;
unsigned long offset, size;
const char *name;
int len;
unsigned long flags = 0;
if (!node)
return NULL;
reg = of_get_property(node, "reg", &len);
if (!reg)
return NULL;
offset = be32_to_cpu(reg[0]);
size = be32_to_cpu(reg[1]);
partname = of_get_property(node, "label", &len);
if (!partname)
partname = of_get_property(node, "name", &len);
name = (char *)partname;
debug("add partition: %s.%s 0x%08lx 0x%08lx\n", cdev->name, partname, offset, size);
if (of_get_property(node, "read-only", &len))
flags = DEVFS_PARTITION_READONLY;
filename = asprintf("%s.%s", cdev->name, partname);
new = devfs_add_partition(cdev->name, offset, size, flags, filename);
if (cdev->mtd && cdev->mtd->type == MTD_NANDFLASH)
dev_add_bb_dev(filename, NULL);
free(filename);
return new;
}
int of_parse_partitions(struct cdev *cdev, struct device_node *node)
{
struct device_node *n;
const char *partname;
char *filename;
if (!node)
return -EINVAL;
for_each_child_of_node(node, n) {
const __be32 *reg;
unsigned long offset, size;
const char *name;
int len;
unsigned long flags = 0;
reg = of_get_property(n, "reg", &len);
if (!reg)
continue;
offset = be32_to_cpu(reg[0]);
size = be32_to_cpu(reg[1]);
partname = of_get_property(n, "label", &len);
if (!partname)
partname = of_get_property(n, "name", &len);
name = (char *)partname;
debug("add partition: %s.%s 0x%08lx 0x%08lx\n", cdev->name, partname, offset, size);
if (of_get_property(n, "read-only", &len))
flags = DEVFS_PARTITION_READONLY;
filename = asprintf("%s.%s", cdev->name, partname);
devfs_add_partition(cdev->name, offset, size, flags, filename);
if (cdev->mtd && cdev->mtd->type == MTD_NANDFLASH)
dev_add_bb_dev(filename, NULL);
free(filename);
of_parse_partition(cdev, n);
}
return 0;

View File

@ -56,6 +56,33 @@ struct cdev *cdev_by_name(const char *filename)
return NULL;
}
/**
* device_find_partition - find a partition belonging to a physical device
*
* @dev: the device which should be searched for partitions
* @name: the partition name
*/
struct cdev *device_find_partition(struct device_d *dev, const char *name)
{
struct cdev *cdev;
struct device_d *child;
list_for_each_entry(cdev, &dev->cdevs, devices_list) {
if (!cdev->partname)
continue;
if (!strcmp(cdev->partname, name))
return cdev;
}
device_for_each_child(dev, child) {
cdev = device_find_partition(child, name);
if (cdev)
return cdev;
}
return NULL;
}
int cdev_find_free_index(const char *basename)
{
int i;
@ -70,6 +97,14 @@ int cdev_find_free_index(const char *basename)
return -EBUSY; /* all indexes are used */
}
int cdev_do_open(struct cdev *cdev, unsigned long flags)
{
if (cdev->ops->open)
return cdev->ops->open(cdev, flags);
return 0;
}
struct cdev *cdev_open(const char *name, unsigned long flags)
{
struct cdev *cdev = cdev_by_name(name);
@ -78,11 +113,9 @@ struct cdev *cdev_open(const char *name, unsigned long flags)
if (!cdev)
return NULL;
if (cdev->ops->open) {
ret = cdev->ops->open(cdev, flags);
if (ret)
return NULL;
}
ret = cdev_do_open(cdev, flags);
if (ret)
return NULL;
return cdev;
}
@ -226,24 +259,26 @@ int devfs_remove(struct cdev *cdev)
return 0;
}
int devfs_add_partition(const char *devname, loff_t offset, loff_t size,
struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size,
int flags, const char *name)
{
struct cdev *cdev, *new;
cdev = cdev_by_name(name);
if (cdev)
return -EEXIST;
return ERR_PTR(-EEXIST);
cdev = cdev_by_name(devname);
if (!cdev)
return -ENOENT;
return ERR_PTR(-ENOENT);
if (offset + size > cdev->size)
return -EINVAL;
return ERR_PTR(-EINVAL);
new = xzalloc(sizeof (*new));
new->name = strdup(name);
if (!strncmp(devname, name, strlen(devname)))
new->partname = xstrdup(name + strlen(devname) + 1);
new->ops = cdev->ops;
new->priv = cdev->priv;
new->size = size;
@ -257,14 +292,14 @@ int devfs_add_partition(const char *devname, loff_t offset, loff_t size,
if (IS_ERR(new->mtd)) {
int ret = PTR_ERR(new->mtd);
free(new);
return ret;
return ERR_PTR(ret);
}
}
#endif
devfs_create(new);
return 0;
return new;
}
int devfs_del_partition(const char *name)
@ -291,6 +326,7 @@ int devfs_del_partition(const char *name)
return ret;
free(cdev->name);
free(cdev->partname);
free(cdev);
return 0;

View File

@ -447,7 +447,10 @@ struct cdev {
struct device_d *dev;
struct list_head list;
struct list_head devices_list;
char *name;
char *name; /* filename under /dev/ */
char *partname; /* the partition name, usually the above without the
* device part, i.e. name = "nand0.barebox" -> partname = "barebox"
*/
loff_t offset;
loff_t size;
unsigned int flags;
@ -458,8 +461,10 @@ struct cdev {
int devfs_create(struct cdev *);
int devfs_remove(struct cdev *);
int cdev_find_free_index(const char *);
struct cdev *device_find_partition(struct device_d *dev, const char *name);
struct cdev *cdev_by_name(const char *filename);
struct cdev *cdev_open(const char *name, unsigned long flags);
int cdev_do_open(struct cdev *, unsigned long flags);
void cdev_close(struct cdev *cdev);
int cdev_flush(struct cdev *cdev);
ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags);
@ -472,7 +477,7 @@ int cdev_erase(struct cdev *cdev, size_t count, loff_t offset);
#define DEVFS_IS_PARTITION (1 << 2)
#define DEVFS_IS_CHARACTER_DEV (1 << 3)
int devfs_add_partition(const char *devname, loff_t offset, loff_t size,
struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size,
int flags, const char *name);
int devfs_del_partition(const char *name);

View File

@ -221,6 +221,7 @@ extern int of_platform_populate(struct device_node *root,
struct device_d *parent);
extern struct device_d *of_find_device_by_node(struct device_node *np);
struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node);
int of_parse_partitions(struct cdev *cdev, struct device_node *node);
int of_device_is_stdout_path(struct device_d *dev);
const char *of_get_model(void);
@ -228,6 +229,8 @@ void *of_flatten_dtb(struct device_node *node);
int of_add_memory(struct device_node *node, bool dump);
void of_add_memory_bank(struct device_node *node, bool dump, int r,
u64 base, u64 size);
struct device_d *of_find_device_by_node_path(const char *path);
int of_find_path(struct device_node *node, const char *propname, char **outpath);
#else
static inline int of_parse_partitions(struct cdev *cdev,
struct device_node *node)
@ -679,4 +682,11 @@ static inline int of_property_write_u64(struct device_node *np,
return of_property_write_u64_array(np, propname, &value, 1);
}
extern const struct of_device_id of_default_bus_match_table[];
int of_device_enable(struct device_node *node);
int of_device_enable_path(const char *path);
int of_device_disable(struct device_node *node);
int of_device_disable_path(const char *path);
#endif /* __OF_H */