diff options
205 files changed, 4749 insertions, 1214 deletions
diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst index ef1a6a507e..837bf5cf32 100644 --- a/Documentation/boards/imx.rst +++ b/Documentation/boards/imx.rst @@ -47,7 +47,7 @@ The images can also always be started second stage:: bootm /mnt/tftp/barebox-freescale-imx51-babbage.img Internal Boot Mode Through Internal RAM(IRAM) ---------------------------------------- +--------------------------------------------- The Internal Boot Mode Through Internal RAM is supported on: diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst index 3d664f1f02..4c5b06db47 100644 --- a/Documentation/devicetree/bindings/barebox/barebox,state.rst +++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst @@ -40,8 +40,8 @@ variable. The node name may end with ``@<ADDRESS>``, but the suffix is sripped from the variable name. State variables have a type. Currenty supported types are: ``uint8``, -``uint32``, ``enum32`` and ``mac`` address. Fixed length strings are -planned but not implemented. Variable length strings are not planned. +``uint32``, ``enum32``, ``mac`` address or ``string``. Variable length +strings are not planned. Required properties: @@ -49,8 +49,8 @@ Required properties: ``#size-cells = <1>``. Defines the ``offset`` and ``size`` of the variable in the ``raw`` backend. ``size`` must fit the node ``type``. Variables are not allowed to overlap. -* ``type``: Should be ``uint8``, ``uint32``, ``enum32`` or ``mac`` for - the type of the variable +* ``type``: Should be ``uint8``, ``uint32``, ``enum32``, ``mac`` or + ``string`` for the type of the variable * ``names``: For ``enum32`` values only, this specifies the values possible for ``enum32``. @@ -82,6 +82,17 @@ Example:: }; }; +Variable Types +-------------- + +* ``uint8``: +* ``uint32``: +* ``enum32``: The ``default`` value is an integer representing an + offset into the names array. +* ``mac``: +* ``string``: The length of the string excluding the trailing 0 is + determined by the length given in the ``reg`` property. + Backends -------- 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/Makefile b/arch/arm/boards/beagle/Makefile index 01c7a259e9..3bee9a22ab 100644 --- a/arch/arm/boards/beagle/Makefile +++ b/arch/arm/boards/beagle/Makefile @@ -1,2 +1,3 @@ obj-y += board.o lwl-y += lowlevel.o +bbenv-y += defaultenv-beagle diff --git a/arch/arm/boards/beagle/board.c b/arch/arm/boards/beagle/board.c index 775621069c..4ac9517dbe 100644 --- a/arch/arm/boards/beagle/board.c +++ b/arch/arm/boards/beagle/board.c @@ -21,7 +21,10 @@ #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> #include <generated/mach-types.h> #include <mach/gpmc.h> @@ -31,6 +34,7 @@ #include <i2c/i2c.h> #include <linux/err.h> #include <usb/ehci.h> +#include <asm/barebox-arm.h> #ifdef CONFIG_DRIVER_SERIAL_NS16550 @@ -42,6 +46,9 @@ */ static int beagle_console_init(void) { + if (barebox_arm_machine() != MACH_TYPE_OMAP3_BEAGLE) + return 0; + barebox_set_model("Texas Instruments beagle"); barebox_set_hostname("beagle"); @@ -82,6 +89,9 @@ static struct gpmc_nand_platform_data nand_plat = { static int beagle_mem_init(void) { + if (barebox_arm_machine() != MACH_TYPE_OMAP3_BEAGLE) + return 0; + omap_add_ram0(SZ_128M); return 0; @@ -90,6 +100,9 @@ mem_initcall(beagle_mem_init); static int beagle_devices_init(void) { + if (barebox_arm_machine() != MACH_TYPE_OMAP3_BEAGLE) + return 0; + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); omap3_add_i2c1(NULL); @@ -107,6 +120,13 @@ 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; } device_initcall(beagle_devices_init); diff --git a/arch/arm/boards/beagle/env/boot/mmc b/arch/arm/boards/beagle/defaultenv-beagle/boot/mmc index db638f8cf8..db638f8cf8 100644 --- a/arch/arm/boards/beagle/env/boot/mmc +++ b/arch/arm/boards/beagle/defaultenv-beagle/boot/mmc diff --git a/arch/arm/boards/beagle/env/boot/nand-ubi b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi index e0ef904432..e0ef904432 100644 --- a/arch/arm/boards/beagle/env/boot/nand-ubi +++ b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi diff --git a/arch/arm/boards/beagle/env/boot/nand-ubi-dt b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi-dt index 5fc0a6c53a..5fc0a6c53a 100644 --- a/arch/arm/boards/beagle/env/boot/nand-ubi-dt +++ b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi-dt diff --git a/arch/arm/boards/beagle/env/init/mtdparts-nand b/arch/arm/boards/beagle/defaultenv-beagle/init/mtdparts-nand index 9335bb17a3..9335bb17a3 100644 --- a/arch/arm/boards/beagle/env/init/mtdparts-nand +++ b/arch/arm/boards/beagle/defaultenv-beagle/init/mtdparts-nand diff --git a/arch/arm/boards/beagle/env/network/eth0-discover b/arch/arm/boards/beagle/defaultenv-beagle/network/eth0-discover index 86d13f5c43..86d13f5c43 100644 --- a/arch/arm/boards/beagle/env/network/eth0-discover +++ b/arch/arm/boards/beagle/defaultenv-beagle/network/eth0-discover diff --git a/arch/arm/boards/beagle/lowlevel.c b/arch/arm/boards/beagle/lowlevel.c index d6e6b9f91c..30cc1f2c54 100644 --- a/arch/arm/boards/beagle/lowlevel.c +++ b/arch/arm/boards/beagle/lowlevel.c @@ -1,4 +1,5 @@ #include <init.h> +#include <debug_ll.h> #include <io.h> #include <linux/sizes.h> #include <asm/barebox-arm-head.h> @@ -11,6 +12,7 @@ #include <mach/sdrc.h> #include <mach/syslib.h> #include <mach/sys_info.h> +#include <generated/mach-types.h> /** * @brief Do the pin muxing required for Board operation. @@ -157,6 +159,22 @@ static void sdrc_init(void) return; } +static noinline int beagle_board_init_sdram(void) +{ + struct barebox_arm_boarddata *bd = (void *)OMAP3_SRAM_SCRATCH_SPACE + 0x10; + + boarddata_create(bd, MACH_TYPE_OMAP3_BEAGLE); + + barebox_arm_entry(0x80000000, SZ_128M, bd); +} + +ENTRY_FUNCTION(start_omap3_beagleboard_sdram, bootinfo, r1, r2) +{ + omap3_save_bootinfo((void *)bootinfo); + + beagle_board_init_sdram(); +} + /** * @brief The basic entry point for board initialization. * @@ -166,28 +184,37 @@ static void sdrc_init(void) * * @return void */ -static int beagle_board_init(void) +static noinline int beagle_board_init(void) { int in_sdram = omap3_running_in_sdram(); + struct barebox_arm_boarddata bd; if (!in_sdram) omap3_core_init(); mux_config(); + + omap_uart_lowlevel_init((void *)OMAP3_UART3_BASE); + /* Dont reconfigure SDRAM while running in SDRAM! */ if (!in_sdram) sdrc_init(); - return 0; + boarddata_create(&bd, MACH_TYPE_OMAP3_BEAGLE); + + barebox_arm_entry(0x80000000, SZ_128M, &bd); } -void __naked __bare_init barebox_arm_reset_vector(uint32_t *data) +ENTRY_FUNCTION(start_omap3_beagleboard_sram, bootinfo, r1, r2) { - omap3_save_bootinfo(data); + omap3_save_bootinfo((void *)bootinfo); arm_cpu_lowlevel_init(); - beagle_board_init(); + omap3_gp_romcode_call(OMAP3_GP_ROMCODE_API_L2_INVAL, 0); + + relocate_to_current_adr(); + setup_c(); - barebox_arm_entry(0x80000000, SZ_128M, NULL); + beagle_board_init(); } 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/omap3530_beagle_defconfig b/arch/arm/configs/omap3530_beagle_defconfig index 3068fbb94b..070f1566ee 100644 --- a/arch/arm/configs/omap3530_beagle_defconfig +++ b/arch/arm/configs/omap3530_beagle_defconfig @@ -1,67 +1,79 @@ CONFIG_ARCH_OMAP=y +CONFIG_OMAP_MULTI_BOARDS=y CONFIG_MACH_BEAGLE=y CONFIG_THUMB2_BAREBOX=y -CONFIG_CMD_ARM_MMUINFO=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y -CONFIG_PBL_IMAGE=y CONFIG_MMU=y -CONFIG_TEXT_BASE=0x87e00000 -CONFIG_MALLOC_SIZE=0x2000000 +CONFIG_TEXT_BASE=0x0 +CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y +CONFIG_RELOCATABLE=y CONFIG_PROMPT="barebox> " -CONFIG_LONGHELP=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +CONFIG_BLSPEC=y +CONFIG_IMD_TARGET=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/beagle/env" -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_MENU=y -CONFIG_CMD_MENU_MANAGEMENT=y -CONFIG_CMD_TIME=y -CONFIG_CMD_DIRNAME=y -CONFIG_CMD_LN=y -CONFIG_CMD_READLINK=y -CONFIG_CMD_TFTP=y -CONFIG_CMD_ECHO_E=y -CONFIG_CMD_LOADB=y -CONFIG_CMD_MEMINFO=y +CONFIG_RESET_SOURCE=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_OMAP_UART_PORT=3 +CONFIG_DEBUG_INITCALLS=y +CONFIG_CMD_DMESG=y +CONFIG_LONGHELP=y CONFIG_CMD_IOMEM=y -CONFIG_CMD_CRC=y -CONFIG_CMD_CRC_CMP=y -CONFIG_CMD_MD5SUM=y -CONFIG_CMD_FLASH=y +CONFIG_CMD_IMD=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_BOOTM_OFTREE_UIMAGE=y # CONFIG_CMD_BOOTU is not set -CONFIG_CMD_RESET=y CONFIG_CMD_GO=y -CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_RESET=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_DEFAULTENV=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_I2C=y +CONFIG_CMD_MSLEEP=y +CONFIG_CMD_READF=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_HOST=y CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_MENU=y +CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_MENUTREE=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_CRC=y +CONFIG_CMD_CRC_CMP=y +CONFIG_CMD_DETECT=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_TIME=y CONFIG_NET=y -CONFIG_CMD_DHCP=y CONFIG_NET_NFS=y -CONFIG_CMD_PING=y CONFIG_NET_NETCONSOLE=y -CONFIG_NET_RESOLV=y CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y CONFIG_NET_USB=y @@ -81,6 +93,7 @@ CONFIG_MCI=y CONFIG_MCI_STARTUP=y CONFIG_MCI_OMAP_HSMMC=y CONFIG_MFD_TWL4030=y +CONFIG_FS_EXT4=y CONFIG_FS_TFTP=y CONFIG_FS_NFS=y CONFIG_FS_FAT=y diff --git a/arch/arm/configs/omap3530_beagle_xload_defconfig b/arch/arm/configs/omap3530_beagle_xload_defconfig index 585ee0f1d1..074cc2116b 100644 --- a/arch/arm/configs/omap3530_beagle_xload_defconfig +++ b/arch/arm/configs/omap3530_beagle_xload_defconfig @@ -1,21 +1,25 @@ CONFIG_ARCH_OMAP=y CONFIG_OMAP_BUILD_IFT=y +CONFIG_OMAP3_USBBOOT=y +CONFIG_OMAP3_USB_LOADER=y +CONFIG_OMAP_MULTI_BOARDS=y CONFIG_MACH_BEAGLE=y CONFIG_THUMB2_BAREBOX=y -# CONFIG_CMD_ARM_CPUINFO is not set -# CONFIG_ARM_EXCEPTIONS is not set -CONFIG_TEXT_BASE=0x40200000 -CONFIG_MEMORY_LAYOUT_FIXED=y -CONFIG_STACK_BASE=0x4020F000 +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_ARM_UNWIND=y +CONFIG_MMU=y +CONFIG_TEXT_BASE=0x0 CONFIG_STACK_SIZE=0xc00 -CONFIG_MALLOC_BASE=0x87BFFF10 +CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_DUMMY=y +CONFIG_RELOCATABLE=y CONFIG_PROMPT="X-load Beagle>" CONFIG_SHELL_NONE=y # CONFIG_ERRNO_MESSAGES is not set # CONFIG_TIMESTAMP is not set CONFIG_CONSOLE_SIMPLE=y # CONFIG_DEFAULT_ENVIRONMENT is not set +CONFIG_OFDEVICE=y CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y # CONFIG_SPI is not set @@ -33,6 +37,7 @@ CONFIG_MCI=y CONFIG_MCI_STARTUP=y # CONFIG_MCI_WRITE is not set CONFIG_MCI_OMAP_HSMMC=y +# CONFIG_PINCTRL is not set # CONFIG_FS_RAMFS is not set # CONFIG_FS_DEVFS is not set CONFIG_FS_FAT=y diff --git a/arch/arm/configs/phytec-phycard-omap3_defconfig b/arch/arm/configs/phytec-phycard-omap3_defconfig index a2564d4459..5865ebd8b9 100644 --- a/arch/arm/configs/phytec-phycard-omap3_defconfig +++ b/arch/arm/configs/phytec-phycard-omap3_defconfig @@ -7,7 +7,6 @@ CONFIG_CPU_V7=y CONFIG_CPU_32v7=y CONFIG_ARCH_OMAP3=y CONFIG_OMAP_CLOCK_SOURCE_S32K=y -CONFIG_OMAP3_CLOCK_CONFIG=y CONFIG_OMAP3_COPY_CLOCK_SRAM=n CONFIG_OMAP_GPMC=y CONFIG_MACH_PCAAL1=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 304ed0cee7..8e5097b560 100644 --- a/arch/arm/cpu/start.c +++ b/arch/arm/cpu/start.c @@ -28,17 +28,22 @@ #include <asm/cache.h> #include <memory.h> +#include <debug_ll.h> #include "mmu-early.h" unsigned long arm_stack_top; static void *barebox_boarddata; -/* - * return the boarddata variable passed to barebox_arm_entry - */ -void *barebox_arm_boarddata(void) +u32 barebox_arm_machine(void) { - return barebox_boarddata; + struct barebox_arm_boarddata *bd; + + if (!barebox_boarddata) + return 0; + + bd = barebox_boarddata; + + return bd->machine; } static void *barebox_boot_dtb; @@ -61,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; @@ -81,17 +88,23 @@ static noinline __noreturn void __start(unsigned long membase, } } - /* - * If boarddata is a pointer inside valid memory and contains a - * FDT magic then use it as later to probe devices - */ - if (boarddata && get_unaligned_be32(boarddata) == FDT_MAGIC) { - uint32_t totalsize = get_unaligned_be32(boarddata + 4); - endmem -= ALIGN(totalsize, 64); - barebox_boot_dtb = (void *)endmem; - pr_debug("found DTB in boarddata, copying to 0x%p\n", - barebox_boot_dtb); - memcpy(barebox_boot_dtb, boarddata, totalsize); + if (boarddata) { + if (get_unaligned_be32(boarddata) == FDT_MAGIC) { + uint32_t totalsize = get_unaligned_be32(boarddata + 4); + endmem -= ALIGN(totalsize, 64); + barebox_boot_dtb = (void *)endmem; + pr_debug("found DTB in boarddata, copying to 0x%p\n", + barebox_boot_dtb); + memcpy(barebox_boot_dtb, boarddata, totalsize); + } else if (((struct barebox_arm_boarddata *)boarddata)->magic == + BAREBOX_ARM_BOARDDATA_MAGIC) { + endmem -= ALIGN(sizeof(struct barebox_arm_boarddata), 64); + barebox_boarddata = (void *)endmem; + pr_debug("found machine type in boarddata, copying to 0x%p\n", + barebox_boarddata); + memcpy(barebox_boarddata, boarddata, + sizeof(struct barebox_arm_boarddata)); + } } if ((unsigned long)_text > membase + memsize || 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/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h index dbc8aaaba7..0b8acb8b8e 100644 --- a/arch/arm/include/asm/barebox-arm.h +++ b/arch/arm/include/asm/barebox-arm.h @@ -48,7 +48,32 @@ void setup_c(void); void relocate_to_current_adr(void); void relocate_to_adr(unsigned long target); void __noreturn barebox_arm_entry(unsigned long membase, unsigned long memsize, void *boarddata); -void *barebox_arm_boarddata(void); + +struct barebox_arm_boarddata { +#define BAREBOX_ARM_BOARDDATA_MAGIC 0xabe742c3 + u32 magic; + u32 machine; /* machine number to pass to barebox. This may or may + * not be a ARM machine number registered on arm.linux.org.uk. + * It must only be unique across barebox. Please use a number + * that do not potientially clashes with registered machines, + * i.e. use a number > 0x10000. + */ +}; + +/* + * Create a boarddata struct at given address. Suitable to be passed + * as boarddata to barebox_arm_entry(). The machine can be retrieved + * later with barebox_arm_machine(). + */ +static inline void boarddata_create(void *adr, u32 machine) +{ + struct barebox_arm_boarddata *bd = adr; + + bd->magic = BAREBOX_ARM_BOARDDATA_MAGIC; + bd->machine = machine; +} + +u32 barebox_arm_machine(void); #if defined(CONFIG_RELOCATABLE) && defined(CONFIG_ARM_EXCEPTIONS) void arm_fixup_vectors(void); 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/include/mach/imx28-regs.h b/arch/arm/mach-mxs/include/mach/imx28-regs.h index de0d882414..1a90ec2aa5 100644 --- a/arch/arm/mach-mxs/include/mach/imx28-regs.h +++ b/arch/arm/mach-mxs/include/mach/imx28-regs.h @@ -34,6 +34,7 @@ #define IMX_WDT_BASE 0x80056000 #define IMX_I2C0_BASE 0x80058000 #define IMX_I2C1_BASE 0x8005a000 +#define IMX_PWM_BASE 0x80064000 #define IMX_TIM1_BASE 0x80068000 #define IMX_UART0_BASE 0x8006a000 #define IMX_UART1_BASE 0x8006c000 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/Kconfig b/arch/arm/mach-omap/Kconfig index bc00d5bf7f..af359756ba 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -54,14 +54,6 @@ config OMAP_CLOCK_SOURCE_S32K config OMAP_CLOCK_SOURCE_DMTIMER0 bool -config OMAP3_CLOCK_CONFIG - prompt "Clock Configuration" - bool - depends on ARCH_OMAP3 - default y - help - Say Y here if you like to have OMAP3 Clock configuration done. - config OMAP_GPMC prompt "Support for GPMC configuration" bool @@ -128,6 +120,21 @@ config OMAP4_USBBOOT You need the utility program omap4_usbboot to boot from USB. Please read omap4_usb_booting.txt for more information. +config OMAP3_USBBOOT + bool "enable booting from USB" + depends on ARCH_OMAP3 + help + Say Y here if you want to be able to boot the 2nd stage via USB. This + works by transferring the 2nd stage image using the MUSB controller + which is already initialized by the ROM code. Use the omap3-usb-loader + tool selectable below to upload images. + +config OMAP3_USB_LOADER + bool "enable omap3 USB loader host tool" + depends on ARCH_OMAP3 + help + Say Y here to build the omap3 usb loader tool. + config OMAP_SERIALBOOT bool "enable booting from serial" select XYMODEM @@ -150,6 +157,13 @@ config MACH_AFI_GF help Say Y here if you are using afis GF +config MACH_BEAGLE + bool "Texas Instrument's Beagle Board" + select HAVE_DEFAULT_ENVIRONMENT_NEW + select ARCH_OMAP3 + help + Say Y here if you are using Beagle Board + config MACH_BEAGLEBONE bool "Texas Instrument's Beagle Bone" select ARCH_AM33XX @@ -173,13 +187,6 @@ config MACH_OMAP343xSDP help Say Y here if you are using SDP343x platform -config MACH_BEAGLE - bool "Texas Instrument's Beagle Board" - select HAVE_DEFAULT_ENVIRONMENT_NEW - select ARCH_OMAP3 - help - Say Y here if you are using Beagle Board - config MACH_OMAP3EVM bool "Texas Instrument's OMAP3 EVM" select ARCH_OMAP3 diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile index bef1d0500f..65072b91e4 100644 --- a/arch/arm/mach-omap/Makefile +++ b/arch/arm/mach-omap/Makefile @@ -25,12 +25,14 @@ obj-$(CONFIG_ARCH_OMAP4) += omap4_generic.o omap4_clock.o pbl-$(CONFIG_ARCH_OMAP4) += omap4_generic.o omap4_clock.o obj-pbl-$(CONFIG_ARCH_AM33XX) += am33xx_generic.o am33xx_clock.o am33xx_mux.o obj-$(CONFIG_ARCH_AM33XX) += am33xx_scrm.o -obj-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock.o -pbl-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock.o +obj-$(CONFIG_ARCH_OMAP3) += omap3_clock.o +pbl-$(CONFIG_ARCH_OMAP3) += omap3_clock.o obj-$(CONFIG_OMAP_GPMC) += gpmc.o devices-gpmc-nand.o obj-$(CONFIG_SHELL_NONE) += xload.o obj-$(CONFIG_MFD_TWL6030) += omap4_twl6030_mmc.o obj-$(CONFIG_OMAP4_USBBOOT) += omap4_rom_usb.o +obj-$(CONFIG_OMAP3_USBBOOT) += omap3_xload_usb.o +pbl-$(CONFIG_OMAP3_USBBOOT) += omap3_xload_usb.o obj-$(CONFIG_CMD_BOOT_ORDER) += boot_order.o obj-$(CONFIG_BAREBOX_UPDATE_AM33XX_SPI_NOR_MLO) += am33xx_bbu_spi_mlo.o obj-$(CONFIG_BAREBOX_UPDATE_AM33XX_NAND) += am33xx_bbu_nand.o 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-omap/include/mach/omap3-clock.h b/arch/arm/mach-omap/include/mach/omap3-clock.h index 1ef46aa3e5..7c52da754f 100644 --- a/arch/arm/mach-omap/include/mach/omap3-clock.h +++ b/arch/arm/mach-omap/include/mach/omap3-clock.h @@ -107,7 +107,7 @@ /* PER DPLL */ #define PER_M6X2 3 /* 288MHz: CM_CLKSEL1_EMU */ #define PER_M5X2 4 /* 216MHz: CM_CLKSEL_CAM */ -#define PER_M4X2 9 /* 96MHz : CM_CLKSEL_DSS-dss1 */ +#define PER_M4X2 2 /* 432MHz: CM_CLKSEL_DSS-dss1 */ #define PER_M3X2 16 /* 54MHz : CM_CLKSEL_DSS-tv */ #define CLSEL1_EMU_VAL ((CORE_M3X2 << 16) | (PER_M6X2 << 24) | (0x0a50)) diff --git a/arch/arm/mach-omap/include/mach/omap3-generic.h b/arch/arm/mach-omap/include/mach/omap3-generic.h index 7db0838a5f..ab53b98971 100644 --- a/arch/arm/mach-omap/include/mach/omap3-generic.h +++ b/arch/arm/mach-omap/include/mach/omap3-generic.h @@ -29,4 +29,6 @@ void __noreturn omap3_reset_cpu(unsigned long addr); int omap3_init(void); int omap3_devices_init(void); +void *omap3_xload_boot_usb(void); + #endif /* __MACH_OMAP3_GENERIC_H */ diff --git a/arch/arm/mach-omap/omap3_generic.c b/arch/arm/mach-omap/omap3_generic.c index dbb0b5f86c..0f2e9ce6b7 100644 --- a/arch/arm/mach-omap/omap3_generic.c +++ b/arch/arm/mach-omap/omap3_generic.c @@ -435,9 +435,6 @@ static void try_unlock_memory(void) * Does early system init of disabling the watchdog, enable * memory and configuring the clocks. * - * prcm_init is called only if CONFIG_OMAP3_CLOCK_CONFIG is defined. - * We depend on link time clean up to remove a_init if no caller exists. - * * @warning Called path is with SRAM stack * * @return void @@ -459,9 +456,7 @@ void omap3_core_init(void) sdelay(100); -#ifdef CONFIG_OMAP3_CLOCK_CONFIG prcm_init(); -#endif } #define OMAP3_TRACING_VECTOR1 0x4020ffb4 diff --git a/arch/arm/mach-omap/omap3_xload_usb.c b/arch/arm/mach-omap/omap3_xload_usb.c new file mode 100644 index 0000000000..e7dc21e4a7 --- /dev/null +++ b/arch/arm/mach-omap/omap3_xload_usb.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * Based on a patch by: + * + * Copyright (C) 2011 Rick Bronson + * + * 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 <io.h> +#include <malloc.h> +#include <mach/omap3-silicon.h> +#include <mach/omap3-generic.h> + +static void __iomem *omap3_usb_base = (void __iomem *)OMAP3_MUSB0_BASE; + +#define OMAP34XX_USB_EP(n) (omap3_usb_base + 0x100 + 0x10 * (n)) + +#define MUSB_RXCSR 0x06 +#define MUSB_RXCOUNT 0x08 +#define MUSB_TXCSR 0x02 +#define MUSB_FIFOSIZE 0x0F +#define OMAP34XX_USB_RXCSR(n) (OMAP34XX_USB_EP(n) + MUSB_RXCSR) +#define OMAP34XX_USB_RXCOUNT(n) (OMAP34XX_USB_EP(n) + MUSB_RXCOUNT) +#define OMAP34XX_USB_TXCSR(n) (OMAP34XX_USB_EP(n) + MUSB_TXCSR) +#define OMAP34XX_USB_FIFOSIZE(n) (OMAP34XX_USB_EP(n) + MUSB_FIFOSIZE) +#define OMAP34XX_USB_FIFO(n) (omap3_usb_base + 0x20 + ((n) * 4)) + +/* memory mapped registers */ +#define BULK_ENDPOINT 1 +#define MUSB_RXCSR_RXPKTRDY 0x0001 +#define MUSB_TXCSR_TXPKTRDY 0x0001 + +#define PACK4(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a)) +#define USBLOAD_CMD_FILE PACK4('U', 'S', 'B', 's') /* send file size */ +#define USBLOAD_CMD_JUMP PACK4('U', 'S', 'B', 'j') /* go where I tell you */ +#define USBLOAD_CMD_FILE_REQ PACK4('U', 'S', 'B', 'f') /* file request */ +#define USBLOAD_CMD_ECHO_SZ PACK4('U', 'S', 'B', 'n') /* echo file size */ +#define USBLOAD_CMD_REPORT_SZ PACK4('U', 'S', 'B', 'o') /* report file size */ +#define USBLOAD_CMD_MESSAGE PACK4('U', 'S', 'B', 'm') /* message for debug */ + +static int usb_send(unsigned char *buffer, unsigned int buffer_size) +{ + unsigned int cntr; + u16 txcsr; + void __iomem *reg = (void *)OMAP34XX_USB_TXCSR(BULK_ENDPOINT); + void __iomem *bulk_fifo = (void *)OMAP34XX_USB_FIFO(BULK_ENDPOINT); + + txcsr = readw(reg); + + if (txcsr & MUSB_TXCSR_TXPKTRDY) + return 0; + + for (cntr = 0; cntr < buffer_size; cntr++) + writeb(buffer[cntr], bulk_fifo); + + txcsr = readw(reg); + txcsr |= MUSB_TXCSR_TXPKTRDY; + writew(txcsr, reg); + + return buffer_size; +} + +static int usb_recv(u8 *buffer) +{ + int cntr; + u16 count = 0; + u16 rxcsr; + void __iomem *reg = (void *)OMAP34XX_USB_RXCSR(BULK_ENDPOINT); + void __iomem *bulk_fifo = (void *)OMAP34XX_USB_FIFO(BULK_ENDPOINT); + + rxcsr = readw(reg); + + if (!(rxcsr & MUSB_RXCSR_RXPKTRDY)) + return 0; + + count = readw((void *)OMAP34XX_USB_RXCOUNT(BULK_ENDPOINT)); + for (cntr = 0; cntr < count; cntr++) + *buffer++ = readb(bulk_fifo); + + /* Clear the RXPKTRDY bit */ + rxcsr = readw(reg); + rxcsr &= ~MUSB_RXCSR_RXPKTRDY; + writew(rxcsr, reg); + + return count; +} + +static unsigned char usb_outbuffer[64]; + +static void usb_msg(unsigned int cmd, const char *msg) +{ + unsigned char *p_char = usb_outbuffer; + + *(int *)p_char = cmd; + + p_char += sizeof(cmd); + + if (msg) { + while (*msg) + *p_char++= *msg++; + *p_char++= 0; + } + + usb_send(usb_outbuffer, p_char - usb_outbuffer); +} + +static void usb_code(unsigned int cmd, u32 code) +{ + unsigned int *p_int = (unsigned int *)usb_outbuffer; + + *p_int++ = cmd; + *p_int++ = code; + usb_send (usb_outbuffer, ((unsigned char *) p_int) - usb_outbuffer); +} + +void *omap3_xload_boot_usb(void) +{ + int res; + void *buf; + u32 *buf32; + u32 total; + void *addr; + u32 bytes; + int size; + int cntr; + void *fn; + u8 __buf[512]; + + buf32 = buf = __buf; + + usb_msg (USBLOAD_CMD_FILE_REQ, "file req"); + for (cntr = 0; cntr < 10000000; cntr++) { + size = usb_recv(buf); + if (!size) + continue; + + switch (buf32[0]) { + case USBLOAD_CMD_FILE: + pr_debug ("USBLOAD_CMD_FILE total = %d size = 0x%x addr = 0x%x\n", + res, buf32[1], buf32[2]); + total = buf32[1]; /* get size and address */ + addr = (void *)buf32[2]; + usb_code(USBLOAD_CMD_ECHO_SZ, total); + + bytes = 0; + + while (bytes < total) { + size = usb_recv(buf); + memcpy(addr, buf, size); + addr += size; + bytes += size; + } + + usb_code(USBLOAD_CMD_REPORT_SZ, total); /* tell him we got this many bytes */ + usb_msg (USBLOAD_CMD_FILE_REQ, "file req"); /* see if they have another file for us */ + break; + case USBLOAD_CMD_JUMP: + pr_debug("USBLOAD_CMD_JUMP total = %d addr = 0x%x val = 0x%x\n", + res, buf32[0], buf32[1]); + fn = (void *)buf32[1]; + goto out; + default: + break; + } + } + + fn = NULL; +out: + + return fn; +} diff --git a/arch/arm/mach-omap/xload.c b/arch/arm/mach-omap/xload.c index 85c9120ccf..4a0714ed93 100644 --- a/arch/arm/mach-omap/xload.c +++ b/arch/arm/mach-omap/xload.c @@ -14,6 +14,7 @@ #include <xymodem.h> #include <mach/generic.h> #include <mach/am33xx-generic.h> +#include <mach/omap3-generic.h> #include <net.h> #include <environment.h> #include <dhcp.h> @@ -284,13 +285,16 @@ static __noreturn int omap_xload(void) func = omap_xload_boot_mmc(); break; case BOOTSOURCE_USB: - if (IS_ENABLED(CONFIG_FS_OMAP4_USBBOOT)) { + if (IS_ENABLED(CONFIG_OMAP3_USBBOOT) && cpu_is_omap3()) { + printf("booting from USB\n"); + func = omap3_xload_boot_usb(); + } else if (IS_ENABLED(CONFIG_FS_OMAP4_USBBOOT)) { printf("booting from USB\n"); func = omap4_xload_boot_usb(); - break; } else { printf("booting from USB not enabled\n"); } + break; case BOOTSOURCE_NAND: printf("booting from NAND\n"); func = omap_xload_boot_nand(barebox_part->nand_offset, 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/login.c b/commands/login.c index 210eb203ac..bf5085c854 100644 --- a/commands/login.c +++ b/commands/login.c @@ -71,7 +71,7 @@ static int do_login(int argc, char *argv[]) run_command(timeout_cmd); } - if (check_passwd(passwd, passwd_len)) + if (check_passwd(passwd, passwd_len) == 1) return 0; } while(1); 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 742065ea63..ab18602715 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/common/state.c b/common/state.c index 7076f5764d..1243320226 100644 --- a/common/state.c +++ b/common/state.c @@ -64,6 +64,7 @@ enum state_variable_type { STATE_TYPE_U8, STATE_TYPE_U32, STATE_TYPE_MAC, + STATE_TYPE_STRING, }; /* instance of a single variable */ @@ -90,7 +91,7 @@ struct variable_type { struct list_head list; int (*export)(struct state_variable *, struct device_node *, enum state_convert); - int (*import)(struct state_variable *, const struct device_node *); + int (*import)(struct state_variable *, struct device_node *); struct state_variable *(*create)(struct state *state, const char *name, struct device_node *); }; @@ -113,6 +114,7 @@ static int state_set_dirty(struct param_d *p, void *priv) struct state_uint32 { struct state_variable var; struct param_d *param; + struct state *state; uint32_t value; uint32_t value_default; }; @@ -141,18 +143,21 @@ static int state_uint32_export(struct state_variable *var, struct state_uint32 *su32 = to_state_uint32(var); int ret; - if (su32->value_default || conv == STATE_CONVERT_FIXUP) { + if (su32->value_default) { ret = of_property_write_u32(node, "default", su32->value_default); - if (ret || conv == STATE_CONVERT_FIXUP) + if (ret) return ret; } + if (conv == STATE_CONVERT_FIXUP) + return 0; + return of_property_write_u32(node, "value", su32->value); } static int state_uint32_import(struct state_variable *sv, - const struct device_node *node) + struct device_node *node) { struct state_uint32 *su32 = to_state_uint32(sv); @@ -163,6 +168,17 @@ static int state_uint32_import(struct state_variable *sv, return 0; } +static int state_uint8_set(struct param_d *p, void *priv) +{ + struct state_uint32 *su32 = priv; + struct state *state = su32->state; + + if (su32->value > 255) + return -ERANGE; + + return state_set_dirty(p, state); +} + static struct state_variable *state_uint8_create(struct state *state, const char *name, struct device_node *node) { @@ -171,8 +187,8 @@ static struct state_variable *state_uint8_create(struct state *state, su32 = xzalloc(sizeof(*su32)); - param = dev_add_param_int(&state->dev, name, state_set_dirty, - NULL, &su32->value, "%d", state); + param = dev_add_param_int(&state->dev, name, state_uint8_set, + NULL, &su32->value, "%u", su32); if (IS_ERR(param)) { free(su32); return ERR_CAST(param); @@ -185,6 +201,7 @@ static struct state_variable *state_uint8_create(struct state *state, #else su32->var.raw = &su32->value + 3; #endif + su32->state = state; return &su32->var; } @@ -235,13 +252,16 @@ static int state_enum32_export(struct state_variable *var, int ret, i, len; char *prop, *str; - if (enum32->value_default || conv == STATE_CONVERT_FIXUP) { + if (enum32->value_default) { ret = of_property_write_u32(node, "default", enum32->value_default); - if (ret || conv == STATE_CONVERT_FIXUP) + if (ret) return ret; } + if (conv == STATE_CONVERT_FIXUP) + return 0; + ret = of_property_write_u32(node, "value", enum32->value); if (ret) return ret; @@ -265,7 +285,7 @@ static int state_enum32_export(struct state_variable *var, } static int state_enum32_import(struct state_variable *sv, - const struct device_node *node) + struct device_node *node) { struct state_enum32 *enum32 = to_state_enum32(sv); int len; @@ -350,17 +370,22 @@ static int state_mac_export(struct state_variable *var, struct state_mac *mac = to_state_mac(var); int ret; - ret = of_property_write_u8_array(node, "default", mac->value_default, - ARRAY_SIZE(mac->value_default)); - if (ret || conv == STATE_CONVERT_FIXUP) - return ret; + if (!is_zero_ether_addr(mac->value_default)) { + ret = of_property_write_u8_array(node, "default", mac->value_default, + ARRAY_SIZE(mac->value_default)); + if (ret) + return ret; + } + + if (conv == STATE_CONVERT_FIXUP) + return 0; return of_property_write_u8_array(node, "value", mac->value, ARRAY_SIZE(mac->value)); } static int state_mac_import(struct state_variable *sv, - const struct device_node *node) + struct device_node *node) { struct state_mac *mac = to_state_mac(sv); @@ -397,6 +422,151 @@ out: return ERR_PTR(ret); } +/* + * string + */ +struct state_string { + struct state_variable var; + struct param_d *param; + struct state *state; + char *value; + const char *value_default; + char raw[]; +}; + +static inline struct state_string *to_state_string(struct state_variable *s) +{ + return container_of(s, struct state_string, var); +} + +static int state_string_export(struct state_variable *var, + struct device_node *node, enum state_convert conv) +{ + struct state_string *string = to_state_string(var); + int ret = 0; + + if (string->value_default) { + ret = of_set_property(node, "default", string->value_default, + strlen(string->value_default) + 1, 1); + + if (ret) + return ret; + } + + if (conv == STATE_CONVERT_FIXUP) + return 0; + + if (string->value) + ret = of_set_property(node, "value", string->value, + strlen(string->value) + 1, 1); + + return ret; +} + +static int state_string_copy_to_raw(struct state_string *string, + const char *src) +{ + size_t len; + + len = strlen(src); + if (len > string->var.size) + return -EILSEQ; + + /* copy string and clear remaining contents of buffer */ + memcpy(string->raw, src, len); + memset(string->raw + len, 0x0, string->var.size - len); + + return 0; +} + +static int state_string_import(struct state_variable *sv, + struct device_node *node) +{ + struct state_string *string = to_state_string(sv); + const char *value = NULL; + size_t len; + int ret; + + of_property_read_string(node, "default", &string->value_default); + if (string->value_default) { + len = strlen(string->value_default); + if (len > string->var.size) + return -EILSEQ; + } + + ret = of_property_read_string(node, "value", &value); + if (ret) + value = string->value_default; + + if (value) + return state_string_copy_to_raw(string, value); + + return 0; +} + +static int state_string_set(struct param_d *p, void *priv) +{ + struct state_string *string = priv; + struct state *state = string->state; + int ret; + + ret = state_string_copy_to_raw(string, string->value); + if (ret) + return ret; + + return state_set_dirty(p, state); +} + +static int state_string_get(struct param_d *p, void *priv) +{ + struct state_string *string = priv; + + free(string->value); + if (string->raw[0]) + string->value = xstrndup(string->raw, string->var.size); + else + string->value = xstrdup(""); + + return 0; +} + +static struct state_variable *state_string_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_string *string; + u32 start_size[2]; + int ret; + + ret = of_property_read_u32_array(node, "reg", start_size, + ARRAY_SIZE(start_size)); + if (ret) { + dev_err(&state->dev, + "%s: reg property not found\n", name); + return ERR_PTR(ret); + } + + /* limit to arbitrary len of 4k */ + if (start_size[1] > 4096) + return ERR_PTR(-EILSEQ); + + string = xzalloc(sizeof(*string) + start_size[1]); + string->var.size = start_size[1]; + string->var.raw = &string->raw; + string->state = state; + + string->param = dev_add_param_string(&state->dev, name, state_string_set, + state_string_get, &string->value, string); + if (IS_ERR(string->param)) { + ret = PTR_ERR(string->param); + goto out; + } + + return &string->var; +out: + free(string); + return ERR_PTR(ret); +} + static struct variable_type types[] = { { .type = STATE_TYPE_U8, @@ -422,6 +592,12 @@ static struct variable_type types[] = { .export = state_mac_export, .import = state_mac_import, .create = state_mac_create, + }, { + .type = STATE_TYPE_STRING, + .type_name = "string", + .export = state_string_export, + .import = state_string_import, + .create = state_string_create, }, }; 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/bus/omap-gpmc.c b/drivers/bus/omap-gpmc.c index 6752c42a35..8ae909a1b6 100644 --- a/drivers/bus/omap-gpmc.c +++ b/drivers/bus/omap-gpmc.c @@ -24,6 +24,14 @@ #define GPMC_CS_NUM 8 #define GPMC_NR_WAITPINS 4 +#define GPMC_BURST_4 4 /* 4 word burst */ +#define GPMC_BURST_8 8 /* 8 word burst */ +#define GPMC_BURST_16 16 /* 16 word burst */ +#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */ +#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */ +#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */ +#define GPMC_MUX_AD 2 /* Addr-Data multiplex */ + #define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31) #define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30) #define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29) @@ -55,6 +63,9 @@ #define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN (1 << 7) #define GPMC_CONFIG7_CSVALID (1 << 6) +#define GPMC_DEVICETYPE_NOR 0 +#define GPMC_DEVICETYPE_NAND 2 + static unsigned int gpmc_cs_num = GPMC_CS_NUM; static unsigned int gpmc_nr_waitpins; static unsigned long gpmc_l3_clk = 100000000; /* This should be a proper clock */ @@ -149,7 +160,7 @@ static void gpmc_cs_bool_timings(struct gpmc_config *gpmc_config, const struct g if (p->oe_extra_delay) gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY; if (p->we_extra_delay) - gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY; + gpmc_config->cfg[3] |= GPMC_CONFIG4_WEEXTRADELAY; if (p->cycle2cyclesamecsen) gpmc_config->cfg[5] |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN; if (p->cycle2cyclediffcsen) @@ -220,6 +231,8 @@ static int gpmc_timings_to_config(struct gpmc_config *gpmc_config, const struct if (div < 0) return div; + gpmc_config->cfg[0] |= div - 1; + ret |= set_cfg(gpmc_config, 0, 18, 19, t->wait_monitoring); ret |= set_cfg(gpmc_config, 0, 25, 26, t->clk_activation); @@ -255,6 +268,60 @@ static int gpmc_timings_to_config(struct gpmc_config *gpmc_config, const struct return 0; } +static int gpmc_settings_to_config(struct gpmc_config *gpmc_config, + struct gpmc_settings *p) +{ + u32 config1 = gpmc_config->cfg[0]; + + /* Page/burst mode supports lengths of 4, 8 and 16 bytes */ + if (p->burst_read || p->burst_write) { + switch (p->burst_len) { + case GPMC_BURST_4: + case GPMC_BURST_8: + case GPMC_BURST_16: + break; + default: + pr_err("%s: invalid page/burst-length (%d)\n", + __func__, p->burst_len); + return -EINVAL; + } + } + + if (p->wait_pin > gpmc_nr_waitpins) { + pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin); + return -EINVAL; + } + + config1 |= GPMC_CONFIG1_DEVICESIZE((p->device_width - 1)); + + if (p->sync_read) + config1 |= GPMC_CONFIG1_READTYPE_SYNC; + if (p->sync_write) + config1 |= GPMC_CONFIG1_WRITETYPE_SYNC; + if (p->wait_on_read) + config1 |= GPMC_CONFIG1_WAIT_READ_MON; + if (p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_WRITE_MON; + if (p->wait_on_read || p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin); + if (p->device_nand) + config1 |= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND); + if (p->mux_add_data) + config1 |= GPMC_CONFIG1_MUXTYPE(p->mux_add_data); + if (p->burst_read) + config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP; + if (p->burst_write) + config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP; + if (p->burst_read || p->burst_write) { + config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3); + config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0; + } + + gpmc_config->cfg[0] = config1; + + return 0; +} + /** * gpmc_read_settings_dt - read gpmc settings from device-tree * @np: pointer to device-tree node for a gpmc child device @@ -464,6 +531,77 @@ static int gpmc_probe_nand_child(struct device_d *dev, return 0; } +/** + * gpmc_probe_generic_child - configures the gpmc for a child device + * @pdev: pointer to gpmc platform device + * @child: pointer to device-tree node for child device + * + * Allocates and configures a GPMC chip-select for a child device. + * Returns 0 on success and appropriate negative error code on failure. + */ +static int gpmc_probe_generic_child(struct device_d *dev, + struct device_node *child) +{ + struct gpmc_settings gpmc_s = {}; + struct gpmc_timings gpmc_t = {}; + struct resource res; + int ret, cs; + struct gpmc_config cfg = {}; + resource_size_t size; + + if (of_property_read_u32(child, "reg", &cs) < 0) { + dev_err(dev, "%s has no 'reg' property\n", + child->full_name); + return -ENODEV; + } + + if (of_address_to_resource(child, 0, &res) < 0) { + dev_err(dev, "%s has malformed 'reg' property\n", + child->full_name); + return -ENODEV; + } + + gpmc_read_settings_dt(child, &gpmc_s); + gpmc_read_timings_dt(child, &gpmc_t); + + ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width); + if (ret < 0) + goto err; + + gpmc_timings_to_config(&cfg, &gpmc_t); + + cfg.base = res.start; + + size = resource_size(&res); + if (size > SZ_64M) + cfg.size = GPMC_SIZE_128M; + else if (size > SZ_32M) + cfg.size = GPMC_SIZE_64M; + else if (size > SZ_16M) + cfg.size = GPMC_SIZE_32M; + else + cfg.size = GPMC_SIZE_16M; + + gpmc_settings_to_config(&cfg, &gpmc_s); + + gpmc_cs_config(cs, &cfg); + + /* create platform device, NULL on error or when disabled */ + if (of_get_property(child, "compatible", NULL) && !of_platform_device_create(child, dev)) + goto err_child_fail; + + return 0; + +err_child_fail: + + dev_err(dev, "failed to create gpmc child %s\n", child->name); + ret = -ENODEV; + +err: + + return ret; +} + static int gpmc_probe(struct device_d *dev) { struct device_node *child, *node = dev->device_node; @@ -488,6 +626,10 @@ static int gpmc_probe(struct device_d *dev) if (!strncmp(child->name, "nand", 4)) ret = gpmc_probe_nand_child(dev, child); + else if (strncmp(child->name, "ethernet", 8) == 0 || + strncmp(child->name, "nor", 3) == 0 || + strncmp(child->name, "uart", 4) == 0) + ret = gpmc_probe_generic_child(dev, child); else dev_warn(dev, "unhandled child %s\n", child->name); diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index 77a13bc7ac..a408044264 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -158,6 +158,7 @@ int __init mx28_clocks_init(void __iomem *regs) clkdev_add_physbase(clks[uart], IMX_UART3_BASE, NULL); clkdev_add_physbase(clks[uart], IMX_UART4_BASE, NULL); clkdev_add_physbase(clks[gpmi], MXS_GPMI_BASE, NULL); + clkdev_add_physbase(clks[pwm], IMX_PWM_BASE, NULL); if (IS_ENABLED(CONFIG_DRIVER_VIDEO_STM)) clkdev_add_physbase(clks[lcdif_comp], IMX_FB_BASE, NULL); 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/of/platform.c b/drivers/of/platform.c index ab3ccab3b6..2c075dbae3 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -118,7 +118,7 @@ static void of_device_make_bus_id(struct device_d *dev) * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ -static struct device_d *of_platform_device_create(struct device_node *np, +struct device_d *of_platform_device_create(struct device_node *np, struct device_d *parent) { struct device_d *dev; 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/pwm/Kconfig b/drivers/pwm/Kconfig index 8324d5ef19..97c3deff10 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -22,4 +22,10 @@ config PWM_IMX help This enables PWM support for Freescale i.MX SoCs +config PWM_MXS + bool "i.MXs PWM Support" + depends on ARCH_MXS + help + This enables PWM support for Freescale i.MX23/i.MX28 SoCs + endif diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index dea9956c04..46865a24ee 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_PXA) += pxa_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o +obj-$(CONFIG_PWM_MXS) += pwm-mxs.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index cc33dec363..360520195a 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -181,12 +181,13 @@ struct pwm_device *pwm_request(const char *devname) } EXPORT_SYMBOL_GPL(pwm_request); -static struct pwm_device *of_node_to_pwm_device(struct device_node *np) +static struct pwm_device *of_node_to_pwm_device(struct device_node *np, int id) { struct pwm_device *pwm; list_for_each_entry(pwm, &pwm_list, node) { - if (pwm->hwdev && pwm->hwdev->device_node == np) + if (pwm->hwdev && pwm->hwdev->device_node == np && + pwm->chip->id == id) return pwm; } @@ -210,7 +211,7 @@ struct pwm_device *of_pwm_request(struct device_node *np, const char *con_id) return ERR_PTR(ret); } - pwm = of_node_to_pwm_device(args.np); + pwm = of_node_to_pwm_device(args.np, args.args[0]); if (IS_ERR(pwm)) { pr_debug("%s(): PWM chip not found\n", __func__); return pwm; diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c new file mode 100644 index 0000000000..e66744288b --- /dev/null +++ b/drivers/pwm/pwm-mxs.c @@ -0,0 +1,174 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <common.h> +#include <init.h> +#include <errno.h> +#include <io.h> +#include <pwm.h> +#include <stmp-device.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <asm-generic/div64.h> + +#define SET 0x4 +#define CLR 0x8 +#define TOG 0xc + +#define PWM_CTRL 0x0 +#define PWM_ACTIVE0 0x10 +#define PWM_PERIOD0 0x20 +#define PERIOD_PERIOD(p) ((p) & 0xffff) +#define PERIOD_PERIOD_MAX 0x10000 +#define PERIOD_ACTIVE_HIGH (3 << 16) +#define PERIOD_INACTIVE_LOW (2 << 18) +#define PERIOD_CDIV(div) (((div) & 0x7) << 20) +#define PERIOD_CDIV_MAX 8 + +static const unsigned int cdiv[PERIOD_CDIV_MAX] = { + 1, 2, 4, 8, 16, 64, 256, 1024 +}; + +struct mxs_pwm; + +struct mxs_pwm_chip { + struct pwm_chip chip; + struct mxs_pwm *mxs; +}; + +struct mxs_pwm { + struct mxs_pwm_chip pwm[8]; + struct clk *clk; + void __iomem *base; +}; + +#define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip) + +static int mxs_pwm_config(struct pwm_chip *chip, int duty_ns, int period_ns) +{ + struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); + int div = 0; + unsigned int period_cycles, duty_cycles; + unsigned long rate; + unsigned long long c; + + rate = clk_get_rate(mxs->mxs->clk); + while (1) { + c = rate / cdiv[div]; + c = c * period_ns; + do_div(c, 1000000000); + if (c < PERIOD_PERIOD_MAX) + break; + div++; + if (div >= PERIOD_CDIV_MAX) + return -EINVAL; + } + + period_cycles = c; + c *= duty_ns; + do_div(c, period_ns); + duty_cycles = c; + + writel(duty_cycles << 16, + mxs->mxs->base + PWM_ACTIVE0 + mxs->chip.id * 0x20); + writel(PERIOD_PERIOD(period_cycles) | PERIOD_ACTIVE_HIGH | + PERIOD_INACTIVE_LOW | PERIOD_CDIV(div), + mxs->mxs->base + PWM_PERIOD0 + mxs->chip.id * 0x20); + + return 0; +} + +static int mxs_pwm_enable(struct pwm_chip *chip) +{ + struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); + + writel(1 << mxs->chip.id, mxs->mxs->base + PWM_CTRL + SET); + + return 0; +} + +static void mxs_pwm_disable(struct pwm_chip *chip) +{ + struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); + + writel(1 << mxs->chip.id, mxs->mxs->base + PWM_CTRL + CLR); +} + +static struct pwm_ops mxs_pwm_ops = { + .config = mxs_pwm_config, + .enable = mxs_pwm_enable, + .disable = mxs_pwm_disable, +}; + +static int mxs_pwm_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct mxs_pwm *mxs; + int ret, i; + uint32_t npwm; + + mxs = xzalloc(sizeof(*mxs)); + + mxs->base = dev_request_mem_region(dev, 0); + if (IS_ERR(mxs->base)) + return PTR_ERR(mxs->base); + + mxs->clk = clk_get(dev, NULL); + if (IS_ERR(mxs->clk)) + return PTR_ERR(mxs->clk); + + clk_enable(mxs->clk); + + ret = stmp_reset_block(mxs->base, 0); + if (ret) + return ret; + + ret = of_property_read_u32(np, "fsl,pwm-number", &npwm); + if (ret < 0) { + dev_err(dev, "failed to get pwm number: %d\n", ret); + return ret; + } + + for (i = 0; i < npwm; i++) { + struct mxs_pwm_chip *mxspwm = &mxs->pwm[i]; + + mxspwm->chip.ops = &mxs_pwm_ops; + mxspwm->chip.devname = asprintf("pwm%d", i); + mxspwm->chip.id = i; + mxspwm->mxs = mxs; + + ret = pwmchip_add(&mxspwm->chip, dev); + if (ret < 0) { + dev_err(dev, "failed to add pwm chip %d\n", ret); + return ret; + } + } + + return 0; +} + +static const struct of_device_id mxs_pwm_dt_ids[] = { + { .compatible = "fsl,imx23-pwm", }, + { /* sentinel */ } +}; + +static struct driver_d mxs_pwm_driver = { + .name = "mxs-pwm", + .of_compatible = mxs_pwm_dt_ids, + .probe = mxs_pwm_probe, +}; + +coredevice_platform_driver(mxs_pwm_driver); + +MODULE_ALIAS("platform:mxs-pwm"); +MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); +MODULE_DESCRIPTION("Freescale MXS PWM Driver"); +MODULE_LICENSE("GPL v2"); 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/drivers/video/Kconfig b/drivers/video/Kconfig index f096a5456b..8e6ae99b95 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -93,4 +93,16 @@ config DRIVER_VIDEO_EDID This enabled support for reading and parsing EDID data from an attached monitor. +config DRIVER_VIDEO_BACKLIGHT + bool "Add backlight support" + help + Enable this for backlight support. + +config DRIVER_VIDEO_BACKLIGHT_PWM + bool "PWM backlight support" + depends on PWM + depends on DRIVER_VIDEO_BACKLIGHT + help + Enable this to get support for backlight devices driven by a PWM. + endif diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ae9f6e545e..76fad5c8e8 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -1,6 +1,8 @@ obj-$(CONFIG_VIDEO) += fb.o obj-$(CONFIG_DRIVER_VIDEO_EDID) += edid.o obj-$(CONFIG_OFDEVICE) += of_display_timing.o +obj-$(CONFIG_DRIVER_VIDEO_BACKLIGHT) += backlight.o +obj-$(CONFIG_DRIVER_VIDEO_BACKLIGHT_PWM) += backlight-pwm.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o diff --git a/drivers/video/backlight-pwm.c b/drivers/video/backlight-pwm.c new file mode 100644 index 0000000000..91b148109b --- /dev/null +++ b/drivers/video/backlight-pwm.c @@ -0,0 +1,199 @@ +/* + * pwm backlight support for barebox + * + * (C) Copyright 2014 Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <common.h> +#include <malloc.h> +#include <init.h> +#include <video/backlight.h> +#include <pwm.h> +#include <linux/err.h> +#include <of.h> +#include <gpio.h> +#include <of_gpio.h> +#include <asm-generic/div64.h> + +struct pwm_backlight { + struct backlight_device backlight; + struct pwm_device *pwm; + uint32_t period; + unsigned int *levels; + int enable_gpio; + int enable_active_high; + int max_value; + int enabled; +}; + +static int backlight_pwm_enable(struct pwm_backlight *pwm_backlight) +{ + int ret; + + if (pwm_backlight->enabled) + return 0; + + ret = pwm_enable(pwm_backlight->pwm); + if (ret) + return ret; + + if (gpio_is_valid(pwm_backlight->enable_gpio)) { + gpio_direction_output(pwm_backlight->enable_gpio, + pwm_backlight->enable_active_high); + } + + pwm_backlight->enabled = 1; + + return 0; +} + +static int backlight_pwm_disable(struct pwm_backlight *pwm_backlight) +{ + if (!pwm_backlight->enabled) + return 0; + + if (gpio_is_valid(pwm_backlight->enable_gpio)) { + gpio_direction_output(pwm_backlight->enable_gpio, + !pwm_backlight->enable_active_high); + /* + * Only disable PWM when an enable gpio is present. + * The output of the PWM is undefined when the PWM + * is disabled. + */ + pwm_disable(pwm_backlight->pwm); + pwm_backlight->enabled = 0; + } + + return 0; +} + +static int backlight_pwm_set(struct backlight_device *backlight, + int brightness) +{ + struct pwm_backlight *pwm_backlight = container_of(backlight, + struct pwm_backlight, backlight); + unsigned long long duty = pwm_backlight->period; + unsigned int max = pwm_backlight->backlight.brightness_max; + + duty *= brightness; + do_div(duty, max); + + pwm_config(pwm_backlight->pwm, duty, pwm_backlight->period); + + if (brightness) + return backlight_pwm_enable(pwm_backlight); + else + return backlight_pwm_disable(pwm_backlight); +} + +static int pwm_backlight_parse_dt(struct device_d *dev, + struct pwm_backlight *pwm_backlight) +{ + struct device_node *node = dev->device_node; + struct property *prop; + int length; + u32 value; + int ret; + enum of_gpio_flags flags; + + if (!node) + return -ENODEV; + + /* determine the number of brightness levels */ + prop = of_find_property(node, "brightness-levels", &length); + if (!prop) + return -EINVAL; + + pwm_backlight->backlight.brightness_max = length / sizeof(u32); + + /* read brightness levels from DT property */ + if (pwm_backlight->backlight.brightness_max > 0) { + size_t size = sizeof(*pwm_backlight->levels) * + pwm_backlight->backlight.brightness_max; + + pwm_backlight->levels = xzalloc(size); + if (!pwm_backlight->levels) + return -ENOMEM; + + ret = of_property_read_u32_array(node, "brightness-levels", + pwm_backlight->levels, + pwm_backlight->backlight.brightness_max); + if (ret < 0) + return ret; + + ret = of_property_read_u32(node, "default-brightness-level", + &value); + if (ret < 0) + return ret; + + pwm_backlight->backlight.brightness_default = value; + pwm_backlight->backlight.brightness_max--; + } + + pwm_backlight->enable_gpio = of_get_named_gpio_flags(node, "enable-gpios", 0, &flags); + + if (gpio_is_valid(pwm_backlight->enable_gpio)) { + if (!(flags & OF_GPIO_ACTIVE_LOW)) + pwm_backlight->enable_active_high = 1; + } + + return 0; +} + +static int backlight_pwm_of_probe(struct device_d *dev) +{ + int ret; + struct pwm_backlight *pwm_backlight; + struct pwm_device *pwm; + + pwm = of_pwm_request(dev->device_node, NULL); + if (IS_ERR(pwm)) + return PTR_ERR(pwm); + + pwm_backlight = xzalloc(sizeof(*pwm_backlight)); + pwm_backlight->pwm = pwm; + pwm_backlight->period = pwm_get_period(pwm); + + ret = pwm_backlight_parse_dt(dev, pwm_backlight); + if (ret) + return ret; + + pwm_backlight->period = pwm_get_period(pwm_backlight->pwm); + + pwm_backlight->backlight.brightness_set = backlight_pwm_set; + pwm_backlight->backlight.node = dev->device_node; + + ret = backlight_register(&pwm_backlight->backlight); + if (ret) + return ret; + + return 0; +} + +static struct of_device_id backlight_pwm_of_ids[] = { + { + .compatible = "pwm-backlight", + }, { + /* sentinel */ + } +}; + +static struct driver_d backlight_pwm_of_driver = { + .name = "pwm-backlight", + .probe = backlight_pwm_of_probe, + .of_compatible = DRV_OF_COMPAT(backlight_pwm_of_ids), +}; +device_platform_driver(backlight_pwm_of_driver); diff --git a/drivers/video/backlight.c b/drivers/video/backlight.c new file mode 100644 index 0000000000..ddde6f8523 --- /dev/null +++ b/drivers/video/backlight.c @@ -0,0 +1,90 @@ +#include <common.h> +#include <driver.h> +#include <linux/list.h> +#include <video/backlight.h> + +static LIST_HEAD(backlights); + +int backlight_set_brightness(struct backlight_device *bl, int brightness) +{ + int ret, step, i, num_steps; + + if (brightness > bl->brightness_max) + brightness = bl->brightness_max; + + if (brightness == bl->brightness_cur) + return 0; + + if (brightness > bl->brightness_cur) + step = 1; + else + step = -1; + + i = bl->brightness_cur; + + num_steps = abs(brightness - bl->brightness_cur); + + while (1) { + i += step; + + ret = bl->brightness_set(bl, i); + if (ret) + return ret; + + if (i == brightness) + break; + + udelay(100000 / num_steps); + } + + + bl->brightness_cur = bl->brightness = brightness; + + return ret; +} + +int backlight_set_brightness_default(struct backlight_device *bl) +{ + int ret; + + ret = backlight_set_brightness(bl, bl->brightness_default); + + return ret; +} + +static int backlight_brightness_set(struct param_d *p, void *priv) +{ + struct backlight_device *bl = priv; + + return backlight_set_brightness(bl, bl->brightness); +} + +int backlight_register(struct backlight_device *bl) +{ + int ret; + + sprintf(bl->dev.name, "backlight"); + bl->dev.id = DEVICE_ID_DYNAMIC; + + ret = register_device(&bl->dev); + if (ret) + return ret; + + dev_add_param_int(&bl->dev, "brightness", backlight_brightness_set, + NULL, &bl->brightness, "%d", bl); + + list_add_tail(&bl->list, &backlights); + + return ret; +} + +struct backlight_device *of_backlight_find(struct device_node *node) +{ + struct backlight_device *bl; + + list_for_each_entry(bl, &backlights, list) + if (bl->node == node) + return bl; + + return NULL; +} diff --git a/drivers/video/stm.c b/drivers/video/stm.c index 3c90c0dc3f..bf913f1ec6 100644 --- a/drivers/video/stm.c +++ b/drivers/video/stm.c @@ -317,7 +317,7 @@ static int stmfb_activate_var(struct fb_info *fb_info) size = calc_line_length(mode->xres, fb_info->bits_per_pixel) * mode->yres; - if (pdata->fixed_screen) { + if (pdata && pdata->fixed_screen) { if (pdata->fixed_screen_size < size) return -ENOMEM; fb_info->screen_base = pdata->fixed_screen; @@ -497,16 +497,37 @@ static int stmfb_probe(struct device_d *hw_dev) return PTR_ERR(fbi.clk); clk_enable(fbi.clk); + fbi.info.bits_per_pixel = 16; + /* add runtime video info */ - fbi.info.modes.modes = pdata->mode_list; - fbi.info.modes.num_modes = pdata->mode_cnt; - fbi.info.mode = &fbi.info.modes.modes[0]; - fbi.info.xres = fbi.info.mode->xres; - fbi.info.yres = fbi.info.mode->yres; - if (pdata->bits_per_pixel) - fbi.info.bits_per_pixel = pdata->bits_per_pixel; - else - fbi.info.bits_per_pixel = 16; + if (pdata) { + fbi.info.modes.modes = pdata->mode_list; + fbi.info.modes.num_modes = pdata->mode_cnt; + fbi.info.mode = &fbi.info.modes.modes[0]; + if (pdata->bits_per_pixel) + fbi.info.bits_per_pixel = pdata->bits_per_pixel; + } else { + struct display_timings *modes; + struct device_node *display; + + if (!IS_ENABLED(CONFIG_OFDEVICE) || !hw_dev->device_node) + return -EINVAL; + + display = of_parse_phandle(hw_dev->device_node, "display", 0); + if (!display) { + dev_err(hw_dev, "no display phandle\n"); + return -EINVAL; + } + + modes = of_get_display_timings(display); + if (IS_ERR(modes)) { + dev_err(hw_dev, "unable to parse display timings\n"); + return PTR_ERR(modes); + } + + fbi.info.modes.modes = modes->modes; + fbi.info.modes.num_modes = modes->num_modes; + } hw_dev->info = stmfb_info; @@ -519,9 +540,20 @@ static int stmfb_probe(struct device_d *hw_dev) return 0; } +static __maybe_unused struct of_device_id stmfb_compatible[] = { + { + .compatible = "fsl,imx23-lcdif", + }, { + .compatible = "fsl,imx28-lcdif", + }, { + /* sentinel */ + } +}; + static struct driver_d stmfb_driver = { .name = "stmfb", .probe = stmfb_probe, + .of_compatible = DRV_OF_COMPAT(stmfb_compatible), }; device_platform_driver(stmfb_driver); 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 587cb2651f..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) @@ -105,6 +107,7 @@ include $(srctree)/images/Makefile.imx include $(srctree)/images/Makefile.imxhabv4 include $(srctree)/images/Makefile.mvebu include $(srctree)/images/Makefile.mxs +include $(srctree)/images/Makefile.omap3 include $(srctree)/images/Makefile.rockchip include $(srctree)/images/Makefile.socfpga include $(srctree)/images/Makefile.tegra 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/images/Makefile.omap3 b/images/Makefile.omap3 new file mode 100644 index 0000000000..694ec30836 --- /dev/null +++ b/images/Makefile.omap3 @@ -0,0 +1,19 @@ +# %.mlo - convert into mlo image +# ---------------------------------------------------------------- +quiet_cmd_omap3_mlo_image = MLO $@ + cmd_omap3_mlo_image = scripts/omap_signGP -o $@ -l 0x40200000 -c $< + +$(obj)/%.omap3_mlo: $(obj)/% FORCE + $(call if_changed,omap3_mlo_image) + +pblx-$(CONFIG_MACH_BEAGLE) += start_omap3_beagleboard_sdram start_omap3_beagleboard_sram +FILE_barebox-beagleboard.img = start_omap3_beagleboard_sdram.pblx +omap3-barebox-$(CONFIG_MACH_BEAGLE) += barebox-beagleboard.img +FILE_barebox-beagleboard-mlo.img = start_omap3_beagleboard_sram.pblx.omap3_mlo +omap3-mlo-$(CONFIG_MACH_BEAGLE) += barebox-beagleboard-mlo.img + +ifdef CONFIG_OMAP_BUILD_IFT +image-y += $(omap3-mlo-y) +else +image-y += $(omap3-barebox-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/include/of.h b/include/of.h index c02f5f49ab..1db210b38a 100644 --- a/include/of.h +++ b/include/of.h @@ -224,6 +224,8 @@ extern int of_modalias_node(struct device_node *node, char *modalias, int len); extern struct device_node *of_get_root_node(void); extern int of_set_root_node(struct device_node *node); +extern struct device_d *of_platform_device_create(struct device_node *np, + struct device_d *parent); extern int of_platform_populate(struct device_node *root, const struct of_device_id *matches, struct device_d *parent); diff --git a/include/pwm.h b/include/pwm.h index 59d86d497d..911c760839 100644 --- a/include/pwm.h +++ b/include/pwm.h @@ -57,12 +57,14 @@ struct pwm_ops { /** * struct pwm_chip - abstract a PWM + * @id: The id of this pwm * @devname: unique identifier for this pwm * @ops: The callbacks for this PWM * @duty_ns: The duty cycle of the PWM, in nano-seconds * @period_ns: The period of the PWM, in nano-seconds */ struct pwm_chip { + int id; const char *devname; struct pwm_ops *ops; int duty_ns; diff --git a/include/video/backlight.h b/include/video/backlight.h new file mode 100644 index 0000000000..56e0341ea4 --- /dev/null +++ b/include/video/backlight.h @@ -0,0 +1,20 @@ +#ifndef __VIDEO_BACKLIGHT_H +#define __VIDEO_BACKLIGHT_H + +struct backlight_device { + int brightness; + int brightness_cur; + int brightness_max; + int brightness_default; + int (*brightness_set)(struct backlight_device *, int brightness); + struct list_head list; + struct device_d dev; + struct device_node *node; +}; + +int backlight_set_brightness(struct backlight_device *, int brightness); +int backlight_set_brightness_default(struct backlight_device *); +int backlight_register(struct backlight_device *); +struct backlight_device *of_backlight_find(struct device_node *node); + +#endif /* __VIDEO_BACKLIGHT_H */ diff --git a/include/xfuncs.h b/include/xfuncs.h index 8efc99dbc4..940a1d67ed 100644 --- a/include/xfuncs.h +++ b/include/xfuncs.h @@ -7,6 +7,7 @@ void *xmalloc(size_t size); void *xrealloc(void *ptr, size_t size); void *xzalloc(size_t size); char *xstrdup(const char *s); +char *xstrndup(const char *s, size_t size); void* xmemalign(size_t alignment, size_t bytes); void* xmemdup(const void *orig, size_t size); 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..b23885958b 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; } @@ -225,7 +233,7 @@ static int param_string_set(struct device_d *dev, struct param_d *p, const char char *value_save = *ps->value; if (!val) - return -EINVAL; + val = ""; *ps->value = xstrdup(val); @@ -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/lib/xfuncs.c b/lib/xfuncs.c index 0e78b670a5..f0219c43a5 100644 --- a/lib/xfuncs.c +++ b/lib/xfuncs.c @@ -63,6 +63,28 @@ char *xstrdup(const char *s) } EXPORT_SYMBOL(xstrdup); +char *xstrndup(const char *s, size_t n) +{ + int m; + char *t; + + /* We can just xmalloc(n+1) and strncpy into it, */ + /* but think about xstrndup("abc", 10000) wastage! */ + m = n; + t = (char*) s; + while (m) { + if (!*t) break; + m--; + t++; + } + n -= m; + t = xmalloc(n + 1); + t[n] = '\0'; + + return memcpy(t, s, n); +} +EXPORT_SYMBOL(xstrndup); + void* xmemalign(size_t alignment, size_t bytes) { void *p = memalign(alignment, bytes); 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 - diff --git a/scripts/Makefile b/scripts/Makefile index 74c22136db..a3f6222d08 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -24,6 +24,9 @@ HOSTLOADLIBES_mxsimage = `pkg-config --libs openssl` HOSTCFLAGS_mxs-usb-loader.o = `pkg-config --cflags libusb-1.0` HOSTLOADLIBES_mxs-usb-loader = `pkg-config --libs libusb-1.0` hostprogs-$(CONFIG_ARCH_MXS_USBLOADER) += mxs-usb-loader +HOSTCFLAGS_omap3-usb-loader.o = `pkg-config --cflags libusb-1.0` +HOSTLOADLIBES_omap3-usb-loader = `pkg-config --libs libusb-1.0` +hostprogs-$(CONFIG_OMAP3_USB_LOADER) += omap3-usb-loader subdir-y += mod subdir-$(CONFIG_OMAP4_USBBOOT) += omap4_usbboot diff --git a/scripts/omap3-usb-loader.c b/scripts/omap3-usb-loader.c new file mode 100644 index 0000000000..edf6043edf --- /dev/null +++ b/scripts/omap3-usb-loader.c @@ -0,0 +1,921 @@ +/* + * OMAP Loader, a USB uploader application targeted at OMAP3 processors + * Copyright (C) 2008 Martin Mueller <martinmm@pfump.org> + * Copyright (C) 2014 Grant Hernandez <grant.h.hernandez@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <string.h> +#include <stdbool.h> + +/* + * Reasons for the name change: this is a complete rewrite of + * the unversioned omap3_usbload so to lower ambiguity the name was changed. + * The GPLv2 license specifies rewrites as derived work. + */ +#define PROG_NAME "OMAP Loader" +#define VERSION "1.0.0" + +#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define OMAP_IS_BIG_ENDIAN +#endif + +#ifdef OMAP_IS_BIG_ENDIAN +#include <arpa/inet.h> +#endif + +#include <unistd.h> /* for usleep and friends */ +#include <getopt.h> +#include <errno.h> +#include <libgen.h> /* for basename */ + +#include <libusb-1.0/libusb.h> /* the main event */ + +/* Device specific defines (OMAP) + * Primary source: http://www.ti.com/lit/pdf/sprugn4 + * Section 26.4.5 "Peripheral Booting" + */ +#define OMAP_BASE_ADDRESS 0x40200000 +#define OMAP_PERIPH_BOOT 0xF0030002 +#define OMAP_VENDOR_ID 0x0451 +#define OMAP_PRODUCT_ID 0xD00E +/* TODO: dynamically discover these endpoints */ +#define OMAP_USB_BULK_IN 0x81 +#define OMAP_USB_BULK_OUT 0x01 +#define OMAP_ASIC_ID_LEN 69 + +#ifdef OMAP_IS_BIG_ENDIAN +#define cpu_to_le32(v) (((v & 0xff) << 24) | ((v & 0xff00) << 8) | \ + ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24)) +#define le32_to_cpu(v) cpu_to_le32(v) +#else +#define cpu_to_le32(v) (v) +#define le32_to_cpu(v) (v) +#endif + +/* + * taken from x-loader/drivers/usb/usb.c + * All credit to Martin Mueller + */ +#define PACK4(a,b,c,d) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)) +#define USBLOAD_CMD_FILE PACK4('U','S','B','s') /* file size request */ +#define USBLOAD_CMD_FILE_REQ PACK4('U','S','B','f') /* file size resp */ +#define USBLOAD_CMD_JUMP PACK4('U','S','B','j') /* execute code here */ +#define USBLOAD_CMD_ECHO_SZ PACK4('U','S','B','n') /* file size confirm to */ +#define USBLOAD_CMD_REPORT_SZ PACK4('U','S','B','o') /* confirm full file */ +#define USBLOAD_CMD_MESSAGE PACK4('U','S','B','m') /* debug message */ + +/* USB transfer characteristics */ +#define USB_MAX_WAIT 5000 +#define USB_TIMEOUT 1000 +#define USB_MAX_TIMEOUTS (USB_MAX_WAIT/USB_TIMEOUT) + +/* stores the data and attributes of a file to upload in to memory */ +struct file_upload { + size_t size; + void *data; + uint32_t addr; + char *path; + char *basename; +}; + +/* stores all of the arguments read in by getopt in main() */ +struct arg_state { + struct file_upload **files; + int numfiles; + uint32_t jumptarget; + uint16_t vendor, product; +}; + +static int g_verbose = 0; + +static void log_error(char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + fprintf(stdout, "[-] "); + vfprintf(stdout, fmt, va); + va_end(va); +} + +static void log_info(char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + fprintf(stdout, "[+] "); + vfprintf(stdout, fmt, va); + va_end(va); +} + +static bool omap_usb_read(libusb_device_handle *handle, unsigned char *data, + int length, int *actuallength) +{ + int ret = 0; + int iter = 0; + int sizeleft = length; + + if (!actuallength) + return false; + + while (sizeleft > 0) { + int actualread = 0; + int readamt = sizeleft; + + ret = libusb_bulk_transfer(handle, OMAP_USB_BULK_IN, data + iter, + readamt, &actualread, USB_TIMEOUT); + + if (ret == LIBUSB_ERROR_TIMEOUT) { + sizeleft -= actualread; + iter += actualread; + + /* we got some data, lets cut our losses and stop here */ + if (iter > 0) + break; + + log_error("device timed out while transfering in %d bytes (got %d)\n", + length, iter); + + return false; + } else if (ret == LIBUSB_SUCCESS) { + /* we cant trust actualRead on anything but a timeout or success */ + sizeleft -= actualread; + iter += actualread; + + /* stop at the first sign of data */ + if (iter > 0) + break; + } else { + log_error("fatal transfer error (BULK_IN) for %d bytes (got %d): %s\n", + length, iter, libusb_error_name(ret)); + return false; + } + } + + *actuallength = iter; + + return true; +} + +static bool omap_usb_write(libusb_device_handle *handle, void *data, int length) +{ + int ret = 0; + int numtimeouts = 0; + int iter = 0; + int sizeleft = length; + + while (sizeleft > 0) { + int actualwrite = 0; + int writeamt = sizeleft > 512 ? 512 : sizeleft; + + ret = libusb_bulk_transfer(handle, OMAP_USB_BULK_OUT, data + iter, + writeamt, &actualwrite, USB_TIMEOUT); + + if (ret == LIBUSB_ERROR_TIMEOUT) { + numtimeouts++; + sizeleft -= actualwrite; + iter += actualwrite; + + /* build in some reliablity */ + if (numtimeouts > USB_MAX_TIMEOUTS) { + log_error("device timed out while transfering out %d bytes (%d made it)\n", + length, iter); + return false; + } + } else if (ret == LIBUSB_SUCCESS) { + /* we cant trust actualWrite on anything but a timeout or success */ + sizeleft -= actualwrite; + iter += actualwrite; + } else { + log_error("fatal transfer error (BULK_OUT) for %d bytes (%d made it): %s\n", + length, iter, libusb_error_name(ret)); + return false; + } + } + + return true; +} + +static unsigned char *omap_usb_get_string(libusb_device_handle *handle, uint8_t idx) +{ + unsigned char *data = NULL; + int len = 0; + int ret = 0; + + if (!handle) + return NULL; + + while (true) { + if (!len || ret < 0) { + len += 256; + data = realloc(data, len); + + if (!data) + return NULL; + } + + ret = libusb_get_string_descriptor_ascii(handle, idx, data, len); + + /* we can still recover... */ + if (ret < 0) { + if (ret == LIBUSB_ERROR_INVALID_PARAM) + continue; /* try again with an increased size */ + + log_error("failed to lookup string index %hhu: %s\n", + idx, libusb_error_name(ret)); + + /* unrecoverable */ + free(data); + return NULL; + } else { + /* we got something! */ + break; + } + } + + return data; +} + +uint16_t omap_products[] = { + 0xd009, + 0xd00f, +}; + +static libusb_device_handle *omap_usb_open(libusb_context *ctx, uint16_t vendor, uint16_t product) +{ + libusb_device **devlist; + libusb_device_handle *handle; + struct libusb_device_descriptor desc; + ssize_t count, i; + int ret; + + log_info("scanning for USB device matching %04hx:%04hx...\n", + vendor, product); + + while (1) { + if ((count = libusb_get_device_list(ctx, &devlist)) < 0) { + log_error("failed to gather USB device list: %s\n", + libusb_error_name(count)); + return NULL; + } + + for (i = 0; i < count; i++) { + ret = libusb_get_device_descriptor(devlist[i], &desc); + if (ret < 0) { + log_error("failed to get USB device descriptor: %s\n", + libusb_error_name(ret)); + libusb_free_device_list(devlist, 1); + return NULL; + } + + if (desc.idVendor != vendor) + continue; + + if (product) { + if (desc.idProduct != product) + continue; + goto found; + } + + for (i = 0; i < sizeof(omap_products) / sizeof(uint16_t); i++) + if (desc.idProduct == omap_products[i]) { + product = desc.idProduct; + goto found; + } + } + + libusb_free_device_list(devlist, 1); + + /* nothing found yet. have a 10ms nap */ + usleep(10000); + } +found: + ret = libusb_open(devlist[i], &handle); + if (ret < 0) { + log_error("failed to open USB device %04hx:%04hx: %s\n", + vendor, product, libusb_error_name(ret)); + libusb_free_device_list(devlist, 1); + return NULL; + } + + ret = libusb_claim_interface(handle, 0); + if (ret) { + printf("Claim failed\n"); + return NULL; + } + + /* grab the manufacturer and product strings for printing */ + unsigned char *mfgstr = omap_usb_get_string(handle, desc.iManufacturer); + unsigned char *prodstr = omap_usb_get_string(handle, desc.iProduct); + + log_info("successfully opened %04hx:%04hx (", vendor, product); + + if (mfgstr) { + fprintf(stdout, prodstr ? "%s " : "%s", mfgstr); + free(mfgstr); + } + + if (prodstr) { + fprintf(stdout, "%s", prodstr); + free(prodstr); + } + + fprintf(stdout, ")\n"); + + return handle; +} + +static unsigned char *read_file(char *path, size_t *readamt) +{ + FILE *fp = fopen(path, "rb"); + + if (!fp) { + log_error("failed to open file \'%s\': %s\n", path, + strerror(errno)); + return NULL; + } + + unsigned char *data = NULL; + size_t allocsize = 0; + size_t iter = 0; + + while (1) { + if (iter >= iter) { + allocsize += 1024; + data = realloc(data, allocsize); + if (!data) + return NULL; + } + + size_t readsize = allocsize - iter; + size_t ret = fread(data + iter, sizeof (unsigned char), readsize, fp); + + iter += ret; + + if (ret != readsize) { + if (feof(fp)) { + break; + } else if (ferror(fp)) { + log_error("error file reading file \'%s\': %s\n", + path, strerror(errno)); + free(data); + return NULL; + } + } + } + + /* trim the allocation down to size */ + data = realloc(data, iter); + *readamt = iter; + + return data; +} + +static int transfer_first_stage(libusb_device_handle * handle, struct arg_state *args) +{ + unsigned char *buffer = NULL; + uint32_t cmd = 0; + uint32_t filelen = 0; + int bufsize = 0x200; + int transLen = 0; + int i; + void *data; + uint32_t *dbuf; + + struct file_upload *file = args->files[0]; + + /* TODO determine buffer size based on endpoint */ + buffer = calloc(bufsize, sizeof (unsigned char)); + filelen = cpu_to_le32(file->size); + + data = file->data; + dbuf = data; + + if (le32toh(dbuf[5]) == 0x45534843) { + int chsettingssize = 512 + 2 * sizeof(uint32_t); + + log_info("CHSETTINGS image detected. Skipping header\n"); + + data += chsettingssize; + filelen -= chsettingssize; + } + + /* read the ASIC ID */ + if (!omap_usb_read(handle, buffer, bufsize, &transLen)) { + log_error("failed to read ASIC ID from USB connection. " + "Check your USB device!\n"); + goto fail; + } + + if (transLen != OMAP_ASIC_ID_LEN) { + log_error("got some ASIC ID, but it's not the right length, %d " + "(expected %d)\n", transLen, OMAP_ASIC_ID_LEN); + goto fail; + } + + /* optionally, print some ASIC ID info */ + if (g_verbose) { + char *fields[] = + { "Num Subblocks", "Device ID Info", "Reserved", + "Ident Data", "Reserved", "CRC (4 bytes)" + }; + int fieldLen[] = { 1, 7, 4, 23, 23, 11 }; + int field = 0; + int nextSep = 0; + + log_info("got ASIC ID - "); + + for (i = 0; i < transLen; i++) { + if (i == nextSep) { + fprintf(stdout, "%s%s ", + (field > 0) ? ", " : "", fields[field]); + nextSep += fieldLen[field]; + field++; + + fprintf(stdout, "["); + } + + fprintf(stdout, "%02x", buffer[i]); + + if (i + 1 == nextSep) + fprintf(stdout, "]"); + } + + fprintf(stdout, "\n"); + } + + /* send the peripheral boot command */ + cmd = cpu_to_le32(OMAP_PERIPH_BOOT); + + if (!omap_usb_write(handle, (unsigned char *) &cmd, sizeof (cmd))) { + log_error("failed to send the peripheral boot command 0x%08x\n", + OMAP_PERIPH_BOOT); + goto fail; + } + + /* send the length of the first file (little endian) */ + if (!omap_usb_write + (handle, (unsigned char *) &filelen, sizeof (filelen))) { + log_error("failed to length specifier of %u to OMAP BootROM\n", + filelen); + goto fail; + } + + /* send the file! */ + if (!omap_usb_write(handle, data, filelen)) { + log_error("failed to send file \'%s\' (size %u)\n", + file->basename, filelen); + goto fail; + } + + free(buffer); + return 1; + + fail: + free(buffer); + return 0; +} + +static int transfer_other_files(libusb_device_handle *handle, struct arg_state *args) +{ + uint32_t *buffer = NULL; + int bufsize = 128 * sizeof (*buffer); + int numfailures = 0; /* build in some reliablity */ + int maxfailures = 3; + int transLen = 0; + int curfile = 1; /* skip the first file */ + size_t len; + + buffer = calloc(bufsize, sizeof(unsigned char)); + + /* handle the state machine for the X-Loader */ + while (curfile < args->numfiles) { + uint32_t opcode = 0; + uint8_t *extra = NULL; + struct file_upload *f = args->files[curfile]; + + /* read the opcode from xloader ID */ + if (!omap_usb_read + (handle, (unsigned char *) buffer, bufsize, &transLen)) { + numfailures++; + + if (numfailures >= maxfailures) { + log_error("failed to read command from X-Loader\n"); + goto fail; + } + + /* sleep a bit */ + usleep(2000 * 1000); /* 2s */ + continue; /* try the opcode read again */ + } + + if (transLen < 8) { + log_error("failed to recieve enough data for the opcode\n"); + goto fail; + } + + /* extract the opcode and extra data pointer */ + opcode = le32_to_cpu(buffer[0]); + extra = (uint8_t *)buffer; + + switch (opcode) { + case USBLOAD_CMD_FILE_REQ: + /* X-loader is requesting a file to be sent */ + /* send the opcode, size, and addr */ + buffer[0] = cpu_to_le32(USBLOAD_CMD_FILE); + buffer[1] = cpu_to_le32(f->size); + buffer[2] = cpu_to_le32(f->addr); + + if (!omap_usb_write(handle, (unsigned char *)buffer, sizeof(*buffer) * 3)) { + log_error("failed to send load file command to the X-loader\n"); + goto fail; + } + + if (g_verbose) { + log_info("uploading \'%s\' (size %zu) to 0x%08x\n", + f->basename, f->size, f->addr); + } + + break; + case USBLOAD_CMD_ECHO_SZ: + /* X-loader confirms the size to recieve */ + if (buffer[1] != f->size) { + log_error + ("X-loader failed to recieve the right file size for " + "file \'%s\' (got %u, expected %zu)\n", + f->basename, buffer[1], f->size); + goto fail; + } + + /* upload the raw file data */ + if (!omap_usb_write(handle, f->data, f->size)) { + log_error + ("failed to send file \'%s\' to the X-loader\n", + f->basename); + goto fail; + } + + break; + case USBLOAD_CMD_REPORT_SZ: + /* X-loader confirms the amount of data it recieved */ + if (buffer[1] != f->size) { + log_error + ("X-loader failed to recieve the right amount of data for " + "file \'%s\' (got %u, expected %zu)\n", + f->basename, buffer[1], f->size); + goto fail; + } + + curfile++; /* move on to the next file */ + break; + case USBLOAD_CMD_MESSAGE: + /* X-loader debug message */ + len = strlen((char *)extra); + + if (len > (bufsize - sizeof (opcode) - 1)) + log_error("X-loader debug message not NUL terminated (size %zu)\n", + len); + else + fprintf(stdout, "X-loader Debug: %s\n", extra); + break; + default: + log_error("unknown X-Loader opcode 0x%08X (%c%c%c%c)\n", + opcode, extra[0], extra[1], extra[2], + extra[3]); + goto fail; + } + } + + /* we're done uploading files to X-loader send the jump command */ + buffer[0] = cpu_to_le32(USBLOAD_CMD_JUMP); + buffer[1] = cpu_to_le32(args->jumptarget); + + if (!omap_usb_write + (handle, (unsigned char *) buffer, sizeof (*buffer) * 2)) { + log_error + ("failed to send the final jump command to the X-loader. " + "Target was 0x%08x\n", args->jumptarget); + goto fail; + } + + if (g_verbose) + log_info("jumping to address 0x%08x\n", args->jumptarget); + + free(buffer); + return 1; + + fail: + free(buffer); + return 0; +} + +static int process_args(struct arg_state *args) +{ + int i; + + /* For each file, load it in to memory + * TODO: defer this until transfer time (save memory and pipeline IO) + */ + + for (i = 0; i < args->numfiles; i++) { + struct file_upload *f = args->files[i]; + + f->data = read_file(f->path, &f->size); + + if (!f->data) { + return 1; + } + } + + if (g_verbose > 0) { + for (i = 0; i < args->numfiles; i++) { + struct file_upload *f = args->files[i]; + + printf("File \'%s\' at 0x%08x, size %zu\n", + f->basename, f->addr, f->size); + } + } + + libusb_context *ctx; + libusb_device_handle *dev; + int ret; + + if ((ret = libusb_init(&ctx)) < 0) { + log_error("failed to initialize libusb context: %s\n", + libusb_error_name(ret)); + return ret; + } + + dev = omap_usb_open(ctx, args->vendor, args->product); + + if (!dev) { + libusb_exit(ctx); + return 1; + } + + /* Communicate with the TI BootROM directly + * - retrieve ASIC ID + * - start peripheral boot + * - upload first file + * - execute first file + */ + if (!transfer_first_stage(dev, args)) { + log_error("failed to transfer the first stage file \'%s\'\n", + args->files[0]->basename); + goto fail; + } + + /* Note: this is a race between the target's processor getting X-loader + * running and our processor. If we fail to communicate with the X-loader, + * it's possible that it hasn't been fully initialized. I'm not going to put + * some stupid, arbitrary sleep value here. The transfer_other_files function + * should be robust enough to handle some errors. + */ + + /* If we are passed one file, assume that the user just wants to + * upload some initial code with no X-loader chaining + */ + if (args->numfiles > 1) { + if (!transfer_other_files(dev, args)) { + log_error + ("failed to transfer the additional files in to memory\n"); + goto fail; + } + } + + log_info("successfully transfered %d %s\n", args->numfiles, + (args->numfiles > 1) ? "files" : "file"); + + /* safely close our USB handle and context */ + libusb_close(dev); + libusb_exit(ctx); + return 0; + +fail: + libusb_close(dev); + libusb_exit(ctx); + + return 1; +} + +/* getopt configuration */ +static int do_version = 0; +static const char *const short_opt = "f:a:j:i:p:vh"; +static const struct option long_opt[] = { + {"file", 1, NULL, 'f'}, + {"addr", 1, NULL, 'a'}, + {"jump", 1, NULL, 'j'}, + {"vendor", 1, NULL, 'i'}, + {"product", 1, NULL, 'p'}, + {"verbose", 0, NULL, 'v'}, + {"help", 0, NULL, 'h'}, + {"version", 0, &do_version, 1}, + {NULL, 0, NULL, 0} +}; + +static void usage(char *exe) +{ + printf( +"Usage: %s [options] -f first-stage [-f file -a addr]...\n" +"Options:\n" +" -f, --file Provide the filename of a binary file to be\n" +" uploaded. The first file specified is uploaded to\n" +" the fixed address 0x%08x as defined by the manual.\n" +" Additional files must be followed by an address\n" +" argument (-a).\n" +" -a, --addr The address to load the prior file at.\n" +" -j, --jump Specify the address to jump to after loading all\n" +" of the files in to memory.\n" +" -i, --vendor Override the default vendor ID to poll for\n" +" (default 0x%04x).\n" +" -p, --product Poll for specific product id. Default: All known OMAP chips\n" +" -h, --help Display this message.\n" +" -v, --verbose Enable verbose output.\n" +"\n" +"Description:\n" +" %s's basic usage is to upload an arbitrary file in to the memory\n" +" of a TI OMAP3 compatible processor. This program directly\n" +" communicates with the TI BootROM in order to upload a first stage\n" +" payload, in most cases, TI's X-Loader. Using a compatible X-Loader\n" +" will enable the upload of any file to any part in device memory.\n" +"\n" +"Examples:\n" +" Uploading a compatible X-Loader, U-Boot, Kernel, and RAMDisk, then jumping\n" +" to the U-Boot image for further bootloading:\n" +" %s -f x-load.bin -f u-boot.bin -a 0x80200000 -f uImage -a 0x80800000 \\\n" +" -f uRamdisk -a 0x81000000 -j 0x80200000\n" +" Uploading arbitrary code to be executed (doesn't have to be X-loader):\n" +" %s -f exec_me.bin\n" +" Trying to debug an upload issue using verbose output:\n" +" %s -v -f exec_me.bin -f file1.bin -a 0xdeadbeef -j 0xabad1dea\n" +"\n" +"Authors:\n" +" Grant Hernandez <grant.h.hernandez@gmail.com> - rewrite of omap3_usbload to\n" +" use the newer libusb 1.0\n" +" Martin Mueller <martinmm@pfump.org> - initial code (omap3_usbload)\n" +" and X-Loader patch\n", + exe, OMAP_BASE_ADDRESS, OMAP_VENDOR_ID, PROG_NAME, exe, exe, exe + ); +} + +static void license(void) +{ + printf( +"Copyright (C) 2008 Martin Mueller <martinmm@pfump.org>\n" +"Copyright (C) 2014 Grant Hernandez <grant.h.hernandez@gmail.com>\n" +"License GPLv2: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n" +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n" + ); +} + +int main(int argc, char *argv[]) +{ + int opt; + bool gotfile = false; + bool gotjump = false; + int filecount = 0; + char *exe = NULL; + + /* temporary local file object */ + struct file_upload file; + /* total arg state */ + struct arg_state *args = calloc(1, sizeof (*args)); + + if (argc < 1) { + log_error("invalid arguments (no argv[0])\n"); + return 1; + } + + exe = argv[0]; + + fprintf(stdout, "%s %s\n", PROG_NAME, VERSION); + + /* set the default vendor and product */ + args->vendor = OMAP_VENDOR_ID; + args->product = 0; + + while ((opt = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) { + switch (opt) { + case 0: + if (do_version) { + license(); + return 0; + } + break; + case 'f': + if (gotfile) { + log_error("missing address argument (-a) for file \'%s\'\n", + file.path); + usage(exe); + return 1; + } + + file.path = strdup(optarg); + + /* necessary to be sure that we own all the memory + and that the path input can be modified */ + char *tmpPath = strdup(file.path); + file.basename = strdup(basename(tmpPath)); + free(tmpPath); + + filecount++; + + /* the first file gets uploaded to a fixed address + as specified by the technical reference manual */ + if (filecount == 1) { + file.addr = OMAP_BASE_ADDRESS; + + /* commit the file object with the processor specified base address */ + args->files = realloc(args->files, filecount); + args->numfiles = filecount; + args->files[filecount - 1] = malloc(sizeof (file)); + memcpy(args->files[filecount - 1], &file, sizeof (file)); + } else { + /* commit only after an address is specified */ + gotfile = true; + } + break; + case 'a': + if (!gotfile) { + log_error + ("missing file argument (-f) before address \'%s\'\n", + optarg); + usage(exe); + return 1; + } + + /* passing 0 to strtoul enables detection of the 0x prefix with + base-10 fallback if missing */ + file.addr = strtoul(optarg, NULL, 0); + + /* commit the file object */ + args->files = realloc(args->files, filecount); + args->numfiles = filecount; + args->files[filecount - 1] = malloc(sizeof(file)); + memcpy(args->files[filecount - 1], &file, sizeof(file)); + + gotfile = false; + break; + case 'j': + args->jumptarget = strtoul(optarg, NULL, 0); + gotjump = true; + break; + case 'i': + args->vendor = (uint16_t)strtoul(optarg, NULL, 0); + break; + case 'p': + args->product = (uint16_t)strtoul(optarg, NULL, 0); + break; + case 'v': + g_verbose++; + break; + case 'h': + usage(exe); + return 0; + default: + usage(exe); + return 1; + } + } + + if (gotfile) { + log_error("got file \'%s\', but no address!\n", file.path); + usage(exe); + return 1; + } + + if (args->numfiles <= 0) { + log_error("at least one file needs to be specified\n"); + usage(exe); + return 1; + } + + if (args->numfiles == 1 && gotjump) { + log_info + ("WARNING: jump target 0x%08x specified, but will never be taken " + "(more than one file required)\n", args->jumptarget); + } else if (args->numfiles > 1 && !gotjump) { + log_info + ("WARNING: no jump target specified. Defaulting to the first " + "file's (\'%s\') address 0x%08x\n", + args->files[1]->basename, args->files[1]->addr); + args->jumptarget = args->files[1]->addr; + } + + return process_args(args); +} |