diff options
162 files changed, 2496 insertions, 1089 deletions
diff --git a/Documentation/user/reset-reason.rst b/Documentation/user/reset-reason.rst new file mode 100644 index 0000000000..26d37f86dd --- /dev/null +++ b/Documentation/user/reset-reason.rst @@ -0,0 +1,47 @@ +.. _reset_reason: + +Reset Reason +------------ + +To handle a device in a secure and safe manner many applications are using +a watchdog or other ways to reset a system to bring it back into life if it +hangs or crashes somehow. + +In these cases the hardware restarts and runs the bootloader again. Depending on +the root cause of the hang or crash, the bootloader sometimes should not just +re-start the main system again. Maybe it should do some kind of recovery instead. +For example it should wait for another update (for the case the cause of a +crash is a failed update) or should start into a fall back system instead. + +In order to handle failing systems gracefully the bootloader needs the +information why it runs. This is called the "reset reason". It is provided by +the global variable ``system.reset`` and can be used in scripts via +``$global.system.reset``. + +The following values can help to detect the reason why the bootloader runs: + +* ``unknown``: the software wasn't able to detect the reset cause or there + isn't support for this feature at all. +* ``POR`` (Power On Reset): a cold start. The power of the system + was switched on. This is a regular state and nothing to worry about. +* ``RST`` (ReSeT): a warm start. The user has triggered a reset somehow. This + is a regular state and nothing to worry about. +* ``WDG`` (WatchDoG): also some kind of warm start, but triggered by a watchdog + unit. It depends on the application if this reason signals a regular state + and therefore nothing to worry about, or if this state was entered by a hanging + or crashed system and must implicitly be handled. +* ``WKE`` (WaKEup): a mixture of cold and warm start. The system is woken up + from some state of suspend. This is a regular state and nothing to worry + about. +* ``JTAG``: an external JTAG based debugger has triggered the reset. +* ``THERM`` (THERMal): some SoCs are able to detect if they got reset in + response to an overtemperature event. This can be a regular state and nothing + to worry about (the reset has brought the system back into a safe state) or + must implicitly be handled. +* ``EXT`` (EXTernal): some SoCs have special device pins for external reset + signals other than the ``RST`` one. Application specific how to handle this + state. + +It depends on your board/SoC and its features if the hardware is able to detect +these reset reasons. Most of the time only ``POR`` and ``RST`` are supported +but often ``WDG`` as well. diff --git a/Documentation/user/system-reset.rst b/Documentation/user/system-reset.rst new file mode 100644 index 0000000000..e76e3a23c1 --- /dev/null +++ b/Documentation/user/system-reset.rst @@ -0,0 +1,64 @@ +.. _system_reset: + +System Restart +-------------- + +When running the reset command barebox restarts the SoC somehow. Restart can +be done in software, but a more reliable way is to use a hard reset line, which +really resets the whole machine. +The most common way to force such a hard reset is by using a watchdog. Its +trigger time will be setup as short as possible and after that the software just +waits for its reset. Very simple and most of the time it does what's expected. + +But there are some drawbacks within this simple approach. + +* most used watchdogs are built-in units in the SoCs. There is nothing wrong + with that, but these units can mostly reset the CPU core and sometimes a little + bit more of the SoC. This means this reset is not exactly the same than the + real POR (e.g. power on reset). In this case you must still handle different + hardware in a special way because it hasn't seen the reset the CPU has seen. + Enabled DMA units for example can continue to run and transfer data while the + CPU core runs through its reset code. This can trigger very strange failures. + +* when interacting with flash memories (mostly NOR types and used to store the + root filesystem) it cannot provide data (sometimes called 'array mode') the + CPU wants to read after a reset while it is still in some programming mode. + And if the software is currently changing some data inside the flash and + an internal reset happens the CPU and the flash memory are doing different + things and the system hangs until a real POR which also resets the flash + memory into the 'array mode'. + +* some SoC's boot behaviour gets parametrized by so called 'bootstrap pins'. + These pins can have a different meaning at reset time and at run-time later + on (multi purpose pins) but their correct values at reset time are very + important to boot the SoC sucessfully. If external devices are connected to + these multi purpose pins they can disturb the reset values, and so parametrizing + the boot behaviour differently and hence crashing the SoC until the next real + POR happens which also resets the external devices (and keep them away from the + multi purpose pins). + +* when power management comes into play another level of failure is + possible. To save power the software can lower the clock(s), but to really + save power, the power supply voltages must be lowered as well. Most PMICs + (e.g. power management controllers) are dedicated external companion devices, + loosely connected to their SoC. If the SoC's internal reset source now resets + the CPU it may increases its clock(s) back to the frequencies after a POR, but + the external PMIC still provides voltages related to lower frequencies. The + system isn't consistent any more. If you are in luck, the SoC still works + somehow, even if the voltages are out of their specifications for the + currently used clock speeds. But don't rely on it. + +To workaround these issues the reset signal triggered by a SoC internal source +must be 'visible' to the external devices to also reset them like a real POR does. +But many SoCs do not provide such a signal. So you can't use the internal reset +source if you face one of the above listed issues! + +A different solution is to use the PMIC (if available) to trigger the reset. +Many PMICs provide their own watchdog units and if they trigger a reset they +also switch their voltages back to the real POR values. This will be a system +wide reset, like the POR is. + +Drawback of the PMIC solution is, you can't use the SoC's internal mechanisms to +detect the :ref:`reset_reason` anymore. From the SoC point of view it is always +a POR when the PMIC handles the system reset. If you are in luck the PMIC +instead can provide this information if you depend on it. diff --git a/Documentation/user/ubi.rst b/Documentation/user/ubi.rst index a187680e2c..c300c0f951 100644 --- a/Documentation/user/ubi.rst +++ b/Documentation/user/ubi.rst @@ -5,9 +5,6 @@ barebox has both UBI and UBIFS support. For handling UBI barebox has commands si the Linux commands :ref:`command_ubiformat`, :ref:`command_ubiattach`, :ref:`command_ubidetach`, :ref:`command_ubimkvol` and :ref:`command_ubirmvol`. -The following examples assume we work on the first UBI device. Replace ``ubi0`` with -the appropriate number when you have multiple UBI devices. - The first step for preparing a pristine Flash for UBI is to :ref:`command_ubiformat` the device: @@ -28,17 +25,17 @@ After a device has been formatted it can be attached with :ref:`command_ubiattac ubiattach /dev/nand0.root -This will create the controlling node ``/dev/ubi0`` and also register all volumes present -on the device as ``/dev/ubi0.<volname>``. When freshly formatted there won't be any volumes -present. A volume can be created with: +This will create the controlling node ``/dev/nand0.root.ubi`` and also register all volumes +present on the device as ``/dev/nand0.root.ubi.<volname>``. When freshly formatted there won't +be any volumes present. A volume can be created with: .. code-block:: sh - ubimkvol /dev/ubi0 root 0 + ubimkvol /dev/nand0.root.ubi root 0 The first parameter is the controlling node. The second parameter is the name of the volume. -In this case the volume can be found under ``/dev/ubi.root``. The third parameter contains -the size. A size of zero means that all available space shall be used. +In this case the volume can be found under ``/dev/dev/nand0.root.ubi.root``. The third +parameter contains the size. A size of zero means that all available space shall be used. The next step is to write a UBIFS image to the volume. The image must be created on a host using the ``mkfs.ubifs`` command. ``mkfs.ubifs`` requires several arguments for describing the @@ -46,7 +43,7 @@ flash layout. Values for these arguments can be retrieved from a ``devinfo ubi`` .. code-block:: sh - barebox@Phytec pcm970:/ devinfo ubi0 + barebox@Phytec pcm970:/ devinfo nand0.root.ubi Parameters: peb_size: 16384 leb_size: 15360 @@ -76,38 +73,27 @@ The UBIFS image can be transferred to the board for example with TFTP: .. code-block:: sh - cp /mnt/tftp/root.ubifs /dev/ubi0.root + cp /mnt/tftp/root.ubifs /dev/nand0.root.ubi.root Finally it can be mounted using the :ref:`command_mount` command: .. code-block:: sh - mkdir -p /mnt/ubi - mount -t ubifs /dev/ubi0.root /mnt/ubi + mount /dev/nand0.root.ubi.root +The default mount path when the mount point is skipped is ``/mnt/<devname>``, +so in this example it will be ``/mnt/nand0.root.ubi.root``. The second time the UBIFS is mounted the above can be simplified to: .. code-block:: sh ubiattach /dev/nand0.root - mount -t ubifs /dev/ubi0.root /mnt/ubi + mount /dev/nand0.root.ubi.root Mounting the UBIFS can also be made transparent with the automount command. -With this helper script in ``/env/bin/automount-ubi:``: - -.. code-block:: sh - - #!/bin/sh - - if [ ! -e /dev/ubi0 ]; then - ubiattach /dev/nand0 || exit 1 - fi - - mount -t ubifs /dev/ubi0.root $automount_path - - -The command ``automount -d /mnt/ubi/ '/env/bin/automount-ubi'`` will automatically -attach the UBI device and mount the UBIFS image to ``/mnt/ubi`` whenever ``/mnt/ubi`` +The command ``automount -d /mnt/nand0.root.ubi.root 'mount nand0.root.ubi.root'`` +will automatically attach the UBI device and mount the UBIFS image to +``/mnt/nand0.root.ubi.root`` whenever ``/mnt/nand0.root.ubi.root`` is first accessed. The automount command can be added to ``/env/init/automount`` to execute it during startup. diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst index 3d68bbb9ae..0d6daee70e 100644 --- a/Documentation/user/user-manual.rst +++ b/Documentation/user/user-manual.rst @@ -28,6 +28,8 @@ Contents: ubi booting-linux system-setup + reset-reason + system-reset * :ref:`search` * :ref:`genindex` @@ -1,5 +1,5 @@ VERSION = 2015 -PATCHLEVEL = 06 +PATCHLEVEL = 07 SUBLEVEL = 0 EXTRAVERSION = NAME = None diff --git a/arch/arm/boards/beagle/board.c b/arch/arm/boards/beagle/board.c index b7efe95627..4ac9517dbe 100644 --- a/arch/arm/boards/beagle/board.c +++ b/arch/arm/boards/beagle/board.c @@ -21,6 +21,8 @@ #include <driver.h> #include <linux/sizes.h> #include <io.h> +#include <bbu.h> +#include <filetype.h> #include <ns16550.h> #include <envfs.h> #include <asm/armlinux.h> @@ -118,6 +120,11 @@ static int beagle_devices_init(void) armlinux_set_architecture(MACH_TYPE_OMAP3_BEAGLE); + bbu_register_std_file_update("nand-xload", 0, + "/dev/nand0.xload.bb", filetype_ch_image); + bbu_register_std_file_update("nand", 0, + "/dev/nand0.barebox.bb", filetype_arm_barebox); + defaultenv_append_directory(defaultenv_beagle); return 0; diff --git a/arch/arm/boards/freescale-mx53-qsb/flash-header-imx53-loco.imxcfg b/arch/arm/boards/freescale-mx53-qsb/flash-header-imx53-loco.imxcfg index 95bcd19805..f43b484ee6 100644 --- a/arch/arm/boards/freescale-mx53-qsb/flash-header-imx53-loco.imxcfg +++ b/arch/arm/boards/freescale-mx53-qsb/flash-header-imx53-loco.imxcfg @@ -30,7 +30,7 @@ wm 32 0x63fd9090 0x4d444c44 wm 32 0x63fd907c 0x01370138 wm 32 0x63fd9080 0x013b013c wm 32 0x63fd9018 0x00011740 -wm 32 0x63fd9000 0xc3190000 +wm 32 0x63fd9000 0x83190000 wm 32 0x63fd900c 0x9f5152e3 wm 32 0x63fd9010 0xb68e8a63 wm 32 0x63fd9014 0x01ff00db @@ -43,6 +43,7 @@ wm 32 0x63fd901c 0x00008033 wm 32 0x63fd901c 0x00028031 wm 32 0x63fd901c 0x052080b0 wm 32 0x63fd901c 0x04008040 +wm 32 0x63fd9000 0xc3190000 wm 32 0x63fd901c 0x0000803a wm 32 0x63fd901c 0x0000803b wm 32 0x63fd901c 0x00028039 diff --git a/arch/arm/boards/phytec-som-am335x/board.c b/arch/arm/boards/phytec-som-am335x/board.c index 74e39d70fc..7a878415f8 100644 --- a/arch/arm/boards/phytec-som-am335x/board.c +++ b/arch/arm/boards/phytec-som-am335x/board.c @@ -68,7 +68,10 @@ static int physom_devices_init(void) of_device_enable_path("/chosen/environment-spi"); break; case BOOTSOURCE_MMC: - omap_set_bootmmc_devname("mmc0"); + if (bootsource_get_instance() == 0) + omap_set_bootmmc_devname("mmc0"); + else + omap_set_bootmmc_devname("mmc1"); break; default: of_device_enable_path("/chosen/environment-nand"); diff --git a/arch/arm/configs/am335x_mlo_defconfig b/arch/arm/configs/am335x_mlo_defconfig index 1dd7567d0d..b66a653681 100644 --- a/arch/arm/configs/am335x_mlo_defconfig +++ b/arch/arm/configs/am335x_mlo_defconfig @@ -9,6 +9,7 @@ CONFIG_THUMB2_BAREBOX=y # CONFIG_MEMINFO is not set CONFIG_MMU=y CONFIG_TEXT_BASE=0x0 +CONFIG_BAREBOX_MAX_PBLX_SIZE=0x1b400 CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_TLSF=y CONFIG_RELOCATABLE=y diff --git a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig index bf04fa3b18..224854c7cc 100644 --- a/arch/arm/configs/lubbock_defconfig +++ b/arch/arm/configs/lubbock_defconfig @@ -6,7 +6,6 @@ CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y # CONFIG_BANNER is not set CONFIG_MMU=y -CONFIG_TEXT_BASE=0xa3d00000 CONFIG_BAREBOX_MAX_BARE_INIT_SIZE=0x80000 CONFIG_MALLOC_SIZE=0x1000000 CONFIG_EXPERIMENTAL=y diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index ca54a1a491..ec369ae42e 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -1,70 +1,68 @@ CONFIG_ARCH_SOCFPGA=y -CONFIG_ARCH_SOCFPGA_FPGA=y CONFIG_MACH_SOCFPGA_EBV_SOCRATES=y CONFIG_MACH_SOCFPGA_TERASIC_SOCKIT=y CONFIG_THUMB2_BAREBOX=y -CONFIG_CMD_ARM_MMUINFO=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y CONFIG_MMU=y -CONFIG_TEXT_BASE=0x0 CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_RELOCATABLE=y -CONFIG_LONGHELP=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y # CONFIG_TIMESTAMP is not set CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y -CONFIG_CMD_EDIT=y -CONFIG_CMD_SLEEP=y -CONFIG_CMD_MSLEEP=y -CONFIG_CMD_SAVEENV=y -CONFIG_CMD_EXPORT=y -CONFIG_CMD_PRINTENV=y -CONFIG_CMD_READLINE=y -CONFIG_CMD_LET=y -CONFIG_CMD_MENU=y -CONFIG_CMD_MENU_MANAGEMENT=y -CONFIG_CMD_TIME=y -CONFIG_CMD_LN=y -CONFIG_CMD_FILETYPE=y -CONFIG_CMD_ECHO_E=y -CONFIG_CMD_MEMINFO=y +CONFIG_LONGHELP=y CONFIG_CMD_IOMEM=y -CONFIG_CMD_MM=y -CONFIG_CMD_CRC=y -CONFIG_CMD_CRC_CMP=y -CONFIG_CMD_MD5SUM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_ARM_MMUINFO=y CONFIG_CMD_BOOTM_SHOW_TYPE=y CONFIG_CMD_BOOTM_VERBOSE=y CONFIG_CMD_BOOTM_INITRD=y CONFIG_CMD_BOOTM_OFTREE=y -CONFIG_CMD_RESET=y CONFIG_CMD_GO=y -CONFIG_CMD_OFTREE=y -CONFIG_CMD_OF_PROPERTY=y -CONFIG_CMD_OF_NODE=y -CONFIG_CMD_MEMTEST=y -CONFIG_CMD_BAREBOX_UPDATE=y -CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_RESET=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y CONFIG_CMD_MAGICVAR=y CONFIG_CMD_MAGICVAR_HELP=y -CONFIG_CMD_GPIO=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_FILETYPE=y +CONFIG_CMD_LN=y +CONFIG_CMD_MD5SUM=y CONFIG_CMD_UNCOMPRESS=y -CONFIG_CMD_SPI=y -CONFIG_CMD_LED=y -CONFIG_CMD_LED_TRIGGER=y +CONFIG_CMD_LET=y +CONFIG_CMD_MSLEEP=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_DHCP=y CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_MENU=y +CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_CRC=y +CONFIG_CMD_CRC_CMP=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_MM=y CONFIG_CMD_CLK=y CONFIG_CMD_DETECT=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_SPI=y +CONFIG_CMD_LED_TRIGGER=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_OF_NODE=y +CONFIG_CMD_OF_PROPERTY=y +CONFIG_CMD_OFTREE=y +CONFIG_CMD_TIME=y CONFIG_NET=y -CONFIG_CMD_DHCP=y -CONFIG_CMD_PING=y CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y CONFIG_OFDEVICE=y diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c index 91badc97b3..8e5097b560 100644 --- a/arch/arm/cpu/start.c +++ b/arch/arm/cpu/start.c @@ -66,6 +66,8 @@ static noinline __noreturn void __start(unsigned long membase, setup_c(); + barrier(); + pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize); barebox_boarddata = boarddata; diff --git a/arch/arm/dts/am33xx-strip.dtsi b/arch/arm/dts/am33xx-strip.dtsi index 3dc9a5798a..04cf3151ea 100644 --- a/arch/arm/dts/am33xx-strip.dtsi +++ b/arch/arm/dts/am33xx-strip.dtsi @@ -11,8 +11,6 @@ aliases { /delete-property/ i2c1; /delete-property/ i2c2; - /delete-property/ mmc0; - /delete-property/ mmc1; /delete-property/ mmc2; /delete-property/ d_can0; /delete-property/ d_can1; @@ -21,7 +19,6 @@ /delete-node/ &i2c1; /delete-node/ &i2c2; -/delete-node/ &mmc2; /delete-node/ &mmc3; /delete-node/ &hwspinlock; /delete-node/ &wdt2; @@ -46,3 +43,5 @@ /delete-node/ &mcasp0; /delete-node/ &mcasp1; /delete-node/ &rng; +/delete-node/ &rtc; +/delete-node/ &wkup_m3; diff --git a/arch/arm/dts/imx6dl-tx6u-801x.dts b/arch/arm/dts/imx6dl-tx6u-801x.dts index 43104b2b88..a480408f50 100644 --- a/arch/arm/dts/imx6dl-tx6u-801x.dts +++ b/arch/arm/dts/imx6dl-tx6u-801x.dts @@ -18,12 +18,12 @@ &gpmi { partition@0 { label = "barebox"; - reg = <0x0 0x100000>; + reg = <0x0 0x400000>; }; partition@1 { label = "barebox-environment"; - reg = <0x100000 0x100000>; + reg = <0x400000 0x100000>; }; }; diff --git a/arch/arm/mach-clps711x/reset.c b/arch/arm/mach-clps711x/reset.c index 67c9c8b8c5..859d8ae574 100644 --- a/arch/arm/mach-clps711x/reset.c +++ b/arch/arm/mach-clps711x/reset.c @@ -11,7 +11,7 @@ void __noreturn reset_cpu(unsigned long addr) { - arch_shutdown(); + shutdown_barebox(); asm("mov pc, #0"); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 3ccd060a5b..f8f6004630 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -127,15 +127,6 @@ config BAREBOX_UPDATE_IMX_EXTERNAL_NAND depends on MTD_WRITE default y -config BAREBOX_UPDATE_IMX6_NAND - bool - depends on ARCH_IMX6 - depends on BAREBOX_UPDATE - depends on MTD - depends on MTD_WRITE - depends on NAND_MXS - default y - comment "Freescale i.MX System-on-Chip" config ARCH_IMX1 diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 0320d1c2ea..458d7b45bb 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -22,6 +22,5 @@ obj-y += devices.o imx.o esdctl.o obj-y += boot.o obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o obj-$(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) += imx-bbu-external-nand.o -obj-$(CONFIG_BAREBOX_UPDATE_IMX6_NAND) += imx6-bbu-nand.o pbl-y += esdctl.o lwl-y += cpu_init.o diff --git a/arch/arm/mach-imx/include/mach/bbu.h b/arch/arm/mach-imx/include/mach/bbu.h index 5eb9a47363..8039091395 100644 --- a/arch/arm/mach-imx/include/mach/bbu.h +++ b/arch/arm/mach-imx/include/mach/bbu.h @@ -75,15 +75,6 @@ static inline int imx_bbu_external_nor_register_handler(const char *name, char * } #endif -#if defined(CONFIG_BAREBOX_UPDATE_IMX6_NAND) -int imx6_bbu_nand_register_handler(const char *name, unsigned long flags); -#else -static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) -{ - return -ENOSYS; -} -#endif - #if defined(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) int imx_bbu_external_nand_register_handler(const char *name, char *devicefile, unsigned long flags); diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c index 2029b90acb..00758450cc 100644 --- a/arch/arm/mach-mxs/ocotp.c +++ b/arch/arm/mach-mxs/ocotp.c @@ -43,6 +43,7 @@ #define OCOTP_WORD_OFFSET 0x20 struct ocotp_priv { + struct device_d dev; struct cdev cdev; void __iomem *base; unsigned int write_enable; @@ -194,13 +195,19 @@ static int mxs_ocotp_probe(struct device_d *dev) priv->cdev.size = cpu_is_mx23() ? 128 : 160; priv->cdev.name = DRIVERNAME; + strcpy(priv->dev.name, "ocotp"); + priv->dev.parent = dev; + err = register_device(&priv->dev); + if (err) + return err; + err = devfs_create(&priv->cdev); if (err < 0) return err; if (IS_ENABLED(CONFIG_MXS_OCOTP_WRITABLE)) { mxs_ocotp_ops.write = mxs_ocotp_cdev_write; - dev_add_param_bool(dev, "permanent_write_enable", + dev_add_param_bool(&priv->dev, "permanent_write_enable", NULL, NULL, &priv->write_enable, NULL); } diff --git a/arch/arm/mach-omap/am33xx_bbu_spi_mlo.c b/arch/arm/mach-omap/am33xx_bbu_spi_mlo.c index 97dc54ee10..702bb9af59 100644 --- a/arch/arm/mach-omap/am33xx_bbu_spi_mlo.c +++ b/arch/arm/mach-omap/am33xx_bbu_spi_mlo.c @@ -97,41 +97,6 @@ out: return ret; } -static int spi_nor_handler(struct bbu_handler *handler, - struct bbu_data *data) -{ - int fd, ret; - - if (file_detect_type(data->image, data->len) != filetype_arm_barebox) { - if (!bbu_force(data, "Not an ARM barebox image")) - return -EINVAL; - } - - fd = open(data->devicefile, O_RDWR | O_CREAT); - if (fd < 0) - return fd; - - debug("%s: eraseing %s from 0 to 0x%08x\n", __func__, - data->devicefile, data->len); - ret = erase(fd, data->len, 0); - if (ret) { - printf("erasing %s failed with %s\n", data->devicefile, - strerror(-ret)); - goto err_close; - } - - ret = write(fd, data->image, data->len); - if (ret < 0) - goto err_close; - - ret = 0; - -err_close: - close(fd); - - return ret; -} - /* * Register a am33xx MLO update handler for SPI NOR */ @@ -152,24 +117,3 @@ int am33xx_bbu_spi_nor_mlo_register_handler(const char *name, char *devicefile) return ret; } - -/* - * Register a am33xx update handler for SPI NOR - */ -int am33xx_bbu_spi_nor_register_handler(const char *name, char *devicefile) -{ - struct bbu_handler *handler; - int ret; - - handler = xzalloc(sizeof(*handler)); - handler->devicefile = devicefile; - handler->name = name; - handler->handler = spi_nor_handler; - - ret = bbu_register_handler(handler); - - if (ret) - free(handler); - - return ret; -} diff --git a/arch/arm/mach-omap/include/mach/bbu.h b/arch/arm/mach-omap/include/mach/bbu.h index 36d87e1a00..da5c214d3a 100644 --- a/arch/arm/mach-omap/include/mach/bbu.h +++ b/arch/arm/mach-omap/include/mach/bbu.h @@ -5,18 +5,17 @@ #ifdef CONFIG_BAREBOX_UPDATE_AM33XX_SPI_NOR_MLO int am33xx_bbu_spi_nor_mlo_register_handler(const char *name, char *devicefile); -int am33xx_bbu_spi_nor_register_handler(const char *name, char *devicefile); #else static inline int am33xx_bbu_spi_nor_mlo_register_handler(const char *name, char *devicefile) { return 0; } +#endif static inline int am33xx_bbu_spi_nor_register_handler(const char *name, char *devicefile) { - return 0; + return bbu_register_std_file_update(name, 0, devicefile, filetype_arm_barebox); } -#endif #ifdef CONFIG_BAREBOX_UPDATE_AM33XX_NAND int am33xx_bbu_nand_xloadslots_register_handler(const char *name, diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 610fb1c80e..2b7f631757 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -4,6 +4,7 @@ config ARCH_TEXT_BASE hex default 0xa0000000 if MACH_MIOA701 default 0xa3f00000 if MACH_PCM027 + default 0xa3d00000 if MACH_LUBBOCK default 0x83f00000 if MACH_ZYLONITE # ---------------------------------------------------------- diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index 90b3533b1f..73b26efd20 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -1,5 +1,9 @@ if ARCH_SOCFPGA +config ARCH_TEXT_BASE + hex + default 0x0 + config ARCH_SOCFPGA_XLOAD bool prompt "Build preloader image" diff --git a/arch/arm/mach-tegra/include/mach/lowlevel.h b/arch/arm/mach-tegra/include/mach/lowlevel.h index 768b13d968..0c76b8883c 100644 --- a/arch/arm/mach-tegra/include/mach/lowlevel.h +++ b/arch/arm/mach-tegra/include/mach/lowlevel.h @@ -243,11 +243,20 @@ void tegra_ll_delay_usec(int delay) while ((int)readl(TEGRA_TMRUS_BASE + TIMER_CNTR_1US) - timeout < 0); } +/* reset vector for the AVP, to be called from board reset vector */ +void tegra_avp_reset_vector(uint32_t boarddata); + +/* reset vector for the main CPU complex */ +void tegra_maincomplex_entry(void); + static __always_inline void tegra_cpu_lowlevel_setup(void) { uint32_t r; + if (tegra_cpu_is_maincomplex()) + tegra_maincomplex_entry(); + /* set the cpu to SVC32 mode */ __asm__ __volatile__("mrs %0, cpsr":"=r"(r)); r &= ~0x1f; @@ -258,10 +267,4 @@ void tegra_cpu_lowlevel_setup(void) tegra_ll_delay_setup(); } -/* reset vector for the AVP, to be called from board reset vector */ -void tegra_avp_reset_vector(uint32_t boarddata); - -/* reset vector for the main CPU complex */ -void tegra_maincomplex_entry(void); - #endif /* __TEGRA_LOWLEVEL_H */ diff --git a/arch/arm/mach-tegra/tegra_avp_init.c b/arch/arm/mach-tegra/tegra_avp_init.c index 91fd894dca..20fcf3f1d1 100644 --- a/arch/arm/mach-tegra/tegra_avp_init.c +++ b/arch/arm/mach-tegra/tegra_avp_init.c @@ -265,9 +265,6 @@ void tegra_avp_reset_vector(uint32_t boarddata) /* put boarddata in scratch reg, for main CPU to fetch after startup */ writel(boarddata, TEGRA_PMC_BASE + PMC_SCRATCH(10)); - if (tegra_cpu_is_maincomplex()) - tegra_maincomplex_entry(); - /* we want to bring up the high performance CPU complex */ if (tegra_get_chiptype() >= TEGRA30) tegra_cluster_switch_hp(); diff --git a/arch/blackfin/include/asm/io.h b/arch/blackfin/include/asm/io.h index 2837b6a1aa..703104e1b8 100644 --- a/arch/blackfin/include/asm/io.h +++ b/arch/blackfin/include/asm/io.h @@ -90,21 +90,21 @@ extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); extern void __iounmap(void *addr, unsigned long size); -extern inline void *ioremap(unsigned long physaddr, unsigned long size) +static inline void *ioremap(unsigned long physaddr, unsigned long size) { return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); } -extern inline void *ioremap_nocache(unsigned long physaddr, +static inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) { return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); } -extern inline void *ioremap_writethrough(unsigned long physaddr, +static inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) { return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); } -extern inline void *ioremap_fullcache(unsigned long physaddr, +static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) { return __ioremap(physaddr, size, IOMAP_FULL_CACHING); diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h index eaa1e4a03f..f46363732a 100644 --- a/arch/blackfin/include/asm/processor.h +++ b/arch/blackfin/include/asm/processor.h @@ -36,7 +36,7 @@ #include <asm/ptrace.h> #include <asm/current.h> -extern inline unsigned long rdusp(void) +static inline unsigned long rdusp(void) { unsigned long usp; @@ -44,7 +44,7 @@ extern inline unsigned long rdusp(void) return usp; } -extern inline void wrusp(unsigned long usp) +static inline void wrusp(unsigned long usp) { __asm__ __volatile__("usp = %0;\n\t"::"da"(usp)); } @@ -130,7 +130,7 @@ static inline void exit_thread(void) /* * Return saved PC of a blocked thread. */ -extern inline unsigned long thread_saved_pc(struct thread_struct *t) +static inline unsigned long thread_saved_pc(struct thread_struct *t) { extern void scheduling_functions_start_here(void); extern void scheduling_functions_end_here(void); diff --git a/arch/blackfin/include/asm/swab.h b/arch/blackfin/include/asm/swab.h index 89de6507ca..1f645db374 100644 --- a/arch/blackfin/include/asm/swab.h +++ b/arch/blackfin/include/asm/swab.h @@ -12,7 +12,7 @@ #ifdef __GNUC__ -static __inline__ __attribute_const__ __u32 __arch_swahb32(__u32 xx) +static inline __attribute_const__ __u32 __arch_swahb32(__u32 xx) { __u32 tmp; __asm__("%1 = %0 >> 8 (V);\n\t" @@ -23,7 +23,7 @@ static __inline__ __attribute_const__ __u32 __arch_swahb32(__u32 xx) } #define __arch_swahb32 __arch_swahb32 -static __inline__ __attribute_const__ __u32 __arch_swahw32(__u32 xx) +static inline __attribute_const__ __u32 __arch_swahw32(__u32 xx) { __u32 rv; __asm__("%0 = PACK(%1.L, %1.H);\n\t": "=d"(rv): "d"(xx)); @@ -31,13 +31,13 @@ static __inline__ __attribute_const__ __u32 __arch_swahw32(__u32 xx) } #define __arch_swahw32 __arch_swahw32 -static __inline__ __attribute_const__ __u32 __arch_swab32(__u32 xx) +static inline __attribute_const__ __u32 __arch_swab32(__u32 xx) { return __arch_swahb32(__arch_swahw32(xx)); } #define __arch_swab32 __arch_swab32 -static __inline__ __attribute_const__ __u16 __arch_swab16(__u16 xx) +static inline __attribute_const__ __u16 __arch_swab16(__u16 xx) { __u32 xw = xx; __asm__("%0 <<= 8;\n %0.L = %0.L + %0.H (NS);\n": "+d"(xw)); diff --git a/arch/mips/mach-bcm47xx/reset.c b/arch/mips/mach-bcm47xx/reset.c index f1dc68afb5..00aee190fe 100644 --- a/arch/mips/mach-bcm47xx/reset.c +++ b/arch/mips/mach-bcm47xx/reset.c @@ -15,11 +15,6 @@ * */ -/** - * @file - * @brief Resetting an malta board - */ - #include <common.h> #include <io.h> #include <mach/hardware.h> diff --git a/arch/ppc/include/asm/atomic.h b/arch/ppc/include/asm/atomic.h index 23f22df1b7..a98d892ea7 100644 --- a/arch/ppc/include/asm/atomic.h +++ b/arch/ppc/include/asm/atomic.h @@ -21,7 +21,7 @@ typedef struct { int counter; } atomic_t; extern void atomic_clear_mask(unsigned long mask, unsigned long *addr); extern void atomic_set_mask(unsigned long mask, unsigned long *addr); -extern __inline__ int atomic_add_return(int a, atomic_t *v) +static inline int atomic_add_return(int a, atomic_t *v) { int t; @@ -37,7 +37,7 @@ extern __inline__ int atomic_add_return(int a, atomic_t *v) return t; } -extern __inline__ int atomic_sub_return(int a, atomic_t *v) +static inline int atomic_sub_return(int a, atomic_t *v) { int t; @@ -53,7 +53,7 @@ extern __inline__ int atomic_sub_return(int a, atomic_t *v) return t; } -extern __inline__ int atomic_inc_return(atomic_t *v) +static inline int atomic_inc_return(atomic_t *v) { int t; @@ -69,7 +69,7 @@ extern __inline__ int atomic_inc_return(atomic_t *v) return t; } -extern __inline__ int atomic_dec_return(atomic_t *v) +static inline int atomic_dec_return(atomic_t *v) { int t; diff --git a/arch/ppc/include/asm/bitops.h b/arch/ppc/include/asm/bitops.h index e4572bcd4d..2fdd57eff0 100644 --- a/arch/ppc/include/asm/bitops.h +++ b/arch/ppc/include/asm/bitops.h @@ -28,7 +28,7 @@ * These used to be if'd out here because using : "cc" as a constraint * resulted in errors from egcs. Things may be OK with gcc-2.95. */ -extern __inline__ void set_bit(int nr, volatile void * addr) +static inline void set_bit(int nr, volatile void * addr) { unsigned long old; unsigned long mask = 1 << (nr & 0x1f); @@ -45,7 +45,7 @@ extern __inline__ void set_bit(int nr, volatile void * addr) : "cc" ); } -extern __inline__ void clear_bit(int nr, volatile void *addr) +static inline void clear_bit(int nr, volatile void *addr) { unsigned long old; unsigned long mask = 1 << (nr & 0x1f); @@ -62,7 +62,7 @@ extern __inline__ void clear_bit(int nr, volatile void *addr) : "cc"); } -extern __inline__ void change_bit(int nr, volatile void *addr) +static inline void change_bit(int nr, volatile void *addr) { unsigned long old; unsigned long mask = 1 << (nr & 0x1f); @@ -79,7 +79,7 @@ extern __inline__ void change_bit(int nr, volatile void *addr) : "cc"); } -extern __inline__ int test_and_set_bit(int nr, volatile void *addr) +static inline int test_and_set_bit(int nr, volatile void *addr) { unsigned int old, t; unsigned int mask = 1 << (nr & 0x1f); @@ -98,7 +98,7 @@ extern __inline__ int test_and_set_bit(int nr, volatile void *addr) return (old & mask) != 0; } -extern __inline__ int test_and_clear_bit(int nr, volatile void *addr) +static inline int test_and_clear_bit(int nr, volatile void *addr) { unsigned int old, t; unsigned int mask = 1 << (nr & 0x1f); @@ -117,7 +117,7 @@ extern __inline__ int test_and_clear_bit(int nr, volatile void *addr) return (old & mask) != 0; } -extern __inline__ int test_and_change_bit(int nr, volatile void *addr) +static inline int test_and_change_bit(int nr, volatile void *addr) { unsigned int old, t; unsigned int mask = 1 << (nr & 0x1f); @@ -138,7 +138,7 @@ extern __inline__ int test_and_change_bit(int nr, volatile void *addr) #endif /* __INLINE_BITOPS */ /* Return the bit position of the most significant 1 bit in a word */ -extern __inline__ int __ilog2(unsigned int x) +static inline int __ilog2(unsigned int x) { int lz; @@ -146,14 +146,14 @@ extern __inline__ int __ilog2(unsigned int x) return 31 - lz; } -extern __inline__ int ffz(unsigned int x) +static inline int ffz(unsigned int x) { if ((x = ~x) == 0) return 32; return __ilog2(x & -x); } -static __inline__ int __ffs(unsigned long x) +static inline int __ffs(unsigned long x) { return __ilog2(x & -x); } @@ -177,7 +177,7 @@ static inline int fls(unsigned int x) * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ -extern __inline__ int ffs(int x) +static inline int ffs(int x) { return __ilog2(x & -x) + 1; } diff --git a/arch/ppc/include/asm/io.h b/arch/ppc/include/asm/io.h index 98bf5132cd..f83ab6ee0b 100644 --- a/arch/ppc/include/asm/io.h +++ b/arch/ppc/include/asm/io.h @@ -136,7 +136,7 @@ static inline void __raw_writel(unsigned int v, volatile void __iomem *addr) /* * 8, 16 and 32 bit, big and little endian I/O operations, with barrier. */ -extern inline u8 in_8(const volatile u8 __iomem *addr) +static inline u8 in_8(const volatile u8 __iomem *addr) { u8 ret; @@ -145,12 +145,12 @@ extern inline u8 in_8(const volatile u8 __iomem *addr) return ret; } -extern inline void out_8(volatile u8 __iomem *addr, u8 val) +static inline void out_8(volatile u8 __iomem *addr, u8 val) { __asm__ __volatile__("sync;stb%U0%X0 %1,%0" : "=m" (*addr) : "r" (val)); } -extern inline u16 in_le16(const volatile u16 __iomem *addr) +static inline u16 in_le16(const volatile u16 __iomem *addr) { u16 ret; @@ -159,7 +159,7 @@ extern inline u16 in_le16(const volatile u16 __iomem *addr) return ret; } -extern inline u16 in_be16(const volatile u16 __iomem *addr) +static inline u16 in_be16(const volatile u16 __iomem *addr) { u16 ret; @@ -168,18 +168,18 @@ extern inline u16 in_be16(const volatile u16 __iomem *addr) return ret; } -extern inline void out_le16(volatile u16 __iomem *addr, u16 val) +static inline void out_le16(volatile u16 __iomem *addr, u16 val) { __asm__ __volatile__("sync; sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } -extern inline void out_be16(volatile u16 __iomem *addr, u16 val) +static inline void out_be16(volatile u16 __iomem *addr, u16 val) { __asm__ __volatile__("sync;sth%U0%X0 %1,%0" : "=m" (*addr) : "r" (val)); } -extern inline u32 in_le32(const volatile u32 __iomem *addr) +static inline u32 in_le32(const volatile u32 __iomem *addr) { u32 ret; @@ -188,7 +188,7 @@ extern inline u32 in_le32(const volatile u32 __iomem *addr) return ret; } -extern inline u32 in_be32(const volatile u32 __iomem *addr) +static inline u32 in_be32(const volatile u32 __iomem *addr) { u32 ret; @@ -197,13 +197,13 @@ extern inline u32 in_be32(const volatile u32 __iomem *addr) return ret; } -extern inline void out_le32(volatile u32 __iomem *addr, u32 val) +static inline void out_le32(volatile u32 __iomem *addr, u32 val) { __asm__ __volatile__("sync; stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } -extern inline void out_be32(volatile u32 __iomem *addr, u32 val) +static inline void out_be32(volatile u32 __iomem *addr, u32 val) { __asm__ __volatile__("sync;stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val)); } diff --git a/arch/ppc/include/asm/swab.h b/arch/ppc/include/asm/swab.h index c581e3ef73..110488e641 100644 --- a/arch/ppc/include/asm/swab.h +++ b/arch/ppc/include/asm/swab.h @@ -19,7 +19,7 @@ #ifdef __KERNEL__ -static __inline__ __u16 ld_le16(const volatile __u16 *addr) +static inline __u16 ld_le16(const volatile __u16 *addr) { __u16 val; @@ -28,7 +28,7 @@ static __inline__ __u16 ld_le16(const volatile __u16 *addr) } #define __arch_swab16p ld_le16 -static __inline__ void st_le16(volatile __u16 *addr, const __u16 val) +static inline void st_le16(volatile __u16 *addr, const __u16 val) { __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } @@ -39,7 +39,7 @@ static inline void __arch_swab16s(__u16 *addr) } #define __arch_swab16s __arch_swab16s -static __inline__ __u32 ld_le32(const volatile __u32 *addr) +static inline __u32 ld_le32(const volatile __u32 *addr) { __u32 val; @@ -48,7 +48,7 @@ static __inline__ __u32 ld_le32(const volatile __u32 *addr) } #define __arch_swab32p ld_le32 -static __inline__ void st_le32(volatile __u32 *addr, const __u32 val) +static inline void st_le32(volatile __u32 *addr, const __u32 val) { __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } diff --git a/arch/sandbox/include/asm/byteorder.h b/arch/sandbox/include/asm/byteorder.h index 37316f2371..3d82bcba6e 100644 --- a/arch/sandbox/include/asm/byteorder.h +++ b/arch/sandbox/include/asm/byteorder.h @@ -1,8 +1,8 @@ -#ifndef _I386_BYTEORDER_H -#define _I386_BYTEORDER_H +#ifndef _SANDBOX_BYTEORDER_H +#define _SANDBOX_BYTEORDER_H #include <asm/types.h> #include <linux/byteorder/little_endian.h> -#endif /* _I386_BYTEORDER_H */ +#endif /* _SANDBOX_BYTEORDER_H */ diff --git a/commands/automount.c b/commands/automount.c index a29f286b22..b491d203fd 100644 --- a/commands/automount.c +++ b/commands/automount.c @@ -70,4 +70,3 @@ BAREBOX_CMD_START(automount) BAREBOX_CMD_GROUP(CMD_GRP_PART) BAREBOX_CMD_HELP(cmd_automount_help) BAREBOX_CMD_END - diff --git a/commands/detect.c b/commands/detect.c index d8e0afc314..1586a6fb54 100644 --- a/commands/detect.c +++ b/commands/detect.c @@ -68,10 +68,7 @@ static int do_detect(int argc, char *argv[]) return COMMAND_ERROR_USAGE; for (i = optind; i < argc; i++) { - dev = get_device_by_name(argv[i]); - if (!dev) - return -ENODEV; - ret = device_detect(dev); + ret = device_detect_by_name(argv[i]); if (ret && option_error) return ret; } diff --git a/commands/devinfo.c b/commands/devinfo.c index e61aaa24e8..3c9d6a6b9d 100644 --- a/commands/devinfo.c +++ b/commands/devinfo.c @@ -68,11 +68,8 @@ static int do_devinfo(int argc, char *argv[]) } } else { dev = get_device_by_name(argv[1]); - - if (!dev) { - printf("no such device: %s\n",argv[1]); - return -1; - } + if (!dev) + return -ENODEV; if (dev->num_resources) printf("Resources:\n"); diff --git a/commands/digest.c b/commands/digest.c index 340c07a248..4cc615d775 100644 --- a/commands/digest.c +++ b/commands/digest.c @@ -68,7 +68,7 @@ err: return ret; } -static void prints_algo_help(void) +static void __maybe_unused prints_algo_help(void) { puts("\navailable algo:\n"); digest_algo_prints("\t"); diff --git a/commands/export.c b/commands/export.c index 2e8bb49676..4b4cf1e12e 100644 --- a/commands/export.c +++ b/commands/export.c @@ -59,4 +59,3 @@ BAREBOX_CMD_START(export) BAREBOX_CMD_GROUP(CMD_GRP_ENV) BAREBOX_CMD_HELP(cmd_export_help) BAREBOX_CMD_END - diff --git a/commands/false.c b/commands/false.c index 6ef9af3155..90aa2cc9ea 100644 --- a/commands/false.c +++ b/commands/false.c @@ -32,4 +32,3 @@ BAREBOX_CMD_START(false) BAREBOX_CMD_GROUP(CMD_GRP_SCRIPT) BAREBOX_CMD_COMPLETE(empty_complete) BAREBOX_CMD_END - diff --git a/commands/help.c b/commands/help.c index 6e61bde1af..3d36d9bf48 100644 --- a/commands/help.c +++ b/commands/help.c @@ -148,4 +148,3 @@ BAREBOX_CMD_START(help) BAREBOX_CMD_HELP(cmd_help_help) BAREBOX_CMD_COMPLETE(command_complete) BAREBOX_CMD_END - diff --git a/commands/mount.c b/commands/mount.c index 939e9bc853..aa769d46fe 100644 --- a/commands/mount.c +++ b/commands/mount.c @@ -79,6 +79,8 @@ static int do_mount(int argc, char *argv[]) if (!strncmp(devstr, "/dev/", 5)) devstr += 5; + device_detect_by_name(devstr); + cdev = cdev_by_name(devstr); if (!cdev) return -ENOENT; diff --git a/commands/net.c b/commands/net.c index 7508c992f2..219c7efcda 100644 --- a/commands/net.c +++ b/commands/net.c @@ -64,4 +64,3 @@ BAREBOX_CMD_START(ethact) BAREBOX_CMD_GROUP(CMD_GRP_NET) BAREBOX_CMD_COMPLETE(eth_complete) BAREBOX_CMD_END - diff --git a/commands/readline.c b/commands/readline.c index e537498878..b6e0e3e091 100644 --- a/commands/readline.c +++ b/commands/readline.c @@ -53,4 +53,3 @@ BAREBOX_CMD_START(readline) BAREBOX_CMD_GROUP(CMD_GRP_CONSOLE) BAREBOX_CMD_HELP(cmd_readline_help) BAREBOX_CMD_END - diff --git a/commands/timeout.c b/commands/timeout.c index 2b99d4f749..ef1a037c19 100644 --- a/commands/timeout.c +++ b/commands/timeout.c @@ -84,4 +84,3 @@ BAREBOX_CMD_START(timeout) BAREBOX_CMD_GROUP(CMD_GRP_CONSOLE) BAREBOX_CMD_HELP(cmd_timeout_help) BAREBOX_CMD_END - diff --git a/commands/trigger.c b/commands/trigger.c index b605448a91..2758ce74e8 100644 --- a/commands/trigger.c +++ b/commands/trigger.c @@ -105,4 +105,3 @@ BAREBOX_CMD_START(trigger) BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_HELP(cmd_trigger_help) BAREBOX_CMD_END - diff --git a/commands/true.c b/commands/true.c index fbb34e7690..24dea46929 100644 --- a/commands/true.c +++ b/commands/true.c @@ -32,4 +32,3 @@ BAREBOX_CMD_START(true) BAREBOX_CMD_GROUP(CMD_GRP_SCRIPT) BAREBOX_CMD_COMPLETE(empty_complete) BAREBOX_CMD_END - diff --git a/commands/ubi.c b/commands/ubi.c index 94da799b8c..9463127151 100644 --- a/commands/ubi.c +++ b/commands/ubi.c @@ -179,4 +179,3 @@ BAREBOX_CMD_START(ubirmvol) BAREBOX_CMD_GROUP(CMD_GRP_PART) BAREBOX_CMD_HELP(cmd_ubirmvol_help) BAREBOX_CMD_END - diff --git a/commands/version.c b/commands/version.c index 898c719433..090f2dd136 100644 --- a/commands/version.c +++ b/commands/version.c @@ -33,4 +33,3 @@ BAREBOX_CMD_START(version) BAREBOX_CMD_GROUP(CMD_GRP_INFO) BAREBOX_CMD_COMPLETE(empty_complete) BAREBOX_CMD_END - diff --git a/common/Kconfig b/common/Kconfig index 3dfb5ac194..983d3059fc 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -97,6 +97,14 @@ config FILE_LIST config ARCH_DMA_ADDR_T_64BIT bool +config BAREBOX_UPDATE_IMX_NAND_FCB + bool + depends on ARCH_IMX6 || ARCH_IMX28 + depends on BAREBOX_UPDATE + depends on MTD_WRITE + depends on NAND_MXS + default y + menu "General Settings" config LOCALVERSION @@ -201,6 +209,16 @@ config BAREBOX_MAX_BARE_INIT_SIZE this will allow your bare_init to fit in SRAM as example ARCH can overwrite it via ARCH_BAREBOX_MAX_BARE_INIT_SIZE +config BAREBOX_MAX_PBLX_SIZE + depends on PBL_MULTI_IMAGES + depends on IMAGE_COMPRESSION + prompt "Maximum PBLX size" + hex + default 0xffffffff + help + Define the maximum size of the PBLX image. + The pblx is a self extracting barebox binary. + config HAVE_CONFIGURABLE_MEMORY_LAYOUT bool diff --git a/common/Makefile b/common/Makefile index 2738238c67..74801f7e28 100644 --- a/common/Makefile +++ b/common/Makefile @@ -52,6 +52,7 @@ lwl-$(CONFIG_IMD) += imd-barebox.o obj-$(CONFIG_IMD) += imd.o obj-$(CONFIG_FILE_LIST) += file-list.o obj-$(CONFIG_FIRMWARE) += firmware.o +obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o quiet_cmd_pwd_h = PWDH $@ ifdef CONFIG_PASSWORD diff --git a/common/bbu.c b/common/bbu.c index 7fb154a230..4d71fa4a87 100644 --- a/common/bbu.c +++ b/common/bbu.c @@ -20,6 +20,12 @@ #include <linux/list.h> #include <errno.h> #include <readkey.h> +#include <filetype.h> +#include <libfile.h> +#include <fs.h> +#include <fcntl.h> +#include <malloc.h> +#include <linux/stat.h> static LIST_HEAD(bbu_image_handlers); @@ -153,3 +159,110 @@ int bbu_register_handler(struct bbu_handler *handler) return 0; } + +struct bbu_std { + struct bbu_handler handler; + enum filetype filetype; +}; + +static int bbu_std_file_handler(struct bbu_handler *handler, + struct bbu_data *data) +{ + struct bbu_std *std = container_of(handler, struct bbu_std, handler); + int fd, ret; + enum filetype filetype; + struct stat s; + unsigned oflags = O_WRONLY; + + filetype = file_detect_type(data->image, data->len); + if (filetype != std->filetype) { + if (!bbu_force(data, "incorrect image type. Expected: %s, got %s", + file_type_to_string(std->filetype), + file_type_to_string(filetype))) + return -EINVAL; + } + + ret = stat(data->devicefile, &s); + if (ret) { + oflags |= O_CREAT; + } else { + if (!S_ISREG(s.st_mode) && s.st_size < data->len) { + printf("Image (%lld) is too big for device (%d)\n", + s.st_size, data->len); + } + } + + ret = bbu_confirm(data); + if (ret) + return ret; + + fd = open(data->devicefile, oflags); + if (fd < 0) + return fd; + + ret = protect(fd, data->len, 0, 0); + if (ret && ret != -ENOSYS) { + printf("unprotecting %s failed with %s\n", data->devicefile, + strerror(-ret)); + goto err_close; + } + + ret = erase(fd, data->len, 0); + if (ret && ret != -ENOSYS) { + printf("erasing %s failed with %s\n", data->devicefile, + strerror(-ret)); + goto err_close; + } + + ret = write_full(fd, data->image, data->len); + if (ret < 0) + goto err_close; + + protect(fd, data->len, 0, 1); + + ret = 0; + +err_close: + close(fd); + + return ret; +} + +/** + * bbu_register_std_file_update() - register a barebox update handler for a + * standard file-to-device-copy operation + * @name: Name of the handler + * @flags: BBU_HANDLER_FLAG_* flags + * @devicefile: the file to write the update image to + * @imagetype: The filetype that the update image must have + * + * This update handler us suitable for a standard file-to-device copy operation. + * The handler checks for a filetype and unprotects/erases the device if + * necessary. If devicefile belongs to a device then the device is checkd for + * enough space before touching it. + * + * Return: 0 if successful, negative error code otherwise + */ +int bbu_register_std_file_update(const char *name, unsigned long flags, + char *devicefile, enum filetype imagetype) +{ + struct bbu_std *std; + struct bbu_handler *handler; + int ret; + + std = xzalloc(sizeof(*std)); + std->filetype = imagetype; + + handler = &std->handler; + + handler->flags = flags; + handler->devicefile = devicefile; + handler->name = name; + handler->handler = bbu_std_file_handler; + + ret = bbu_register_handler(handler); + if (ret) + free(std); + + return ret; +} diff --git a/common/blspec.c b/common/blspec.c index 3506388eb5..7e84ff3cec 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -30,6 +30,7 @@ #include <of.h> #include <linux/stat.h> #include <linux/err.h> +#include <mtd/ubi-user.h> /* * blspec_entry_var_set - set a variable to a value @@ -436,6 +437,35 @@ err_out: } /* + * blspec_scan_ubi - scan over a cdev containing UBI volumes + * + * This function attaches a cdev as UBI devices and collects all blspec + * entries found in the UBI volumes + * + * returns the number of entries found or a negative error code if some unexpected + * error occured. + */ +static int blspec_scan_ubi(struct blspec *blspec, struct cdev *cdev) +{ + struct device_d *child; + int ret, found = 0; + + pr_debug("%s: %s\n", __func__, cdev->name); + + ret = ubi_attach_mtd_dev(cdev->mtd, UBI_DEV_NUM_AUTO, 0, 20); + if (ret && ret != -EEXIST) + return 0; + + device_for_each_child(cdev->dev, child) { + ret = blspec_scan_device(blspec, child); + if (ret > 0) + found += ret; + } + + return found; +} + +/* * blspec_scan_cdev - scan over a cdev * * Given a cdev this function mounts the filesystem and collects all blspec @@ -446,9 +476,9 @@ err_out: */ static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev) { - int ret; + int ret, found = 0; void *buf = xzalloc(512); - enum filetype type; + enum filetype type, filetype; const char *rootpath; pr_debug("%s: %s\n", __func__, cdev->name); @@ -460,16 +490,26 @@ static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev) } type = file_detect_partition_table(buf, 512); + filetype = file_detect_type(buf, 512); free(buf); if (type == filetype_mbr || type == filetype_gpt) return -EINVAL; + if (filetype == filetype_ubi && IS_ENABLED(CONFIG_MTD_UBI)) { + ret = blspec_scan_ubi(blspec, cdev); + if (ret > 0) + found += ret; + } + rootpath = cdev_mount_default(cdev, NULL); - if (IS_ERR(rootpath)) - return PTR_ERR(rootpath); + if (!IS_ERR(rootpath)) { + ret = blspec_scan_directory(blspec, rootpath); + if (ret > 0) + found += ret; + } - return blspec_scan_directory(blspec, rootpath); + return found; } /* @@ -575,17 +615,10 @@ int blspec_scan_devicename(struct blspec *blspec, const char *devname) { struct device_d *dev; struct cdev *cdev; - const char *colon; pr_debug("%s: %s\n", __func__, devname); - colon = strchr(devname, '.'); - if (colon) { - char *name = xstrdup(devname); - *strchr(name, '.') = 0; - device_detect_by_name(name); - free(name); - } + device_detect_by_name(devname); cdev = cdev_by_name(devname); if (cdev) { diff --git a/common/complete.c b/common/complete.c index 5b71f03cf8..f0ef576401 100644 --- a/common/complete.c +++ b/common/complete.c @@ -466,4 +466,3 @@ int complete(char *instr, char **outstr) return reprint; } - diff --git a/common/filetype.c b/common/filetype.c index 25d97614e4..28a4b2ca25 100644 --- a/common/filetype.c +++ b/common/filetype.c @@ -60,6 +60,7 @@ static const struct filetype_str filetype_str[] = { "TI OMAP CH boot image (big endian)", "ch-image-be" }, [filetype_xz_compressed] = { "XZ compressed", "xz" }, [filetype_exe] = { "MS-DOS executable", "exe" }, + [filetype_mxs_bootstream] = { "Freescale MXS bootstream", "mxsbs" }, }; const char *file_type_to_string(enum filetype f) @@ -292,6 +293,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize) if (buf8[0] == 'M' && buf8[1] == 'Z') return filetype_exe; + if (le32_to_cpu(buf[5]) == 0x504d5453) + return filetype_mxs_bootstream; if (is_barebox_arm_head(_buf)) return filetype_arm_barebox; diff --git a/arch/arm/mach-imx/imx6-bbu-nand.c b/common/imx-bbu-nand-fcb.c index d2bfedbad5..22031f5b7f 100644 --- a/arch/arm/mach-imx/imx6-bbu-nand.c +++ b/common/imx-bbu-nand-fcb.c @@ -17,7 +17,7 @@ * */ -#define pr_fmt(fmt) "imx6-bbu-nand: " fmt +#define pr_fmt(fmt) "imx-bbu-nand-fcb: " fmt #include <filetype.h> #include <common.h> @@ -28,17 +28,17 @@ #include <linux/sizes.h> #include <bbu.h> #include <fs.h> -#include <mach/bbu.h> #include <linux/mtd/mtd-abi.h> #include <linux/mtd/nand_mxs.h> #include <linux/mtd/mtd.h> #include <linux/stat.h> +#include <io.h> struct dbbt_block { uint32_t Checksum; uint32_t FingerPrint; uint32_t Version; - uint32_t reserved; + uint32_t numberBB; /* reserved on i.MX6 */ uint32_t DBBTNumOfPages; }; @@ -102,6 +102,16 @@ struct fcb_block { uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */ }; +struct imx_nand_fcb_bbu_handler { + struct bbu_handler handler; + + void (*fcb_create)(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd); + void (*dbbt_create)(struct imx_nand_fcb_bbu_handler *imx_handler, + struct dbbt_block *dbbt, int num_bad_blocks); + enum filetype filetype; +}; + #define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET) #define GETBIT(v,n) (((v) >> (n)) & 0x1) @@ -228,7 +238,8 @@ static ssize_t raw_write_page(struct mtd_info *mtd, void *buf, loff_t offset) return ret; } -static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) +static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd) { fcb->FingerPrint = 0x20424346; fcb->Version = 0x01000000; @@ -241,42 +252,37 @@ static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1; fcb->EccBlockNEccType = fcb->EccBlock0EccType; - /* Also hardcoded in kobs-ng */ - fcb->DataSetup = 80; - fcb->DataHold = 60; - fcb->AddressSetup = 25; - fcb->DSAMPLE_TIME = 6; - fcb->MetadataBytes = 0x0000000a; fcb->EccBlock0Size = 0x00000200; fcb->EccBlockNSize = 0x00000200; fcb->NumEccBlocksPerPage = mtd->writesize / fcb->EccBlock0Size - 1; - /* DBBT search area starts at third block */ - fcb->DBBTSearchAreaStartAddress = mtd->erasesize / mtd->writesize * 2; + /* DBBT search area starts at second page on first block */ + fcb->DBBTSearchAreaStartAddress = 1; fcb->BadBlockMarkerByte = mxs_nand_mark_byte_offset(mtd); fcb->BadBlockMarkerStartBit = mxs_nand_mark_bit_offset(mtd); fcb->BBMarkerPhysicalOffset = mtd->writesize; + imx_handler->fcb_create(imx_handler, fcb, mtd); + fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4); return 0; } -static int imx6_bbu_erase(struct mtd_info *mtd) +static int imx_bbu_erase(struct mtd_info *mtd) { uint64_t offset = 0; - int len = SZ_2M; struct erase_info erase; int ret; - while (len > 0) { + while (offset < mtd->size) { pr_debug("erasing at 0x%08llx\n", offset); if (mtd_block_isbad(mtd, offset)) { - offset += mtd->erasesize; pr_debug("erase skip block @ 0x%08llx\n", offset); + offset += mtd->erasesize; continue; } @@ -289,13 +295,13 @@ static int imx6_bbu_erase(struct mtd_info *mtd) return ret; offset += mtd->erasesize; - len -= mtd->erasesize; } return 0; } -static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len) +static int imx_bbu_write_firmware(struct mtd_info *mtd, unsigned block, + unsigned num_blocks, void *buf, size_t len) { uint64_t offset = block * mtd->erasesize; int ret; @@ -304,13 +310,16 @@ static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, s while (len > 0) { int now = min(len, mtd->erasesize); + if (!num_blocks) + return -ENOSPC; + pr_debug("writing %p at 0x%08llx, left 0x%08x\n", buf, offset, len); if (mtd_block_isbad(mtd, offset)) { + pr_debug("write skip block @ 0x%08llx\n", offset); offset += mtd->erasesize; block++; - pr_debug("write skip block @ 0x%08llx\n", offset); continue; } @@ -322,6 +331,7 @@ static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, s len -= now; buf += now; block++; + num_blocks--; } return block; @@ -348,35 +358,40 @@ static int dbbt_data_create(struct mtd_info *mtd, void *buf, int block_last) return n_bad_blocks; } -static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data) +static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data) { + struct imx_nand_fcb_bbu_handler *imx_handler = + container_of(handler, struct imx_nand_fcb_bbu_handler, handler); struct cdev *bcb_cdev; struct mtd_info *mtd; - int ret, block_fw1, block_fw2, block_last; + int ret, block_fw1, block_fw2; struct fcb_block *fcb; struct dbbt_block *dbbt; void *fcb_raw_page, *dbbt_page, *dbbt_data_page; void *ecc; int written; void *fw; - unsigned fw_size; + unsigned fw_size, partition_size; int i; + enum filetype filetype; + unsigned num_blocks_fcb_dbbt, num_blocks, num_blocks_fw; - if (file_detect_type(data->image, data->len) != filetype_arm_barebox && - !bbu_force(data, "Not an ARM barebox image")) - return -EINVAL; + filetype = file_detect_type(data->image, data->len); - ret = bbu_confirm(data); - if (ret) - return ret; + if (filetype != imx_handler->filetype && + !bbu_force(data, "Image is not of type %s but of type %s", + file_type_to_string(imx_handler->filetype), + file_type_to_string(filetype))) + return -EINVAL; - bcb_cdev = cdev_by_name("nand0"); + bcb_cdev = cdev_by_name(handler->devicefile); if (!bcb_cdev) { pr_err("%s: No FCB device!\n", __func__); return -ENODEV; } mtd = bcb_cdev->mtd; + partition_size = mtd->size; fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize); @@ -396,30 +411,45 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da fw = xzalloc(fw_size); memcpy(fw, data->image, data->len); - block_fw1 = 4; + num_blocks_fcb_dbbt = 4; + num_blocks = partition_size / mtd->erasesize; + num_blocks_fw = (num_blocks - num_blocks_fcb_dbbt) / 2; + + block_fw1 = num_blocks_fcb_dbbt; + block_fw2 = num_blocks_fcb_dbbt + num_blocks_fw; + + pr_info("writing first firmware to block %d (ofs 0x%08x)\n", + block_fw1, block_fw1 * mtd->erasesize); + pr_info("writing second firmware to block %d (ofs 0x%08x)\n", + block_fw2, block_fw2 * mtd->erasesize); + pr_info("maximum size per firmware: 0x%08x bytes\n", + num_blocks_fw * mtd->erasesize); - ret = imx6_bbu_erase(mtd); + if (num_blocks_fw * mtd->erasesize < fw_size) + return -ENOSPC; + + ret = bbu_confirm(data); if (ret) goto out; - ret = imx6_bbu_write_firmware(mtd, block_fw1, fw, fw_size); - if (ret < 0) + ret = imx_bbu_erase(mtd); + if (ret) goto out; - block_fw2 = ret; - - ret = imx6_bbu_write_firmware(mtd, block_fw2, fw, fw_size); + ret = imx_bbu_write_firmware(mtd, block_fw1, num_blocks_fw, fw, fw_size); if (ret < 0) goto out; - block_last = ret; + ret = imx_bbu_write_firmware(mtd, block_fw2, num_blocks_fw, fw, fw_size); + if (ret < 0) + goto out; fcb->Firmware1_startingPage = block_fw1 * mtd->erasesize / mtd->writesize; fcb->Firmware2_startingPage = block_fw2 * mtd->erasesize / mtd->writesize; fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize; fcb->PagesInFirmware2 = fcb->PagesInFirmware1; - fcb_create(fcb, mtd); + fcb_create(imx_handler, fcb, mtd); encode_hamming_13_8(fcb, ecc, 512); /* @@ -431,10 +461,6 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da */ memset(fcb_raw_page + mtd->writesize, 0xFF, 2); - ret = raw_write_page(mtd, fcb_raw_page, 0); - if (ret) - goto out; - ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize); if (ret) goto out; @@ -443,21 +469,29 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da dbbt->FingerPrint = 0x54424244; dbbt->Version = 0x01000000; - ret = dbbt_data_create(mtd, dbbt_data_page, block_last); + ret = dbbt_data_create(mtd, dbbt_data_page, block_fw2 + num_blocks_fw); if (ret < 0) goto out; - if (ret > 0) + if (ret > 0) { dbbt->DBBTNumOfPages = 1; + if (imx_handler->dbbt_create) + imx_handler->dbbt_create(imx_handler, dbbt, ret); + } - for (i = 2; i < 4; i++) { - ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page); + for (i = 0; i < 4; i++) { + ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize * i); + if (ret) + goto out; + + ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize, + mtd->writesize, &written, dbbt_page); if (ret) goto out; if (dbbt->DBBTNumOfPages > 0) { - ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 4, - 2048, &written, dbbt_data_page); + ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 5, + mtd->writesize, &written, dbbt_data_page); if (ret) goto out; } @@ -472,16 +506,127 @@ out: return ret; } +static void imx6_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd) +{ + /* Also hardcoded in kobs-ng */ + fcb->DataSetup = 80; + fcb->DataHold = 60; + fcb->AddressSetup = 25; + fcb->DSAMPLE_TIME = 6; + fcb->MetadataBytes = 10; +} + int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) { + struct imx_nand_fcb_bbu_handler *imx_handler; struct bbu_handler *handler; int ret; - handler = xzalloc(sizeof(*handler)); - handler->devicefile = "/dev/nand0"; + imx_handler = xzalloc(sizeof(*imx_handler)); + imx_handler->fcb_create = imx6_fcb_create; + imx_handler->filetype = filetype_arm_barebox; + + handler = &imx_handler->handler; + handler->devicefile = "nand0.barebox"; + handler->name = name; + handler->flags = flags; + handler->handler = imx_bbu_nand_update; + + ret = bbu_register_handler(handler); + if (ret) + free(handler); + + return ret; +} + +#ifdef CONFIG_ARCH_IMX28 +#include <mach/imx28-regs.h> + +#define GPMI_TIMING0 0x00000070 +#define GPMI_TIMING0_ADDRESS_SETUP_MASK (0xff << 16) +#define GPMI_TIMING0_ADDRESS_SETUP_OFFSET 16 +#define GPMI_TIMING0_DATA_HOLD_MASK (0xff << 8) +#define GPMI_TIMING0_DATA_HOLD_OFFSET 8 +#define GPMI_TIMING0_DATA_SETUP_MASK 0xff +#define GPMI_TIMING0_DATA_SETUP_OFFSET 0 + +#define GPMI_TIMING1 0x00000080 + +#define BCH_MODE 0x00000020 + +#define BCH_FLASH0LAYOUT0 0x00000080 +#define BCH_FLASHLAYOUT0_NBLOCKS_MASK (0xff << 24) +#define BCH_FLASHLAYOUT0_NBLOCKS_OFFSET 24 +#define BCH_FLASHLAYOUT0_META_SIZE_MASK (0xff << 16) +#define BCH_FLASHLAYOUT0_META_SIZE_OFFSET 16 +#define BCH_FLASHLAYOUT0_ECC0_MASK (0xf << 12) +#define BCH_FLASHLAYOUT0_ECC0_OFFSET 12 +#define BCH_FLASHLAYOUT0_DATA0_SIZE_MASK 0xfff +#define BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET 0 + +#define BCH_FLASH0LAYOUT1 0x00000090 +#define BCH_FLASHLAYOUT1_PAGE_SIZE_MASK (0xffff << 16) +#define BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET 16 +#define BCH_FLASHLAYOUT1_ECCN_MASK (0xf << 12) +#define BCH_FLASHLAYOUT1_ECCN_OFFSET 12 +#define BCH_FLASHLAYOUT1_DATAN_SIZE_MASK 0xfff +#define BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET 0 + +static void imx28_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct fcb_block *fcb, struct mtd_info *mtd) +{ + u32 fl0, fl1, t0; + void __iomem *bch_regs = (void *)MXS_BCH_BASE; + void __iomem *gpmi_regs = (void *)MXS_GPMI_BASE; + + fl0 = readl(bch_regs + BCH_FLASH0LAYOUT0); + fl1 = readl(bch_regs + BCH_FLASH0LAYOUT1); + t0 = readl(gpmi_regs + GPMI_TIMING0); + + fcb->MetadataBytes = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE); + fcb->DataSetup = BF_VAL(t0, GPMI_TIMING0_DATA_SETUP); + fcb->DataHold = BF_VAL(t0, GPMI_TIMING0_DATA_HOLD); + fcb->AddressSetup = BF_VAL(t0, GPMI_TIMING0_ADDRESS_SETUP); + fcb->MetadataBytes = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE); + fcb->NumEccBlocksPerPage = BF_VAL(fl0, BCH_FLASHLAYOUT0_NBLOCKS); + fcb->EraseThreshold = readl(bch_regs + BCH_MODE); +} + +static void imx28_dbbt_create(struct imx_nand_fcb_bbu_handler *imx_handler, + struct dbbt_block *dbbt, int num_bad_blocks) +{ + uint32_t a = 0; + uint8_t *p = (void *)dbbt; + int i; + + dbbt->numberBB = num_bad_blocks; + + for (i = 4; i < 512; i++) + a += p[i]; + + a ^= 0xffffffff; + + dbbt->Checksum = a; +} + +int imx28_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + struct imx_nand_fcb_bbu_handler *imx_handler; + struct bbu_handler *handler; + int ret; + + imx_handler = xzalloc(sizeof(*imx_handler)); + imx_handler->fcb_create = imx28_fcb_create; + imx_handler->dbbt_create = imx28_dbbt_create; + + imx_handler->filetype = filetype_mxs_bootstream; + + handler = &imx_handler->handler; + handler->devicefile = "nand0.barebox"; handler->name = name; handler->flags = flags; - handler->handler = imx6_bbu_nand_update; + handler->handler = imx_bbu_nand_update; ret = bbu_register_handler(handler); if (ret) @@ -489,3 +634,4 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) return ret; } +#endif diff --git a/common/kallsyms.c b/common/kallsyms.c index 53e22cdc73..e15dec5dfc 100644 --- a/common/kallsyms.c +++ b/common/kallsyms.c @@ -212,4 +212,3 @@ int sprint_symbol(char *buffer, unsigned long address) return len; } EXPORT_SYMBOL_GPL(sprint_symbol); - diff --git a/common/parser.c b/common/parser.c index 4a48210c4d..207599f429 100644 --- a/common/parser.c +++ b/common/parser.c @@ -284,4 +284,3 @@ int run_shell(void) } return 0; } - diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 24cb5bc62b..338bea1280 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -113,14 +113,29 @@ int device_detect(struct device_d *dev) return dev->detect(dev); } -int device_detect_by_name(const char *devname) +int device_detect_by_name(const char *__devname) { - struct device_d *dev = get_device_by_name(devname); + char *devname = xstrdup(__devname); + char *str = devname; + struct device_d *dev; + int ret = -ENODEV; + + while (1) { + strsep(&str, "."); + + dev = get_device_by_name(devname); + if (dev) + ret = device_detect(dev); - if (!dev) - return -ENODEV; + if (!str) + break; + else + *(str - 1) = '.'; + } - return device_detect(dev); + free(devname); + + return ret; } static int match(struct driver_d *drv, struct device_d *dev) diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig index 31f7d2d4ea..ebd8da9591 100644 --- a/drivers/mci/Kconfig +++ b/drivers/mci/Kconfig @@ -95,7 +95,7 @@ config MCI_OMAP_HSMMC config MCI_PXA bool "PXA" - depends on ARCH_PXA + depends on ARCH_PXA2XX help Enable this entry to add support to read and write SD cards on a XScale PXA25x / PXA27x based system. diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 49ea88cac4..ea1be556b4 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -20,6 +20,16 @@ config MTD_RAW_DEVICE default n prompt "mtdraw device to read/write both data+oob" +config MTD_CONCAT + bool + prompt "MTD concatenating support" + help + Support for concatenating several MTD devices into a single + (virtual) one. This allows you to have -for example- a JFFS(2) + file system spanning multiple physical flash chips. This option + needs driver support, currently only the cfi-flash driver supports + concatenating MTD devices. + source "drivers/mtd/devices/Kconfig" source "drivers/mtd/nor/Kconfig" source "drivers/mtd/nand/Kconfig" diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 148ec6ca23..d3ae7fca3e 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -6,3 +6,4 @@ obj-y += devices/ obj-$(CONFIG_MTD) += core.o partition.o obj-$(CONFIG_MTD_OOB_DEVICE) += mtdoob.o obj-$(CONFIG_MTD_RAW_DEVICE) += mtdraw.o +obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c index 681dc9313c..fda903441c 100644 --- a/drivers/mtd/core.c +++ b/drivers/mtd/core.c @@ -18,7 +18,9 @@ #include <common.h> #include <linux/mtd/nand.h> #include <linux/mtd/mtd.h> +#include <mtd/ubi-user.h> #include <cmdlinepart.h> +#include <filetype.h> #include <init.h> #include <xfuncs.h> #include <driver.h> @@ -542,7 +544,42 @@ static int of_mtd_fixup(struct device_node *root, void *ctx) return 0; } -int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) +static int mtd_detect(struct device_d *dev) +{ + struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev); + int bufsize = 512; + void *buf; + int ret; + enum filetype filetype; + size_t retlen; + + /* + * Do not try to attach an UBI device if this device has partitions + * as it's not a good idea to attach UBI on a raw device when the + * real UBI only spans the first partition. + */ + if (!list_empty(&mtd->partitions)) + return -EBUSY; + + buf = xmalloc(bufsize); + + ret = mtd_read(mtd, 0, bufsize, &retlen, buf); + if (ret) + goto out; + + filetype = file_detect_type(buf, bufsize); + if (filetype == filetype_ubi) { + ret = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 20); + if (ret == -EEXIST) + ret = 0; + } +out: + free(buf); + + return ret; +} + +int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id) { struct mtddev_hook *hook; int ret; @@ -554,6 +591,9 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) if (mtd->parent) mtd->class_dev.parent = mtd->parent; + if (IS_ENABLED(CONFIG_MTD_UBI)) + mtd->class_dev.detect = mtd_detect; + ret = register_device(&mtd->class_dev); if (ret) return ret; diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 345c348c69..9c3925bde1 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -21,7 +21,8 @@ config MTD_DATAFLASH_WRITE_VERIFY config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" - depends on MTD_SPI_NOR + depends on SPI + select MTD_SPI_NOR help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF, diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index c941767de9..794c9dbd82 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -148,14 +148,14 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset) { struct m25p *flash = nor->priv; - dev_dbg(nor->dev, "%dKiB at 0x%08x\n", - flash->mtd.erasesize / 1024, (u32)offset); + dev_dbg(nor->dev, "%dKiB at 0x%08x\n", + flash->mtd.erasesize / 1024, (u32)offset); - /* Set up command buffer. */ - flash->command[0] = nor->erase_opcode; - m25p_addr2cmd(nor, offset, flash->command); + /* Set up command buffer. */ + flash->command[0] = nor->erase_opcode; + m25p_addr2cmd(nor, offset, flash->command); - spi_write(flash->spi, flash->command, m25p_cmdsz(nor)); + spi_write(flash->spi, flash->command, m25p_cmdsz(nor)); return 0; } @@ -213,11 +213,11 @@ static const struct platform_device_id m25p_ids[] = { {"w25q128"}, {"w25q256"}, {"cat25c11"}, {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, - /* - * Generic support for SPI NOR that can be identified by the JEDEC READ - * ID opcode (0x9F). Use this, if possible. - */ - {"nor-jedec"}, + /* + * Generic support for SPI NOR that can be identified by the JEDEC READ + * ID opcode (0x9F). Use this, if possible. + */ + {"nor-jedec"}, { }, }; @@ -233,7 +233,7 @@ static int m25p_probe(struct device_d *dev) struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; - char *flash_name = NULL; + const char *flash_name = NULL; int device_id; int ret; @@ -277,13 +277,10 @@ static int m25p_probe(struct device_d *dev) return ret; device_id = DEVICE_ID_SINGLE; - if (dev->device_node) { - const char *alias = of_alias_get(dev->device_node); - if (alias) - flash_name = xstrdup(alias); - } else if (data && data->name) { + if (dev->device_node) + flash_name = of_alias_get(dev->device_node); + else if (data && data->name) flash_name = data->name; - } if (!flash_name) { device_id = DEVICE_ID_DYNAMIC; diff --git a/drivers/mtd/mtd.h b/drivers/mtd/mtd.h index 414bd6cdb5..2a85265f98 100644 --- a/drivers/mtd/mtd.h +++ b/drivers/mtd/mtd.h @@ -25,7 +25,7 @@ */ struct mtddev_hook { struct list_head hook; - int (*add_mtd_device)(struct mtd_info *mtd, char *devname, void **priv); + int (*add_mtd_device)(struct mtd_info *mtd, const char *devname, void **priv); int (*del_mtd_device)(struct mtd_info *mtd, void **priv); void *priv; }; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c new file mode 100644 index 0000000000..10d3dc4c36 --- /dev/null +++ b/drivers/mtd/mtdconcat.c @@ -0,0 +1,765 @@ +/* + * MTD device concatenation layer + * + * Copyright © 2002 Robert Kaiser <rkaiser@sysgo.de> + * Copyright © 2002-2010 David Woodhouse <dwmw2@infradead.org> + * + * NAND support by Christian Gan <cgan@iders.ca> + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include <common.h> +#include <malloc.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/concat.h> + +#include <asm-generic/div64.h> + +/* + * Our storage structure: + * Subdev points to an array of pointers to struct mtd_info objects + * which is allocated along with this structure + * + */ +struct mtd_concat { + struct mtd_info mtd; + int num_subdev; + struct mtd_info **subdev; +}; + +/* + * how to calculate the size required for the above structure, + * including the pointer array subdev points to: + */ +#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \ + ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *))) + +/* + * Given a pointer to the MTD object in the mtd_concat structure, + * we can retrieve the pointer to that structure with this macro. + */ +#define CONCAT(x) ((struct mtd_concat *)(x)) + +/* + * MTD methods which look up the relevant subdevice, translate the + * effective address and pass through to the subdevice. + */ + +static int +concat_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int ret = 0, err; + int i; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) { + /* Not destined for this subdev */ + size = 0; + from -= subdev->size; + continue; + } + if (from + len > subdev->size) + /* First part goes into this subdev */ + size = subdev->size - from; + else + /* Entire transaction goes into this subdev */ + size = len; + + err = mtd_read(subdev, from, size, &retsize, buf); + + /* Save information about bitflips! */ + if (unlikely(err)) { + if (mtd_is_eccerr(err)) { + mtd->ecc_stats.failed++; + ret = err; + } else if (mtd_is_bitflip(err)) { + mtd->ecc_stats.corrected++; + /* Do not overwrite -EBADMSG !! */ + if (!ret) + ret = err; + } else + return err; + } + + *retlen += retsize; + len -= size; + if (len == 0) + return ret; + + buf += size; + from = 0; + } + return -EINVAL; +} + +static int +concat_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t * retlen, const u_char * buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) { + size = 0; + to -= subdev->size; + continue; + } + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + err = mtd_write(subdev, to, size, &retsize, buf); + if (err) + break; + + *retlen += retsize; + len -= size; + if (len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; + } + return err; +} + +static int +concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ + struct mtd_concat *concat = CONCAT(mtd); + struct mtd_oob_ops devops = *ops; + int i, err, ret = 0; + + ops->retlen = ops->oobretlen = 0; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + + if (from >= subdev->size) { + from -= subdev->size; + continue; + } + + /* partial read ? */ + if (from + devops.len > subdev->size) + devops.len = subdev->size - from; + + err = mtd_read_oob(subdev, from, &devops); + ops->retlen += devops.retlen; + ops->oobretlen += devops.oobretlen; + + /* Save information about bitflips! */ + if (unlikely(err)) { + if (mtd_is_eccerr(err)) { + mtd->ecc_stats.failed++; + ret = err; + } else if (mtd_is_bitflip(err)) { + mtd->ecc_stats.corrected++; + /* Do not overwrite -EBADMSG !! */ + if (!ret) + ret = err; + } else + return err; + } + + if (devops.datbuf) { + devops.len = ops->len - ops->retlen; + if (!devops.len) + return ret; + devops.datbuf += devops.retlen; + } + if (devops.oobbuf) { + devops.ooblen = ops->ooblen - ops->oobretlen; + if (!devops.ooblen) + return ret; + devops.oobbuf += ops->oobretlen; + } + + from = 0; + } + return -EINVAL; +} + +static int +concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) +{ + struct mtd_concat *concat = CONCAT(mtd); + struct mtd_oob_ops devops = *ops; + int i, err; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + ops->retlen = ops->oobretlen = 0; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + + if (to >= subdev->size) { + to -= subdev->size; + continue; + } + + /* partial write ? */ + if (to + devops.len > subdev->size) + devops.len = subdev->size - to; + + err = mtd_write_oob(subdev, to, &devops); + ops->retlen += devops.retlen; + ops->oobretlen += devops.oobretlen; + if (err) + return err; + + if (devops.datbuf) { + devops.len = ops->len - ops->retlen; + if (!devops.len) + return 0; + devops.datbuf += devops.retlen; + } + if (devops.oobbuf) { + devops.ooblen = ops->ooblen - ops->oobretlen; + if (!devops.ooblen) + return 0; + devops.oobbuf += devops.oobretlen; + } + to = 0; + } + return -EINVAL; +} + +static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) +{ + int err; + wait_queue_head_t waitq; + + erase->mtd = mtd; + erase->priv = (unsigned long) &waitq; + + err = mtd_erase(mtd, erase); + + return err; +} + +static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct mtd_concat *concat = CONCAT(mtd); + struct mtd_info *subdev; + int i, err; + uint64_t length, offset = 0; + struct erase_info *erase; + + /* + * Check for proper erase block alignment of the to-be-erased area. + * It is easier to do this based on the super device's erase + * region info rather than looking at each particular sub-device + * in turn. + */ + if (!concat->mtd.numeraseregions) { + /* the easy case: device has uniform erase block size */ + if (instr->addr & (concat->mtd.erasesize - 1)) + return -EINVAL; + if (instr->len & (concat->mtd.erasesize - 1)) + return -EINVAL; + } else { + /* device has variable erase size */ + struct mtd_erase_region_info *erase_regions = + concat->mtd.eraseregions; + + /* + * Find the erase region where the to-be-erased area begins: + */ + for (i = 0; i < concat->mtd.numeraseregions && + instr->addr >= erase_regions[i].offset; i++) ; + --i; + + /* + * Now erase_regions[i] is the region in which the + * to-be-erased area begins. Verify that the starting + * offset is aligned to this region's erase size: + */ + if (i < 0 || instr->addr & (erase_regions[i].erasesize - 1)) + return -EINVAL; + + /* + * now find the erase region where the to-be-erased area ends: + */ + for (; i < concat->mtd.numeraseregions && + (instr->addr + instr->len) >= erase_regions[i].offset; + ++i) ; + --i; + /* + * check if the ending offset is aligned to this region's erase size + */ + if (i < 0 || ((instr->addr + instr->len) & + (erase_regions[i].erasesize - 1))) + return -EINVAL; + } + + /* make a local copy of instr to avoid modifying the caller's struct */ + erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); + + if (!erase) + return -ENOMEM; + + *erase = *instr; + length = instr->len; + + /* + * find the subdevice where the to-be-erased area begins, adjust + * starting offset to be relative to the subdevice start + */ + for (i = 0; i < concat->num_subdev; i++) { + subdev = concat->subdev[i]; + if (subdev->size <= erase->addr) { + erase->addr -= subdev->size; + offset += subdev->size; + } else { + break; + } + } + + /* must never happen since size limit has been verified above */ + BUG_ON(i >= concat->num_subdev); + + /* now do the erase: */ + err = 0; + for (; length > 0; i++) { + /* loop for all subdevices affected by this request */ + subdev = concat->subdev[i]; /* get current subdevice */ + + /* limit length to subdevice's size: */ + if (erase->addr + length > subdev->size) + erase->len = subdev->size - erase->addr; + else + erase->len = length; + + length -= erase->len; + if ((err = concat_dev_erase(subdev, erase))) { + /* sanity check: should never happen since + * block alignment has been checked above */ + BUG_ON(err == -EINVAL); + if (erase->fail_addr != 0xffffffff) + instr->fail_addr = erase->fail_addr + offset; + break; + } + /* + * erase->addr specifies the offset of the area to be + * erased *within the current subdevice*. It can be + * non-zero only the first time through this loop, i.e. + * for the first subdevice where blocks need to be erased. + * All the following erases must begin at the start of the + * current subdevice, i.e. at offset zero. + */ + erase->addr = 0; + offset += subdev->size; + } + instr->state = erase->state; + kfree(erase); + if (err) + return err; + + if (instr->callback) + instr->callback(instr); + return 0; +} + +static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = -EINVAL; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + uint64_t size; + + if (ofs >= subdev->size) { + size = 0; + ofs -= subdev->size; + continue; + } + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = mtd_lock(subdev, ofs, size); + if (err) + break; + + len -= size; + if (len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + + return err; +} + +static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = 0; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + uint64_t size; + + if (ofs >= subdev->size) { + size = 0; + ofs -= subdev->size; + continue; + } + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = mtd_unlock(subdev, ofs, size); + if (err) + break; + + len -= size; + if (len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + + return err; +} + +static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, res = 0; + + if (!mtd_can_have_bb(concat->subdev[0])) + return res; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + + if (ofs >= subdev->size) { + ofs -= subdev->size; + continue; + } + + res = mtd_block_isbad(subdev, ofs); + break; + } + + return res; +} + +static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = -EINVAL; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + + if (ofs >= subdev->size) { + ofs -= subdev->size; + continue; + } + + err = mtd_block_markbad(subdev, ofs); + if (!err) + mtd->ecc_stats.badblocks++; + break; + } + + return err; +} + +/* + * This function constructs a virtual MTD device by concatenating + * num_devs MTD devices. A pointer to the new device object is + * stored to *new_dev upon success. This function does _not_ + * register any devices: this is the caller's responsibility. + */ +struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */ + int num_devs, /* number of subdevices */ + const char *name) +{ /* name for the new device */ + int i; + size_t size; + struct mtd_concat *concat; + uint32_t max_erasesize, curr_erasesize; + int num_erase_region; + int max_writebufsize = 0; + + printk(KERN_NOTICE "Concatenating MTD devices:\n"); + for (i = 0; i < num_devs; i++) + printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name); + printk(KERN_NOTICE "into device \"%s\"\n", name); + + /* allocate the device structure */ + size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); + concat = kzalloc(size, GFP_KERNEL); + if (!concat) { + printk + ("memory allocation error while creating concatenated device \"%s\"\n", + name); + return NULL; + } + concat->subdev = (struct mtd_info **) (concat + 1); + + /* + * Set up the new "super" device's MTD object structure, check for + * incompatibilities between the subdevices. + */ + concat->mtd.type = subdev[0]->type; + concat->mtd.flags = subdev[0]->flags; + concat->mtd.size = subdev[0]->size; + concat->mtd.erasesize = subdev[0]->erasesize; + concat->mtd.writesize = subdev[0]->writesize; + + for (i = 0; i < num_devs; i++) + if (max_writebufsize < subdev[i]->writebufsize) + max_writebufsize = subdev[i]->writebufsize; + concat->mtd.writebufsize = max_writebufsize; + + concat->mtd.subpage_sft = subdev[0]->subpage_sft; + concat->mtd.oobsize = subdev[0]->oobsize; + concat->mtd.oobavail = subdev[0]->oobavail; + if (subdev[0]->read_oob) + concat->mtd.read_oob = concat_read_oob; + if (subdev[0]->write_oob) + concat->mtd.write_oob = concat_write_oob; + if (subdev[0]->block_isbad) + concat->mtd.block_isbad = concat_block_isbad; + if (subdev[0]->block_markbad) + concat->mtd.block_markbad = concat_block_markbad; + + concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; + + concat->subdev[0] = subdev[0]; + + for (i = 1; i < num_devs; i++) { + if (concat->mtd.type != subdev[i]->type) { + kfree(concat); + printk("Incompatible device type on \"%s\"\n", + subdev[i]->name); + return NULL; + } + if (concat->mtd.flags != subdev[i]->flags) { + /* + * Expect all flags except MTD_WRITEABLE to be + * equal on all subdevices. + */ + if ((concat->mtd.flags ^ subdev[i]-> + flags) & ~MTD_WRITEABLE) { + kfree(concat); + printk("Incompatible device flags on \"%s\"\n", + subdev[i]->name); + return NULL; + } else + /* if writeable attribute differs, + make super device writeable */ + concat->mtd.flags |= + subdev[i]->flags & MTD_WRITEABLE; + } + + concat->mtd.size += subdev[i]->size; + concat->mtd.ecc_stats.badblocks += + subdev[i]->ecc_stats.badblocks; + if (concat->mtd.writesize != subdev[i]->writesize || + concat->mtd.subpage_sft != subdev[i]->subpage_sft || + concat->mtd.oobsize != subdev[i]->oobsize || + !concat->mtd.read_oob != !subdev[i]->read_oob || + !concat->mtd.write_oob != !subdev[i]->write_oob) { + kfree(concat); + printk("Incompatible OOB or ECC data on \"%s\"\n", + subdev[i]->name); + return NULL; + } + concat->subdev[i] = subdev[i]; + + } + + concat->mtd.ecclayout = subdev[0]->ecclayout; + + concat->num_subdev = num_devs; + concat->mtd.name = xstrdup(name); + + concat->mtd.erase = concat_erase; + concat->mtd.read = concat_read; + concat->mtd.write = concat_write; + concat->mtd.lock = concat_lock; + concat->mtd.unlock = concat_unlock; + + /* + * Combine the erase block size info of the subdevices: + * + * first, walk the map of the new device and see how + * many changes in erase size we have + */ + max_erasesize = curr_erasesize = subdev[0]->erasesize; + num_erase_region = 1; + for (i = 0; i < num_devs; i++) { + if (subdev[i]->numeraseregions == 0) { + /* current subdevice has uniform erase size */ + if (subdev[i]->erasesize != curr_erasesize) { + /* if it differs from the last subdevice's erase size, count it */ + ++num_erase_region; + curr_erasesize = subdev[i]->erasesize; + if (curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } else { + /* current subdevice has variable erase size */ + int j; + for (j = 0; j < subdev[i]->numeraseregions; j++) { + + /* walk the list of erase regions, count any changes */ + if (subdev[i]->eraseregions[j].erasesize != + curr_erasesize) { + ++num_erase_region; + curr_erasesize = + subdev[i]->eraseregions[j]. + erasesize; + if (curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + } + } + + if (num_erase_region == 1) { + /* + * All subdevices have the same uniform erase size. + * This is easy: + */ + concat->mtd.erasesize = curr_erasesize; + concat->mtd.numeraseregions = 0; + } else { + uint64_t tmp64; + + /* + * erase block size varies across the subdevices: allocate + * space to store the data describing the variable erase regions + */ + struct mtd_erase_region_info *erase_region_p; + uint64_t begin, position; + + concat->mtd.erasesize = max_erasesize; + concat->mtd.numeraseregions = num_erase_region; + concat->mtd.eraseregions = erase_region_p = + kmalloc(num_erase_region * + sizeof (struct mtd_erase_region_info), GFP_KERNEL); + if (!erase_region_p) { + kfree(concat); + printk + ("memory allocation error while creating erase region list" + " for device \"%s\"\n", name); + return NULL; + } + + /* + * walk the map of the new device once more and fill in + * in erase region info: + */ + curr_erasesize = subdev[0]->erasesize; + begin = position = 0; + for (i = 0; i < num_devs; i++) { + if (subdev[i]->numeraseregions == 0) { + /* current subdevice has uniform erase size */ + if (subdev[i]->erasesize != curr_erasesize) { + /* + * fill in an mtd_erase_region_info structure for the area + * we have walked so far: + */ + erase_region_p->offset = begin; + erase_region_p->erasesize = + curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; + begin = position; + + curr_erasesize = subdev[i]->erasesize; + ++erase_region_p; + } + position += subdev[i]->size; + } else { + /* current subdevice has variable erase size */ + int j; + for (j = 0; j < subdev[i]->numeraseregions; j++) { + /* walk the list of erase regions, count any changes */ + if (subdev[i]->eraseregions[j]. + erasesize != curr_erasesize) { + erase_region_p->offset = begin; + erase_region_p->erasesize = + curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; + begin = position; + + curr_erasesize = + subdev[i]->eraseregions[j]. + erasesize; + ++erase_region_p; + } + position += + subdev[i]->eraseregions[j]. + numblocks * (uint64_t)curr_erasesize; + } + } + } + /* Now write the final entry */ + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; + } + + return &concat->mtd; +} + +/* + * This function destroys an MTD object obtained from concat_mtd_devs() + */ + +void mtd_concat_destroy(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + if (concat->mtd.numeraseregions) + kfree(concat->mtd.eraseregions); + kfree(concat); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>"); +MODULE_DESCRIPTION("Generic support for concatenating of MTD devices"); diff --git a/drivers/mtd/mtdoob.c b/drivers/mtd/mtdoob.c index 10d17e90d2..6160ddba08 100644 --- a/drivers/mtd/mtdoob.c +++ b/drivers/mtd/mtdoob.c @@ -69,7 +69,7 @@ static struct file_operations mtd_ops_oob = { .lseek = dev_lseek_default, }; -static int add_mtdoob_device(struct mtd_info *mtd, char *devname, void **priv) +static int add_mtdoob_device(struct mtd_info *mtd, const char *devname, void **priv) { struct mtdoob *mtdoob; diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c index c25e4062ee..ae4bec2a4c 100644 --- a/drivers/mtd/mtdraw.c +++ b/drivers/mtd/mtdraw.c @@ -281,7 +281,7 @@ static const struct file_operations mtd_raw_fops = { .lseek = dev_lseek_default, }; -static int add_mtdraw_device(struct mtd_info *mtd, char *devname, void **priv) +static int add_mtdraw_device(struct mtd_info *mtd, const char *devname, void **priv) { struct mtdraw *mtdraw; diff --git a/drivers/mtd/nor/cfi_flash.c b/drivers/mtd/nor/cfi_flash.c index 0fa41bf67b..f2268dfde7 100644 --- a/drivers/mtd/nor/cfi_flash.c +++ b/drivers/mtd/nor/cfi_flash.c @@ -40,6 +40,8 @@ #include <errno.h> #include <progress.h> #include <linux/err.h> +#include <asm/unaligned.h> +#include <linux/mtd/concat.h> #include "cfi_flash.h" /* @@ -58,7 +60,9 @@ * */ -static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT}; +static unsigned int flash_offset_cfi[2] = { + FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT +}; /* * Check if chip width is defined. If not, start detecting with 8bit. @@ -72,7 +76,7 @@ static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT}; * Functions */ -static void flash_add_byte (struct flash_info *info, cfiword_t * cword, uchar c) +static void flash_add_byte(struct flash_info *info, cfiword_t *cword, u8 c) { if (bankwidth_is_1(info)) { *cword = c; @@ -94,7 +98,7 @@ static void flash_add_byte (struct flash_info *info, cfiword_t * cword, uchar c) #endif } -static int flash_write_cfiword (struct flash_info *info, ulong dest, +static int flash_write_cfiword(struct flash_info *info, unsigned long dest, cfiword_t cword) { void *dstaddr = (void *)dest; @@ -110,34 +114,21 @@ static int flash_write_cfiword (struct flash_info *info, ulong dest, else if (bankwidth_is_8(info)) flag = ((flash_read64(dstaddr) & cword) == cword); else - return 2; + return -EIO; if (!flag) - return 2; + return -EIO; info->cfi_cmd_set->flash_prepare_write(info); flash_write_word(info, cword, (void *)dest); - return flash_status_check (info, find_sector (info, dest), + return flash_status_check(info, find_sector (info, dest), info->write_tout, "write"); } #ifdef DEBUG -/* - * Debug support - */ -void print_longlong (char *str, unsigned long long data) -{ - int i; - char *cp; - - cp = (unsigned char *) &data; - for (i = 0; i < 8; i++) - sprintf (&str[i * 2], "%2.2x", *cp++); -} - -static void flash_printqry (struct cfi_qry *qry) +static void flash_printqry(struct cfi_qry *qry) { u8 *p = (u8 *)qry; int x, y; @@ -163,9 +154,9 @@ static void flash_printqry (struct cfi_qry *qry) /* * read a character at a port width address */ -uchar flash_read_uchar (struct flash_info *info, uint offset) +u8 flash_read_uchar(struct flash_info *info, unsigned int offset) { - uchar *cp = flash_make_addr(info, 0, offset); + u8 *cp = flash_make_addr(info, 0, offset); #if defined __LITTLE_ENDIAN return flash_read8(cp); #else @@ -177,23 +168,20 @@ uchar flash_read_uchar (struct flash_info *info, uint offset) * read a long word by picking the least significant byte of each maximum * port size word. Swap for ppc format. */ -static ulong flash_read_long (struct flash_info *info, flash_sect_t sect, uint offset) +static unsigned long flash_read_long(struct flash_info *info, flash_sect_t sect, + unsigned int offset) { - uchar *addr; - ulong retval; - -#ifdef DEBUG + u8 *addr; + unsigned long retval; int x; -#endif + addr = flash_make_addr (info, sect, offset); -#ifdef DEBUG dev_dbg(info->dev, "long addr is at %p info->portwidth = %d\n", addr, info->portwidth); - for (x = 0; x < 4 * info->portwidth; x++) { + for (x = 0; x < 4 * info->portwidth; x++) dev_dbg(info->dev, "addr[%x] = 0x%x\n", x, flash_read8(addr + x)); - } -#endif + #if defined __LITTLE_ENDIAN retval = ((flash_read8(addr) << 16) | (flash_read8(addr + info->portwidth) << 24) | @@ -216,14 +204,14 @@ static ulong flash_read_long (struct flash_info *info, flash_sect_t sect, uint o u32 jedec_read_mfr(struct flash_info *info) { int bank = 0; - uchar mfr; + u8 mfr; /* According to JEDEC "Standard Manufacturer's Identification Code" * (http://www.jedec.org/download/search/jep106W.pdf) * several first banks can contain 0x7f instead of actual ID */ do { - mfr = flash_read_uchar (info, + mfr = flash_read_uchar(info, (bank << 8) | FLASH_OFFSET_MANUFACTURER_ID); bank++; } while (mfr == FLASH_ID_CONTINUATION); @@ -231,7 +219,7 @@ u32 jedec_read_mfr(struct flash_info *info) return mfr; } -static void flash_read_cfi (struct flash_info *info, void *buf, +static void flash_read_cfi(struct flash_info *info, void *buf, unsigned int start, size_t len) { u8 *p = buf; @@ -241,45 +229,53 @@ static void flash_read_cfi (struct flash_info *info, void *buf, p[i] = flash_read_uchar(info, start + i); } -static int flash_detect_width (struct flash_info *info, struct cfi_qry *qry) +static int flash_detect_width(struct flash_info *info, struct cfi_qry *qry) { int cfi_offset; + int pw, cw; + + for (pw = CFG_FLASH_CFI_WIDTH; pw <= FLASH_CFI_64BIT; pw <<= 1) { + for (cw = FLASH_CFI_BY8; cw <= pw; cw <<= 1) { + info->chipwidth = cw; + info->portwidth = pw; + + flash_write_cmd(info, 0, 0, AMD_CMD_RESET); + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); + for (cfi_offset = 0; + cfi_offset < sizeof(flash_offset_cfi) / sizeof(unsigned int); + cfi_offset++) { - for (info->portwidth = CFG_FLASH_CFI_WIDTH; - info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) { - for (info->chipwidth = FLASH_CFI_BY8; - info->chipwidth <= info->portwidth; - info->chipwidth <<= 1) { - flash_write_cmd (info, 0, 0, AMD_CMD_RESET); - flash_write_cmd (info, 0, 0, FLASH_CMD_RESET); - for (cfi_offset=0; cfi_offset < sizeof(flash_offset_cfi)/sizeof(uint); cfi_offset++) { - flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI); - if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') - && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') - && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { - flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, - sizeof(struct cfi_qry)); - info->interface = le16_to_cpu(qry->interface_desc); - - info->cfi_offset=flash_offset_cfi[cfi_offset]; - dev_dbg(info->dev, "device interface is %d\n", - info->interface); - dev_dbg(info->dev, "found port %d chip %d chip_lsb %d ", - info->portwidth, info->chipwidth, info->chip_lsb); - dev_dbg(info->dev, "port %d bits chip %d bits\n", - info->portwidth << CFI_FLASH_SHIFT_WIDTH, - info->chipwidth << CFI_FLASH_SHIFT_WIDTH); - return 1; - } + flash_write_cmd(info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI); + + if (flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP, 'Q') && + flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') && + flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) + goto found; } } } - dev_dbg(info->dev, "not found\n"); + + dev_dbg(info->dev, "no flash found\n"); + + return -ENODEV; + +found: + flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, + sizeof(struct cfi_qry)); + info->interface = get_unaligned_le16(&qry->interface_desc); + info->cfi_offset = flash_offset_cfi[cfi_offset]; + dev_dbg(info->dev, "device interface is %d\n", info->interface); + dev_dbg(info->dev, "found port %d chip %d chip_lsb %d ", + info->portwidth, info->chipwidth, info->chip_lsb); + dev_dbg(info->dev, "port %d bits chip %d bits\n", + info->portwidth << CFI_FLASH_SHIFT_WIDTH, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + return 0; } -static int flash_detect_cfi (struct flash_info *info, struct cfi_qry *qry) +static int flash_detect_cfi(struct flash_info *info, struct cfi_qry *qry) { int ret; @@ -287,180 +283,184 @@ static int flash_detect_cfi (struct flash_info *info, struct cfi_qry *qry) info->chip_lsb = 0; ret = flash_detect_width (info, qry); - if (!ret) { - info->chip_lsb = 1; - ret = flash_detect_width (info, qry); - } - return ret; + if (!ret) + return 0; + + info->chip_lsb = 1; + return flash_detect_width (info, qry); } /* * The following code cannot be run from FLASH! */ -static ulong flash_get_size (struct flash_info *info) +static int flash_detect_size(struct flash_info *info) { - int i, j; + int i, j, ret; flash_sect_t sect_cnt; unsigned long sector; unsigned long tmp; int size_ratio; - uchar num_erase_regions; + int num_erase_regions; int erase_region_size; int erase_region_count; int cur_offset = 0; - struct cfi_qry qry; + struct cfi_qry qry = {}; unsigned long base = (unsigned long)info->base; - memset(&qry, 0, sizeof(qry)); - info->ext_addr = 0; info->cfi_version = 0; -#ifdef CFG_FLASH_PROTECTION - info->legacy_unlock = 0; -#endif /* first only malloc space for the first sector */ - info->start = xmalloc(sizeof(ulong)); + info->start = xmalloc(sizeof(*info->eraseregions)); info->start[0] = base; info->protect = 0; - if (flash_detect_cfi (info, &qry)) { - info->vendor = le16_to_cpu(qry.p_id); - info->ext_addr = le16_to_cpu(qry.p_adr); - num_erase_regions = qry.num_erase_regions; + ret = flash_detect_cfi(info, &qry); + if (ret) + return ret; - if (info->ext_addr) { - info->cfi_version = (ushort) flash_read_uchar (info, - info->ext_addr + 3) << 8; - info->cfi_version |= (ushort) flash_read_uchar (info, - info->ext_addr + 4); - } + info->vendor = get_unaligned_le16(&qry.p_id); + info->ext_addr = get_unaligned_le16(&qry.p_adr); + num_erase_regions = qry.num_erase_regions; + + if (info->ext_addr) { + info->cfi_version = (u16)flash_read_uchar (info, + info->ext_addr + 3) << 8; + info->cfi_version |= (u16)flash_read_uchar (info, + info->ext_addr + 4); + } #ifdef DEBUG - flash_printqry (&qry); + flash_printqry(&qry); #endif - switch (info->vendor) { -#ifdef CONFIG_DRIVER_CFI_INTEL - case CFI_CMDSET_INTEL_EXTENDED: - case CFI_CMDSET_INTEL_STANDARD: + switch (info->vendor) { + case CFI_CMDSET_INTEL_EXTENDED: + case CFI_CMDSET_INTEL_STANDARD: + if (IS_ENABLED(CONFIG_DRIVER_CFI_INTEL)) info->cfi_cmd_set = &cfi_cmd_set_intel; - break; -#endif -#ifdef CONFIG_DRIVER_CFI_AMD - case CFI_CMDSET_AMD_STANDARD: - case CFI_CMDSET_AMD_EXTENDED: + break; + case CFI_CMDSET_AMD_STANDARD: + case CFI_CMDSET_AMD_EXTENDED: + if (IS_ENABLED(CONFIG_DRIVER_CFI_AMD)) info->cfi_cmd_set = &cfi_cmd_set_amd; + break; + } + + if (!info->cfi_cmd_set) { + dev_err(info->dev, "unsupported vendor 0x%04x\n", info->vendor); + return -ENOSYS; + } + + info->cfi_cmd_set->flash_read_jedec_ids (info); + flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); + + info->cfi_cmd_set->flash_fixup (info, &qry); + + dev_dbg(info->dev, "manufacturer is %d\n", info->vendor); + dev_dbg(info->dev, "manufacturer id is 0x%x\n", info->manufacturer_id); + dev_dbg(info->dev, "device id is 0x%x\n", info->device_id); + dev_dbg(info->dev, "device id2 is 0x%x\n", info->device_id2); + dev_dbg(info->dev, "cfi version is 0x%04x\n", info->cfi_version); + + size_ratio = info->portwidth / info->chipwidth; + + /* if the chip is x8/x16 reduce the ratio by half */ + if ((info->interface == FLASH_CFI_X8X16) + && (info->chipwidth == FLASH_CFI_BY8) + && (size_ratio != 1)) { + size_ratio >>= 1; + } + + dev_dbg(info->dev, "size_ratio %d port %d bits chip %d bits\n", + size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + dev_dbg(info->dev, "found %d erase regions\n", num_erase_regions); + + info->eraseregions = xzalloc(sizeof(*info->eraseregions) * num_erase_regions); + info->numeraseregions = num_erase_regions; + sect_cnt = 0; + sector = base; + + for (i = 0; i < num_erase_regions; i++) { + struct mtd_erase_region_info *region = &info->eraseregions[i]; + + if (i > NUM_ERASE_REGIONS) { + dev_info(info->dev, "%d erase regions found, only %d used\n", + num_erase_regions, NUM_ERASE_REGIONS); break; -#endif - default: - dev_err(info->dev, "unsupported vendor\n"); - return 0; } - info->cfi_cmd_set->flash_read_jedec_ids (info); - flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI); - - info->cfi_cmd_set->flash_fixup (info, &qry); - - dev_dbg(info->dev, "manufacturer is %d\n", info->vendor); - dev_dbg(info->dev, "manufacturer id is 0x%x\n", info->manufacturer_id); - dev_dbg(info->dev, "device id is 0x%x\n", info->device_id); - dev_dbg(info->dev, "device id2 is 0x%x\n", info->device_id2); - dev_dbg(info->dev, "cfi version is 0x%04x\n", info->cfi_version); - - size_ratio = info->portwidth / info->chipwidth; - /* if the chip is x8/x16 reduce the ratio by half */ - if ((info->interface == FLASH_CFI_X8X16) - && (info->chipwidth == FLASH_CFI_BY8) - && (size_ratio != 1)) { - size_ratio >>= 1; - } - dev_dbg(info->dev, "size_ratio %d port %d bits chip %d bits\n", - size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, - info->chipwidth << CFI_FLASH_SHIFT_WIDTH); - dev_dbg(info->dev, "found %d erase regions\n", num_erase_regions); - info->eraseregions = xzalloc(sizeof(*(info->eraseregions)) * num_erase_regions); - info->numeraseregions = num_erase_regions; - sect_cnt = 0; - sector = base; - - for (i = 0; i < num_erase_regions; i++) { - struct mtd_erase_region_info *region = &info->eraseregions[i]; - - if (i > NUM_ERASE_REGIONS) { - dev_info(info->dev, "%d erase regions found, only %d used\n", - num_erase_regions, NUM_ERASE_REGIONS); - break; - } - tmp = le32_to_cpu(qry.erase_region_info[i]); - dev_dbg(info->dev, "erase region %u: 0x%08lx\n", i, tmp); - - erase_region_count = (tmp & 0xffff) + 1; - tmp >>= 16; - erase_region_size = - (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; - dev_dbg(info->dev, "erase_region_count = %d erase_region_size = %d\n", - erase_region_count, erase_region_size); - - region->offset = cur_offset; - region->erasesize = erase_region_size * size_ratio; - region->numblocks = erase_region_count; - cur_offset += erase_region_size * size_ratio * erase_region_count; - - /* increase the space malloced for the sector start addresses */ - info->start = xrealloc(info->start, sizeof(ulong) * (erase_region_count + sect_cnt)); - info->protect = xrealloc(info->protect, sizeof(uchar) * (erase_region_count + sect_cnt)); - - for (j = 0; j < erase_region_count; j++) { - info->start[sect_cnt] = sector; - sector += (erase_region_size * size_ratio); - - /* - * Only read protection status from supported devices (intel...) - */ - switch (info->vendor) { - case CFI_CMDSET_INTEL_EXTENDED: - case CFI_CMDSET_INTEL_STANDARD: - info->protect[sect_cnt] = - flash_isset (info, sect_cnt, - FLASH_OFFSET_PROTECT, - FLASH_STATUS_PROTECT); - break; - default: - info->protect[sect_cnt] = 0; /* default: not protected */ - } - - sect_cnt++; + tmp = get_unaligned_le32(&qry.erase_region_info[i]); + dev_dbg(info->dev, "erase region %u: 0x%08lx\n", i, tmp); + + erase_region_count = (tmp & 0xffff) + 1; + tmp >>= 16; + erase_region_size = + (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; + dev_dbg(info->dev, "erase_region_count = %d erase_region_size = %d\n", + erase_region_count, erase_region_size); + + region->offset = cur_offset; + region->erasesize = erase_region_size * size_ratio; + region->numblocks = erase_region_count; + cur_offset += erase_region_size * size_ratio * erase_region_count; + + /* increase the space malloced for the sector start addresses */ + info->start = xrealloc(info->start, sizeof(*info->eraseregions) * + (erase_region_count + sect_cnt)); + info->protect = xrealloc(info->protect, sizeof(*info->eraseregions) * + (erase_region_count + sect_cnt)); + + for (j = 0; j < erase_region_count; j++) { + info->start[sect_cnt] = sector; + sector += (erase_region_size * size_ratio); + + /* + * Only read protection status from supported devices (intel...) + */ + switch (info->vendor) { + case CFI_CMDSET_INTEL_EXTENDED: + case CFI_CMDSET_INTEL_STANDARD: + info->protect[sect_cnt] = + flash_isset (info, sect_cnt, + FLASH_OFFSET_PROTECT, + FLASH_STATUS_PROTECT); + break; + default: + info->protect[sect_cnt] = 0; /* default: not protected */ } - } - info->sector_count = sect_cnt; - /* multiply the size by the number of chips */ - info->size = (1 << qry.dev_size) * size_ratio; - info->buffer_size = (1 << le16_to_cpu(qry.max_buf_write_size)); - info->erase_blk_tout = 1 << (qry.block_erase_timeout_typ + - qry.block_erase_timeout_max); - info->buffer_write_tout = 1 << (qry.buf_write_timeout_typ + - qry.buf_write_timeout_max); - info->write_tout = 1 << (qry.word_write_timeout_typ + - qry.word_write_timeout_max); - info->flash_id = FLASH_MAN_CFI; - if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { - info->portwidth >>= 1; /* XXX - Need to test on x8/x16 in parallel. */ + sect_cnt++; } - flash_write_cmd (info, 0, 0, info->cmd_reset); } - return info->size; + info->sector_count = sect_cnt; + /* multiply the size by the number of chips */ + info->size = (1 << qry.dev_size) * size_ratio; + info->buffer_size = (1 << get_unaligned_le16(&qry.max_buf_write_size)); + info->erase_blk_tout = 1 << (qry.block_erase_timeout_typ + + qry.block_erase_timeout_max); + info->buffer_write_tout = 1 << (qry.buf_write_timeout_typ + + qry.buf_write_timeout_max); + info->write_tout = 1 << (qry.word_write_timeout_typ + + qry.word_write_timeout_max); + info->flash_id = FLASH_MAN_CFI; + + if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) + info->portwidth >>= 1; /* XXX - Need to test on x8/x16 in parallel. */ + + flash_write_cmd(info, 0, 0, info->cmd_reset); + + return 0; } /* loop through the sectors from the highest address * when the passed address is greater or equal to the sector address * we have a match */ -flash_sect_t find_sector (struct flash_info *info, ulong addr) +flash_sect_t find_sector(struct flash_info *info, unsigned long addr) { flash_sect_t sector; @@ -468,6 +468,7 @@ flash_sect_t find_sector (struct flash_info *info, ulong addr) if (addr >= info->start[sector]) break; } + return sector; } @@ -496,43 +497,40 @@ out: return ret; } -/* - * Copy memory to flash, returns: - * 0 - OK - * 1 - write timeout - * 2 - Flash not erased - */ -static int write_buff (struct flash_info *info, const uchar * src, ulong addr, ulong cnt) +static int write_buff(struct flash_info *info, const u8 *src, + unsigned long addr, unsigned long cnt) { - ulong wp; - uchar *p; + unsigned long wp; + u8 *p; int aln; cfiword_t cword; - int i, rc; + int i, ret; #ifdef CONFIG_CFI_BUFFER_WRITE int buffered_size; #endif /* get lower aligned address */ - wp = (addr & ~(info->portwidth - 1)); + wp = addr & ~(info->portwidth - 1); /* handle unaligned start */ - if ((aln = addr - wp) != 0) { + aln = addr - wp; + if (aln) { cword = 0; - p = (uchar*)wp; + p = (u8 *)wp; for (i = 0; i < aln; ++i) - flash_add_byte (info, &cword, flash_read8(p + i)); + flash_add_byte(info, &cword, flash_read8(p + i)); for (; (i < info->portwidth) && (cnt > 0); i++) { - flash_add_byte (info, &cword, *src++); + flash_add_byte(info, &cword, *src++); cnt--; } + for (; (cnt == 0) && (i < info->portwidth); ++i) - flash_add_byte (info, &cword, flash_read8(p + i)); + flash_add_byte(info, &cword, flash_read8(p + i)); - rc = flash_write_cfiword (info, wp, cword); - if (rc != 0) - return rc; + ret = flash_write_cfiword(info, wp, cword); + if (ret) + return ret; wp += i; } @@ -545,12 +543,17 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u /* prohibit buffer write when buffer_size is 1 */ if (info->buffer_size == 1) { cword = 0; + for (i = 0; i < info->portwidth; i++) - flash_add_byte (info, &cword, *src++); - if ((rc = flash_write_cfiword (info, wp, cword)) != 0) - return rc; + flash_add_byte(info, &cword, *src++); + + ret = flash_write_cfiword(info, wp, cword); + if (ret) + return ret; + wp += info->portwidth; cnt -= info->portwidth; + continue; } @@ -558,8 +561,11 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u i = buffered_size - (wp % buffered_size); if (i > cnt) i = cnt; - if ((rc = info->cfi_cmd_set->flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) - return rc; + + ret = info->cfi_cmd_set->flash_write_cfibuffer(info, wp, src, i); + if (ret) + return ret; + i -= i & (info->portwidth - 1); wp += i; src += i; @@ -568,64 +574,67 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u #else while (cnt >= info->portwidth) { cword = 0; - for (i = 0; i < info->portwidth; i++) { - flash_add_byte (info, &cword, *src++); - } - if ((rc = flash_write_cfiword (info, wp, cword)) != 0) - return rc; + + for (i = 0; i < info->portwidth; i++) + flash_add_byte(info, &cword, *src++); + + ret = flash_write_cfiword(info, wp, cword); + if (ret) + return ret; + wp += info->portwidth; cnt -= info->portwidth; } #endif /* CONFIG_CFI_BUFFER_WRITE */ - if (cnt == 0) { + if (cnt == 0) return 0; - } /* * handle unaligned tail bytes */ cword = 0; - p = (uchar*)wp; + p = (u8 *)wp; + for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { - flash_add_byte (info, &cword, *src++); + flash_add_byte(info, &cword, *src++); --cnt; } - for (; i < info->portwidth; ++i) { - flash_add_byte (info, &cword, flash_read8(p + i)); - } - return flash_write_cfiword (info, wp, cword); + for (; i < info->portwidth; ++i) + flash_add_byte(info, &cword, flash_read8(p + i)); + + return flash_write_cfiword(info, wp, cword); } -static int flash_real_protect (struct flash_info *info, long sector, int prot) +static int flash_real_protect(struct flash_info *info, long sector, int prot) { - int retcode = 0; - - retcode = info->cfi_cmd_set->flash_real_protect(info, sector, prot); + int ret; - if (retcode) - return retcode; + ret = info->cfi_cmd_set->flash_real_protect(info, sector, prot); + if (ret) + return ret; - if ((retcode = - flash_status_check (info, sector, info->erase_blk_tout, - prot ? "protect" : "unprotect")) == 0) { + ret = flash_status_check(info, sector, info->erase_blk_tout, + prot ? "protect" : "unprotect"); + if (ret) + return ret; - info->protect[sector] = prot; + info->protect[sector] = prot; - /* - * On some of Intel's flash chips (marked via legacy_unlock) - * unprotect unprotects all locking. - */ - if ((prot == 0) && (info->legacy_unlock)) { - flash_sect_t i; + /* + * On some of Intel's flash chips (marked via legacy_unlock) + * unprotect unprotects all locking. + */ + if (prot == 0 && info->legacy_unlock) { + flash_sect_t i; - for (i = 0; i < info->sector_count; i++) { - if (info->protect[i]) - flash_real_protect (info, i, 1); - } + for (i = 0; i < info->sector_count; i++) { + if (info->protect[i]) + flash_real_protect (info, i, 1); } } - return retcode; + + return 0; } static int cfi_mtd_protect(struct flash_info *finfo, loff_t offset, size_t len, int prot) @@ -637,12 +646,12 @@ static int cfi_mtd_protect(struct flash_info *finfo, loff_t offset, size_t len, end = find_sector(finfo, (unsigned long)finfo->base + offset + len - 1); for (i = start; i <= end; i++) { - ret = flash_real_protect (finfo, i, prot); + ret = flash_real_protect(finfo, i, prot); if (ret) - goto out; + return ret; } -out: - return ret; + + return 0; } static int cfi_mtd_lock(struct mtd_info *mtd, loff_t offset, size_t len) @@ -665,50 +674,53 @@ static void cfi_info (struct device_d* dev) int i; if (info->flash_id != FLASH_MAN_CFI) { - puts ("missing or unknown FLASH type\n"); + printf("missing or unknown FLASH type\n"); return; } - printf ("CFI conformant FLASH (%d x %d)", + printf("CFI conformant FLASH (%d x %d)", (info->portwidth << 3), (info->chipwidth << 3)); - printf (" Size: %ld MB in %d Sectors\n", + printf(" Size: %ld MB in %d Sectors\n ", info->size >> 20, info->sector_count); - printf (" "); + switch (info->vendor) { case CFI_CMDSET_INTEL_STANDARD: - printf ("Intel Standard"); + printf("Intel Standard"); break; case CFI_CMDSET_INTEL_EXTENDED: - printf ("Intel Extended"); + printf("Intel Extended"); break; case CFI_CMDSET_AMD_STANDARD: - printf ("AMD Standard"); + printf("AMD Standard"); break; case CFI_CMDSET_AMD_EXTENDED: - printf ("AMD Extended"); + printf("AMD Extended"); break; default: - printf ("Unknown (%d)", info->vendor); + printf("Unknown (%d)", info->vendor); break; } - printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", + printf(" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", info->manufacturer_id, info->device_id); - if (info->device_id == 0x7E) { + + if (info->device_id == 0x7E) printf("%04X", info->device_id2); - } - printf ("\n Erase timeout: %ld ms, write timeout: %ld us\n", + + printf("\n Erase timeout: %ld ms, write timeout: %ld us\n", info->erase_blk_tout, info->write_tout); + if (info->buffer_size > 1) { - printf (" Buffer write timeout: %ld us, buffer size: %d bytes\n", + printf(" Buffer write timeout: %ld us, buffer size: %d bytes\n", info->buffer_write_tout, info->buffer_size); } - puts ("\n Sector Start Addresses:"); + printf("\n Sector Start Addresses:"); + for (i = 0; i < info->sector_count; ++i) { if ((i % 5) == 0) - printf ("\n"); + printf("\n"); #ifdef CFG_FLASH_EMPTY_INFO { int k; @@ -724,7 +736,7 @@ static void cfi_info (struct device_d* dev) else size = info->start[0] + info->size - info->start[i]; erased = 1; - flash = (volatile unsigned long *) info->start[i]; + flash = (volatile unsigned long *)info->start[i]; size = size >> 2; /* divide by 4 for longword access */ for (k = 0; k < size; k++) { if (*flash++ != 0xffffffff) { @@ -734,13 +746,13 @@ static void cfi_info (struct device_d* dev) } /* print empty and read-only info */ - printf (" %08lX %c %s ", + printf(" %08lX %c %s ", info->start[i], erased ? 'E' : ' ', info->protect[i] ? "RO" : " "); } #else /* ! CFG_FLASH_EMPTY_INFO */ - printf (" %08lX %s ", + printf(" %08lX %s ", info->start[i], info->protect[i] ? "RO" : " "); #endif @@ -749,41 +761,8 @@ static void cfi_info (struct device_d* dev) return; } -#if 0 -/* - * flash_read_user_serial - read the OneTimeProgramming cells - */ -static void flash_read_user_serial (struct flash_info *info, void *buffer, int offset, - int len) -{ - uchar *src; - uchar *dst; - - dst = buffer; - src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION); - flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); - memcpy (dst, src + offset, len); - flash_write_cmd (info, 0, 0, info->cmd_reset); -} - -/* - * flash_read_factory_serial - read the device Id from the protection area - */ -static void flash_read_factory_serial (struct flash_info *info, void *buffer, int offset, - int len) -{ - uchar *src; - - src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION); - flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); - memcpy (buffer, src + offset, len); - flash_write_cmd (info, 0, 0, info->cmd_reset); -} - -#endif - -int flash_status_check (struct flash_info *info, flash_sect_t sector, - uint64_t tout, char *prompt) +int flash_status_check(struct flash_info *info, flash_sect_t sector, + u64 tout, char *prompt) { return info->cfi_cmd_set->flash_status_check(info, sector, tout, prompt); } @@ -792,10 +771,10 @@ int flash_status_check (struct flash_info *info, flash_sect_t sector, * wait for XSR.7 to be set. Time out with an error if it does not. * This routine does not set the flash to read-array mode. */ -int flash_generic_status_check (struct flash_info *info, flash_sect_t sector, - uint64_t tout, char *prompt) +int flash_generic_status_check(struct flash_info *info, flash_sect_t sector, + u64 tout, char *prompt) { - uint64_t start; + u64 start; tout *= 1000000; @@ -806,12 +785,15 @@ int flash_generic_status_check (struct flash_info *info, flash_sect_t sector, dev_err(info->dev, "Flash %s timeout at address %lx data %lx\n", prompt, info->start[sector], flash_read_long (info, sector, 0)); - flash_write_cmd (info, sector, 0, info->cmd_reset); - return ERR_TIMOUT; + + flash_write_cmd(info, sector, 0, info->cmd_reset); + + return -ETIMEDOUT; } - udelay (1); /* also triggers watchdog */ + udelay(1); /* also triggers watchdog */ } - return ERR_OK; + + return 0; } /* @@ -831,23 +813,22 @@ void flash_make_cmd(struct flash_info *info, u32 cmd, cfiword_t *cmdbuf) * Write a proper sized command to the correct address */ void flash_write_cmd(struct flash_info *info, flash_sect_t sect, - uint offset, u32 cmd) + unsigned int offset, u32 cmd) { - - uchar *addr; + u8 *addr; cfiword_t cword; addr = flash_make_addr (info, sect, offset); flash_make_cmd (info, cmd, &cword); - dev_dbg(info->dev, "%s: %p %lX %X => %p " CFI_WORD_FMT "\n", __func__, + dev_vdbg(info->dev, "%s: %p %lX %X => %p " CFI_WORD_FMT "\n", __func__, info, sect, offset, addr, cword); flash_write_word(info, cword, addr); } int flash_isequal(struct flash_info *info, flash_sect_t sect, - uint offset, u32 cmd) + unsigned int offset, u32 cmd) { void *addr; cfiword_t cword; @@ -856,36 +837,29 @@ int flash_isequal(struct flash_info *info, flash_sect_t sect, addr = flash_make_addr (info, sect, offset); flash_make_cmd (info, cmd, &cword); - dev_dbg(info->dev, "is= cmd %x(%c) addr %p ", cmd, cmd, addr); + dev_vdbg(info->dev, "is= cmd %x(%c) addr %p ", cmd, cmd, addr); + if (bankwidth_is_1(info)) { - dev_dbg(info->dev, "is= %x %x\n", flash_read8(addr), (u8)cword); + dev_vdbg(info->dev, "is= %x %x\n", flash_read8(addr), (u8)cword); retval = (flash_read8(addr) == cword); } else if (bankwidth_is_2(info)) { - dev_dbg(info->dev, "is= %4.4x %4.4x\n", flash_read16(addr), (u16)cword); + dev_vdbg(info->dev, "is= %4.4x %4.4x\n", flash_read16(addr), (u16)cword); retval = (flash_read16(addr) == cword); } else if (bankwidth_is_4(info)) { - dev_dbg(info->dev, "is= %8.8x %8.8x\n", flash_read32(addr), (u32)cword); + dev_vdbg(info->dev, "is= %8.8x %8.8x\n", flash_read32(addr), (u32)cword); retval = (flash_read32(addr) == cword); } else if (bankwidth_is_8(info)) { -#ifdef DEBUG - { - char str1[20]; - char str2[20]; - - print_longlong (str1, flash_read32(addr)); - print_longlong (str2, cword); - dev_dbg(info->dev, "is= %s %s\n", str1, str2); - } -#endif + dev_vdbg(info->dev, "is= %16.16llx %16.16llx\n", flash_read64(addr), (u64)cword); retval = (flash_read64(addr) == cword); - } else + } else { retval = 0; + } return retval; } int flash_isset(struct flash_info *info, flash_sect_t sect, - uint offset, u32 cmd) + unsigned int offset, u32 cmd) { void *addr = flash_make_addr (info, sect, offset); cfiword_t cword; @@ -900,14 +874,15 @@ int flash_isset(struct flash_info *info, flash_sect_t sect, retval = ((flash_read32(addr) & cword) == cword); } else if (bankwidth_is_8(info)) { retval = ((flash_read64(addr) & cword) == cword); - } else + } else { retval = 0; + } return retval; } static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) + size_t *retlen, u8 *buf) { struct flash_info *info = container_of(mtd, struct flash_info, mtd); @@ -918,7 +893,7 @@ static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, } static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) + size_t *retlen, const u8 *buf) { struct flash_info *info = container_of(mtd, struct flash_info, mtd); int ret; @@ -935,7 +910,6 @@ static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) int ret; ret = cfi_erase(info, instr->len, instr->addr); - if (ret) { instr->state = MTD_ERASE_FAILED; return -EIO; @@ -947,10 +921,16 @@ static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) return 0; } +struct cfi_priv { + struct flash_info *infos; + int num_devs; + struct mtd_info **mtds; +}; + static void cfi_init_mtd(struct flash_info *info) { struct mtd_info *mtd = &info->mtd; - u_int32_t erasesize; + u32 erasesize; int i; mtd->read = cfi_mtd_read; @@ -961,10 +941,11 @@ static void cfi_init_mtd(struct flash_info *info) mtd->size = info->size; erasesize = 0; - for (i=0; i < info->numeraseregions; i++) { + for (i = 0; i < info->numeraseregions; i++) { if (erasesize < info->eraseregions[i].erasesize) erasesize = info->eraseregions[i].erasesize; } + mtd->erasesize = erasesize; mtd->writesize = 1; @@ -974,38 +955,84 @@ static void cfi_init_mtd(struct flash_info *info) mtd->flags = MTD_CAP_NORFLASH; mtd->type = MTD_NORFLASH; mtd->parent = info->dev; - - add_mtd_device(mtd, "nor", DEVICE_ID_DYNAMIC); } -static int cfi_probe (struct device_d *dev) +static int cfi_probe_one(struct flash_info *info, int num) { - struct flash_info *info = xzalloc(sizeof(*info)); - - dev->priv = (void *)info; + int ret; - /* Init: no FLASHes known */ info->flash_id = FLASH_UNKNOWN; info->cmd_reset = FLASH_CMD_RESET; - info->base = dev_request_mem_region(dev, 0); + info->base = dev_request_mem_region(info->dev, num); if (IS_ERR(info->base)) return PTR_ERR(info->base); - info->dev = dev; - info->size = flash_get_size(info); - - if (info->flash_id == FLASH_UNKNOWN) { - dev_warn(dev, "## Unknown FLASH on Bank at 0x%08x - Size = 0x%08lx = %ld MB\n", - dev->resource[0].start, info->size, info->size << 20); + ret = flash_detect_size(info); + if (ret) { + dev_warn(info->dev, "## Unknown FLASH on Bank at 0x%p - Size = 0x%08lx = %ld MB\n", + info->base, info->size, info->size << 20); return -ENODEV; } - dev_info(dev, "found cfi flash at 0x%p, size %s\n", + dev_info(info->dev, "found cfi flash at 0x%p, size %s\n", info->base, size_human_readable(info->size)); + cfi_init_mtd(info); + + return 0; +} + +static int cfi_probe(struct device_d *dev) +{ + struct cfi_priv *priv; + int i, ret; + struct mtd_info *mtd; + const char *mtd_name = NULL; + + priv = xzalloc(sizeof(*priv)); + + priv->num_devs = dev->num_resources; + priv->infos = xzalloc(sizeof(*priv->infos) * priv->num_devs); + priv->mtds = xzalloc(sizeof(*priv->mtds) * priv->num_devs); + + of_property_read_string(dev->device_node, "linux,mtd-name", &mtd_name); + + if (!mtd_name) + mtd_name = dev_name(dev); + + dev->priv = priv; + + for (i = 0; i < priv->num_devs; i++) { + struct flash_info *info = &priv->infos[i]; + + info->dev = dev; + info->mtd.name = xstrdup(mtd_name); + + ret = cfi_probe_one(info, i); + if (ret) + return ret; + priv->mtds[i] = &priv->infos[i].mtd; + } + dev->info = cfi_info; - cfi_init_mtd(info); + if (priv->num_devs > 1 && IS_ENABLED(CONFIG_MTD_CONCAT)) { + mtd = mtd_concat_create(priv->mtds, priv->num_devs, "nor"); + if (!mtd) { + dev_err(dev, "failed to create concat mtd device\n"); + return -ENODEV; + } + } else { + if (priv->num_devs > 1) + dev_warn(dev, "mtd concat disabled. using first chip only\n"); + mtd = &priv->infos[0].mtd; + } + + mtd->parent = dev; + + ret = add_mtd_device(mtd, "nor", DEVICE_ID_DYNAMIC); + if (ret) + return ret; return 0; } diff --git a/drivers/mtd/nor/cfi_flash.h b/drivers/mtd/nor/cfi_flash.h index aeaf751aba..e82eb28abe 100644 --- a/drivers/mtd/nor/cfi_flash.h +++ b/drivers/mtd/nor/cfi_flash.h @@ -49,32 +49,32 @@ struct cfi_cmd_set; struct flash_info { struct device_d *dev; - ulong size; /* total bank size in bytes */ - ushort sector_count; /* number of erase units */ - ulong flash_id; /* combined device & manufacturer code */ - ulong *start; /* physical sector start addresses */ - uchar *protect; /* sector protection status */ - - uchar portwidth; /* the width of the port */ - uchar chipwidth; /* the width of the chip */ - uchar chip_lsb; /* extra Least Significant Bit in the */ + unsigned long size; /* total bank size in bytes */ + unsigned int sector_count; /* number of erase units */ + unsigned long flash_id; /* combined device & manufacturer code */ + unsigned long *start; /* physical sector start addresses */ + unsigned char *protect; /* sector protection status */ + + unsigned int portwidth; /* the width of the port */ + unsigned int chipwidth; /* the width of the chip */ + unsigned int chip_lsb; /* extra Least Significant Bit in the */ /* address of chip. */ - ushort buffer_size; /* # of bytes in write buffer */ - ulong erase_blk_tout; /* maximum block erase timeout */ - ulong write_tout; /* maximum write timeout */ - ulong buffer_write_tout; /* maximum buffer write timeout */ - ushort vendor; /* the primary vendor id */ - ushort cmd_reset; /* vendor specific reset command */ - ushort interface; /* used for x8/x16 adjustments */ - ushort legacy_unlock; /* support Intel legacy (un)locking */ - uchar manufacturer_id; /* manufacturer id */ - ushort device_id; /* device id */ - ushort device_id2; /* extended device id */ - ushort ext_addr; /* extended query table address */ - ushort cfi_version; /* cfi version */ - ushort cfi_offset; /* offset for cfi query */ - ulong addr_unlock1; /* unlock address 1 for AMD flash roms */ - ulong addr_unlock2; /* unlock address 2 for AMD flash roms */ + unsigned int buffer_size; /* # of bytes in write buffer */ + unsigned long erase_blk_tout; /* maximum block erase timeout */ + unsigned long write_tout; /* maximum write timeout */ + unsigned long buffer_write_tout;/* maximum buffer write timeout */ + unsigned int vendor; /* the primary vendor id */ + unsigned int cmd_reset; /* vendor specific reset command */ + unsigned int interface; /* used for x8/x16 adjustments */ + unsigned int legacy_unlock; /* support Intel legacy (un)locking */ + unsigned int manufacturer_id; /* manufacturer id */ + unsigned int device_id; /* device id */ + unsigned int device_id2; /* extended device id */ + unsigned int ext_addr; /* extended query table address */ + unsigned int cfi_version; /* cfi version */ + unsigned int cfi_offset; /* offset for cfi query */ + unsigned long addr_unlock1; /* unlock address 1 for AMD flash roms */ + unsigned long addr_unlock2; /* unlock address 2 for AMD flash roms */ struct cfi_cmd_set *cfi_cmd_set; struct mtd_info mtd; int numeraseregions; @@ -118,14 +118,16 @@ struct cfi_pri_hdr { struct cfi_cmd_set { - int (*flash_write_cfibuffer) (struct flash_info *info, ulong dest, const uchar * cp, int len); - int (*flash_erase_one) (struct flash_info *info, long sect); - int (*flash_is_busy) (struct flash_info *info, flash_sect_t sect); - void (*flash_read_jedec_ids) (struct flash_info *info); - void (*flash_prepare_write) (struct flash_info *info); - int (*flash_status_check) (struct flash_info *info, flash_sect_t sector, uint64_t tout, char *prompt); - int (*flash_real_protect) (struct flash_info *info, long sector, int prot); - void (*flash_fixup) (struct flash_info *info, struct cfi_qry *qry); + int (*flash_write_cfibuffer)(struct flash_info *info, unsigned long dest, + const u8 *cp, int len); + int (*flash_erase_one)(struct flash_info *info, long sect); + int (*flash_is_busy)(struct flash_info *info, flash_sect_t sect); + void (*flash_read_jedec_ids)(struct flash_info *info); + void (*flash_prepare_write)(struct flash_info *info); + int (*flash_status_check)(struct flash_info *info, flash_sect_t sector, + u64 tout, char *prompt); + int (*flash_real_protect)(struct flash_info *info, long sector, int prot); + void (*flash_fixup)(struct flash_info *info, struct cfi_qry *qry); }; extern struct cfi_cmd_set cfi_cmd_set_intel; @@ -241,17 +243,17 @@ extern struct cfi_cmd_set cfi_cmd_set_amd; /* Prototypes */ int flash_isset(struct flash_info *info, flash_sect_t sect, - uint offset, u32 cmd); + unsigned int offset, u32 cmd); void flash_write_cmd(struct flash_info *info, flash_sect_t sect, - uint offset, u32 cmd); -flash_sect_t find_sector (struct flash_info *info, ulong addr); -int flash_status_check (struct flash_info *info, flash_sect_t sector, - uint64_t tout, char *prompt); -int flash_generic_status_check (struct flash_info *info, flash_sect_t sector, - uint64_t tout, char *prompt); + unsigned int offset, u32 cmd); +flash_sect_t find_sector(struct flash_info *info, unsigned long addr); +int flash_status_check(struct flash_info *info, flash_sect_t sector, + u64 tout, char *prompt); +int flash_generic_status_check(struct flash_info *info, flash_sect_t sector, + u64 tout, char *prompt); int flash_isequal(struct flash_info *info, flash_sect_t sect, - uint offset, u32 cmd); + unsigned int offset, u32 cmd); void flash_make_cmd(struct flash_info *info, u32 cmd, cfiword_t *cmdbuf); static inline void flash_write8(u8 value, void *addr) @@ -298,12 +300,13 @@ static inline u64 flash_read64(void *addr) /* * create an address based on the offset and the port width */ -static inline uchar *flash_make_addr (struct flash_info *info, flash_sect_t sect, uint offset) +static inline u8 *flash_make_addr(struct flash_info *info, flash_sect_t sect, + unsigned int offset) { - return ((uchar *) (info->start[sect] + ((offset * info->portwidth) << info->chip_lsb))); + return ((u8 *)(info->start[sect] + ((offset * info->portwidth) << info->chip_lsb))); } -uchar flash_read_uchar (struct flash_info *info, uint offset); +u8 flash_read_uchar(struct flash_info *info, unsigned int offset); u32 jedec_read_mfr(struct flash_info *info); #ifdef CONFIG_DRIVER_CFI_BANK_WIDTH_1 @@ -332,49 +335,25 @@ u32 jedec_read_mfr(struct flash_info *info); static inline void flash_write_word(struct flash_info *info, cfiword_t datum, void *addr) { - if (bankwidth_is_1(info)) { - debug("fw addr %p val %02x\n", addr, (u8)datum); + if (bankwidth_is_1(info)) flash_write8(datum, addr); - } else if (bankwidth_is_2(info)) { - debug("fw addr %p val %04x\n", addr, (u16)datum); + else if (bankwidth_is_2(info)) flash_write16(datum, addr); - } else if (bankwidth_is_4(info)) { - debug("fw addr %p val %08x\n", addr, (u32)datum); + else if (bankwidth_is_4(info)) flash_write32(datum, addr); - } else if (bankwidth_is_8(info)) { + else if (bankwidth_is_8(info)) flash_write64(datum, addr); - } } -extern void flash_print_info (struct flash_info *); -extern int flash_sect_erase (ulong addr_first, ulong addr_last); -extern int flash_sect_protect (int flag, ulong addr_first, ulong addr_last); +extern void flash_print_info(struct flash_info *); +extern int flash_sect_erase(unsigned long addr_first, unsigned long addr_last); +extern int flash_sect_protect(int flag, unsigned long addr_first, + unsigned long addr_last); /* common/flash.c */ -extern void flash_protect (int flag, ulong from, ulong to, struct flash_info *info); -extern int flash_write (char *, ulong, ulong); -extern struct flash_info *addr2info (ulong); -//extern int write_buff (flash_info_t *info, const uchar *src, ulong addr, ulong cnt); - -/* board/?/flash.c */ -#if defined(CFG_FLASH_PROTECTION) -extern int flash_real_protect(struct flash_info *info, long sector, int prot); -extern void flash_read_user_serial(struct flash_info *info, void * buffer, int offset, int len); -extern void flash_read_factory_serial(struct flash_info *info, void * buffer, int offset, int len); -#endif /* CFG_FLASH_PROTECTION */ - -/*----------------------------------------------------------------------- - * return codes from flash_write(): - */ -#define ERR_OK 0 -#define ERR_TIMOUT 1 -#define ERR_NOT_ERASED 2 -#define ERR_PROTECTED 4 -#define ERR_INVAL 8 -#define ERR_ALIGN 16 -#define ERR_UNKNOWN_FLASH_VENDOR 32 -#define ERR_UNKNOWN_FLASH_TYPE 64 -#define ERR_PROG_ERROR 128 +extern void flash_protect(int flag, unsigned long from, unsigned long to, + struct flash_info *info); +extern int flash_write(char *, unsigned long, unsigned long); /*----------------------------------------------------------------------- * Protection Flags for flash_protect(): @@ -729,4 +708,3 @@ extern void flash_read_factory_serial(struct flash_info *info, void * buffer, in #define FLASH_WRITE_TIMEOUT 500 /* timeout for writes in ms */ #endif /* __CFI_FLASH_H */ - diff --git a/drivers/mtd/nor/cfi_flash_amd.c b/drivers/mtd/nor/cfi_flash_amd.c index 45c59b9d01..9c44561d45 100644 --- a/drivers/mtd/nor/cfi_flash_amd.c +++ b/drivers/mtd/nor/cfi_flash_amd.c @@ -19,7 +19,7 @@ static void cfi_reverse_geometry(struct cfi_qry *qry) } } -static void flash_unlock_seq (struct flash_info *info) +static void flash_unlock_seq(struct flash_info *info) { flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_UNLOCK_START); flash_write_cmd (info, 0, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); @@ -31,7 +31,7 @@ static void flash_unlock_seq (struct flash_info *info) * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct * */ -static void amd_read_jedec_ids (struct flash_info *info) +static void amd_read_jedec_ids(struct flash_info *info) { info->cmd_reset = AMD_CMD_RESET; info->manufacturer_id = 0; @@ -62,20 +62,21 @@ static void amd_read_jedec_ids (struct flash_info *info) udelay(1000); /* some flash are slow to respond */ info->manufacturer_id = jedec_read_mfr(info); - info->device_id = flash_read_uchar (info, + info->device_id = flash_read_uchar(info, FLASH_OFFSET_DEVICE_ID); if (info->device_id == 0x7E) { /* AMD 3-byte (expanded) device ids */ - info->device_id2 = flash_read_uchar (info, + info->device_id2 = flash_read_uchar(info, FLASH_OFFSET_DEVICE_ID2); info->device_id2 <<= 8; - info->device_id2 |= flash_read_uchar (info, + info->device_id2 |= flash_read_uchar(info, FLASH_OFFSET_DEVICE_ID3); } flash_write_cmd(info, 0, 0, info->cmd_reset); } -static int flash_toggle (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd) +static int flash_toggle(struct flash_info *info, flash_sect_t sect, + unsigned int offset, u8 cmd) { void *addr; cfiword_t cword; @@ -83,6 +84,7 @@ static int flash_toggle (struct flash_info *info, flash_sect_t sect, uint offset addr = flash_make_addr (info, sect, offset); flash_make_cmd (info, cmd, &cword); + if (bankwidth_is_1(info)) { retval = flash_read8(addr) != flash_read8(addr); } else if (bankwidth_is_2(info)) { @@ -92,8 +94,9 @@ static int flash_toggle (struct flash_info *info, flash_sect_t sect, uint offset } else if (bankwidth_is_8(info)) { retval = ( (flash_read32( addr ) != flash_read32( addr )) || (flash_read32(addr+4) != flash_read32(addr+4)) ); - } else + } else { retval = 0; + } return retval; } @@ -102,12 +105,12 @@ static int flash_toggle (struct flash_info *info, flash_sect_t sect, uint offset * flash_is_busy - check to see if the flash is busy * This routine checks the status of the chip and returns true if the chip is busy */ -static int amd_flash_is_busy (struct flash_info *info, flash_sect_t sect) +static int amd_flash_is_busy(struct flash_info *info, flash_sect_t sect) { return flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); } -static int amd_flash_erase_one (struct flash_info *info, long sect) +static int amd_flash_erase_one(struct flash_info *info, long sect) { flash_unlock_seq(info); flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_ERASE_START); @@ -124,13 +127,12 @@ static void amd_flash_prepare_write(struct flash_info *info) } #ifdef CONFIG_CFI_BUFFER_WRITE -static int amd_flash_write_cfibuffer (struct flash_info *info, ulong dest, const uchar * cp, - int len) +static int amd_flash_write_cfibuffer(struct flash_info *info, unsigned long dest, + const u8 *cp, int len) { flash_sect_t sector; int cnt; - int retcode; - void *src = (void*)cp; + void *src = (void *)cp; void *dst = (void *)dest; cfiword_t cword; @@ -170,18 +172,18 @@ static int amd_flash_write_cfibuffer (struct flash_info *info, ulong dest, const } } - flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); - retcode = flash_status_check (info, sector, info->buffer_write_tout, + flash_write_cmd(info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); + + return flash_status_check(info, sector, info->buffer_write_tout, "buffer write"); - return retcode; } #else #define amd_flash_write_cfibuffer NULL #endif /* CONFIG_CFI_BUFFER_WRITE */ -static int amd_flash_real_protect (struct flash_info *info, long sector, int prot) +static int amd_flash_real_protect(struct flash_info *info, long sector, int prot) { - if (info->manufacturer_id != (uchar)ATM_MANUFACT) + if (info->manufacturer_id != (u8)ATM_MANUFACT) return 0; if (prot) { @@ -205,7 +207,7 @@ static int amd_flash_real_protect (struct flash_info *info, long sector, int pro * Manufacturer-specific quirks. Add workarounds for geometry * reversal, etc. here. */ -static void flash_fixup_amd (struct flash_info *info, struct cfi_qry *qry) +static void flash_fixup_amd(struct flash_info *info, struct cfi_qry *qry) { /* check if flash geometry needs reversal */ if (qry->num_erase_regions > 1) { @@ -265,4 +267,3 @@ struct cfi_cmd_set cfi_cmd_set_amd = { .flash_real_protect = amd_flash_real_protect, .flash_fixup = amd_flash_fixup, }; - diff --git a/drivers/mtd/nor/cfi_flash_intel.c b/drivers/mtd/nor/cfi_flash_intel.c index 32e581a395..6108d7cc62 100644 --- a/drivers/mtd/nor/cfi_flash_intel.c +++ b/drivers/mtd/nor/cfi_flash_intel.c @@ -6,8 +6,8 @@ * * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct * -*/ -static void intel_read_jedec_ids (struct flash_info *info) + */ +static void intel_read_jedec_ids(struct flash_info *info) { info->cmd_reset = FLASH_CMD_RESET; info->manufacturer_id = 0; @@ -19,7 +19,7 @@ static void intel_read_jedec_ids (struct flash_info *info) udelay(1000); /* some flash are slow to respond */ info->manufacturer_id = jedec_read_mfr(info); - info->device_id = flash_read_uchar (info, + info->device_id = flash_read_uchar(info, FLASH_OFFSET_DEVICE_ID); flash_write_cmd(info, 0, 0, info->cmd_reset); } @@ -28,16 +28,16 @@ static void intel_read_jedec_ids (struct flash_info *info) * flash_is_busy - check to see if the flash is busy * This routine checks the status of the chip and returns true if the chip is busy */ -static int intel_flash_is_busy (struct flash_info *info, flash_sect_t sect) +static int intel_flash_is_busy(struct flash_info *info, flash_sect_t sect) { return !flash_isset (info, sect, 0, FLASH_STATUS_DONE); } -static int intel_flash_erase_one (struct flash_info *info, long sect) +static int intel_flash_erase_one(struct flash_info *info, long sect) { - flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS); - flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE); - flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM); + flash_write_cmd(info, sect, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sect, 0, FLASH_CMD_BLOCK_ERASE); + flash_write_cmd(info, sect, 0, FLASH_CMD_ERASE_CONFIRM); return flash_status_check(info, sect, info->erase_blk_tout, "erase"); } @@ -49,26 +49,26 @@ static void intel_flash_prepare_write(struct flash_info *info) } #ifdef CONFIG_CFI_BUFFER_WRITE -static int intel_flash_write_cfibuffer (struct flash_info *info, ulong dest, const uchar * cp, - int len) +static int intel_flash_write_cfibuffer(struct flash_info *info, + unsigned long dest, const u8 *cp, int len) { flash_sect_t sector; int cnt; - int retcode; + int ret; void *src = (void*)cp; void *dst = (void *)dest; /* reduce width due to possible alignment problems */ const unsigned long ptr = (unsigned long)dest | (unsigned long)cp | info->portwidth; const int width = ptr & -ptr; - sector = find_sector (info, dest); - flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); - flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); + sector = find_sector(info, dest); + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); - retcode = flash_generic_status_check (info, sector, info->buffer_write_tout, + ret = flash_generic_status_check(info, sector, info->buffer_write_tout, "write to buffer"); - if (retcode != ERR_OK) - return retcode; + if (ret) + return ret; /* reduce the number of loops by the width of the port */ cnt = len / width; @@ -95,69 +95,65 @@ static int intel_flash_write_cfibuffer (struct flash_info *info, ulong dest, con } } - flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM); - retcode = flash_status_check (info, sector, + flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM); + ret = flash_status_check(info, sector, info->buffer_write_tout, "buffer write"); - return retcode; + return ret; } #else #define intel_flash_write_cfibuffer NULL #endif /* CONFIG_CFI_BUFFER_WRITE */ -static int intel_flash_status_check (struct flash_info *info, flash_sect_t sector, - uint64_t tout, char *prompt) +static int intel_flash_status_check(struct flash_info *info, flash_sect_t sector, + u64 tout, char *prompt) { - int retcode; - - retcode = flash_generic_status_check (info, sector, tout, prompt); + int ret; - if ((retcode == ERR_OK) - && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { - retcode = ERR_INVAL; - printf ("Flash %s error at address %lx\n", prompt, + ret = flash_generic_status_check(info, sector, tout, prompt); + if (!ret && !flash_isequal(info, sector, 0, FLASH_STATUS_DONE)) { + ret = -EINVAL; + printf("Flash %s error at address %lx\n", prompt, info->start[sector]); - if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) { - puts ("Command Sequence Error.\n"); + + if (flash_isset(info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) { + printf("Command Sequence Error.\n"); } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) { - puts ("Block Erase Error.\n"); - retcode = ERR_NOT_ERASED; - } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) { - puts ("Locking Error\n"); + printf("Block Erase Error.\n"); + ret = -EIO; + } else if (flash_isset(info, sector, 0, FLASH_STATUS_PSLBS)) { + printf("Locking Error\n"); } - if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { - puts ("Block locked.\n"); - retcode = ERR_PROTECTED; + + if (flash_isset(info, sector, 0, FLASH_STATUS_DPS)) { + printf("Block locked.\n"); + ret = -EROFS; } - if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) - puts ("Vpp Low Error.\n"); + + if (flash_isset(info, sector, 0, FLASH_STATUS_VPENS)) + printf("Vpp Low Error.\n"); } - flash_write_cmd (info, sector, 0, info->cmd_reset); - return retcode; + flash_write_cmd(info, sector, 0, info->cmd_reset); + + return ret; } -static int intel_flash_real_protect (struct flash_info *info, long sector, int prot) +static int intel_flash_real_protect(struct flash_info *info, long sector, int prot) { - flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); - flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT); + if (prot) - flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_SET); else - flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_CLEAR); return 0; } -static void intel_flash_fixup (struct flash_info *info, struct cfi_qry *qry) +static void intel_flash_fixup(struct flash_info *info, struct cfi_qry *qry) { -#ifdef CFG_FLASH_PROTECTION - /* read legacy lock/unlock bit from intel flash */ - if (info->ext_addr) { - info->legacy_unlock = flash_read_uchar (info, - info->ext_addr + 5) & 0x08; - } -#endif } struct cfi_cmd_set cfi_cmd_set_intel = { @@ -170,4 +166,3 @@ struct cfi_cmd_set cfi_cmd_set_intel = { .flash_real_protect = intel_flash_real_protect, .flash_fixup = intel_flash_fixup, }; - diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c index 98b90819bd..c11a3db1c5 100644 --- a/drivers/mtd/partition.c +++ b/drivers/mtd/partition.c @@ -31,6 +31,16 @@ static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len, len, retlen, buf); } +static int mtd_part_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + if (to >= mtd->size) + return -EINVAL; + if (ops->datbuf && to + ops->len > mtd->size) + return -EINVAL; + return mtd->master->write_oob(mtd->master, to + mtd->master_offset, ops); +} + static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) { int ret; @@ -160,6 +170,9 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, part->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL; } + if (mtd->write_oob) + part->write_oob = mtd_part_write_oob; + part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; part->size = size; part->name = xstrdup(name); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index b02880eb79..797022636d 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -155,8 +155,8 @@ static int uif_init(struct ubi_device *ubi, int *ref) *ref = 0; sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); - sprintf(ubi->dev.name, "ubi"); - ubi->dev.id = DEVICE_ID_DYNAMIC; + sprintf(ubi->dev.name, "%s.ubi", ubi->mtd->cdev.name); + ubi->dev.id = DEVICE_ID_SINGLE; ubi->dev.parent = &ubi->mtd->class_dev; err = register_device(&ubi->dev); @@ -518,7 +518,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, for (i = 0; i < UBI_MAX_DEVICES; i++) { ubi = ubi_devices[i]; if (ubi && mtd == ubi->mtd) { - ubi_err("mtd%d is already attached to ubi%d", + ubi_debug("mtd%d is already attached to ubi%d", mtd->index, i); return -EEXIST; } @@ -596,9 +596,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, #else ubi->fm_disabled = 1; #endif - - ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); - err = io_init(ubi, max_beb_per1024); if (err) goto out_free; diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 90d5b2dd66..fe71a8d609 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -176,7 +176,7 @@ int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol) priv->ubi = ubi; cdev->ops = &ubi_volume_fops; - cdev->name = asprintf("ubi%d.%s", ubi->ubi_num, vol->name); + cdev->name = asprintf("%s.%s", ubi->cdev.name, vol->name); cdev->priv = priv; cdev->size = vol->used_bytes; cdev->dev = &vol->dev; @@ -239,7 +239,7 @@ int ubi_cdev_add(struct ubi_device *ubi) int ret; cdev->ops = &ubi_fops; - cdev->name = asprintf("ubi%d", ubi->ubi_num); + cdev->name = asprintf("%s.ubi", ubi->mtd->cdev.name); cdev->priv = ubi; cdev->size = 0; diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index 385a7150ba..a1863655fa 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -231,7 +231,7 @@ static int tse_get_ethaddr(struct eth_device *edev, unsigned char *m) return 0; } -static int tse_set_ethaddr(struct eth_device *edev, unsigned char *m) +static int tse_set_ethaddr(struct eth_device *edev, const unsigned char *m) { struct altera_tse_priv *priv = edev->priv; struct alt_tse_mac *mac_dev = priv->tse_regs; diff --git a/drivers/net/ar231x.c b/drivers/net/ar231x.c index 48e4b30fd6..7447c4484d 100644 --- a/drivers/net/ar231x.c +++ b/drivers/net/ar231x.c @@ -70,7 +70,7 @@ static void ar231x_reset_bit_(struct ar231x_eth_priv *priv, (*priv->reset_bit)(val, state); } -static int ar231x_set_ethaddr(struct eth_device *edev, unsigned char *addr); +static int ar231x_set_ethaddr(struct eth_device *edev, const unsigned char *addr); static void ar231x_reset_regs(struct eth_device *edev) { struct ar231x_eth_priv *priv = edev->priv; diff --git a/drivers/net/arc_emac.c b/drivers/net/arc_emac.c index 84e2c75c5e..3dc54cd22b 100644 --- a/drivers/net/arc_emac.c +++ b/drivers/net/arc_emac.c @@ -332,7 +332,7 @@ static int arc_emac_get_ethaddr(struct eth_device *edev, unsigned char *mac) return -1; } -static int arc_emac_set_ethaddr(struct eth_device *edev, unsigned char *mac) +static int arc_emac_set_ethaddr(struct eth_device *edev, const unsigned char *mac) { struct arc_emac_priv *priv = edev->priv; unsigned int addr_low, addr_hi; diff --git a/drivers/net/at91_ether.c b/drivers/net/at91_ether.c index 5a74837f65..523e35590b 100644 --- a/drivers/net/at91_ether.c +++ b/drivers/net/at91_ether.c @@ -261,7 +261,7 @@ static int at91_ether_get_ethaddr(struct eth_device *eth, unsigned char *adr) return -1; } -static int at91_ether_set_ethaddr(struct eth_device *eth, unsigned char *adr) +static int at91_ether_set_ethaddr(struct eth_device *eth, const unsigned char *adr) { int i; diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index c0db96bb53..4d6b7b2e78 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -547,7 +547,7 @@ static int cpsw_get_hwaddr(struct eth_device *edev, unsigned char *mac) return -1; } -static int cpsw_set_hwaddr(struct eth_device *edev, unsigned char *mac) +static int cpsw_set_hwaddr(struct eth_device *edev, const unsigned char *mac) { struct cpsw_slave *slave = edev->priv; struct cpsw_priv *priv = slave->cpsw; diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c index dccb808f95..a4a5dcaf7f 100644 --- a/drivers/net/cs8900.c +++ b/drivers/net/cs8900.c @@ -341,7 +341,7 @@ static int cs8900_get_ethaddr(struct eth_device *dev, unsigned char *mac) return 0; } -static int cs8900_set_ethaddr(struct eth_device *dev, unsigned char *mac) +static int cs8900_set_ethaddr(struct eth_device *dev, const unsigned char *mac) { struct cs8900_priv *priv = (struct cs8900_priv *)dev->priv; int i; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 056ffe28bc..9f8f0e1fa7 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -178,7 +178,7 @@ static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr) * This function must be called before emac_open() if you want to override * the default mac address. */ -static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *addr) +static int davinci_emac_set_ethaddr(struct eth_device *edev, const unsigned char *addr) { struct davinci_emac_priv *priv = edev->priv; int i; diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 213fe41359..800652760a 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -384,7 +384,7 @@ static int dwc_ether_get_ethaddr(struct eth_device *dev, u8 adr[6]) return -1; } -static int dwc_ether_set_ethaddr(struct eth_device *dev, u8 adr[6]) +static int dwc_ether_set_ethaddr(struct eth_device *dev, const unsigned char *adr) { struct dw_eth_dev *priv = dev->priv; struct eth_mac_regs *mac_p = priv->mac_regs_p; diff --git a/drivers/net/dm9k.c b/drivers/net/dm9k.c index c3c2a8052a..1f1938d977 100644 --- a/drivers/net/dm9k.c +++ b/drivers/net/dm9k.c @@ -711,7 +711,7 @@ static int dm9k_get_ethaddr(struct eth_device *edev, unsigned char *adr) return 0; } -static int dm9k_set_ethaddr(struct eth_device *edev, unsigned char *adr) +static int dm9k_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { struct dm9k *priv = (struct dm9k *)edev->priv; int i, oft; diff --git a/drivers/net/ep93xx.c b/drivers/net/ep93xx.c index 4b73abff37..90c12fce75 100644 --- a/drivers/net/ep93xx.c +++ b/drivers/net/ep93xx.c @@ -466,7 +466,7 @@ static int ep93xx_eth_get_ethaddr(struct eth_device *edev, } static int ep93xx_eth_set_ethaddr(struct eth_device *edev, - unsigned char *mac_addr) + const unsigned char *mac_addr) { struct mac_regs *regs = ep93xx_get_regs(edev); diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 7c52a09eaa..6bae7d68a6 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -435,7 +435,7 @@ static int ethoc_get_ethaddr(struct eth_device *edev, unsigned char *mac) return 0; } -static int ethoc_set_ethaddr(struct eth_device *edev, unsigned char *mac) +static int ethoc_set_ethaddr(struct eth_device *edev, const unsigned char *mac) { struct ethoc *dev = edev->priv; diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c index 9a10c9f2e4..78ccb85376 100644 --- a/drivers/net/fec_imx.c +++ b/drivers/net/fec_imx.c @@ -249,7 +249,7 @@ static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac) return -1; } -static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac) +static int fec_set_hwaddr(struct eth_device *dev, const unsigned char *mac) { struct fec_priv *fec = (struct fec_priv *)dev->priv; diff --git a/drivers/net/fec_mpc5200.c b/drivers/net/fec_mpc5200.c index f431d79d1d..14ef872927 100644 --- a/drivers/net/fec_mpc5200.c +++ b/drivers/net/fec_mpc5200.c @@ -211,7 +211,7 @@ static int mpc5xxx_fec_get_ethaddr(struct eth_device *dev, unsigned char *mac) return -1; } -static int mpc5xxx_fec_set_ethaddr(struct eth_device *dev, unsigned char *mac) +static int mpc5xxx_fec_set_ethaddr(struct eth_device *dev, const unsigned char *mac) { mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv; uint8_t currByte; /* byte for which to compute the CRC */ diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 5e47c64e0f..ac698332cf 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -233,7 +233,7 @@ static int gfar_get_ethaddr(struct eth_device *edev, unsigned char *mac) return -ENODEV; } -static int gfar_set_ethaddr(struct eth_device *edev, unsigned char *mac) +static int gfar_set_ethaddr(struct eth_device *edev, const unsigned char *mac) { struct gfar_private *priv = edev->priv; void __iomem *regs = priv->regs; diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index a8974cfcb9..854a666bfc 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -571,7 +571,7 @@ static int ks8851_get_ethaddr(struct eth_device *edev, unsigned char *adr) return 0; } -static int ks8851_set_ethaddr(struct eth_device *edev, unsigned char *adr) +static int ks8851_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { struct ks_net *priv = (struct ks_net *)edev->priv; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 2ac00f3460..6d4973fa2f 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -493,7 +493,7 @@ static int macb_get_ethaddr(struct eth_device *edev, unsigned char *adr) return -1; } -static int macb_set_ethaddr(struct eth_device *edev, unsigned char *adr) +static int macb_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { struct macb_device *macb = edev->priv; diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index 3be2ec531f..aab52c45de 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -486,7 +486,7 @@ recv_err: return ret; } -static int mvneta_set_ethaddr(struct eth_device *edev, unsigned char *mac) +static int mvneta_set_ethaddr(struct eth_device *edev, const unsigned char *mac) { struct mvneta_port *priv = edev->priv; u32 mac_h = (mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3]; diff --git a/drivers/net/netx_eth.c b/drivers/net/netx_eth.c index 96dbc7c5df..64e9886d61 100644 --- a/drivers/net/netx_eth.c +++ b/drivers/net/netx_eth.c @@ -210,7 +210,7 @@ static int netx_eth_get_ethaddr(struct eth_device *edev, unsigned char *adr) return -1; } -static int netx_eth_set_ethaddr(struct eth_device *edev, unsigned char *adr) +static int netx_eth_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv; int xcno = priv->xcno; diff --git a/drivers/net/orion-gbe.c b/drivers/net/orion-gbe.c index 97ffff2b26..e6bd757689 100644 --- a/drivers/net/orion-gbe.c +++ b/drivers/net/orion-gbe.c @@ -322,7 +322,7 @@ recv_err: return ret; } -static int port_set_ethaddr(struct eth_device *edev, unsigned char *mac) +static int port_set_ethaddr(struct eth_device *edev, const unsigned char *mac) { struct port_priv *port = edev->priv; u32 mac_h = (mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3]; diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index d57c706e52..a9eb865358 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -352,7 +352,7 @@ static int rtl8139_get_ethaddr(struct eth_device *edev, unsigned char *m) } static int rtl8139_set_ethaddr(struct eth_device *edev, - unsigned char *mac_addr) + const unsigned char *mac_addr) { struct rtl8139_priv *priv = edev->priv; int i; diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index d6a761087c..47d5e4a893 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -456,7 +456,7 @@ static int rtl8169_get_ethaddr(struct eth_device *edev, unsigned char *m) return 0; } -static int rtl8169_set_ethaddr(struct eth_device *edev, unsigned char *mac_addr) +static int rtl8169_set_ethaddr(struct eth_device *edev, const unsigned char *mac_addr) { struct rtl8169_priv *priv = edev->priv; int i; diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c index c0cf42ad82..5ea1bc3259 100644 --- a/drivers/net/smc91111.c +++ b/drivers/net/smc91111.c @@ -1378,7 +1378,7 @@ static int smc91c111_get_ethaddr(struct eth_device *edev, unsigned char *m) } static int smc91c111_set_ethaddr(struct eth_device *edev, - unsigned char *mac_addr) + const unsigned char *mac_addr) { struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv; unsigned address; diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 9977ae3f32..60cf36ea4a 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -182,7 +182,7 @@ static int smc911x_get_ethaddr(struct eth_device *edev, unsigned char *m) return 0; } -static int smc911x_set_ethaddr(struct eth_device *edev, unsigned char *m) +static int smc911x_set_ethaddr(struct eth_device *edev, const unsigned char *m) { unsigned long addrh, addrl; @@ -630,8 +630,14 @@ static int smc911x_probe(struct device_d *dev) return 0; } +static const struct of_device_id smsc911x_dt_ids[] = { + { .compatible = "smsc,lan9115", }, + { /* sentinel */ } +}; + static struct driver_d smc911x_driver = { .name = "smc911x", .probe = smc911x_probe, + .of_compatible = DRV_OF_COMPAT(smsc911x_dt_ids), }; device_platform_driver(smc911x_driver); diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 2458fb52c7..ca53f12d92 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -65,7 +65,7 @@ static int tap_get_ethaddr(struct eth_device *edev, unsigned char *adr) return -1; } -static int tap_set_ethaddr(struct eth_device *edev, unsigned char *adr) +static int tap_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { return 0; } diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 7cce5b929e..4c53a142f1 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -403,7 +403,7 @@ static int asix_get_ethaddr(struct eth_device *edev, unsigned char *adr) return 0; } -static int asix_set_ethaddr(struct eth_device *edev, unsigned char *adr) +static int asix_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { /* not possible? */ return 0; diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 053da1822a..6360e480fe 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -363,7 +363,7 @@ static int smsc95xx_set_csums(struct usbnet *dev) return 0; } -static int smsc95xx_set_ethaddr(struct eth_device *edev, unsigned char *adr) +static int smsc95xx_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { struct usbnet *udev = container_of(edev, struct usbnet, edev); diff --git a/drivers/net/xgmac.c b/drivers/net/xgmac.c index 3b2273fd79..7cc4d4888f 100644 --- a/drivers/net/xgmac.c +++ b/drivers/net/xgmac.c @@ -674,7 +674,7 @@ static int xgmac_get_ethaddr(struct eth_device *edev, unsigned char *addr) return 0; } -static int xgmac_set_ethaddr(struct eth_device *dev, unsigned char *addr) +static int xgmac_set_ethaddr(struct eth_device *dev, const unsigned char *addr) { struct xgmac_priv *priv = dev->priv; u32 data; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 3a0e7a5f4e..191561da03 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -129,10 +129,24 @@ static struct pci_dev *alloc_pci_dev(void) return dev; } +static u32 pci_size(u32 base, u32 maxbase, u32 mask) +{ + u32 size = maxbase & mask; + if (!size) + return 0; + + size = (size & ~(size-1)) - 1; + + if (base == maxbase && ((base | size) & mask) != mask) + return 0; + + return size + 1; +} + + static void setup_device(struct pci_dev *dev, int max_bar) { - int bar, size; - u32 mask; + int bar; u8 cmd; pci_read_config_byte(dev, PCI_COMMAND, &cmd); @@ -141,9 +155,12 @@ static void setup_device(struct pci_dev *dev, int max_bar) for (bar = 0; bar < max_bar; bar++) { resource_size_t last_addr; + u32 orig, mask, size; + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &orig); pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, 0xfffffffe); pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &mask); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, orig); if (mask == 0 || mask == 0xffffffff) { pr_debug("pbar%d set bad mask\n", bar); @@ -151,7 +168,11 @@ static void setup_device(struct pci_dev *dev, int max_bar) } if (mask & 0x01) { /* IO */ - size = ((~(mask & 0xfffffffe)) & 0xffff) + 1; + size = pci_size(orig, mask, 0xfffffffe); + if (!size) { + pr_debug("pbar%d bad IO mask\n", bar); + continue; + } pr_debug("pbar%d: mask=%08x io %d bytes\n", bar, mask, size); if (last_io + size > dev->bus->resource[PCI_BUS_RESOURCE_IO]->end) { @@ -164,7 +185,11 @@ static void setup_device(struct pci_dev *dev, int max_bar) last_io += size; } else if ((mask & PCI_BASE_ADDRESS_MEM_PREFETCH) && last_mem_pref) /* prefetchable MEM */ { - size = (~(mask & 0xfffffff0)) + 1; + size = pci_size(orig, mask, 0xfffffff0); + if (!size) { + pr_debug("pbar%d bad P-MEM mask\n", bar); + continue; + } pr_debug("pbar%d: mask=%08x P memory %d bytes\n", bar, mask, size); if (last_mem_pref + size > @@ -178,7 +203,11 @@ static void setup_device(struct pci_dev *dev, int max_bar) last_addr = last_mem_pref; last_mem_pref += size; } else { /* non-prefetch MEM */ - size = (~(mask & 0xfffffff0)) + 1; + size = pci_size(orig, mask, 0xfffffff0); + if (!size) { + pr_debug("pbar%d bad NP-MEM mask\n", bar); + continue; + } pr_debug("pbar%d: mask=%08x NP memory %d bytes\n", bar, mask, size); if (last_mem + size > @@ -391,11 +420,6 @@ unsigned int pci_scan_bus(struct pci_bus *bus) bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type); continue; } - - if (class == PCI_CLASS_BRIDGE_HOST) { - pr_debug("skip pci host bridge\n"); - continue; - } } /* diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index 4d636c14ca..c186ad4d39 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -291,6 +291,7 @@ static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv) if (!IS_ENABLED(CONFIG_OFDEVICE)) return; + of_property_read_u32(np, "clock-frequency", &priv->plat.clock); of_property_read_u32(np, "reg-shift", &priv->plat.shift); } @@ -417,7 +418,7 @@ static int ns16550_probe(struct device_d *dev) else ns16550_probe_dt(dev, priv); - if (!plat || !plat->clock) { + if (!priv->plat.clock) { priv->clk = clk_get(dev, NULL); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); @@ -427,12 +428,6 @@ static int ns16550_probe(struct device_d *dev) priv->plat.clock = clk_get_rate(priv->clk); } - if (priv->plat.clock == 0 && IS_ENABLED(CONFIG_OFDEVICE)) { - struct device_node *np = dev->device_node; - - of_property_read_u32(np, "clock-frequency", &priv->plat.clock); - } - if (priv->plat.clock == 0) { dev_err(dev, "no valid clockrate\n"); ret = -EINVAL; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5d9158ffae..13a3e7062a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -25,7 +25,7 @@ config USB_GADGET_DRIVER_AT91 config USB_GADGET_DRIVER_PXA27X bool prompt "PXA27x gadget driver" - depends on ARCH_PXA + depends on ARCH_PXA27X default y select USB_GADGET_DUALSPEED diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ccb702980f..84a05c4f96 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -119,8 +119,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" MUSB_DRIVER_NAME); -#define MUSB_HOST_TIMEOUT 0x5fffff - /*-------------------------------------------------------------------------*/ #ifndef CONFIG_BLACKFIN @@ -1025,17 +1023,18 @@ int musb_init(struct usb_host *host) { struct musb *musb = to_musb(host); void *mbase; - int timeout = MUSB_HOST_TIMEOUT; + u64 start; u8 power; musb_start(musb); mbase = musb->mregs; - do { + start = get_time_ns(); + while (1) { if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM) break; - } while (--timeout); - if (!timeout) - return -ENODEV; + if (is_timeout(start, 4 * SECOND)) + return -ENODEV; + } power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); diff --git a/dts/Bindings/clock/silabs,si5351.txt b/dts/Bindings/clock/silabs,si5351.txt index c40711e8e8..28b28309f5 100644 --- a/dts/Bindings/clock/silabs,si5351.txt +++ b/dts/Bindings/clock/silabs,si5351.txt @@ -17,7 +17,8 @@ Required properties: - #clock-cells: from common clock binding; shall be set to 1. - clocks: from common clock binding; list of parent clock handles, shall be xtal reference clock or xtal and clkin for - si5351c only. + si5351c only. Corresponding clock input names are "xtal" and + "clkin" respectively. - #address-cells: shall be set to 1. - #size-cells: shall be set to 0. @@ -71,6 +72,7 @@ i2c-master-node { /* connect xtal input to 25MHz reference */ clocks = <&ref25>; + clock-names = "xtal"; /* connect xtal input as source of pll0 and pll1 */ silabs,pll-source = <0 0>, <1 0>; diff --git a/dts/Bindings/input/touchscreen/tsc2005.txt b/dts/Bindings/input/touchscreen/tsc2005.txt index 4b641c7bf1..09089a6d69 100644 --- a/dts/Bindings/input/touchscreen/tsc2005.txt +++ b/dts/Bindings/input/touchscreen/tsc2005.txt @@ -32,8 +32,8 @@ Example: touchscreen-fuzz-x = <4>; touchscreen-fuzz-y = <7>; touchscreen-fuzz-pressure = <2>; - touchscreen-max-x = <4096>; - touchscreen-max-y = <4096>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; touchscreen-max-pressure = <2048>; ti,x-plate-ohms = <280>; diff --git a/dts/Bindings/mtd/m25p80.txt b/dts/Bindings/mtd/jedec,spi-nor.txt index f20b111b50..2bee68103b 100644 --- a/dts/Bindings/mtd/m25p80.txt +++ b/dts/Bindings/mtd/jedec,spi-nor.txt @@ -8,8 +8,8 @@ Required properties: is not Linux-only, but in case of Linux, see the "m25p_ids" table in drivers/mtd/devices/m25p80.c for the list of supported chips. - Must also include "nor-jedec" for any SPI NOR flash that can be - identified by the JEDEC READ ID opcode (0x9F). + Must also include "jedec,spi-nor" for any SPI NOR flash that can + be identified by the JEDEC READ ID opcode (0x9F). - reg : Chip-Select number - spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at @@ -25,7 +25,7 @@ Example: flash: m25p80@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "spansion,m25p80", "nor-jedec"; + compatible = "spansion,m25p80", "jedec,spi-nor"; reg = <0>; spi-max-frequency = <40000000>; m25p,fast-read; diff --git a/dts/Bindings/net/cdns-emac.txt b/dts/Bindings/net/cdns-emac.txt index abd67c13d3..4451ee9732 100644 --- a/dts/Bindings/net/cdns-emac.txt +++ b/dts/Bindings/net/cdns-emac.txt @@ -3,7 +3,8 @@ Required properties: - compatible: Should be "cdns,[<chip>-]{emac}" Use "cdns,at91rm9200-emac" Atmel at91rm9200 SoC. - or the generic form: "cdns,emac". + Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC. + Or the generic form: "cdns,emac". - reg: Address and length of the register set for the device - interrupts: Should contain macb interrupt - phy-mode: see ethernet.txt file in the same directory. diff --git a/dts/Bindings/usb/renesas_usbhs.txt b/dts/Bindings/usb/renesas_usbhs.txt index dc2a18f0b3..ddbe304beb 100644 --- a/dts/Bindings/usb/renesas_usbhs.txt +++ b/dts/Bindings/usb/renesas_usbhs.txt @@ -15,10 +15,8 @@ Optional properties: - phys: phandle + phy specifier pair - phy-names: must be "usb" - dmas: Must contain a list of references to DMA specifiers. - - dma-names : Must contain a list of DMA names: - - tx0 ... tx<n> - - rx0 ... rx<n> - - This <n> means DnFIFO in USBHS module. + - dma-names : named "ch%d", where %d is the channel number ranging from zero + to the number of channels (DnFIFOs) minus one. Example: usbhs: usb@e6590000 { diff --git a/dts/src/arm/am335x-bone-common.dtsi b/dts/src/arm/am335x-bone-common.dtsi index c3255e0c90..dbb3f4d2bf 100644 --- a/dts/src/arm/am335x-bone-common.dtsi +++ b/dts/src/arm/am335x-bone-common.dtsi @@ -223,6 +223,25 @@ /include/ "tps65217.dtsi" &tps { + /* + * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only + * mode") at poweroff. Most BeagleBone versions do not support RTC-only + * mode and risk hardware damage if this mode is entered. + * + * For details, see linux-omap mailing list May 2015 thread + * [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller + * In particular, messages: + * http://www.spinics.net/lists/linux-omap/msg118585.html + * http://www.spinics.net/lists/linux-omap/msg118615.html + * + * You can override this later with + * &tps { /delete-property/ ti,pmic-shutdown-controller; } + * if you want to use RTC-only mode and made sure you are not affected + * by the hardware problems. (Tip: double-check by performing a current + * measurement after shutdown: it should be less than 1 mA.) + */ + ti,pmic-shutdown-controller; + regulators { dcdc1_reg: regulator@0 { regulator-name = "vdds_dpr"; diff --git a/dts/src/arm/am335x-boneblack.dts b/dts/src/arm/am335x-boneblack.dts index 5c42d259fa..901739fcb8 100644 --- a/dts/src/arm/am335x-boneblack.dts +++ b/dts/src/arm/am335x-boneblack.dts @@ -80,7 +80,3 @@ status = "okay"; }; }; - -&rtc { - system-power-controller; -}; diff --git a/dts/src/arm/am335x-evmsk.dts b/dts/src/arm/am335x-evmsk.dts index 87fc7a35e8..156d05efcb 100644 --- a/dts/src/arm/am335x-evmsk.dts +++ b/dts/src/arm/am335x-evmsk.dts @@ -654,7 +654,7 @@ wlcore: wlcore@2 { compatible = "ti,wl1271"; reg = <2>; - interrupt-parent = <&gpio1>; + interrupt-parent = <&gpio0>; interrupts = <31 IRQ_TYPE_LEVEL_HIGH>; /* gpio 31 */ ref-clock-frequency = <38400000>; }; diff --git a/dts/src/arm/am35xx-clocks.dtsi b/dts/src/arm/am35xx-clocks.dtsi index 518b8fde88..18cc826e9d 100644 --- a/dts/src/arm/am35xx-clocks.dtsi +++ b/dts/src/arm/am35xx-clocks.dtsi @@ -12,7 +12,7 @@ #clock-cells = <0>; compatible = "ti,am35xx-gate-clock"; clocks = <&ipss_ick>; - reg = <0x059c>; + reg = <0x032c>; ti,bit-shift = <1>; }; @@ -20,7 +20,7 @@ #clock-cells = <0>; compatible = "ti,gate-clock"; clocks = <&rmii_ck>; - reg = <0x059c>; + reg = <0x032c>; ti,bit-shift = <9>; }; @@ -28,7 +28,7 @@ #clock-cells = <0>; compatible = "ti,am35xx-gate-clock"; clocks = <&ipss_ick>; - reg = <0x059c>; + reg = <0x032c>; ti,bit-shift = <2>; }; @@ -36,7 +36,7 @@ #clock-cells = <0>; compatible = "ti,gate-clock"; clocks = <&pclk_ck>; - reg = <0x059c>; + reg = <0x032c>; ti,bit-shift = <10>; }; @@ -44,7 +44,7 @@ #clock-cells = <0>; compatible = "ti,am35xx-gate-clock"; clocks = <&ipss_ick>; - reg = <0x059c>; + reg = <0x032c>; ti,bit-shift = <0>; }; @@ -52,7 +52,7 @@ #clock-cells = <0>; compatible = "ti,gate-clock"; clocks = <&sys_ck>; - reg = <0x059c>; + reg = <0x032c>; ti,bit-shift = <8>; }; @@ -60,7 +60,7 @@ #clock-cells = <0>; compatible = "ti,am35xx-gate-clock"; clocks = <&sys_ck>; - reg = <0x059c>; + reg = <0x032c>; ti,bit-shift = <3>; }; }; diff --git a/dts/src/arm/armada-375.dtsi b/dts/src/arm/armada-375.dtsi index c675257f23..f076ff856d 100644 --- a/dts/src/arm/armada-375.dtsi +++ b/dts/src/arm/armada-375.dtsi @@ -69,7 +69,7 @@ mainpll: mainpll { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <2000000000>; + clock-frequency = <1000000000>; }; /* 25 MHz reference crystal */ refclk: oscillator { diff --git a/dts/src/arm/armada-38x.dtsi b/dts/src/arm/armada-38x.dtsi index ed2dd8ba40..218a2acd36 100644 --- a/dts/src/arm/armada-38x.dtsi +++ b/dts/src/arm/armada-38x.dtsi @@ -585,7 +585,7 @@ mainpll: mainpll { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <2000000000>; + clock-frequency = <1000000000>; }; /* 25 MHz reference crystal */ diff --git a/dts/src/arm/armada-39x.dtsi b/dts/src/arm/armada-39x.dtsi index 0e85fc15ce..ecd1318109 100644 --- a/dts/src/arm/armada-39x.dtsi +++ b/dts/src/arm/armada-39x.dtsi @@ -502,7 +502,7 @@ mainpll: mainpll { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <2000000000>; + clock-frequency = <1000000000>; }; }; }; diff --git a/dts/src/arm/armada-xp-linksys-mamba.dts b/dts/src/arm/armada-xp-linksys-mamba.dts index a2cf2154dc..fdd187c55a 100644 --- a/dts/src/arm/armada-xp-linksys-mamba.dts +++ b/dts/src/arm/armada-xp-linksys-mamba.dts @@ -95,6 +95,11 @@ internal-regs { + rtc@10300 { + /* No crystal connected to the internal RTC */ + status = "disabled"; + }; + /* J10: VCC, NC, RX, NC, TX, GND */ serial@12000 { status = "okay"; diff --git a/dts/src/arm/dm816x.dtsi b/dts/src/arm/dm816x.dtsi index de8427be83..289806adb3 100644 --- a/dts/src/arm/dm816x.dtsi +++ b/dts/src/arm/dm816x.dtsi @@ -382,7 +382,7 @@ ti,hwmods = "usb_otg_hs"; usb0: usb@47401000 { - compatible = "ti,musb-am33xx"; + compatible = "ti,musb-dm816"; reg = <0x47401400 0x400 0x47401000 0x200>; reg-names = "mc", "control"; @@ -422,7 +422,7 @@ }; usb1: usb@47401800 { - compatible = "ti,musb-am33xx"; + compatible = "ti,musb-dm816"; reg = <0x47401c00 0x400 0x47401800 0x200>; reg-names = "mc", "control"; diff --git a/dts/src/arm/dove-cubox.dts b/dts/src/arm/dove-cubox.dts index aae7efc09b..e6fa251e17 100644 --- a/dts/src/arm/dove-cubox.dts +++ b/dts/src/arm/dove-cubox.dts @@ -87,6 +87,7 @@ /* connect xtal input to 25MHz reference */ clocks = <&ref25>; + clock-names = "xtal"; /* connect xtal input as source of pll0 and pll1 */ silabs,pll-source = <0 0>, <1 0>; diff --git a/dts/src/arm/exynos4412-trats2.dts b/dts/src/arm/exynos4412-trats2.dts index 173ffa479a..792394dd0f 100644 --- a/dts/src/arm/exynos4412-trats2.dts +++ b/dts/src/arm/exynos4412-trats2.dts @@ -736,7 +736,7 @@ display-timings { timing-0 { - clock-frequency = <0>; + clock-frequency = <57153600>; hactive = <720>; vactive = <1280>; hfront-porch = <5>; diff --git a/dts/src/arm/exynos5420-peach-pit.dts b/dts/src/arm/exynos5420-peach-pit.dts index 0788d08fb4..146e71118a 100644 --- a/dts/src/arm/exynos5420-peach-pit.dts +++ b/dts/src/arm/exynos5420-peach-pit.dts @@ -711,6 +711,7 @@ num-slots = <1>; broken-cd; cap-sdio-irq; + keep-power-in-suspend; card-detect-delay = <200>; clock-frequency = <400000000>; samsung,dw-mshc-ciu-div = <1>; diff --git a/dts/src/arm/exynos5800-peach-pi.dts b/dts/src/arm/exynos5800-peach-pi.dts index 412f41d626..02eb8b1537 100644 --- a/dts/src/arm/exynos5800-peach-pi.dts +++ b/dts/src/arm/exynos5800-peach-pi.dts @@ -674,6 +674,7 @@ num-slots = <1>; broken-cd; cap-sdio-irq; + keep-power-in-suspend; card-detect-delay = <200>; clock-frequency = <400000000>; samsung,dw-mshc-ciu-div = <1>; diff --git a/dts/src/arm/imx27.dtsi b/dts/src/arm/imx27.dtsi index 6951b66d1a..bc215e4b75 100644 --- a/dts/src/arm/imx27.dtsi +++ b/dts/src/arm/imx27.dtsi @@ -533,7 +533,7 @@ fec: ethernet@1002b000 { compatible = "fsl,imx27-fec"; - reg = <0x1002b000 0x4000>; + reg = <0x1002b000 0x1000>; interrupts = <50>; clocks = <&clks IMX27_CLK_FEC_IPG_GATE>, <&clks IMX27_CLK_FEC_AHB_GATE>; diff --git a/dts/src/arm/omap3-devkit8000.dts b/dts/src/arm/omap3-devkit8000.dts index 134d3f27a8..921de6605f 100644 --- a/dts/src/arm/omap3-devkit8000.dts +++ b/dts/src/arm/omap3-devkit8000.dts @@ -110,6 +110,8 @@ nand@0,0 { reg = <0 0 4>; /* CS0, offset 0, IO size 4 */ nand-bus-width = <16>; + gpmc,device-width = <2>; + ti,nand-ecc-opt = "sw"; gpmc,sync-clk-ps = <0>; gpmc,cs-on-ns = <0>; diff --git a/dts/src/arm/omap3-n900.dts b/dts/src/arm/omap3-n900.dts index 5c16145920..5f5e0f3d5b 100644 --- a/dts/src/arm/omap3-n900.dts +++ b/dts/src/arm/omap3-n900.dts @@ -832,8 +832,8 @@ touchscreen-fuzz-x = <4>; touchscreen-fuzz-y = <7>; touchscreen-fuzz-pressure = <2>; - touchscreen-max-x = <4096>; - touchscreen-max-y = <4096>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; touchscreen-max-pressure = <2048>; ti,x-plate-ohms = <280>; diff --git a/dts/src/arm/tegra124.dtsi b/dts/src/arm/tegra124.dtsi index cf01c818b8..13cc7ca5e0 100644 --- a/dts/src/arm/tegra124.dtsi +++ b/dts/src/arm/tegra124.dtsi @@ -826,7 +826,7 @@ <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; - resets = <&tegra_car 59>, <&tegra_car 22>; + resets = <&tegra_car 22>, <&tegra_car 22>; reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; @@ -838,6 +838,7 @@ nvidia,hssquelch-level = <2>; nvidia,hsdiscon-level = <5>; nvidia,xcvr-hsslew = <12>; + nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -862,7 +863,7 @@ <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; - resets = <&tegra_car 22>, <&tegra_car 22>; + resets = <&tegra_car 58>, <&tegra_car 22>; reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; @@ -874,7 +875,6 @@ nvidia,hssquelch-level = <2>; nvidia,hsdiscon-level = <5>; nvidia,xcvr-hsslew = <12>; - nvidia,has-utmi-pad-registers; status = "disabled"; }; @@ -899,7 +899,7 @@ <&tegra_car TEGRA124_CLK_PLL_U>, <&tegra_car TEGRA124_CLK_USBD>; clock-names = "reg", "pll_u", "utmi-pads"; - resets = <&tegra_car 58>, <&tegra_car 22>; + resets = <&tegra_car 59>, <&tegra_car 22>; reset-names = "usb", "utmi-pads"; nvidia,hssync-start-delay = <0>; nvidia,idle-wait-delay = <17>; diff --git a/dts/src/arm/vexpress-v2p-ca15_a7.dts b/dts/src/arm/vexpress-v2p-ca15_a7.dts index 7a2aeacd62..107395c32d 100644 --- a/dts/src/arm/vexpress-v2p-ca15_a7.dts +++ b/dts/src/arm/vexpress-v2p-ca15_a7.dts @@ -191,6 +191,7 @@ compatible = "arm,cortex-a15-pmu"; interrupts = <0 68 4>, <0 69 4>; + interrupt-affinity = <&cpu0>, <&cpu1>; }; oscclk6a: oscclk6a { diff --git a/dts/src/arm/vexpress-v2p-ca9.dts b/dts/src/arm/vexpress-v2p-ca9.dts index 23662b5a5e..d949facba3 100644 --- a/dts/src/arm/vexpress-v2p-ca9.dts +++ b/dts/src/arm/vexpress-v2p-ca9.dts @@ -33,28 +33,28 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + A9_0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0>; next-level-cache = <&L2>; }; - cpu@1 { + A9_1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <1>; next-level-cache = <&L2>; }; - cpu@2 { + A9_2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <2>; next-level-cache = <&L2>; }; - cpu@3 { + A9_3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <3>; @@ -170,6 +170,7 @@ compatible = "arm,pl310-cache"; reg = <0x1e00a000 0x1000>; interrupts = <0 43 4>; + cache-unified; cache-level = <2>; arm,data-latency = <1 1 1>; arm,tag-latency = <1 1 1>; @@ -181,6 +182,8 @@ <0 61 4>, <0 62 4>, <0 63 4>; + interrupt-affinity = <&A9_0>, <&A9_1>, <&A9_2>, <&A9_3>; + }; dcc { diff --git a/dts/src/arm/zynq-7000.dtsi b/dts/src/arm/zynq-7000.dtsi index a5cd2eda3e..9ea54b3dba 100644 --- a/dts/src/arm/zynq-7000.dtsi +++ b/dts/src/arm/zynq-7000.dtsi @@ -193,7 +193,7 @@ }; gem0: ethernet@e000b000 { - compatible = "cdns,gem"; + compatible = "cdns,zynq-gem"; reg = <0xe000b000 0x1000>; status = "disabled"; interrupts = <0 22 4>; @@ -204,7 +204,7 @@ }; gem1: ethernet@e000c000 { - compatible = "cdns,gem"; + compatible = "cdns,zynq-gem"; reg = <0xe000c000 0x1000>; status = "disabled"; interrupts = <0 45 4>; diff --git a/dts/src/arm64/arm/juno-motherboard.dtsi b/dts/src/arm64/arm/juno-motherboard.dtsi index c138b95a83..351c95bda8 100644 --- a/dts/src/arm64/arm/juno-motherboard.dtsi +++ b/dts/src/arm64/arm/juno-motherboard.dtsi @@ -21,6 +21,20 @@ clock-output-names = "juno_mb:clk25mhz"; }; + v2m_refclk1mhz: refclk1mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = "juno_mb:refclk1mhz"; + }; + + v2m_refclk32khz: refclk32khz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "juno_mb:refclk32khz"; + }; + motherboard { compatible = "arm,vexpress,v2p-p1", "simple-bus"; #address-cells = <2>; /* SMB chipselect number and offset */ @@ -66,6 +80,15 @@ #size-cells = <1>; ranges = <0 3 0 0x200000>; + v2m_sysctl: sysctl@020000 { + compatible = "arm,sp810", "arm,primecell"; + reg = <0x020000 0x1000>; + clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&mb_clk24mhz>; + clock-names = "refclk", "timclk", "apb_pclk"; + #clock-cells = <1>; + clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; + }; + mmci@050000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x050000 0x1000>; @@ -106,16 +129,16 @@ compatible = "arm,sp804", "arm,primecell"; reg = <0x110000 0x10000>; interrupts = <9>; - clocks = <&mb_clk24mhz>, <&soc_smc50mhz>; - clock-names = "timclken1", "apb_pclk"; + clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&mb_clk24mhz>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; v2m_timer23: timer@120000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x120000 0x10000>; interrupts = <9>; - clocks = <&mb_clk24mhz>, <&soc_smc50mhz>; - clock-names = "timclken1", "apb_pclk"; + clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&mb_clk24mhz>; + clock-names = "timclken1", "timclken2", "apb_pclk"; }; rtc@170000 { diff --git a/dts/src/arm64/mediatek/mt8173-evb.dts b/dts/src/arm64/mediatek/mt8173-evb.dts index 43d54017b7..d0ab012fa3 100644 --- a/dts/src/arm64/mediatek/mt8173-evb.dts +++ b/dts/src/arm64/mediatek/mt8173-evb.dts @@ -16,7 +16,8 @@ #include "mt8173.dtsi" / { - model = "mediatek,mt8173-evb"; + model = "MediaTek MT8173 evaluation board"; + compatible = "mediatek,mt8173-evb", "mediatek,mt8173"; aliases { serial0 = &uart0; diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c index fb927149e7..97f028a3ec 100644 --- a/fs/cramfs/cramfs.c +++ b/fs/cramfs/cramfs.c @@ -481,4 +481,3 @@ static int cramfs_init(void) } device_initcall(cramfs_init); - diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 6d7d262f32..ece937d443 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -434,4 +434,3 @@ static int fat_init(void) } coredevice_initcall(fat_init); - diff --git a/fs/ramfs.c b/fs/ramfs.c index fe5eb89824..716f40f5ba 100644 --- a/fs/ramfs.c +++ b/fs/ramfs.c @@ -644,4 +644,3 @@ static int ramfs_init(void) } coredevice_initcall(ramfs_init); - @@ -253,27 +253,24 @@ static void tftp_timer_reset(struct file_priv *priv) priv->progress_timeout = priv->resend_timeout = get_time_ns(); } -static void tftp_handler(void *ctx, char *packet, unsigned len) +static void tftp_recv(struct file_priv *priv, + uint8_t *pkt, unsigned len, uint16_t uh_sport) { - struct file_priv *priv = ctx; - uint16_t proto; - uint16_t *s; - char *pkt = net_eth_to_udp_payload(packet); - struct udphdr *udp = net_eth_to_udphdr(packet); + uint16_t opcode; - len = net_eth_to_udplen(packet); - if (len < 2) + /* according to RFC1350 minimal tftp packet length is 4 bytes */ + if (len < 4) return; - len -= 2; + opcode = ntohs(*(uint16_t *)pkt); - s = (uint16_t *)pkt; - proto = *s++; - pkt = (unsigned char *)s; + /* skip tftp opcode 2-byte field */ + len -= 2; + pkt += 2; - debug("%s: proto 0x%04x\n", __func__, proto); + debug("%s: opcode 0x%04x\n", __func__, opcode); - switch (ntohs(proto)) { + switch (opcode) { case TFTP_RRQ: case TFTP_WRQ: default: @@ -296,14 +293,14 @@ static void tftp_handler(void *ctx, char *packet, unsigned len) priv->state = STATE_DONE; break; } - priv->tftp_con->udp->uh_dport = udp->uh_sport; + priv->tftp_con->udp->uh_dport = uh_sport; priv->state = STATE_WDATA; break; case TFTP_OACK: tftp_parse_oack(priv, pkt, len); - priv->server_port = ntohs(udp->uh_sport); - priv->tftp_con->udp->uh_dport = udp->uh_sport; + priv->server_port = ntohs(uh_sport); + priv->tftp_con->udp->uh_dport = uh_sport; if (priv->push) { /* send first block */ @@ -318,16 +315,14 @@ static void tftp_handler(void *ctx, char *packet, unsigned len) break; case TFTP_DATA: - if (len < 2) - return; len -= 2; priv->block = ntohs(*(uint16_t *)pkt); if (priv->state == STATE_RRQ || priv->state == STATE_OACK) { /* first block received */ priv->state = STATE_RDATA; - priv->tftp_con->udp->uh_dport = udp->uh_sport; - priv->server_port = ntohs(udp->uh_sport); + priv->tftp_con->udp->uh_dport = uh_sport; + priv->server_port = ntohs(uh_sport); priv->last_block = 0; if (priv->block != 1) { /* Assertion */ @@ -376,6 +371,16 @@ static void tftp_handler(void *ctx, char *packet, unsigned len) } } +static void tftp_handler(void *ctx, char *packet, unsigned len) +{ + struct file_priv *priv = ctx; + char *pkt = net_eth_to_udp_payload(packet); + struct udphdr *udp = net_eth_to_udphdr(packet); + + (void)len; + tftp_recv(priv, pkt, net_eth_to_udplen(packet), udp->uh_sport); +} + static struct file_priv *tftp_do_open(struct device_d *dev, int accmode, const char *filename) { diff --git a/images/Makefile b/images/Makefile index 1e1771f35c..a5f589b303 100644 --- a/images/Makefile +++ b/images/Makefile @@ -75,6 +75,8 @@ quiet_cmd_pblx ?= PBLX $@ $(obj)/%.pblx: $(obj)/%.pblb $(obj)/barebox.z FORCE $(call if_changed,pblx,$(@F)) + $(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_PBLX_SIZE)) + $(obj)/%.s: $(obj)/% FORCE $(call if_changed,disasm) diff --git a/images/Makefile.am33xx b/images/Makefile.am33xx index eae2a6a6e1..657aeb0e28 100644 --- a/images/Makefile.am33xx +++ b/images/Makefile.am33xx @@ -7,13 +7,23 @@ quiet_cmd_mlo_image = MLO $@ $(obj)/%.mlo: $(obj)/% FORCE $(call if_changed,mlo_image) +# %.mlospi - convert MLO image for SPI loading +# ---------------------------------------------------------------- +quiet_cmd_mlo_spi_image = SPI-IMG $@ + cmd_mlo_spi_image = scripts/mk-omap-image -s -a 0x402f0400 $<.mlo > $@ + +$(obj)/%.mlospi: $(obj)/% $(obj)/%.mlo FORCE + $(call if_changed,mlo_spi_image) + pblx-$(CONFIG_MACH_AFI_GF) += start_am33xx_afi_gf_sdram FILE_barebox-am33xx-afi-gf.img = start_am33xx_afi_gf_sdram.pblx am33xx-barebox-$(CONFIG_MACH_AFI_GF) += barebox-am33xx-afi-gf.img pblx-$(CONFIG_MACH_AFI_GF) += start_am33xx_afi_gf_sram FILE_barebox-am33xx-afi-gf-mlo.img = start_am33xx_afi_gf_sram.pblx.mlo +FILE_barebox-am33xx-afi-gf-mlo.spi.img = start_am33xx_afi_gf_sram.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_AFI_GF) += barebox-am33xx-afi-gf-mlo.img +am33xx-mlospi-$(CONFIG_MACH_AFI_GF) += barebox-am33xx-afi-gf-mlo.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sdram FILE_barebox-am33xx-phytec-phycore.img = start_am33xx_phytec_phycore_sdram.pblx @@ -25,19 +35,27 @@ am33xx-barebox-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_256mb FILE_barebox-am33xx-phytec-phycore-mlo-256mb.img = start_am33xx_phytec_phycore_sram_256mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-256mb.spi.img = start_am33xx_phytec_phycore_sram_256mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-256mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-256mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_128mb FILE_barebox-am33xx-phytec-phycore-mlo-128mb.img = start_am33xx_phytec_phycore_sram_128mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-128mb.spi.img = start_am33xx_phytec_phycore_sram_128mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-128mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-128mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_512mb FILE_barebox-am33xx-phytec-phycore-mlo-512mb.img = start_am33xx_phytec_phycore_sram_512mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-512mb.spi.img = start_am33xx_phytec_phycore_sram_512mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-512mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-512mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_2x512mb FILE_barebox-am33xx-phytec-phycore-mlo-2x512mb.img = start_am33xx_phytec_phycore_sram_2x512mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-2x512mb.spi.img = start_am33xx_phytec_phycore_sram_2x512mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-2x512mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-2x512mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phyflex_sdram FILE_barebox-am33xx-phytec-phyflex.img = start_am33xx_phytec_phyflex_sdram.pblx @@ -45,11 +63,15 @@ am33xx-barebox-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phyflex_sram_256mb FILE_barebox-am33xx-phytec-phyflex-mlo-256mb.img = start_am33xx_phytec_phyflex_sram_256mb.pblx.mlo +FILE_barebox-am33xx-phytec-phyflex-mlo-256mb.spi.img = start_am33xx_phytec_phyflex_sram_256mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-256mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-256mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phyflex_sram_512mb FILE_barebox-am33xx-phytec-phyflex-mlo-512mb.img = start_am33xx_phytec_phyflex_sram_512mb.pblx.mlo +FILE_barebox-am33xx-phytec-phyflex-mlo-512mb.spi.img = start_am33xx_phytec_phyflex_sram_512mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-512mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-512mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycard_sdram FILE_barebox-am33xx-phytec-phycard.img = start_am33xx_phytec_phycard_sdram.pblx @@ -57,7 +79,9 @@ am33xx-barebox-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycard pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycard_sram_256mb FILE_barebox-am33xx-phytec-phycard-mlo-256mb.img = start_am33xx_phytec_phycard_sram_256mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycard-mlo-256mb.spi.img = start_am33xx_phytec_phycard_sram_256mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycard-mlo-256mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycard-mlo-256mb.spi.img pblx-$(CONFIG_MACH_BEAGLEBONE) += start_am33xx_beaglebone_sdram FILE_barebox-am33xx-beaglebone.img = start_am33xx_beaglebone_sdram.pblx @@ -72,3 +96,7 @@ image-y += $(am33xx-mlo-y) else image-y += $(am33xx-barebox-y) endif + +ifdef CONFIG_OMAP_BUILD_SPI +image-y += $(am33xx-mlospi-y) +endif diff --git a/include/bbu.h b/include/bbu.h index 4a3d35e7ce..7277911718 100644 --- a/include/bbu.h +++ b/include/bbu.h @@ -4,6 +4,7 @@ #include <asm-generic/errno.h> #include <linux/list.h> #include <linux/types.h> +#include <filetype.h> struct bbu_data { #define BBU_FLAG_FORCE (1 << 0) @@ -41,6 +42,9 @@ void bbu_handlers_list(void); int bbu_register_handler(struct bbu_handler *); +int bbu_register_std_file_update(const char *name, unsigned long flags, + char *devicefile, enum filetype imagetype); + #else static inline int bbu_register_handler(struct bbu_handler *unused) @@ -48,6 +52,25 @@ static inline int bbu_register_handler(struct bbu_handler *unused) return -EINVAL; } +static inline int bbu_register_std_file_update(const char *name, unsigned long flags, + char *devicefile, enum filetype imagetype) +{ + return -ENOSYS; +} +#endif + +#if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) +int imx6_bbu_nand_register_handler(const char *name, unsigned long flags); +int imx28_bbu_nand_register_handler(const char *name, unsigned long flags); +#else +static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + return -ENOSYS; +} +static inline int imx28_bbu_nand_register_handler(const char *name, unsigned long flags) +{ + return -ENOSYS; +} #endif #endif /* __INCLUDE_BBU_H */ diff --git a/include/blspec.h b/include/blspec.h index afac5ed7ba..e22e9be11d 100644 --- a/include/blspec.h +++ b/include/blspec.h @@ -35,6 +35,7 @@ int blspec_boot_devicename(const char *devname, int verbose, int dryrun); int blspec_scan_devices(struct blspec *blspec); +int blspec_scan_device(struct blspec *blspec, struct device_d *dev); int blspec_scan_devicename(struct blspec *blspec, const char *devname); int blspec_scan_directory(struct blspec *blspec, const char *root); diff --git a/include/digest.h b/include/digest.h index 7c6711b32a..3a9d305963 100644 --- a/include/digest.h +++ b/include/digest.h @@ -59,6 +59,7 @@ struct digest { /* * digest functions */ +#ifdef CONFIG_DIGEST int digest_algo_register(struct digest_algo *d); void digest_algo_unregister(struct digest_algo *d); void digest_algo_prints(const char *prefix); @@ -76,6 +77,16 @@ int digest_file(struct digest *d, const char *filename, int digest_file_by_name(const char *algo, const char *filename, unsigned char *hash, const unsigned char *sig); +#else +static inline struct digest *digest_alloc(const char *name) +{ + return NULL; +} + +static inline void digest_free(struct digest *d) +{ +} +#endif static inline int digest_init(struct digest *d) { diff --git a/include/filetype.h b/include/filetype.h index cca4dad7f3..e452b7ac9d 100644 --- a/include/filetype.h +++ b/include/filetype.h @@ -34,6 +34,7 @@ enum filetype { filetype_ch_image_be, filetype_exe, filetype_xz_compressed, + filetype_mxs_bootstream, filetype_max, }; diff --git a/include/linux/bitops.h b/include/linux/bitops.h index be5fd38bd5..f3a740c461 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -54,7 +54,7 @@ extern unsigned long __sw_hweight64(__u64 w); (bit) < (size); \ (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) -static __inline__ int get_bitmask_order(unsigned int count) +static inline int get_bitmask_order(unsigned int count) { int order; @@ -62,7 +62,7 @@ static __inline__ int get_bitmask_order(unsigned int count) return order; /* We could be slightly more clever with -1 here... */ } -static __inline__ int get_count_order(unsigned int count) +static inline int get_count_order(unsigned int count) { int order; diff --git a/include/linux/mtd/concat.h b/include/linux/mtd/concat.h new file mode 100644 index 0000000000..ccdbe93a90 --- /dev/null +++ b/include/linux/mtd/concat.h @@ -0,0 +1,34 @@ +/* + * MTD device concatenation layer definitions + * + * Copyright © 2002 Robert Kaiser <rkaiser@sysgo.de> + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef MTD_CONCAT_H +#define MTD_CONCAT_H + + +struct mtd_info *mtd_concat_create( + struct mtd_info *subdev[], /* subdevices to concatenate */ + int num_devs, /* number of subdevices */ + const char *name); /* name for the new device */ + +void mtd_concat_destroy(struct mtd_info *mtd); + +#endif + diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 33f1fd512d..7e828bc98f 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -270,7 +270,7 @@ static inline uint32_t mtd_div_by_wb(uint64_t sz, struct mtd_info *mtd) /* Kernel-side ioctl definitions */ -extern int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id); +extern int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id); extern int del_mtd_device (struct mtd_info *mtd); extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); diff --git a/include/net.h b/include/net.h index 364011b20f..b93e264f54 100644 --- a/include/net.h +++ b/include/net.h @@ -42,7 +42,7 @@ struct eth_device { int (*recv) (struct eth_device*); void (*halt) (struct eth_device*); int (*get_ethaddr) (struct eth_device*, u8 adr[6]); - int (*set_ethaddr) (struct eth_device*, u8 adr[6]); + int (*set_ethaddr) (struct eth_device*, const unsigned char *adr); struct eth_device *next; void *priv; @@ -60,6 +60,7 @@ struct eth_device { IPaddr_t serverip; IPaddr_t netmask; IPaddr_t gateway; + char ethaddr_param[6]; char ethaddr[6]; }; @@ -67,6 +68,7 @@ struct eth_device { int eth_register(struct eth_device* dev); /* Register network device */ void eth_unregister(struct eth_device* dev); /* Unregister network device */ +int eth_set_ethaddr(struct eth_device *edev, const char *ethaddr); int eth_send(struct eth_device *edev, void *packet, int length); /* Send a packet */ int eth_rx(void); /* Check for received packets */ diff --git a/lib/fnmatch.c b/lib/fnmatch.c index 1a5e8d0d3d..0ab530d3b1 100644 --- a/lib/fnmatch.c +++ b/lib/fnmatch.c @@ -218,4 +218,3 @@ int fnmatch(const char *pattern, const char *string, int flags) # undef FOLD } - diff --git a/lib/gui/bmp.c b/lib/gui/bmp.c index 6943a1c8e0..d457c01d84 100644 --- a/lib/gui/bmp.c +++ b/lib/gui/bmp.c @@ -7,6 +7,7 @@ #include <gui/graphic_utils.h> #include <init.h> #include <gui/image_renderer.h> +#include <asm/unaligned.h> struct image *bmp_open(char *inbuf, int insize) { @@ -19,9 +20,9 @@ struct image *bmp_open(char *inbuf, int insize) } img->data = inbuf; - img->height = le32_to_cpu(bmp->header.height); - img->width = le32_to_cpu(bmp->header.width); - img->bits_per_pixel = le16_to_cpu(bmp->header.bit_count); + img->height = get_unaligned_le32(&bmp->header.height); + img->width = get_unaligned_le32(&bmp->header.width); + img->bits_per_pixel = get_unaligned_le16(&bmp->header.bit_count); pr_debug("bmp: %d x %d x %d data@0x%p\n", img->width, img->height, img->bits_per_pixel, img->data); @@ -76,7 +77,7 @@ static int bmp_renderer(struct screen *sc, struct surface *s, struct image *img) for (y = 0; y < height; y++) { image = (char *)bmp + - le32_to_cpu(bmp->header.data_offset); + get_unaligned_le32(&bmp->header.data_offset); image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3); adr = buf + (y + starty) * sc->info.line_length + startx * (sc->info.bits_per_pixel >> 3); @@ -98,7 +99,7 @@ static int bmp_renderer(struct screen *sc, struct surface *s, struct image *img) for (y = 0; y < height; y++) { image = (char *)bmp + - le32_to_cpu(bmp->header.data_offset); + get_unaligned_le32(&bmp->header.data_offset); image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3); adr = buf + (y + starty) * sc->info.line_length + startx * (sc->info.bits_per_pixel >> 3); diff --git a/lib/gui/image_renderer.c b/lib/gui/image_renderer.c index dd29389baa..9bef99a7b0 100644 --- a/lib/gui/image_renderer.c +++ b/lib/gui/image_renderer.c @@ -37,10 +37,10 @@ struct image *image_renderer_open(const char* file) struct image *img; int ret; - data = read_file(file, &size); - if (!data) { - printf("unable to read %s\n", file); - return ERR_PTR(-ENOMEM); + ret = read_file_2(file, &size, &data, FILESIZE_MAX); + if (ret) { + printf("unable to read %s: %s\n", file, strerror(-ret)); + return ERR_PTR(ret); } ir = get_renderer(data, size); diff --git a/lib/libfile.c b/lib/libfile.c index 8acff042c8..ba03700aba 100644 --- a/lib/libfile.c +++ b/lib/libfile.c @@ -184,8 +184,8 @@ again: if (read_size < s.st_size) return -EFBIG; - else - return 0; + + return 0; err_out1: close(fd); diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index 3c0f512634..6e8c822b3a 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -258,4 +258,3 @@ lookbehind_overrun: } EXPORT_SYMBOL(lzo1x_decompress_safe); - diff --git a/lib/parameter.c b/lib/parameter.c index 865ad9f431..60642f001b 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -122,6 +122,14 @@ static const char *param_get_generic(struct device_d *dev, struct param_d *p) return p->value ? p->value : ""; } +static int compare(struct list_head *a, struct list_head *b) +{ + char *na = (char*)list_entry(a, struct param_d, list)->name; + char *nb = (char*)list_entry(b, struct param_d, list)->name; + + return strcmp(na, nb); +} + static int __dev_add_param(struct param_d *param, struct device_d *dev, const char *name, int (*set)(struct device_d *dev, struct param_d *p, const char *val), const char *(*get)(struct device_d *dev, struct param_d *p), @@ -145,7 +153,7 @@ static int __dev_add_param(struct param_d *param, struct device_d *dev, const ch param->flags = flags; param->dev = dev; - list_add_tail(¶m->list, &dev->parameters); + list_add_sort(¶m->list, &dev->parameters, compare); return 0; } @@ -575,7 +583,6 @@ struct param_d *dev_add_param_llint_ro(struct device_d *dev, const char *name, return &piro->param; } -#ifdef CONFIG_NET struct param_ip { struct param_d param; IPaddr_t *ip; @@ -739,7 +746,6 @@ struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, return &pm->param; } -#endif /** * dev_remove_param - remove a parameter from a device and free its diff --git a/lib/random.c b/lib/random.c index 14c7da119d..210fea9946 100644 --- a/lib/random.c +++ b/lib/random.c @@ -25,4 +25,3 @@ void get_random_bytes(void *_buf, int len) while (len--) *buf++ = rand() % 256; } - diff --git a/lib/strtox.c b/lib/strtox.c index 882865b45d..cfe61240cc 100644 --- a/lib/strtox.c +++ b/lib/strtox.c @@ -65,4 +65,3 @@ unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int ba return result; } EXPORT_SYMBOL(simple_strtoull); - diff --git a/net/Makefile b/net/Makefile index 58bf143676..8d564e7299 100644 --- a/net/Makefile +++ b/net/Makefile @@ -1,3 +1,4 @@ +obj-y += lib.o obj-$(CONFIG_NET) += eth.o obj-$(CONFIG_NET) += net.o obj-$(CONFIG_NET_NFS) += nfs.o @@ -116,9 +116,8 @@ static int dns_send(char *name) return ret; } -static void dns_handler(void *ctx, char *packet, unsigned len) +static void dns_recv(struct header *header, unsigned len) { - struct header *header; unsigned char *p, *e, *s; u16 type; int found, stop, dlen; @@ -127,7 +126,6 @@ static void dns_handler(void *ctx, char *packet, unsigned len) debug("%s\n", __func__); /* We sent 1 query. We want to see more that 1 answer. */ - header = (struct header *)net_eth_to_udp_payload(packet); if (ntohs(header->nqueries) != 1) return; @@ -140,7 +138,7 @@ static void dns_handler(void *ctx, char *packet, unsigned len) /* Skip host name */ s = &header->data[0]; - e = packet + len; + e = ((uint8_t *)header) + len; for (p = s; p < e && *p != '\0'; p++) continue; @@ -194,6 +192,13 @@ static void dns_handler(void *ctx, char *packet, unsigned len) } } +static void dns_handler(void *ctx, char *packet, unsigned len) +{ + (void)ctx; + dns_recv((struct header *)net_eth_to_udp_payload(packet), + net_eth_to_udplen(packet)); +} + IPaddr_t resolv(char *host) { IPaddr_t ip; @@ -42,15 +42,27 @@ struct eth_ethaddr { static LIST_HEAD(ethaddr_list); +int eth_set_ethaddr(struct eth_device *edev, const char *ethaddr) +{ + int ret; + + ret = edev->set_ethaddr(edev, ethaddr); + if (ret) + return ret; + + memcpy(edev->ethaddr, ethaddr, ETH_ALEN); + + return 0; +} + static void register_preset_mac_address(struct eth_device *edev, const char *ethaddr) { unsigned char ethaddr_str[sizeof("xx:xx:xx:xx:xx:xx")]; - ethaddr_to_string(ethaddr, ethaddr_str); - if (is_valid_ether_addr(ethaddr)) { + ethaddr_to_string(ethaddr, ethaddr_str); dev_info(&edev->dev, "got preset MAC address: %s\n", ethaddr_str); - dev_set_param(&edev->dev, "ethaddr", ethaddr_str); + eth_set_ethaddr(edev, ethaddr); } } @@ -261,13 +273,11 @@ int eth_rx(void) return 0; } -static int eth_set_ethaddr(struct param_d *param, void *priv) +static int eth_param_set_ethaddr(struct param_d *param, void *priv) { struct eth_device *edev = priv; - edev->set_ethaddr(edev, edev->ethaddr); - - return 0; + return eth_set_ethaddr(edev, edev->ethaddr_param); } #ifdef CONFIG_OFTREE @@ -350,7 +360,8 @@ int eth_register(struct eth_device *edev) dev_add_param_ip(dev, "serverip", NULL, NULL, &edev->serverip, edev); dev_add_param_ip(dev, "gateway", NULL, NULL, &edev->gateway, edev); dev_add_param_ip(dev, "netmask", NULL, NULL, &edev->netmask, edev); - dev_add_param_mac(dev, "ethaddr", eth_set_ethaddr, NULL, edev->ethaddr, edev); + dev_add_param_mac(dev, "ethaddr", eth_param_set_ethaddr, NULL, + edev->ethaddr_param, edev); if (edev->init) edev->init(edev); diff --git a/net/lib.c b/net/lib.c new file mode 100644 index 0000000000..f1c60c9a74 --- /dev/null +++ b/net/lib.c @@ -0,0 +1,109 @@ +/* + * net.c - barebox networking support + * + * Copyright (c) 2015 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * based on U-Boot (LiMon) code + * + * Copyright 1994 - 2000 Neil Russell. + * Copyright 2000 Roland Borde + * Copyright 2000 Paolo Scaffardi + * Copyright 2000-2002 Wolfgang Denk, wd@denx.de + * + * 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 <net.h> +#include <linux/ctype.h> + +int string_to_ethaddr(const char *str, u8 enetaddr[6]) +{ + int reg; + char *e; + + if (!str || strlen(str) != 17) { + memset(enetaddr, 0, 6); + return -EINVAL; + } + + if (str[2] != ':' || str[5] != ':' || str[8] != ':' || + str[11] != ':' || str[14] != ':') + return -EINVAL; + + for (reg = 0; reg < 6; ++reg) { + enetaddr[reg] = simple_strtoul(str, &e, 16); + str = e + 1; + } + + return 0; +} + +void ethaddr_to_string(const u8 enetaddr[6], char *str) +{ + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + enetaddr[0], enetaddr[1], enetaddr[2], enetaddr[3], + enetaddr[4], enetaddr[5]); +} + +void print_IPaddr(IPaddr_t x) +{ + puts(ip_to_string(x)); +} + +char *ip_to_string(IPaddr_t x) +{ + static char s[sizeof("xxx.xxx.xxx.xxx")]; + + x = ntohl(x); + sprintf(s, "%d.%d.%d.%d", + (int) ((x >> 24) & 0xff), + (int) ((x >> 16) & 0xff), + (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff) + ); + + return s; +} + +int string_to_ip(const char *s, IPaddr_t *ip) +{ + IPaddr_t addr = 0; + char *e; + int i; + + if (!s) + return -EINVAL; + + for (i = 0; i < 4; i++) { + unsigned long val; + + if (!isdigit(*s)) + return -EINVAL; + + val = simple_strtoul(s, &e, 10); + if (val > 255) + return -EINVAL; + + addr = (addr << 8) | val; + + if (*e != '.' && i != 3) + return -EINVAL; + + s = e + 1; + } + + *ip = htonl(addr); + + return 0; +} @@ -62,50 +62,6 @@ uint16_t net_checksum(unsigned char *ptr, int len) return xsum & 0xffff; } -char *ip_to_string (IPaddr_t x) -{ - static char s[sizeof("xxx.xxx.xxx.xxx")]; - - x = ntohl (x); - sprintf (s, "%d.%d.%d.%d", - (int) ((x >> 24) & 0xff), - (int) ((x >> 16) & 0xff), - (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff) - ); - return s; -} - -int string_to_ip(const char *s, IPaddr_t *ip) -{ - IPaddr_t addr = 0; - char *e; - int i; - - if (!s) - return -EINVAL; - - for (i = 0; i < 4; i++) { - unsigned long val; - - if (!isdigit(*s)) - return -EINVAL; - - val = simple_strtoul(s, &e, 10); - if (val > 255) - return -EINVAL; - - addr = (addr << 8) | val; - - if (*e != '.' && i != 3) - return -EINVAL; - - s = e + 1; - } - - *ip = htonl(addr); - return 0; -} - IPaddr_t getenv_ip(const char *name) { IPaddr_t ip; @@ -131,40 +87,6 @@ int setenv_ip(const char *name, IPaddr_t ip) return 0; } -void print_IPaddr (IPaddr_t x) -{ - puts(ip_to_string(x)); -} - -int string_to_ethaddr(const char *str, u8 enetaddr[6]) -{ - int reg; - char *e; - - if (!str || strlen(str) != 17) { - memset(enetaddr, 0, 6); - return -EINVAL; - } - - if (str[2] != ':' || str[5] != ':' || str[8] != ':' || - str[11] != ':' || str[14] != ':') - return -EINVAL; - - for (reg = 0; reg < 6; ++reg) { - enetaddr[reg] = simple_strtoul (str, &e, 16); - str = e + 1; - } - - return 0; -} - -void ethaddr_to_string(const u8 enetaddr[6], char *str) -{ - sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", - enetaddr[0], enetaddr[1], enetaddr[2], enetaddr[3], - enetaddr[4], enetaddr[5]); -} - static unsigned char *arp_ether; static IPaddr_t arp_wait_ip; @@ -348,7 +270,7 @@ static struct net_connection *net_new(IPaddr_t dest, rx_handler_f *handler, random_ether_addr(edev->ethaddr); ethaddr_to_string(edev->ethaddr, str); printf("warning: No MAC address set. Using random address %s\n", str); - dev_set_param(&edev->dev, "ethaddr", str); + eth_set_ethaddr(edev, edev->ethaddr); } /* If we don't have an ip only broadcast is allowed */ @@ -667,4 +589,3 @@ static int net_init(void) } postcore_initcall(net_init); - @@ -731,4 +731,3 @@ BAREBOX_CMD_START(nfs) BAREBOX_CMD_OPTS("FILE [LOCALFILE]") BAREBOX_CMD_GROUP(CMD_GRP_NET) BAREBOX_CMD_END - |