From: Jiang Lu <lu.ji...@windriver.com> Extracted from lsi.patch in lsi_acp_linux_6.8.1.18 tarball.
Add the support to read the env value in env-0 and env-1 partitions. This function is needed by some drivers. [Jiang: change file name to lsi_ubootenv.c] Signed-off-by: Jiang Lu <lu.ji...@windriver.com> --- drivers/mtd/nand/Kconfig | 6 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/lsi_ubootenv.c | 568 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 575 insertions(+) create mode 100644 drivers/mtd/nand/lsi_ubootenv.c diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 102ad83..44c1d75 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -534,4 +534,10 @@ config MTD_NAND_EP501X Enables NAND flash support for the Eureka EP501, EP501G1 and EP501G3 controllers. +config MTD_NAND_EP501X_UBOOTENV + tristate "U-Boot Environment Access for LSI's APP and ACP" + depends on ( MTD_NAND_EP501X && CRC32 ) + help + Add U-Boot environment access on LSI's APP/ACP boards. + endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 01a11f8..035b353 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -52,5 +52,6 @@ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ obj-$(CONFIG_MTD_NAND_EP501X) += lsi_acp_nand.o +obj-$(CONFIG_MTD_NAND_EP501X_UBOOTENV) += lsi_ubootenv.o nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/lsi_ubootenv.c b/drivers/mtd/nand/lsi_ubootenv.c new file mode 100644 index 0000000..d9ad283 --- /dev/null +++ b/drivers/mtd/nand/lsi_ubootenv.c @@ -0,0 +1,568 @@ +/* + * drivers/lsi/acp/ubootenv.c + * + * Copyright (C) 2009 LSI + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021.1.1_pre.17 USA + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/vmalloc.h> +#include <linux/mtd/mtd.h> +#include <linux/crc32.h> +#include <linux/io.h> + +/* + ====================================================================== + Data types and Macros + ====================================================================== +*/ +#include <asm/lsi/debug.h> + +/* + ====================================================================== + Global Variables + ====================================================================== +*/ + +static struct kobject *ubootenv_kobj; + + +static unsigned long uboot_env_size = (128 * 1024); +static unsigned long uboot_env_cs_size = (128 * 1024); +static int uboot_env_current = -1; + +#define ENVIRONMENT_DATA_SIZE(size) (size - (2 * sizeof(unsigned long))) + +typedef struct environment { + + unsigned long crc32; + unsigned long flags; + unsigned char data[]; + +} __packed environment_t; + +static environment_t *environment = (environment_t *) 0; + +static unsigned long crc32_lut[256] = { + + /* 0 -- */ 0u, 1996959894u, 3993919788u, 2567524794u, + /* 4 -- */ 124634137u, 1886057615u, 3915621685u, 2657392035u, + /* 8 -- */ 249268274u, 2044508324u, 3772115230u, 2547177864u, + /* 12 -- */ 162941995u, 2125561021u, 3887607047u, 2428444049u, + /* 16 -- */ 498536548u, 1789927666u, 4089016648u, 2227061214u, + /* 20 -- */ 450548861u, 1843258603u, 4107580753u, 2211677639u, + /* 24 -- */ 325883990u, 1684777152u, 4251122042u, 2321926636u, + /* 28 -- */ 335633487u, 1661365465u, 4195302755u, 2366115317u, + /* 32 -- */ 997073096u, 1281953886u, 3579855332u, 2724688242u, + /* 36 -- */ 1006888145u, 1258607687u, 3524101629u, 2768942443u, + /* 40 -- */ 901097722u, 1119000684u, 3686517206u, 2898065728u, + /* 44 -- */ 853044451u, 1172266101u, 3705015759u, 2882616665u, + /* 48 -- */ 651767980u, 1373503546u, 3369554304u, 3218104598u, + /* 52 -- */ 565507253u, 1454621731u, 3485111705u, 3099436303u, + /* 56 -- */ 671266974u, 1594198024u, 3322730930u, 2970347812u, + /* 60 -- */ 795835527u, 1483230225u, 3244367275u, 3060149565u, + /* 64 -- */ 1994146192u, 31158534u, 2563907772u, 4023717930u, + /* 68 -- */ 1907459465u, 112637215u, 2680153253u, 3904427059u, + /* 72 -- */ 2013776290u, 251722036u, 2517215374u, 3775830040u, + /* 76 -- */ 2137656763u, 141376813u, 2439277719u, 3865271297u, + /* 80 -- */ 1802195444u, 476864866u, 2238001368u, 4066508878u, + /* 84 -- */ 1812370925u, 453092731u, 2181625025u, 4111451223u, + /* 88 -- */ 1706088902u, 314042704u, 2344532202u, 4240017532u, + /* 92 -- */ 1658658271u, 366619977u, 2362670323u, 4224994405u, + /* 96 -- */ 1303535960u, 984961486u, 2747007092u, 3569037538u, + /* 100 -- */ 1256170817u, 1037604311u, 2765210733u, 3554079995u, + /* 104 -- */ 1131014506u, 879679996u, 2909243462u, 3663771856u, + /* 108 -- */ 1141124467u, 855842277u, 2852801631u, 3708648649u, + /* 112 -- */ 1342533948u, 654459306u, 3188396048u, 3373015174u, + /* 116 -- */ 1466479909u, 544179635u, 3110523913u, 3462522015u, + /* 120 -- */ 1591671054u, 702138776u, 2966460450u, 3352799412u, + /* 124 -- */ 1504918807u, 783551873u, 3082640443u, 3233442989u, + /* 128 -- */ 3988292384u, 2596254646u, 62317068u, 1957810842u, + /* 132 -- */ 3939845945u, 2647816111u, 81470997u, 1943803523u, + /* 136 -- */ 3814918930u, 2489596804u, 225274430u, 2053790376u, + /* 140 -- */ 3826175755u, 2466906013u, 167816743u, 2097651377u, + /* 144 -- */ 4027552580u, 2265490386u, 503444072u, 1762050814u, + /* 148 -- */ 4150417245u, 2154129355u, 426522225u, 1852507879u, + /* 152 -- */ 4275313526u, 2312317920u, 282753626u, 1742555852u, + /* 156 -- */ 4189708143u, 2394877945u, 397917763u, 1622183637u, + /* 160 -- */ 3604390888u, 2714866558u, 953729732u, 1340076626u, + /* 164 -- */ 3518719985u, 2797360999u, 1068828381u, 1219638859u, + /* 168 -- */ 3624741850u, 2936675148u, 906185462u, 1090812512u, + /* 172 -- */ 3747672003u, 2825379669u, 829329135u, 1181335161u, + /* 176 -- */ 3412177804u, 3160834842u, 628085408u, 1382605366u, + /* 180 -- */ 3423369109u, 3138078467u, 570562233u, 1426400815u, + /* 184 -- */ 3317316542u, 2998733608u, 733239954u, 1555261956u, + /* 188 -- */ 3268935591u, 3050360625u, 752459403u, 1541320221u, + /* 192 -- */ 2607071920u, 3965973030u, 1969922972u, 40735498u, + /* 196 -- */ 2617837225u, 3943577151u, 1913087877u, 83908371u, + /* 200 -- */ 2512341634u, 3803740692u, 2075208622u, 213261112u, + /* 204 -- */ 2463272603u, 3855990285u, 2094854071u, 198958881u, + /* 208 -- */ 2262029012u, 4057260610u, 1759359992u, 534414190u, + /* 212 -- */ 2176718541u, 4139329115u, 1873836001u, 414664567u, + /* 216 -- */ 2282248934u, 4279200368u, 1711684554u, 285281116u, + /* 220 -- */ 2405801727u, 4167216745u, 1634467795u, 376229701u, + /* 224 -- */ 2685067896u, 3608007406u, 1308918612u, 956543938u, + /* 228 -- */ 2808555105u, 3495958263u, 1231636301u, 1047427035u, + /* 232 -- */ 2932959818u, 3654703836u, 1088359270u, 936918000u, + /* 236 -- */ 2847714899u, 3736837829u, 1202900863u, 817233897u, + /* 240 -- */ 3183342108u, 3401237130u, 1404277552u, 615818150u, + /* 244 -- */ 3134207493u, 3453421203u, 1423857449u, 601450431u, + /* 248 -- */ 3009837614u, 3294710456u, 1567103746u, 711928724u, + /* 252 -- */ 3020668471u, 3272380065u, 1510334235u, 755167117u + +}; + +/* + ====================================================================== + Prototypes + ====================================================================== +*/ + +static unsigned long ubootenv_crc32(unsigned char *, unsigned long); +static int ubootenv_initialize(void); +static void ubootenv_finalize(void); +static int ubootenv_read(struct mtd_info *, size_t, void *); +static void create_env_sysfs(void); +/* + ====================================================================== + ====================================================================== +*/ + +/* + ---------------------------------------------------------------------- + ubootenv_crc32 +*/ + +static unsigned long +ubootenv_crc32(unsigned char *start, unsigned long size) +{ + unsigned long crc = (unsigned long)0xffffffff, index; + + DEBUG_PRINT("start=0x%lx size=0x%lx\n", (unsigned long)start, size); + + for (index = 0; index < size; index++) { + unsigned long temp = (crc ^ *(start++)) & 0x000000ff; + crc = ((crc >> 8) & 0x00ffffff) ^ crc32_lut[temp]; + } + return ~crc; +} + +/* + ---------------------------------------------------------------------- + ubootenv_read +*/ + +static int +ubootenv_read(struct mtd_info *mtd, size_t size, void *buffer) +{ + int read = 0; + loff_t offset = 0; + + DEBUG_PRINT("size=0x%x mtd->erasesize=0x%x mtd->size=0x%llx\n", + size, mtd->erasesize, mtd->size); + + if (0 != size % mtd->erasesize) { + ERROR_PRINT("size=%u/%llu is not a multiple of erasesize=%u\n", + size, mtd->size, mtd->erasesize); + return -1; + } + + if (size > mtd->size) { + ERROR_PRINT("size=%llu can't contain size=%u\n", + mtd->size, size); + return -1; + } + + while ((read < size) && (offset < mtd->size)) { + int return_code; + size_t bytes_read; + + DEBUG_PRINT("read=0x%x size=0x%x offset=0x%llx\n", + read, size, offset); + + if (0 != mtd_block_isbad(mtd, offset)) { + offset += mtd->erasesize; + continue; + } + + return_code = mtd_read(mtd, offset, mtd->erasesize, + &bytes_read, (u_char *) buffer); + + if (mtd->erasesize != bytes_read) { + ERROR_PRINT("Error Reading Environment!\n"); + return -1; + } + + offset += mtd->erasesize; + read += mtd->erasesize; + buffer += mtd->erasesize; + } + + return 0; +} + +/* + ---------------------------------------------------------------------- + ubootenv_initialize +*/ + +static int +ubootenv_initialize(void) +{ + environment_t *env0; + environment_t *env1; + unsigned long crc32_env0; + unsigned long crc32_env1; + struct mtd_info *mtd_env0; + struct mtd_info *mtd_env1; + + DEBUG_PRINT("Getting MTD Devices.\n"); + + mtd_env0 = get_mtd_device_nm("env-0"); + if ((struct mtd_info *)-ENODEV == mtd_env0) { + ERROR_PRINT(" --> Couldn't get MTD device by name!\n"); + return -1; + } + + mtd_env1 = get_mtd_device_nm("env-1"); + if ((struct mtd_info *)-ENODEV == mtd_env1) { + ERROR_PRINT(" --> Couldn't get MTD device by name!\n"); + return -1; + } + + /* + * If the erasesize is larger than the size of the environment, + * change the environment size (so reading and writing will + * work as expected) but use the original environment size to + * calculate the checksum. + */ + + if (mtd_env0->erasesize > uboot_env_size) + uboot_env_size = mtd_env0->erasesize; + + DEBUG_PRINT("Allocating Environment Buffers.\n"); + + env0 = vmalloc(uboot_env_size); + if ((environment_t *)0 == env0) { + ERROR_PRINT("Unable to allocate %lu bytes\n", uboot_env_size); + return -1; + } + + env1 = vmalloc(uboot_env_size); + if ((environment_t *) 0 == env1) { + ERROR_PRINT("Unable to allocate %lu bytes\n", uboot_env_size); + vfree((void *) env0); + return -1; + } + + DEBUG_PRINT("Reading Environments.\n"); + + if (0 != ubootenv_read(mtd_env0, uboot_env_size, env0)) + return -1; + + if (0 != ubootenv_read(mtd_env1, uboot_env_size, env1)) + return -1; + + DEBUG_PRINT("Calculating CRC values.\n"); + crc32_env0 = ubootenv_crc32((unsigned char *)env0->data, + ENVIRONMENT_DATA_SIZE(uboot_env_cs_size)); + crc32_env1 = ubootenv_crc32((unsigned char *)env1->data, + ENVIRONMENT_DATA_SIZE(uboot_env_cs_size)); + DEBUG_PRINT("crc32_env0=0x%lx env0->crc32=0x%lx\n", + crc32_env0, env0->crc32); + DEBUG_PRINT("crc32_env2=0x%lx env1->crc32=0x%lx\n", + crc32_env1, env1->crc32); + DEBUG_PRINT("Picking a Copy.\n"); + + if ((crc32_env0 == env0->crc32) && + (crc32_env1 != env1->crc32)) { + /* Use env0 */ + DEBUG_PRINT("Using Copy 0.\n"); + uboot_env_current = 0; + vfree((void *) env1); + environment = env0; + } else if ((crc32_env0 != env0->crc32) && + (crc32_env1 == env1->crc32)) { + /* Use env1 */ + DEBUG_PRINT("Using Copy 1.\n"); + uboot_env_current = 1; + vfree((void *) env0); + environment = env1; + } else if ((crc32_env0 != env0->crc32) && + (crc32_env1 != env1->crc32)) { + /* No Environment Available */ + uboot_env_current = -1; + vfree((void *) env0); + vfree((void *) env1); + ERROR_PRINT("Bad CRCs: No Valid U-Boot Environment Found!\n"); + return -1; + } else if (env0->flags > env1->flags) { + /* Use env0 */ + DEBUG_PRINT("Using Copy 0.\n"); + uboot_env_current = 0; + vfree((void *) env1); + environment = env0; + } else if (env0->flags < env1->flags) { + /* Use env1 */ + DEBUG_PRINT("Using Copy 1.\n"); + uboot_env_current = 1; + vfree((void *) env0); + environment = env1; + } else if (env0->flags == env1->flags) { + /* Use Either */ + DEBUG_PRINT("Using Copy 0.\n"); + uboot_env_current = 0; + vfree((void *) env1); + environment = env0; + } else { + /* No Environment Available */ + uboot_env_current = -1; + vfree((void *) env0); + vfree((void *) env1); + ERROR_PRINT("Bad Flags: No Valid U-Boot Environment Found!\n"); + return -1; + } + + DEBUG_PRINT("Done...\n"); + create_env_sysfs(); + + return 0; +} + +/* + ---------------------------------------------------------------------- + ubootenv_finalize +*/ + +static void +ubootenv_finalize(void) +{ + DEBUG_PRINT("Freeing the environment.\n"); + + if ((void *)0 != environment) + vfree((void *)environment); + + environment = (environment_t *)0; +} + +/* + ====================================================================== + Public Interface + ====================================================================== +*/ + +/* + ---------------------------------------------------------------------- + ubootenv_get +*/ + +int +ubootenv_get(const char *key, char *value) +{ + int return_code = -1; + char *string; + + if (NULL == environment) { + ERROR_PRINT("Environment Isn't Available!\n"); + return -1; + } + + string = environment->data; + + while (0x00 != string[0]) { + if (0 == strncmp(key, string, strlen(key))) { + char *value_ = strchr(string, '='); + ++value_; + strcpy(value, value_); + return_code = 0; + break; + } + + string += (strlen(string) + 1); + } + + return return_code; +} +EXPORT_SYMBOL(ubootenv_get); + +/* + ====================================================================== + ====================================================================== + Sysfs Stuff + ====================================================================== + ====================================================================== +*/ + +struct bin_attribute uboot_env[100]; + +static ssize_t read_env(struct file *filep, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t size) +{ + int retsize = -1; + char *string; + + if (size <= 1) + return 0; + + if (NULL == environment) { + ERROR_PRINT("Environment Isn't Available!\n"); + return -1; + } + + string = environment->data; + + while (0x00 != string[0]) { + if (0 == strncmp(bin_attr->attr.name, + string, strlen(bin_attr->attr.name))) { + char *value_ = strchr(string, '='); + ++value_; + + retsize = 1 + strlcpy(buf, value_, size); + break; + } + + string += (strlen(string) + 1); + } + + return retsize; +} + +static void create_env_sysfs(void) +{ + char *string; + int i = 0; + + if (NULL == environment) { + ERROR_PRINT("Environment Isn't Available!\n"); + return; + } + + string = environment->data; + + while (0x00 != string[0]) { + char *value_ = strchr(string, '='); + char *name = vmalloc(1 + value_ - string); + strlcpy(name, string, 1 + value_ - string); + + uboot_env[i].attr.name = name; + uboot_env[i].attr.mode = 0400; + uboot_env[i].size = strlen(string) - (value_ - string) ; + uboot_env[i].read = read_env; + + if (sysfs_create_bin_file(ubootenv_kobj, &uboot_env[i])) + ERROR_PRINT("unable to add uboot-env sysfs file\n"); + + string += (strlen(string) + 1); + i++; + if (i > 99) { + ERROR_PRINT("More than 100 uboot env variables.\n"); + return; + } + } +} + + +static ssize_t list_env(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i = 1; + while (i < uboot_env_size - 2) { + if (environment->data[i-1] == 0) + if (environment->data[i] == 0) + if (environment->data[i+1] == 0) + break; + i++; + } + memcpy(buf, environment->data, i); + return i; +} + +static DEVICE_ATTR(list_env, 0444, list_env, NULL); + +static struct attribute *attrs[] = { + &dev_attr_list_env.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + + +/* + ====================================================================== + ====================================================================== + Linux Module Stuff + ====================================================================== + ====================================================================== +*/ + +/* + ---------------------------------------------------------------------- + ubootenv_module_init +*/ + +int __init +ubootenv_module_init(void) +{ + int retval; + + DEBUG_PRINT("\n"); + ubootenv_kobj = kobject_create_and_add("uboot-env", kernel_kobj); + if (!ubootenv_kobj) + return -ENOMEM; + + /* Create the files associated with this kobject */ + retval = sysfs_create_group(ubootenv_kobj, &attr_group); + if (retval) + goto fail; + + retval = ubootenv_initialize(); + if (retval) + goto fail; + + return 0; +fail: + kobject_put(ubootenv_kobj); + + return retval; +} + +module_init(ubootenv_module_init); + +/* + ---------------------------------------------------------------------- + ubootenv_module_exit +*/ + +void __exit +ubootenv_module_exit(void) +{ + DEBUG_PRINT("\n"); + kobject_put(ubootenv_kobj); + ubootenv_finalize(); + return; +} + +module_exit(ubootenv_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Jacques <john.jacq...@lsi.com>"); +MODULE_DESCRIPTION("Read Access of the U-Boot Environment"); -- 1.8.3 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto