diff options
333 files changed, 7743 insertions, 4068 deletions
@@ -13,6 +13,11 @@ Eric Bénard <eric@eukrea.com> Franck Jullien <franck.jullien@gmail.com> Jin Zhengxiong <Jason.Jin@freescale.com> Juergen Borleis <jbe@pengutronix.de> +Juergen Borleis <j.beisert@pengutronix.de> +Juergen Borleis <jbe@isonoe.(none)> +Juergen Borleis <jbe@kreuzholzen.de> +Juergen Borleis <jbe@octopus.labnet.pengutronix.de> +Juergen Borleis <juergen@kreuzholzen.de> Marc Reilly <marc@cpdesign.com.au> Nishanth Menon <x0nishan@ti.com> Raphaël Poggi <poggi.raph@gmail.com> diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst index 466f69c5ba..837bf5cf32 100644 --- a/Documentation/boards/imx.rst +++ b/Documentation/boards/imx.rst @@ -46,6 +46,33 @@ 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: + +* i.MX51 + +As can be easily deduced from its name, the Internal Boot Mode Through +Internal RAM is just a variant of Internal Boot Mode so all of the +stated above still applies in this case. What it differs in is the following: + +* Boot process is done in two stages(First stage binary can be + produced with ``imx_v7-xload_defconfig``) +* DCD of the first stage image is set such that the image is fetched + into an unoccupied area or IRAM +* First stage image once uncompressed and set up will look for a + second stage bootloader on the same media it booted from and start + it(see mach-imx/xload.c for more details) +* Second stage images are just regular i.MX boot images + +Since on a typical i.MX SoC unused IRAM area is not enough to run +anything but a PBL this mode, due to its very limited usability, +serves only one purpose -- allow for a portion of a bootloader to be +executed without depending on DRAM to be functional. This peculiarity +of the mode can be used to implement various memory testing +scenarious. + USB Boot ^^^^^^^^ diff --git a/Documentation/boards/socfpga.rst b/Documentation/boards/socfpga.rst index e956bccbe2..358e5ab910 100644 --- a/Documentation/boards/socfpga.rst +++ b/Documentation/boards/socfpga.rst @@ -11,10 +11,34 @@ build the ``socfpga-xload_defconfig``; for second stage use the normal Bootstrapping ------------- -The supported bootsource is a SD card. The Boot ROM searches for a partition of -type A2 and loads what it finds there. When barebox is placed in such a partition -it will then itself try and mount the second partition of the SD card, which must -be of type FAT32. On this partition barebox searches for a file called barebox.bin. +The supported bootsources are: SD card and QSPI. + +Bootsource selection +^^^^^^^^^^^^^^^^^^^^ + ++--------------+-----------+-----------+ +| Board | BSEL[2:0] | CSEL[1:0] | ++==============+===========+===========+ +| Sockit SD | 0b100 | 0b00 | ++--------------+-----------+-----------+ +| Sockit QSPI | 0b110 | 0b00 | ++--------------+-----------+-----------+ +| Socrates SD | 0b101 | 0b11 | ++--------------+-----------+-----------+ +| Socrates QSPI| 0b111 | 0b11 | ++--------------+-----------+-----------+ +| SocDK SD | 0b100 | 0b00 | ++--------------+-----------+-----------+ +| SocDK QSPI | 0b110 | 0b00 | ++--------------+-----------+-----------+ + +SD card +^^^^^^^ + +The Boot ROM searches for a partition of type A2 and loads what it finds there. +When barebox is placed in such a partition it will then itself try and mount the +second partition of the SD card, which must be of type FAT32. On this partition +barebox searches for a file called barebox.bin. To boot barebox on a Terasic SoCkit, the procedure is as follows (sdb1 is the A2 and sdb2 the FAT32 partition):: @@ -34,6 +58,30 @@ proceed with:: For the EBV Socrates use ``images/barebox-socfpga-socrates(-xload).img`` instead. +QSPI +^^^^ + +The Boot ROM loads the preloader starting from address 0x0 on the QSPI flash. +barebox then searches for a barebox image at the 256K offset and loads it. + +The default bootsource is SD card, so to change that to QSPI, you have to:: + + make socfpga-xload_defconfig + make menuconfig + +And then select the options `MTD` and `SPI_CADENCE_QUADSPI`. Now:: + + make + cat images/barebox-socfpga-<board>-xload.img > /dev/mtd0 + +For barebox itself, the build step is like for SD card. The resulting image has to be +written to the offset 256K. + +Warning! There is a known issue with booting from QSPI and doing Cold/Warm-Resets. +Please consult `Rocketboards <http://rocketboards.org/foswiki/Documentation/SocBoardQspiBoot#Serial_Flash_Challenges>`_ +to see how to fix this. + + Updating handoff files ---------------------- diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst index 42b2a34d3a..3d664f1f02 100644 --- a/Documentation/devicetree/bindings/barebox/barebox,state.rst +++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst @@ -1,4 +1,6 @@ -barebox,state +.. _barebox,state: + +barebox state ============= Overview @@ -27,9 +29,6 @@ Required properties: * ``compatible``: should be ``barebox,state``; * ``magic``: A 32bit number used as a magic to identify the state - -Optional properties: - * ``backend``: describes where the data for this state is stored * ``backend-type``: should be ``raw`` or ``dtb``. @@ -40,9 +39,9 @@ These are subnodes of a state node each describing a single 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: ``uint32``, -``enum32`` and ``mac`` address. Fixed length strings are planned but -not implemented. Variable length strings are not planned. +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. Required properties: @@ -50,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 ``uint32``, ``enum32`` or ``mac`` for the type - of the variable +* ``type``: Should be ``uint8``, ``uint32``, ``enum32`` or ``mac`` for + the type of the variable * ``names``: For ``enum32`` values only, this specifies the values possible for ``enum32``. @@ -71,15 +70,15 @@ Example:: foo { reg = <0x00 0x4>; - type = "u32"; + type = "uint32"; default = <0x0>; }; bar { reg = <0x10 0x4>; - type = "enum32"; + type = "enum32"; names = "baz", "qux"; - default ="qux"; + default = <1>; }; }; diff --git a/Documentation/user/booting-linux.rst b/Documentation/user/booting-linux.rst index ac44cbad62..6e7d1550bf 100644 --- a/Documentation/user/booting-linux.rst +++ b/Documentation/user/booting-linux.rst @@ -55,12 +55,13 @@ to free the internal devicetree before calling ``bootm`` Passing Kernel Arguments ^^^^^^^^^^^^^^^^^^^^^^^^ -Depending on the barebox configuration (``CONFIG_FLEXIBLE_BOOTARGS``) there -are to ways to pass bootargs to the Kernel. With ``CONFIG_FLEXIBLE_BOOTARGS`` -disabled the bootm command takes the bootargs from the ``bootargs`` environment -variable. With ``CONFIG_FLEXIBLE_BOOTARGS`` enabled the bootargs are composed -from different :ref:`global_device` variables. All variables beginning with -``global.linux.bootargs.`` will be concatenated to the bootargs: +The simple method to pass bootargs to the kernel is with +``CONFIG_FLEXIBLE_BOOTARGS`` disabled: in this case the bootm command +takes the bootargs from the ``bootargs`` environment variable. + +With ``CONFIG_FLEXIBLE_BOOTARGS`` enabled, the bootargs are composed +from different :ref:`global device<global_device>` variables. All variables beginning +with ``global.linux.bootargs.`` will be concatenated to the bootargs: .. code-block:: sh 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/usb.rst b/Documentation/user/usb.rst index 0ff982bac4..9eb1437135 100644 --- a/Documentation/user/usb.rst +++ b/Documentation/user/usb.rst @@ -101,7 +101,7 @@ Android Fastboot support barebox has support for the android fastboot protocol. There is no dedicated command for initializing the fastboot protocol, instead it is integrated into the Multifunction -Composite Gadget, see :`ref:command_usbgadget` for a usage description. +Composite Gadget, see :ref:`command_usbgadget` for a usage description. The Fastboot gadget supports the following commands: 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 @@ -700,7 +700,7 @@ OBJCOPYFLAGS_barebox.bin = -O binary barebox.bin: barebox FORCE $(call if_changed,objcopy) ifndef CONFIG_PBL_IMAGE - $(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE)) + $(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE)) endif # By default the uImage load address is 2MB below CONFIG_TEXT_BASE, diff --git a/arch/arm/boards/beagle/board.c b/arch/arm/boards/beagle/board.c index 775621069c..c56205e05c 100644 --- a/arch/arm/boards/beagle/board.c +++ b/arch/arm/boards/beagle/board.c @@ -21,6 +21,8 @@ #include <driver.h> #include <linux/sizes.h> #include <io.h> +#include <bbu.h> +#include <filetype.h> #include <ns16550.h> #include <asm/armlinux.h> #include <generated/mach-types.h> @@ -107,6 +109,11 @@ static int beagle_devices_init(void) armlinux_set_architecture(MACH_TYPE_OMAP3_BEAGLE); + bbu_register_std_file_update("nand-xload", 0, + "/dev/nand0.xload.bb", filetype_ch_image); + bbu_register_std_file_update("nand", 0, + "/dev/nand0.barebox.bb", filetype_arm_barebox); + return 0; } device_initcall(beagle_devices_init); diff --git a/arch/arm/boards/eltec-hipercam/lowlevel.c b/arch/arm/boards/eltec-hipercam/lowlevel.c index 8f11f6796f..21542e49e9 100644 --- a/arch/arm/boards/eltec-hipercam/lowlevel.c +++ b/arch/arm/boards/eltec-hipercam/lowlevel.c @@ -24,18 +24,10 @@ static void setup_uart(void) { - void __iomem *uart_base = (void *)0x02020000; - writel(0x1, 0x020e0330); - writel(0x00000000, uart_base + 0x80); - writel(0x00004027, uart_base + 0x84); - writel(0x00000704, uart_base + 0x88); - writel(0x00000a81, uart_base + 0x90); - writel(0x0000002b, uart_base + 0x9c); - writel(0x00013880, uart_base + 0xb0); - writel(0x0000047f, uart_base + 0xa4); - writel(0x0000c34f, uart_base + 0xa8); - writel(0x00000001, uart_base + 0x80); + + imx6_uart_setup_ll(); + putc_ll('>'); } @@ -48,7 +40,9 @@ ENTRY_FUNCTION(start_imx6dl_eltec_hipercam, r0, r1, r2) imx6_cpu_lowlevel_init(); arm_setup_stack(0x00940000 - 8); - setup_uart(); + + if (IS_ENABLED(CONFIG_DEBUG_LL)) + setup_uart(); fdt = __dtb_imx6dl_eltec_hipercam_start - get_runtime_offset(); diff --git a/arch/arm/boards/embest-riotboard/lowlevel.c b/arch/arm/boards/embest-riotboard/lowlevel.c index fe21b9aadc..59010da511 100644 --- a/arch/arm/boards/embest-riotboard/lowlevel.c +++ b/arch/arm/boards/embest-riotboard/lowlevel.c @@ -10,20 +10,6 @@ #include <mach/imx6-mmdc.h> #include <mach/imx6.h> -static inline void setup_uart(void) -{ - /* Enable UART for lowlevel debugging purposes */ - writel(0x00000000, 0x021e8080); - writel(0x00004027, 0x021e8084); - writel(0x00000704, 0x021e8088); - writel(0x00000a81, 0x021e8090); - writel(0x0000002b, 0x021e809c); - writel(0x00013880, 0x021e80b0); - writel(0x0000047f, 0x021e80a4); - writel(0x0000c34f, 0x021e80a8); - writel(0x00000001, 0x021e8080); -} - extern char __dtb_imx6s_riotboard_start[]; ENTRY_FUNCTION(start_imx6s_riotboard, r0, r1, r2) @@ -34,7 +20,7 @@ ENTRY_FUNCTION(start_imx6s_riotboard, r0, r1, r2) if (IS_ENABLED(CONFIG_DEBUG_LL)) { writel(0x4, 0x020e016c); - setup_uart(); + imx6_uart_setup_ll(); putc_ll('a'); } diff --git a/arch/arm/boards/freescale-mx51-babbage/Makefile b/arch/arm/boards/freescale-mx51-babbage/Makefile index 6252c88631..31b8fcd8a2 100644 --- a/arch/arm/boards/freescale-mx51-babbage/Makefile +++ b/arch/arm/boards/freescale-mx51-babbage/Makefile @@ -1,3 +1,6 @@ obj-y += board.o flash-header-imx51-babbage.dcd.o extra-y += flash-header-imx51-babbage.dcd.S flash-header-imx51-babbage.dcd lwl-y += lowlevel.o + +obj-$(CONFIG_ARCH_IMX_XLOAD) += flash-header-imx51-babbage-xload.dcd.o +extra-$(CONFIG_ARCH_IMX_XLOAD) += flash-header-imx51-babbage-xload.dcd.S flash-header-imx51-babbage-xload.dcd diff --git a/arch/arm/boards/freescale-mx51-babbage/board.c b/arch/arm/boards/freescale-mx51-babbage/board.c index 001873b01c..6650ff3408 100644 --- a/arch/arm/boards/freescale-mx51-babbage/board.c +++ b/arch/arm/boards/freescale-mx51-babbage/board.c @@ -169,3 +169,63 @@ static int imx51_babbage_init(void) return 0; } coredevice_initcall(imx51_babbage_init); + +#ifdef CONFIG_ARCH_IMX_XLOAD + +static int imx51_babbage_xload_init_pinmux(void) +{ + static const iomux_v3_cfg_t pinmux[] = { + /* (e)CSPI */ + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI, + MX51_PAD_CSPI1_MISO__ECSPI1_MISO, + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK, + + /* (e)CSPI chip select lines */ + MX51_PAD_CSPI1_SS1__GPIO4_25, + + + /* eSDHC 1 */ + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + }; + + mxc_iomux_v3_setup_multiple_pads(ARRAY_AND_SIZE(pinmux)); + + return 0; +} +coredevice_initcall(imx51_babbage_xload_init_pinmux); + +static int imx51_babbage_xload_init_devices(void) +{ + static int spi0_chipselects[] = { + IMX_GPIO_NR(4, 25), + }; + + static struct spi_imx_master spi0_pdata = { + .chipselect = spi0_chipselects, + .num_chipselect = ARRAY_SIZE(spi0_chipselects), + }; + + static const struct spi_board_info spi0_devices[] = { + { + .name = "mtd_dataflash", + .chip_select = 0, + .max_speed_hz = 25 * 1000 * 1000, + .bus_num = 0, + }, + }; + + imx51_add_mmc0(NULL); + + spi_register_board_info(ARRAY_AND_SIZE(spi0_devices)); + imx51_add_spi0(&spi0_pdata); + + return 0; +} +device_initcall(imx51_babbage_xload_init_devices); + +#endif diff --git a/arch/arm/boards/freescale-mx51-babbage/flash-header-common.imxcfg b/arch/arm/boards/freescale-mx51-babbage/flash-header-common.imxcfg new file mode 100644 index 0000000000..1332b74707 --- /dev/null +++ b/arch/arm/boards/freescale-mx51-babbage/flash-header-common.imxcfg @@ -0,0 +1,58 @@ +soc imx51 +dcdofs 0x400 +wm 32 0x73fa88a0 0x00000200 +wm 32 0x73fa850c 0x000020c5 +wm 32 0x73fa8510 0x000020c5 +wm 32 0x73fa883c 0x00000002 +wm 32 0x73fa8848 0x00000002 +wm 32 0x73fa84b8 0x000000e7 +wm 32 0x73fa84bc 0x00000045 +wm 32 0x73fa84c0 0x00000045 +wm 32 0x73fa84c4 0x00000045 +wm 32 0x73fa84c8 0x00000045 +wm 32 0x73fa8820 0x00000000 +wm 32 0x73fa84a4 0x00000003 +wm 32 0x73fa84a8 0x00000003 +wm 32 0x73fa84ac 0x000000e3 +wm 32 0x73fa84b0 0x000000e3 +wm 32 0x73fa84b4 0x000000e3 +wm 32 0x73fa84cc 0x000000e3 +wm 32 0x73fa84d0 0x000000e2 +wm 32 0x73fa882c 0x00000004 +wm 32 0x73fa88a4 0x00000004 +wm 32 0x73fa88ac 0x00000004 +wm 32 0x73fa88b8 0x00000004 +wm 32 0x83fd9000 0x82a20000 +wm 32 0x83fd9008 0x82a20000 +wm 32 0x83fd9010 0x000ad0d0 +wm 32 0x83fd9004 0x3f3584ab +wm 32 0x83fd900c 0x3f3584ab +wm 32 0x83fd9014 0x04008008 +wm 32 0x83fd9014 0x0000801a +wm 32 0x83fd9014 0x0000801b +wm 32 0x83fd9014 0x00448019 +wm 32 0x83fd9014 0x07328018 +wm 32 0x83fd9014 0x04008008 +wm 32 0x83fd9014 0x00008010 +wm 32 0x83fd9014 0x00008010 +wm 32 0x83fd9014 0x06328018 +wm 32 0x83fd9014 0x03808019 +wm 32 0x83fd9014 0x00408019 +wm 32 0x83fd9014 0x00008000 +wm 32 0x83fd9014 0x0400800c +wm 32 0x83fd9014 0x0000801e +wm 32 0x83fd9014 0x0000801f +wm 32 0x83fd9014 0x0000801d +wm 32 0x83fd9014 0x0732801c +wm 32 0x83fd9014 0x0400800c +wm 32 0x83fd9014 0x00008014 +wm 32 0x83fd9014 0x00008014 +wm 32 0x83fd9014 0x0632801c +wm 32 0x83fd9014 0x0380801d +wm 32 0x83fd9014 0x0040801d +wm 32 0x83fd9014 0x00008004 +wm 32 0x83fd9000 0xb2a20000 +wm 32 0x83fd9008 0xb2a20000 +wm 32 0x83fd9010 0x000ad6d0 +wm 32 0x83fd9034 0x90000000 +wm 32 0x83fd9014 0x00000000 diff --git a/arch/arm/boards/freescale-mx51-babbage/flash-header-imx51-babbage-xload.imxcfg b/arch/arm/boards/freescale-mx51-babbage/flash-header-imx51-babbage-xload.imxcfg new file mode 100644 index 0000000000..b249a7d4bc --- /dev/null +++ b/arch/arm/boards/freescale-mx51-babbage/flash-header-imx51-babbage-xload.imxcfg @@ -0,0 +1,3 @@ +loadaddr CONFIG_ARCH_IMX_UNUSED_IRAM_BASE + +#include "flash-header-common.imxcfg"
\ No newline at end of file diff --git a/arch/arm/boards/freescale-mx51-babbage/flash-header-imx51-babbage.imxcfg b/arch/arm/boards/freescale-mx51-babbage/flash-header-imx51-babbage.imxcfg index bac6816fee..cb60e4752a 100644 --- a/arch/arm/boards/freescale-mx51-babbage/flash-header-imx51-babbage.imxcfg +++ b/arch/arm/boards/freescale-mx51-babbage/flash-header-imx51-babbage.imxcfg @@ -1,59 +1,3 @@ loadaddr 0x90000000 -soc imx51 -dcdofs 0x400 -wm 32 0x73fa88a0 0x00000200 -wm 32 0x73fa850c 0x000020c5 -wm 32 0x73fa8510 0x000020c5 -wm 32 0x73fa883c 0x00000002 -wm 32 0x73fa8848 0x00000002 -wm 32 0x73fa84b8 0x000000e7 -wm 32 0x73fa84bc 0x00000045 -wm 32 0x73fa84c0 0x00000045 -wm 32 0x73fa84c4 0x00000045 -wm 32 0x73fa84c8 0x00000045 -wm 32 0x73fa8820 0x00000000 -wm 32 0x73fa84a4 0x00000003 -wm 32 0x73fa84a8 0x00000003 -wm 32 0x73fa84ac 0x000000e3 -wm 32 0x73fa84b0 0x000000e3 -wm 32 0x73fa84b4 0x000000e3 -wm 32 0x73fa84cc 0x000000e3 -wm 32 0x73fa84d0 0x000000e2 -wm 32 0x73fa882c 0x00000004 -wm 32 0x73fa88a4 0x00000004 -wm 32 0x73fa88ac 0x00000004 -wm 32 0x73fa88b8 0x00000004 -wm 32 0x83fd9000 0x82a20000 -wm 32 0x83fd9008 0x82a20000 -wm 32 0x83fd9010 0x000ad0d0 -wm 32 0x83fd9004 0x3f3584ab -wm 32 0x83fd900c 0x3f3584ab -wm 32 0x83fd9014 0x04008008 -wm 32 0x83fd9014 0x0000801a -wm 32 0x83fd9014 0x0000801b -wm 32 0x83fd9014 0x00448019 -wm 32 0x83fd9014 0x07328018 -wm 32 0x83fd9014 0x04008008 -wm 32 0x83fd9014 0x00008010 -wm 32 0x83fd9014 0x00008010 -wm 32 0x83fd9014 0x06328018 -wm 32 0x83fd9014 0x03808019 -wm 32 0x83fd9014 0x00408019 -wm 32 0x83fd9014 0x00008000 -wm 32 0x83fd9014 0x0400800c -wm 32 0x83fd9014 0x0000801e -wm 32 0x83fd9014 0x0000801f -wm 32 0x83fd9014 0x0000801d -wm 32 0x83fd9014 0x0732801c -wm 32 0x83fd9014 0x0400800c -wm 32 0x83fd9014 0x00008014 -wm 32 0x83fd9014 0x00008014 -wm 32 0x83fd9014 0x0632801c -wm 32 0x83fd9014 0x0380801d -wm 32 0x83fd9014 0x0040801d -wm 32 0x83fd9014 0x00008004 -wm 32 0x83fd9000 0xb2a20000 -wm 32 0x83fd9008 0xb2a20000 -wm 32 0x83fd9010 0x000ad6d0 -wm 32 0x83fd9034 0x90000000 -wm 32 0x83fd9014 0x00000000 + +#include "flash-header-common.imxcfg"
\ No newline at end of file diff --git a/arch/arm/boards/freescale-mx51-babbage/lowlevel.c b/arch/arm/boards/freescale-mx51-babbage/lowlevel.c index 0f453f3367..af40f4405e 100644 --- a/arch/arm/boards/freescale-mx51-babbage/lowlevel.c +++ b/arch/arm/boards/freescale-mx51-babbage/lowlevel.c @@ -1,9 +1,42 @@ +#include <debug_ll.h> +#include <mach/clock-imx51_53.h> #include <common.h> #include <mach/esdctl.h> #include <mach/generic.h> +#include <asm/cache.h> #include <asm/barebox-arm-head.h> #include <asm/barebox-arm.h> +static inline void setup_uart(void) +{ + void __iomem *iomuxbase = IOMEM(MX51_IOMUXC_BASE_ADDR); + void __iomem *ccmbase = IOMEM(MX51_CCM_BASE_ADDR); + + /* + * Restore CCM values that might be changed by the Mask ROM + * code. + * + * Source: RealView debug scripts provided by Freescale + */ + writel(MX5_CCM_CBCDR_RESET_VALUE, ccmbase + MX5_CCM_CBCDR); + writel(MX5_CCM_CSCMR1_RESET_VALUE, ccmbase + MX5_CCM_CSCMR1); + writel(MX5_CCM_CSCDR1_RESET_VALUE, ccmbase + MX5_CCM_CSCDR1); + + /* + * The code below should be more or less a "moral equivalent" + * of: + * MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 + * + * in device tree + */ + writel(0x00000000, iomuxbase + 0x022c); + writel(0x000001c5, iomuxbase + 0x061c); + + imx51_uart_setup_ll(); + + putc_ll('>'); +} + extern char __dtb_imx51_babbage_start[]; ENTRY_FUNCTION(start_imx51_babbage, r0, r1, r2) @@ -11,9 +44,37 @@ ENTRY_FUNCTION(start_imx51_babbage, r0, r1, r2) void *fdt; imx5_cpu_lowlevel_init(); + + if (IS_ENABLED(CONFIG_DEBUG_LL)) + setup_uart(); + arm_setup_stack(0x20000000 - 16); fdt = __dtb_imx51_babbage_start - get_runtime_offset(); imx51_barebox_entry(fdt); } + +static noinline void babbage_entry(void) +{ + arm_early_mmu_cache_invalidate(); + + relocate_to_current_adr(); + setup_c(); + + puts_ll("lowlevel init done\n"); + + imx51_barebox_entry(NULL); +} + +ENTRY_FUNCTION(start_imx51_babbage_xload, r0, r1, r2) +{ + imx5_cpu_lowlevel_init(); + + if (IS_ENABLED(CONFIG_DEBUG_LL)) + setup_uart(); + + arm_setup_stack(0x20000000 - 16); + + babbage_entry(); +} 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/freescale-mx6sx-sabresdb/lowlevel.c b/arch/arm/boards/freescale-mx6sx-sabresdb/lowlevel.c index 4c5a74ea63..af26557e90 100644 --- a/arch/arm/boards/freescale-mx6sx-sabresdb/lowlevel.c +++ b/arch/arm/boards/freescale-mx6sx-sabresdb/lowlevel.c @@ -21,32 +21,16 @@ static inline void setup_uart(void) { - void __iomem *ccmbase = (void *)MX6_CCM_BASE_ADDR; - void __iomem *uartbase = (void *)MX6_UART1_BASE_ADDR; void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR; - writel(0xffffffff, ccmbase + 0x68); - writel(0xffffffff, ccmbase + 0x6c); - writel(0xffffffff, ccmbase + 0x70); - writel(0xffffffff, ccmbase + 0x74); - writel(0xffffffff, ccmbase + 0x78); - writel(0xffffffff, ccmbase + 0x7c); - writel(0xffffffff, ccmbase + 0x80); + imx6_ungate_all_peripherals(); writel(0x0, iomuxbase + 0x24); writel(0x1b0b1, iomuxbase + 0x036C); writel(0x0, iomuxbase + 0x28); writel(0x1b0b1, iomuxbase + 0x0370); - writel(0x00000000, uartbase + 0x80); - writel(0x00004027, uartbase + 0x84); - writel(0x00000784, uartbase + 0x88); - writel(0x00000a81, uartbase + 0x90); - writel(0x0000002b, uartbase + 0x9c); - writel(0x0001b0b0, uartbase + 0xb0); - writel(0x0000047f, uartbase + 0xa4); - writel(0x0000c34f, uartbase + 0xa8); - writel(0x00000001, uartbase + 0x80); + imx6_uart_setup_ll(); putc_ll('>'); } diff --git a/arch/arm/boards/guf-santaro/lowlevel.c b/arch/arm/boards/guf-santaro/lowlevel.c index 7753cea4e2..e2b6df5839 100644 --- a/arch/arm/boards/guf-santaro/lowlevel.c +++ b/arch/arm/boards/guf-santaro/lowlevel.c @@ -9,20 +9,12 @@ static inline void setup_uart(void) { - void __iomem *uartbase = (void *)MX6_UART2_BASE_ADDR; void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR; writel(0x1, iomuxbase + 0x2b0); - writel(0x00000000, uartbase + 0x80); - writel(0x00004027, uartbase + 0x84); - writel(0x00000704, uartbase + 0x88); - writel(0x00000a81, uartbase + 0x90); - writel(0x0000002b, uartbase + 0x9c); - writel(0x00013880, uartbase + 0xb0); - writel(0x0000047f, uartbase + 0xa4); - writel(0x0000c34f, uartbase + 0xa8); - writel(0x00000001, uartbase + 0x80); + imx6_ungate_all_peripherals(); + imx6_uart_setup_ll(); putc_ll('>'); } @@ -32,16 +24,13 @@ extern char __dtb_imx6q_guf_santaro_start[]; ENTRY_FUNCTION(start_imx6q_guf_santaro, r0, r1, r2) { void *fdt; - int i; imx6_cpu_lowlevel_init(); arm_setup_stack(0x00920000 - 8); - for (i = 0x68; i <= 0x80; i += 4) - writel(0xffffffff, MX6_CCM_BASE_ADDR + i); - - setup_uart(); + if (IS_ENABLED(CONFIG_DEBUG_LL)) + setup_uart(); fdt = __dtb_imx6q_guf_santaro_start - get_runtime_offset(); diff --git a/arch/arm/boards/karo-tx6x/lowlevel.c b/arch/arm/boards/karo-tx6x/lowlevel.c index cd4be5e9e7..1e44b1b38d 100644 --- a/arch/arm/boards/karo-tx6x/lowlevel.c +++ b/arch/arm/boards/karo-tx6x/lowlevel.c @@ -22,8 +22,6 @@ static inline void setup_uart(void) { - void __iomem *ccmbase = (void *)MX6_CCM_BASE_ADDR; - void __iomem *uartbase = (void *)MX6_UART1_BASE_ADDR; void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR; writel(0x1, iomuxbase + 0x0314); @@ -31,23 +29,8 @@ static inline void setup_uart(void) writel(0x1, iomuxbase + 0x0330); writel(0x1, iomuxbase + 0x032c); - writel(0xffffffff, ccmbase + 0x68); - writel(0xffffffff, ccmbase + 0x6c); - writel(0xffffffff, ccmbase + 0x70); - writel(0xffffffff, ccmbase + 0x74); - writel(0xffffffff, ccmbase + 0x78); - writel(0xffffffff, ccmbase + 0x7c); - writel(0xffffffff, ccmbase + 0x80); - - writel(0x00000000, uartbase + 0x80); - writel(0x00004027, uartbase + 0x84); - writel(0x00000784, uartbase + 0x88); - writel(0x00000a81, uartbase + 0x90); - writel(0x0000002b, uartbase + 0x9c); - writel(0x0001b0b0, uartbase + 0xb0); - writel(0x0000047f, uartbase + 0xa4); - writel(0x0000c34f, uartbase + 0xa8); - writel(0x00000001, uartbase + 0x80); + imx6_ungate_all_peripherals(); + imx6_uart_setup_ll(); putc_ll('>'); } diff --git a/arch/arm/boards/phytec-phycard-imx6/lowlevel.c b/arch/arm/boards/phytec-phycard-imx6/lowlevel.c index dc106490e7..d85a1ab0a1 100644 --- a/arch/arm/boards/phytec-phycard-imx6/lowlevel.c +++ b/arch/arm/boards/phytec-phycard-imx6/lowlevel.c @@ -26,29 +26,12 @@ static inline void setup_uart(void) { - void __iomem *ccmbase = IOMEM(MX6_CCM_BASE_ADDR); - void __iomem *uartbase = IOMEM(MX6_UART3_BASE_ADDR); void __iomem *iomuxbase = IOMEM(MX6_IOMUXC_BASE_ADDR); writel(0x4, iomuxbase + 0x01f8); - writel(0xffffffff, ccmbase + 0x68); - writel(0xffffffff, ccmbase + 0x6c); - writel(0xffffffff, ccmbase + 0x70); - writel(0xffffffff, ccmbase + 0x74); - writel(0xffffffff, ccmbase + 0x78); - writel(0xffffffff, ccmbase + 0x7c); - writel(0xffffffff, ccmbase + 0x80); - - writel(0x00000000, uartbase + 0x80); - writel(0x00004027, uartbase + 0x84); - writel(0x00000704, uartbase + 0x88); - writel(0x00000a81, uartbase + 0x90); - writel(0x0000002b, uartbase + 0x9c); - writel(0x00013880, uartbase + 0xb0); - writel(0x0000047f, uartbase + 0xa4); - writel(0x0000c34f, uartbase + 0xa8); - writel(0x00000001, uartbase + 0x80); + imx6_ungate_all_peripherals(); + imx6_uart_setup_ll(); putc_ll('>'); } diff --git a/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c b/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c index ee6d7fb262..cd37f88e05 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c +++ b/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c @@ -27,29 +27,12 @@ static inline void setup_uart(void) { - void __iomem *ccmbase = (void *)MX6_CCM_BASE_ADDR; - void __iomem *uartbase = (void *)MX6_UART4_BASE_ADDR; void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR; writel(0x4, iomuxbase + 0x01f8); - writel(0xffffffff, ccmbase + 0x68); - writel(0xffffffff, ccmbase + 0x6c); - writel(0xffffffff, ccmbase + 0x70); - writel(0xffffffff, ccmbase + 0x74); - writel(0xffffffff, ccmbase + 0x78); - writel(0xffffffff, ccmbase + 0x7c); - writel(0xffffffff, ccmbase + 0x80); - - writel(0x00000000, uartbase + 0x80); - writel(0x00004027, uartbase + 0x84); - writel(0x00000704, uartbase + 0x88); - writel(0x00000a81, uartbase + 0x90); - writel(0x0000002b, uartbase + 0x9c); - writel(0x00013880, uartbase + 0xb0); - writel(0x0000047f, uartbase + 0xa4); - writel(0x0000c34f, uartbase + 0xa8); - writel(0x00000001, uartbase + 0x80); + imx6_ungate_all_peripherals(); + imx6_uart_setup_ll(); putc_ll('>'); } 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/boards/tqma6x/lowlevel.c b/arch/arm/boards/tqma6x/lowlevel.c index 23f3407c05..aec84b176b 100644 --- a/arch/arm/boards/tqma6x/lowlevel.c +++ b/arch/arm/boards/tqma6x/lowlevel.c @@ -24,20 +24,6 @@ #include <mach/imx6-mmdc.h> #include <mach/imx6.h> -static inline void setup_uart(void) -{ - /* Enable UART for lowlevel debugging purposes */ - writel(0x00000000, 0x021e8080); - writel(0x00004027, 0x021e8084); - writel(0x00000704, 0x021e8088); - writel(0x00000a81, 0x021e8090); - writel(0x0000002b, 0x021e809c); - writel(0x00013880, 0x021e80b0); - writel(0x0000047f, 0x021e80a4); - writel(0x0000c34f, 0x021e80a8); - writel(0x00000001, 0x021e8080); -} - extern char __dtb_imx6q_mba6x_start[]; extern char __dtb_imx6dl_mba6x_start[]; @@ -51,7 +37,7 @@ ENTRY_FUNCTION(start_imx6q_mba6x, r0, r1, r2) if (IS_ENABLED(CONFIG_DEBUG_LL)) { writel(0x2, 0x020e0338); - setup_uart(); + imx6_uart_setup_ll(); putc_ll('a'); } @@ -72,7 +58,7 @@ ENTRY_FUNCTION(start_imx6dl_mba6x, r0, r1, r2) if (IS_ENABLED(CONFIG_DEBUG_LL)) { writel(0x2, 0x020e035c); - setup_uart(); + imx6_uart_setup_ll(); putc_ll('a'); } diff --git a/arch/arm/boards/variscite-mx6/lowlevel.c b/arch/arm/boards/variscite-mx6/lowlevel.c index 22e7eae32b..b0b930d438 100644 --- a/arch/arm/boards/variscite-mx6/lowlevel.c +++ b/arch/arm/boards/variscite-mx6/lowlevel.c @@ -28,30 +28,13 @@ static inline void setup_uart(void) { - void __iomem *ccmbase = (void *)MX6_CCM_BASE_ADDR; - void __iomem *uartbase = (void *)MX6_UART1_BASE_ADDR; void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR; writel(0x03, iomuxbase + 0x0280); writel(0x03, iomuxbase + 0x0284); - writel(0xffffffff, ccmbase + 0x68); - writel(0xffffffff, ccmbase + 0x6c); - writel(0xffffffff, ccmbase + 0x70); - writel(0xffffffff, ccmbase + 0x74); - writel(0xffffffff, ccmbase + 0x78); - writel(0xffffffff, ccmbase + 0x7c); - writel(0xffffffff, ccmbase + 0x80); - - writel(0x00000000, uartbase + 0x80); - writel(0x00004027, uartbase + 0x84); - writel(0x00000704, uartbase + 0x88); - writel(0x00000a81, uartbase + 0x90); - writel(0x0000002b, uartbase + 0x9c); - writel(0x00013880, uartbase + 0xb0); - writel(0x0000047f, uartbase + 0xa4); - writel(0x0000c34f, uartbase + 0xa8); - writel(0x00000001, uartbase + 0x80); + imx6_ungate_all_peripherals(); + imx6_uart_setup_ll(); putc_ll('>'); } 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/imx_v7-xload_defconfig b/arch/arm/configs/imx_v7-xload_defconfig new file mode 100644 index 0000000000..1d82f98f49 --- /dev/null +++ b/arch/arm/configs/imx_v7-xload_defconfig @@ -0,0 +1,52 @@ +CONFIG_ARCH_IMX=y +CONFIG_ARCH_IMX_IMXIMAGE=y +CONFIG_ARCH_IMX_XLOAD=y + +CONFIG_ARCH_IMX51=y +CONFIG_IMX_MULTI_BOARDS=y +CONFIG_MACH_FREESCALE_MX51_PDK=y + +CONFIG_THUMB2_BAREBOX=y +# CONFIG_CMD_ARM_CPUINFO is not set +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_MMU=y +CONFIG_TEXT_BASE=0x0 +CONFIG_MALLOC_SIZE=0x0 +CONFIG_MALLOC_DUMMY=y +CONFIG_RELOCATABLE=y +CONFIG_BAUDRATE=115200 +CONFIG_SHELL_NONE=y + +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_IMX51_UART=y +CONFIG_DEBUG_IMX_UART_PORT=1 + +CONFIG_HAS_DEBUG_LL=y + +CONFIG_MTD=y +# CONFIG_MTD_WRITE is not set +CONFIG_MTD_DATAFLASH=y + +# CONFIG_ERRNO_MESSAGES is not set +# CONFIG_TIMESTAMP is not set +# CONFIG_DEFAULT_ENVIRONMENT is not set +CONFIG_DRIVER_SERIAL_IMX=y + +CONFIG_MCI=y +CONFIG_MCI_STARTUP=y +# CONFIG_MCI_WRITE is not set + +CONFIG_MCI_IMX_ESDHC=y + +CONFIG_EEPROM_AT25=y + +CONFIG_WATCHDOG_IMX_RESET_SOURCE=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_IMX=y + +# CONFIG_FS_RAMFS is not set +# CONFIG_FS_DEVFS is not set +CONFIG_FS_FAT=y +CONFIG_BOOTSTRAP=y +CONFIG_BOOTSTRAP_DISK=y +CONFIG_BOOTSTRAP_DEVFS=y diff --git a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig index bf04fa3b18..224854c7cc 100644 --- a/arch/arm/configs/lubbock_defconfig +++ b/arch/arm/configs/lubbock_defconfig @@ -6,7 +6,6 @@ CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y # CONFIG_BANNER is not set CONFIG_MMU=y -CONFIG_TEXT_BASE=0xa3d00000 CONFIG_BAREBOX_MAX_BARE_INIT_SIZE=0x80000 CONFIG_MALLOC_SIZE=0x1000000 CONFIG_EXPERIMENTAL=y diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index ca54a1a491..ec369ae42e 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -1,70 +1,68 @@ CONFIG_ARCH_SOCFPGA=y -CONFIG_ARCH_SOCFPGA_FPGA=y CONFIG_MACH_SOCFPGA_EBV_SOCRATES=y CONFIG_MACH_SOCFPGA_TERASIC_SOCKIT=y CONFIG_THUMB2_BAREBOX=y -CONFIG_CMD_ARM_MMUINFO=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y CONFIG_MMU=y -CONFIG_TEXT_BASE=0x0 CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_RELOCATABLE=y -CONFIG_LONGHELP=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y # CONFIG_TIMESTAMP is not set CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y -CONFIG_CMD_EDIT=y -CONFIG_CMD_SLEEP=y -CONFIG_CMD_MSLEEP=y -CONFIG_CMD_SAVEENV=y -CONFIG_CMD_EXPORT=y -CONFIG_CMD_PRINTENV=y -CONFIG_CMD_READLINE=y -CONFIG_CMD_LET=y -CONFIG_CMD_MENU=y -CONFIG_CMD_MENU_MANAGEMENT=y -CONFIG_CMD_TIME=y -CONFIG_CMD_LN=y -CONFIG_CMD_FILETYPE=y -CONFIG_CMD_ECHO_E=y -CONFIG_CMD_MEMINFO=y +CONFIG_LONGHELP=y CONFIG_CMD_IOMEM=y -CONFIG_CMD_MM=y -CONFIG_CMD_CRC=y -CONFIG_CMD_CRC_CMP=y -CONFIG_CMD_MD5SUM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_ARM_MMUINFO=y CONFIG_CMD_BOOTM_SHOW_TYPE=y CONFIG_CMD_BOOTM_VERBOSE=y CONFIG_CMD_BOOTM_INITRD=y CONFIG_CMD_BOOTM_OFTREE=y -CONFIG_CMD_RESET=y CONFIG_CMD_GO=y -CONFIG_CMD_OFTREE=y -CONFIG_CMD_OF_PROPERTY=y -CONFIG_CMD_OF_NODE=y -CONFIG_CMD_MEMTEST=y -CONFIG_CMD_BAREBOX_UPDATE=y -CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_RESET=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y CONFIG_CMD_MAGICVAR=y CONFIG_CMD_MAGICVAR_HELP=y -CONFIG_CMD_GPIO=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_FILETYPE=y +CONFIG_CMD_LN=y +CONFIG_CMD_MD5SUM=y CONFIG_CMD_UNCOMPRESS=y -CONFIG_CMD_SPI=y -CONFIG_CMD_LED=y -CONFIG_CMD_LED_TRIGGER=y +CONFIG_CMD_LET=y +CONFIG_CMD_MSLEEP=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_DHCP=y CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_MENU=y +CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_CRC=y +CONFIG_CMD_CRC_CMP=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_MM=y CONFIG_CMD_CLK=y CONFIG_CMD_DETECT=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_SPI=y +CONFIG_CMD_LED_TRIGGER=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_OF_NODE=y +CONFIG_CMD_OF_PROPERTY=y +CONFIG_CMD_OFTREE=y +CONFIG_CMD_TIME=y CONFIG_NET=y -CONFIG_CMD_DHCP=y -CONFIG_CMD_PING=y CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y CONFIG_OFDEVICE=y diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c index 304ed0cee7..91fd9b987b 100644 --- a/arch/arm/cpu/start.c +++ b/arch/arm/cpu/start.c @@ -61,6 +61,8 @@ static noinline __noreturn void __start(unsigned long membase, setup_c(); + barrier(); + pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize); barebox_boarddata = boarddata; diff --git a/arch/arm/crypto/.gitignore b/arch/arm/crypto/.gitignore new file mode 100644 index 0000000000..b22a068f76 --- /dev/null +++ b/arch/arm/crypto/.gitignore @@ -0,0 +1 @@ +/sha256-core.S diff --git a/arch/arm/dts/am335x-phytec-phycard-som-mlo.dts b/arch/arm/dts/am335x-phytec-phycard-som-mlo.dts index 17d9152977..f9ed627120 100644 --- a/arch/arm/dts/am335x-phytec-phycard-som-mlo.dts +++ b/arch/arm/dts/am335x-phytec-phycard-som-mlo.dts @@ -9,6 +9,7 @@ #include "am33xx.dtsi" #include "am335x-phytec-phycard-som.dtsi" +#include "am33xx-strip.dtsi" / { model = "Phytec phyCARD AM335x"; diff --git a/arch/arm/dts/am335x-phytec-phycore-som-mlo.dts b/arch/arm/dts/am335x-phytec-phycore-som-mlo.dts index b08a59e0f5..f70835f8cd 100644 --- a/arch/arm/dts/am335x-phytec-phycore-som-mlo.dts +++ b/arch/arm/dts/am335x-phytec-phycore-som-mlo.dts @@ -9,6 +9,7 @@ #include "am33xx.dtsi" #include "am335x-phytec-phycore-som.dtsi" +#include "am33xx-strip.dtsi" / { model = "Phytec phyCORE AM335x"; diff --git a/arch/arm/dts/am335x-phytec-phyflex-som-mlo.dts b/arch/arm/dts/am335x-phytec-phyflex-som-mlo.dts index 5294ff5976..736d7ef664 100644 --- a/arch/arm/dts/am335x-phytec-phyflex-som-mlo.dts +++ b/arch/arm/dts/am335x-phytec-phyflex-som-mlo.dts @@ -9,6 +9,7 @@ #include "am33xx.dtsi" #include "am335x-phytec-phyflex-som.dtsi" +#include "am33xx-strip.dtsi" / { model = "Phytec phyFLEX AM335x"; diff --git a/arch/arm/dts/am33xx-strip.dtsi b/arch/arm/dts/am33xx-strip.dtsi new file mode 100644 index 0000000000..04cf3151ea --- /dev/null +++ b/arch/arm/dts/am33xx-strip.dtsi @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 PHYTEC Messtechnik GmbH, + * Author: Wadim Egorov <w.egorov@phytec.de> + * + * 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. + */ + +/ { + aliases { + /delete-property/ i2c1; + /delete-property/ i2c2; + /delete-property/ mmc2; + /delete-property/ d_can0; + /delete-property/ d_can1; + }; +}; + +/delete-node/ &i2c1; +/delete-node/ &i2c2; +/delete-node/ &mmc3; +/delete-node/ &hwspinlock; +/delete-node/ &wdt2; +/delete-node/ &dcan0; +/delete-node/ &dcan1; +/delete-node/ &mailbox; +/delete-node/ &timer1; +/delete-node/ &timer2; +/delete-node/ &timer3; +/delete-node/ &timer4; +/delete-node/ &timer5; +/delete-node/ &timer6; +/delete-node/ &timer7; +/delete-node/ &spi1; +/delete-node/ &epwmss0; +/delete-node/ &epwmss1; +/delete-node/ &epwmss2; +/delete-node/ &lcdc; +/delete-node/ &tscadc; +/delete-node/ &sham; +/delete-node/ &aes; +/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/dts/socfpga.dtsi b/arch/arm/dts/socfpga.dtsi index afac867c99..14c0654b2a 100644 --- a/arch/arm/dts/socfpga.dtsi +++ b/arch/arm/dts/socfpga.dtsi @@ -587,6 +587,20 @@ status = "disabled"; }; + qspi: spi@ff705000 { + compatible = "cdns,qspi-nor"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xff705000 0x1000>, + <0xffa00000 0x1000>; + interrupts = <0 151 4>; + ext-decoder = <0>; /* external decoder */ + fifo-depth = <128>; + clocks = <&qspi_clk>; + clock-names = "qspi_clk"; + status = "disabled"; + }; + /* Local timer */ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; diff --git a/arch/arm/dts/socfpga_cyclone5_socdk.dts b/arch/arm/dts/socfpga_cyclone5_socdk.dts index 025d07c18c..fec321a9d5 100644 --- a/arch/arm/dts/socfpga_cyclone5_socdk.dts +++ b/arch/arm/dts/socfpga_cyclone5_socdk.dts @@ -61,3 +61,23 @@ vmmc-supply = <®ulator_3_3v>; vqmmc-supply = <®ulator_3_3v>; }; + +&qspi { + status = "okay"; + + flash: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q00"; + reg = <0>; + spi-max-frequency = <108000000>; + m25p,fast-read; + cdns,page-size = <256>; + cdns,block-size = <16>; + cdns,read-delay = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; + }; +}; diff --git a/arch/arm/dts/socfpga_cyclone5_sockit.dts b/arch/arm/dts/socfpga_cyclone5_sockit.dts index e8e00aedfc..1c3fb4d39c 100644 --- a/arch/arm/dts/socfpga_cyclone5_sockit.dts +++ b/arch/arm/dts/socfpga_cyclone5_sockit.dts @@ -119,3 +119,23 @@ interrupts = <0x0 0xa6 0x4>; }; }; + +&qspi { + status = "okay"; + + flash: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q00"; + reg = <0>; + spi-max-frequency = <108000000>; + m25p,fast-read; + cdns,page-size = <256>; + cdns,block-size = <16>; + cdns,read-delay = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; + }; +}; diff --git a/arch/arm/dts/socfpga_cyclone5_socrates.dts b/arch/arm/dts/socfpga_cyclone5_socrates.dts index 7fa5e63076..125ad1b850 100644 --- a/arch/arm/dts/socfpga_cyclone5_socrates.dts +++ b/arch/arm/dts/socfpga_cyclone5_socrates.dts @@ -62,3 +62,23 @@ &mmc { status = "okay"; }; + +&qspi { + status = "okay"; + + flash: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q00"; + reg = <0>; + spi-max-frequency = <100000000>; + m25p,fast-read; + cdns,page-size = <256>; + cdns,block-size = <16>; + cdns,read-delay = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; + }; +}; diff --git a/arch/arm/include/asm/bitsperlong.h b/arch/arm/include/asm/bitsperlong.h new file mode 100644 index 0000000000..6dc0bb0c13 --- /dev/null +++ b/arch/arm/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include <asm-generic/bitsperlong.h> diff --git a/arch/arm/include/asm/posix_types.h b/arch/arm/include/asm/posix_types.h index aee050eeb8..22cae6230c 100644 --- a/arch/arm/include/asm/posix_types.h +++ b/arch/arm/include/asm/posix_types.h @@ -1,78 +1 @@ -/* - * linux/include/asm-arm/posix_types.h - * - * Copyright (C) 1996-1998 Russell King. - * - * 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. - * - * Changelog: - * 27-06-1996 RMK Created - */ -#ifndef __ARCH_ARM_POSIX_TYPES_H -#define __ARCH_ARM_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned long __kernel_ino_t; -typedef unsigned short __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid_t; -typedef unsigned short __kernel_gid_t; -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_daddr_t; -typedef char * __kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned short __kernel_old_uid_t; -typedef unsigned short __kernel_old_gid_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { -#if defined(__KERNEL__) || defined(__USE_ALL) - int val[2]; -#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ - int __val[2]; -#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ -} __kernel_fsid_t; - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) - -#undef __FD_SET -#define __FD_SET(fd, fdsetp) \ - (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31))) - -#undef __FD_CLR -#define __FD_CLR(fd, fdsetp) \ - (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31))) - -#undef __FD_ISSET -#define __FD_ISSET(fd, fdsetp) \ - ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0) - -#undef __FD_ZERO -#define __FD_ZERO(fdsetp) \ - (memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp))) - -#endif - -#endif +#include <asm-generic/posix_types.h> diff --git a/arch/arm/include/asm/types.h b/arch/arm/include/asm/types.h index 81bd357ada..1a7f47add0 100644 --- a/arch/arm/include/asm/types.h +++ b/arch/arm/include/asm/types.h @@ -31,7 +31,7 @@ typedef unsigned long long __u64; */ #ifdef __KERNEL__ -#define BITS_PER_LONG 32 +#include <asm/bitsperlong.h> #ifndef __ASSEMBLY__ @@ -47,11 +47,6 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -/* Dma addresses are 32-bits wide. */ - -typedef u32 dma_addr_t; -typedef u32 dma64_addr_t; - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ 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 c713477701..f8f6004630 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -68,6 +68,21 @@ config ARCH_IMX_IMXIMAGE help if enabled the imx-image tool is compiled +config ARCH_IMX_XLOAD + bool + depends on ARCH_IMX51 + prompt "Build preloader image" + +config ARCH_IMX_UNUSED_IRAM_BASE + hex + depends on ARCH_IMX_XLOAD + default 0x1ffe2000 if ARCH_IMX51 + +config ARCH_IMX_UNUSED_IRAM_SIZE + hex + depends on ARCH_IMX_XLOAD + default 0x16000 if ARCH_IMX51 + choice depends on ARCH_IMX_INTERNAL_BOOT prompt "Internal boot source" @@ -112,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 ae953b1bf8..458d7b45bb 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -12,6 +12,7 @@ pbl-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o esdctl-v4.o obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o clk-imx6.o lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o +obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o obj-$(CONFIG_IMX_IIM) += iim.o obj-$(CONFIG_IMX_OCOTP) += ocotp.o obj-$(CONFIG_NAND_IMX) += nand.o @@ -21,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/imx6.c b/arch/arm/mach-imx/imx6.c index 73630e7092..7508964bf5 100644 --- a/arch/arm/mach-imx/imx6.c +++ b/arch/arm/mach-imx/imx6.c @@ -30,7 +30,8 @@ void imx6_init_lowlevel(void) void __iomem *aips1 = (void *)MX6_AIPS1_ON_BASE_ADDR; void __iomem *aips2 = (void *)MX6_AIPS2_ON_BASE_ADDR; void __iomem *iomux = (void *)MX6_IOMUXC_BASE_ADDR; - int is_imx6q = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6Q; + bool is_imx6q = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6Q; + bool is_imx6d = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6D; uint32_t val; /* @@ -67,28 +68,29 @@ void imx6_init_lowlevel(void) * not output clock after reset, MX6DL and MX6SL have added 396M pfd * workaround in ROM code, as bus clock need it */ - writel(BM_ANADIG_PFD_480_PFD3_CLKGATE | - BM_ANADIG_PFD_480_PFD2_CLKGATE | - BM_ANADIG_PFD_480_PFD1_CLKGATE | - BM_ANADIG_PFD_480_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_SET); - writel(BM_ANADIG_PFD_528_PFD3_CLKGATE | - (is_imx6q ? BM_ANADIG_PFD_528_PFD2_CLKGATE : 0) | - BM_ANADIG_PFD_528_PFD1_CLKGATE | - BM_ANADIG_PFD_528_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_SET); - - writel(BM_ANADIG_PFD_480_PFD3_CLKGATE | - BM_ANADIG_PFD_480_PFD2_CLKGATE | - BM_ANADIG_PFD_480_PFD1_CLKGATE | - BM_ANADIG_PFD_480_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_CLR); - writel(BM_ANADIG_PFD_528_PFD3_CLKGATE | - (is_imx6q ? BM_ANADIG_PFD_528_PFD2_CLKGATE : 0) | - BM_ANADIG_PFD_528_PFD2_CLKGATE | - BM_ANADIG_PFD_528_PFD1_CLKGATE | - BM_ANADIG_PFD_528_PFD0_CLKGATE, - MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_CLR); + if (is_imx6q || is_imx6d) { + writel(BM_ANADIG_PFD_480_PFD3_CLKGATE | + BM_ANADIG_PFD_480_PFD2_CLKGATE | + BM_ANADIG_PFD_480_PFD1_CLKGATE | + BM_ANADIG_PFD_480_PFD0_CLKGATE, + MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_SET); + writel(BM_ANADIG_PFD_528_PFD3_CLKGATE | + (is_imx6q ? BM_ANADIG_PFD_528_PFD2_CLKGATE : 0) | + BM_ANADIG_PFD_528_PFD1_CLKGATE | + BM_ANADIG_PFD_528_PFD0_CLKGATE, + MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_SET); + + writel(BM_ANADIG_PFD_480_PFD3_CLKGATE | + BM_ANADIG_PFD_480_PFD2_CLKGATE | + BM_ANADIG_PFD_480_PFD1_CLKGATE | + BM_ANADIG_PFD_480_PFD0_CLKGATE, + MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_CLR); + writel(BM_ANADIG_PFD_528_PFD3_CLKGATE | + (is_imx6q ? BM_ANADIG_PFD_528_PFD2_CLKGATE : 0) | + BM_ANADIG_PFD_528_PFD1_CLKGATE | + BM_ANADIG_PFD_528_PFD0_CLKGATE, + MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_CLR); + } val = readl(iomux + IOMUXC_GPR4); val |= IMX6Q_GPR4_VPU_WR_CACHE_SEL | IMX6Q_GPR4_VPU_RD_CACHE_SEL | 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-imx/include/mach/clock-imx51_53.h b/arch/arm/mach-imx/include/mach/clock-imx51_53.h index 6004a6d36c..0f25dfbf2f 100644 --- a/arch/arm/mach-imx/include/mach/clock-imx51_53.h +++ b/arch/arm/mach-imx/include/mach/clock-imx51_53.h @@ -149,6 +149,7 @@ #define MX5_CCM_CACRR_ARM_PODF_MASK (0x7) /* Define the bits in register CBCDR */ +#define MX5_CCM_CBCDR_RESET_VALUE (0x19239145) #define MX5_CCM_CBCDR_EMI_CLK_SEL (0x1 << 26) #define MX5_CCM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) #define MX5_CCM_CBCDR_DDR_HF_SEL_OFFSET (30) @@ -193,6 +194,7 @@ #define MX5_CCM_CBCMR_PERCLK_IPG_CLK_SEL (0x1 << 0) /* Define the bits in register CSCMR1 */ +#define MX5_CCM_CSCMR1_RESET_VALUE (0xa6a2a020) #define MX5_CCM_CSCMR1_SSI_EXT2_CLK_SEL_OFFSET (30) #define MX5_CCM_CSCMR1_SSI_EXT2_CLK_SEL_MASK (0x3 << 30) #define MX5_CCM_CSCMR1_SSI_EXT1_CLK_SEL_OFFSET (28) @@ -259,6 +261,7 @@ #define MX5_CCM_CSCMR2_SPDIF0_CLK_SEL_MASK (0x3) /* Define the bits in register CSCDR1 */ +#define MX5_CCM_CSCDR1_RESET_VALUE (0x00c30318) #define MX5_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_OFFSET (22) #define MX5_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK (0x7 << 22) #define MX5_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET (19) @@ -585,5 +588,3 @@ #define MX5_SRPGC_EMI_PDNSCR (MX5_SRPGC_EMI_BASE + 0x8) #endif /* __ARCH_ARM_MACH_MX51_CRM_REGS_H__ */ - - diff --git a/arch/arm/mach-imx/include/mach/debug_ll.h b/arch/arm/mach-imx/include/mach/debug_ll.h index f34eaa139f..ab939b3a88 100644 --- a/arch/arm/mach-imx/include/mach/debug_ll.h +++ b/arch/arm/mach-imx/include/mach/debug_ll.h @@ -3,6 +3,7 @@ #include <io.h> #include <config.h> +#include <common.h> #include <mach/imx1-regs.h> #include <mach/imx21-regs.h> #include <mach/imx25-regs.h> @@ -13,8 +14,40 @@ #include <mach/imx53-regs.h> #include <mach/imx6-regs.h> +#include <serial/imx-uart.h> + #ifdef CONFIG_DEBUG_LL +#define __IMX_UART_BASE(soc, num) soc##_UART##num##_BASE_ADDR +#define IMX_UART_BASE(soc, num) __IMX_UART_BASE(soc, num) + +static inline void imx_uart_setup_ll(void __iomem *uartbase, + unsigned int refclock) +{ + writel(0x00000000, uartbase + UCR1); + + writel(UCR2_IRTS | UCR2_WS | UCR2_TXEN | UCR2_RXEN | UCR2_SRST, + uartbase + UCR2); + writel(UCR3_DSR | UCR3_DCD | UCR3_RI | UCR3_ADNIMP | UCR3_RXDMUXSEL, + uartbase + UCR3); + writel((0b10 << UFCR_TXTL_SHF) | UFCR_RFDIV1 | (1 << UFCR_RXTL_SHF), + uartbase + UFCR); + + writel(baudrate_to_ubir(CONFIG_BAUDRATE), + uartbase + UBIR); + writel(refclock_to_ubmr(refclock), + uartbase + UBMR); + + writel(UCR1_UARTEN, uartbase + UCR1); +} + +#define __imx_uart_setup_ll(refclock) \ + do { \ + imx_uart_setup_ll(IOMEM(IMX_UART_BASE(IMX_DEBUG_SOC, \ + CONFIG_DEBUG_IMX_UART_PORT)), \ + refclock); \ + } while(0) + #ifdef CONFIG_DEBUG_IMX1_UART #define IMX_DEBUG_SOC MX1 #elif defined CONFIG_DEBUG_IMX21_UART @@ -37,21 +70,20 @@ #error "unknown i.MX debug uart soc type" #endif -#define __IMX_UART_BASE(soc, num) soc##_UART##num##_BASE_ADDR -#define IMX_UART_BASE(soc, num) __IMX_UART_BASE(soc, num) - -#define URTX0 0x40 /* Transmitter Register */ - -#define UCR1 0x80 /* Control Register 1 */ -#define UCR1_UARTEN (1 << 0) /* UART enabled */ +static inline void imx51_uart_setup_ll(void) +{ + __imx_uart_setup_ll(54000000); +} -#define USR2 0x98 /* Status Register 2 */ -#define USR2_TXDC (1 << 3) /* Transmitter complete */ +static inline void imx6_uart_setup_ll(void) +{ + __imx_uart_setup_ll(80000000); +} static inline void PUTC_LL(int c) { - void __iomem *base = (void *)IMX_UART_BASE(IMX_DEBUG_SOC, - CONFIG_DEBUG_IMX_UART_PORT); + void __iomem *base = IOMEM(IMX_UART_BASE(IMX_DEBUG_SOC, + CONFIG_DEBUG_IMX_UART_PORT)); if (!base) return; @@ -63,5 +95,28 @@ static inline void PUTC_LL(int c) writel(c, base + URTX0); } +#else + +static inline void imx_uart_setup_ll(void __iomem *uartbase, + unsigned int refclock) +{ +} + +static inline void imx51_uart_setup_ll(void) {} +static inline void imx6_uart_setup_ll(void) {} + #endif /* CONFIG_DEBUG_LL */ + +static inline void imx_ungate_all_peripherals(void __iomem *ccmbase) +{ + int i; + for (i = 0x68; i <= 0x80; i += 4) + writel(0xffffffff, ccmbase + i); +} + +static inline void imx6_ungate_all_peripherals(void) +{ + imx_ungate_all_peripherals(IOMEM(MX6_CCM_BASE_ADDR)); +} + #endif /* __MACH_DEBUG_LL_H__ */ diff --git a/arch/arm/mach-imx/xload.c b/arch/arm/mach-imx/xload.c new file mode 100644 index 0000000000..16d56ab288 --- /dev/null +++ b/arch/arm/mach-imx/xload.c @@ -0,0 +1,52 @@ +#include <bootsource.h> +#include <bootstrap.h> +#include <common.h> +#include <malloc.h> +#include <init.h> +#include <envfs.h> +#include <linux/sizes.h> +#include <fs.h> +#include <io.h> + +#include <linux/clkdev.h> +#include <linux/stat.h> +#include <linux/clk.h> + +#include <mach/devices-imx51.h> + +static __noreturn int imx_xload(void) +{ + enum bootsource bootsource = bootsource_get(); + void *buf; + + switch (bootsource) { + case BOOTSOURCE_MMC: + pr_info("booting from MMC\n"); + buf = bootstrap_read_disk("disk0.0", "fat"); + break; + case BOOTSOURCE_SPI: + pr_info("booting from SPI\n"); + buf = bootstrap_read_devfs("dataflash0", false, + SZ_256K, SZ_1M, SZ_1M); + break; + default: + pr_err("unknown bootsource %d\n", bootsource); + hang(); + } + + if (!buf) { + pr_err("failed to load barebox.bin\n"); + hang(); + } + + bootstrap_boot(buf, 0); + + hang(); +} + +static int imx_devices_init(void) +{ + barebox_main = imx_xload; + return 0; +} +coredevice_initcall(imx_devices_init); diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig index 444ddf8377..bc00d5bf7f 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -110,6 +110,15 @@ config ARCH_TEXT_BASE default 0x80e80000 if MACH_OMAP343xSDP default 0x80e80000 if MACH_BEAGLE +config AM33XX_NET_BOOT + bool "enable AM335x network boot" + select ENVIRONMENT_VARIABLES + select NET_DHCP + select FS_TFTP + select DRIVER_NET_CPSW + default n + depends on ARCH_AM33XX && NET + config OMAP4_USBBOOT bool "enable booting from USB" default n 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/am33xx_generic.c b/arch/arm/mach-omap/am33xx_generic.c index ee30351fa4..7ce32f01e1 100644 --- a/arch/arm/mach-omap/am33xx_generic.c +++ b/arch/arm/mach-omap/am33xx_generic.c @@ -145,6 +145,9 @@ static int am33xx_bootsource(void) case 0x44: src = BOOTSOURCE_USB; break; + case 0x46: + src = BOOTSOURCE_NET; + break; default: src = BOOTSOURCE_UNKNOWN; } 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/xload.c b/arch/arm/mach-omap/xload.c index 7c8c350114..85c9120ccf 100644 --- a/arch/arm/mach-omap/xload.c +++ b/arch/arm/mach-omap/xload.c @@ -13,6 +13,10 @@ #include <filetype.h> #include <xymodem.h> #include <mach/generic.h> +#include <mach/am33xx-generic.h> +#include <net.h> +#include <environment.h> +#include <dhcp.h> struct omap_barebox_part *barebox_part; @@ -224,6 +228,45 @@ static void *omap_serial_boot(void){ return buf; } +static void *am33xx_net_boot(void) +{ + void *buf = NULL; + int err; + int len; + struct dhcp_req_param dhcp_param; + const char *bootfile; + + am33xx_register_ethaddr(0, 0); + + memset(&dhcp_param, 0, sizeof(struct dhcp_req_param)); + dhcp_param.vendor_id = "am335x barebox-mlo"; + err = dhcp(20, &dhcp_param); + if (err) { + printf("dhcp failed\n"); + return NULL; + } + + err = mount(ip_to_string(net_get_serverip()), "tftp", "/", NULL); + if (err < 0) { + printf("Unable to mount.\n"); + return NULL; + } + + bootfile = getenv("bootfile"); + if (!bootfile) { + printf("bootfile not found.\n"); + return NULL; + } + + buf = read_file(bootfile, &len); + if (!buf) + printf("could not read %s.\n", bootfile); + + umount("/"); + + return buf; +} + /* * Replaces the default shell in xload configuration */ @@ -264,6 +307,14 @@ static __noreturn int omap_xload(void) func = omap_serial_boot(); break; } + case BOOTSOURCE_NET: + if (IS_ENABLED(CONFIG_AM33XX_NET_BOOT)) { + printf("booting from NET\n"); + func = am33xx_net_boot(); + break; + } else { + printf("booting from network not enabled\n"); + } default: printf("unknown boot source. Fall back to 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-socfpga/include/mach/generic.h b/arch/arm/mach-socfpga/include/mach/generic.h index 2f5cda0d02..1f4247f803 100644 --- a/arch/arm/mach-socfpga/include/mach/generic.h +++ b/arch/arm/mach-socfpga/include/mach/generic.h @@ -15,4 +15,9 @@ static inline void __udelay(unsigned us) for (i = 0; i < us * 3; i++); } +struct socfpga_barebox_part { + unsigned int nor_offset; + unsigned int nor_size; +}; + #endif /* __MACH_SOCFPGA_GENERIC_H */ diff --git a/arch/arm/mach-socfpga/include/mach/sequencer.c b/arch/arm/mach-socfpga/include/mach/sequencer.c index 90efcc826b..c299f754a8 100644 --- a/arch/arm/mach-socfpga/include/mach/sequencer.c +++ b/arch/arm/mach-socfpga/include/mach/sequencer.c @@ -48,11 +48,14 @@ ****************************************************************************** ******************************************************************************/ +#ifndef ARMCOMPILER + // Temporary workaround to place the initial stack pointer at a safe offset from end #define STRINGIFY(s) STRINGIFY_STR(s) #define STRINGIFY_STR(s) #s asm(".global __alt_stack_pointer"); asm("__alt_stack_pointer = " STRINGIFY(STACK_POINTER)); +#endif #include <mach/sdram.h> @@ -222,18 +225,13 @@ static int check_test_mem(int start) static void set_failing_group_stage(uint32_t group, uint32_t stage, uint32_t substage) { - ALTERA_ASSERT(group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - - // Only set the global stage if there was not been any other failing group if (gbl->error_stage == CAL_STAGE_NIL) { gbl->error_substage = substage; gbl->error_stage = stage; gbl->error_group = group; - TCLRPT_SET(debug_summary_report->error_sub_stage, substage); - TCLRPT_SET(debug_summary_report->error_stage, stage); - TCLRPT_SET(debug_summary_report->error_group, group); } + } static inline void reg_file_set_group(uint32_t set_group) @@ -292,13 +290,6 @@ static inline void select_curr_shadow_reg_using_rank(uint32_t rank) static void initialize(void) { - TRACE_FUNC(); - - //USER calibration has control over path to memory - - // In Hard PHY this is a 2-bit control: - // 0: AFI Mux Select - // 1: DDIO Mux Select IOWR_32DIRECT(PHY_MGR_MUX_SEL, 0, 0x3); //USER memory clock is not stable we begin initialization @@ -480,27 +471,18 @@ static void scc_mgr_initialize(void) static inline void scc_mgr_set_dqs_bus_in_delay(uint32_t read_group, uint32_t delay) { - ALTERA_ASSERT(read_group < RW_MGR_MEM_IF_READ_DQS_WIDTH); - - // Load the setting in the SCC manager WRITE_SCC_DQS_IN_DELAY(read_group, delay); } static inline void scc_mgr_set_dqs_io_in_delay(uint32_t write_group, uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - - // Load the setting in the SCC manager WRITE_SCC_DQS_IO_IN_DELAY(delay); } static inline void scc_mgr_set_dqs_en_phase(uint32_t read_group, uint32_t phase) { - ALTERA_ASSERT(read_group < RW_MGR_MEM_IF_READ_DQS_WIDTH); - - // Load the setting in the SCC manager WRITE_SCC_DQS_EN_PHASE(read_group, phase); } @@ -529,9 +511,6 @@ static void scc_mgr_set_dqs_en_phase_all_ranks(uint32_t read_group, uint32_t pha static inline void scc_mgr_set_dqdqs_output_phase(uint32_t write_group, uint32_t phase) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - - // Load the setting in the SCC manager WRITE_SCC_DQDQS_OUT_PHASE(write_group, phase); } @@ -560,9 +539,6 @@ static void scc_mgr_set_dqdqs_output_phase_all_ranks(uint32_t write_group, uint3 static inline void scc_mgr_set_dqs_en_delay(uint32_t read_group, uint32_t delay) { - ALTERA_ASSERT(read_group < RW_MGR_MEM_IF_READ_DQS_WIDTH); - - // Load the setting in the SCC manager WRITE_SCC_DQS_EN_DELAY(read_group, delay); } @@ -592,8 +568,6 @@ static void scc_mgr_set_oct_out1_delay(uint32_t write_group, uint32_t delay) { uint32_t read_group; - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - // Load the setting in the SCC manager // Although OCT affects only write data, the OCT delay is controlled by the DQS logic block // which is instantiated once per read group. For protocols where a write group consists @@ -613,8 +587,6 @@ static void scc_mgr_set_oct_out2_delay(uint32_t write_group, uint32_t delay) { uint32_t read_group; - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - // Load the setting in the SCC manager // Although OCT affects only write data, the OCT delay is controlled by the DQS logic block // which is instantiated once per read group. For protocols where a write group consists @@ -640,9 +612,6 @@ static inline void scc_mgr_set_dq_out1_delay(uint32_t write_group, uint32_t dq_i uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - ALTERA_ASSERT(dq < RW_MGR_MEM_DATA_WIDTH); - // Load the setting in the SCC manager WRITE_SCC_DQ_OUT1_DELAY(dq_in_group, delay); @@ -652,9 +621,6 @@ static inline void scc_mgr_set_dq_out2_delay(uint32_t write_group, uint32_t dq_i uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - ALTERA_ASSERT(dq < RW_MGR_MEM_DATA_WIDTH); - // Load the setting in the SCC manager WRITE_SCC_DQ_OUT2_DELAY(dq_in_group, delay); @@ -664,9 +630,6 @@ static inline void scc_mgr_set_dq_in_delay(uint32_t write_group, uint32_t dq_in_ uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - ALTERA_ASSERT(dq < RW_MGR_MEM_DATA_WIDTH); - // Load the setting in the SCC manager WRITE_SCC_DQ_IN_DELAY(dq_in_group, delay); @@ -706,50 +669,29 @@ static inline void scc_mgr_set_hhp_dqse_map(void) static inline void scc_mgr_set_dqs_out1_delay(uint32_t write_group, uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - - // Load the setting in the SCC manager WRITE_SCC_DQS_IO_OUT1_DELAY(delay); } static inline void scc_mgr_set_dqs_out2_delay(uint32_t write_group, uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - - // Load the setting in the SCC manager WRITE_SCC_DQS_IO_OUT2_DELAY(delay); } static inline void scc_mgr_set_dm_out1_delay(uint32_t write_group, uint32_t dm, uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - ALTERA_ASSERT(dm < RW_MGR_NUM_DM_PER_WRITE_GROUP); - - // Load the setting in the SCC manager WRITE_SCC_DM_IO_OUT1_DELAY(dm, delay); - } static inline void scc_mgr_set_dm_out2_delay(uint32_t write_group, uint32_t dm, uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - ALTERA_ASSERT(dm < RW_MGR_NUM_DM_PER_WRITE_GROUP); - - // Load the setting in the SCC manager WRITE_SCC_DM_IO_OUT2_DELAY(dm, delay); - } static inline void scc_mgr_set_dm_in_delay(uint32_t write_group, uint32_t dm, uint32_t delay) { - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - ALTERA_ASSERT(dm < RW_MGR_NUM_DM_PER_WRITE_GROUP); - - // Load the setting in the SCC manager WRITE_SCC_DM_IO_IN_DELAY(dm, delay); - } static inline void scc_mgr_set_dm_bypass(uint32_t write_group, uint32_t dm, uint32_t bypass) @@ -1144,8 +1086,6 @@ static inline void delay_for_n_mem_clocks(const uint32_t clocks) uint8_t outer; uint16_t c_loop; - TRACE_FUNC("clocks=%lu ... start", clocks); - afi_clocks = (clocks + AFI_RATE_RATIO - 1) / AFI_RATE_RATIO; /* scale (rounding up) to get afi clocks */ // Note, we don't bother accounting for being off a little bit because of a few extra instructions in outer loops @@ -1204,14 +1144,11 @@ static inline void delay_for_n_mem_clocks(const uint32_t clocks) } while (c_loop-- != 0); } } - - TRACE_FUNC("clocks=%lu ... end", clocks); } // should always use constants as argument to ensure all computations are performed at compile time static inline void delay_for_n_ns(const uint32_t nanoseconds) { - TRACE_FUNC("nanoseconds=%lu ... end", nanoseconds); delay_for_n_mem_clocks((1000 * nanoseconds) / (1000000 / AFI_CLK_FREQ) * AFI_RATE_RATIO); } @@ -1230,8 +1167,6 @@ static void rw_mgr_mem_initialize(void) { uint32_t r; - TRACE_FUNC(); - //USER The reset / cke part of initialization is broadcasted to all ranks IOWR_32DIRECT(RW_MGR_SET_CS_AND_ODT_MASK, 0, RW_MGR_RANK_ALL); @@ -1295,6 +1230,7 @@ static void rw_mgr_mem_initialize(void) continue; } + //USER set rank set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_OFF); @@ -1343,8 +1279,6 @@ static void rw_mgr_mem_handoff(void) { uint32_t r; - TRACE_FUNC(); - for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS; r++) { if (param->skip_ranks[r]) { //USER request to skip the rank @@ -1484,8 +1418,6 @@ static void rw_mgr_mem_calibrate_read_load_patterns(uint32_t rank_bgn, uint32_t uint32_t rank_end = all_ranks ? RW_MGR_MEM_NUMBER_OF_RANKS : (rank_bgn + NUM_RANKS_PER_SHADOW_REG); - TRACE_FUNC(); - for (r = rank_bgn; r < rank_end; r++) { if (param->skip_ranks[r]) { //USER request to skip the rank @@ -1794,7 +1726,7 @@ static void rw_mgr_decr_vfifo(uint32_t grp, uint32_t * v) static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) { - uint32_t i, d, v, p, sr; + uint32_t i, d, v, p; uint32_t max_working_cnt; uint32_t fail_cnt; t_btfld bit_chk; @@ -1804,10 +1736,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) uint32_t test_status; uint32_t found_passing_read, found_failing_read, initial_failing_dtap; - TRACE_FUNC("%lu", grp); - BFM_STAGE("find_dqs_en_phase"); - ALTERA_ASSERT(grp < RW_MGR_MEM_IF_READ_DQS_WIDTH); - reg_file_set_sub_stage(CAL_SUBSTAGE_VFIFO_CENTER); scc_mgr_set_dqs_en_delay_all_ranks(grp, 0); @@ -1825,9 +1753,7 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) tmp_delay += IO_DELAY_PER_DQS_EN_DCHAIN_TAP; } dtaps_per_ptap--; - ALTERA_ASSERT(dtaps_per_ptap <= IO_DQS_EN_DELAY_MAX); tmp_delay = 0; - TCLRPT_SET(debug_summary_report->computed_dtap_per_ptap, dtaps_per_ptap); // VFIFO sweep @@ -1938,35 +1864,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) } } - // Record the debug data - // Currently dqsen is the same for all ranks - for (sr = 0; sr < NUM_SHADOW_REGS; sr++) { - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].work_begin, - work_bgn); - if (found_begin) { - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].phase_begin, - p); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].delay_begin, - d); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].vfifo_begin, - v % VFIFO_SIZE); - } else if (p == IO_DQS_EN_PHASE_MAX) { - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].phase_begin, - 0); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].delay_begin, - 0); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].vfifo_begin, - (v + 1) % VFIFO_SIZE); - } else { - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].phase_begin, - p + 1); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].delay_begin, - 0); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].vfifo_begin, - v % VFIFO_SIZE); - } - } - //USER We have found a working dtap before the ptap found above if (found_begin == 1) { max_working_cnt++; @@ -2086,14 +1983,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) BFM_GBL_SET(dqs_enable_right_edge[grp].d, d - 1); BFM_GBL_SET(dqs_enable_right_edge[grp].ps, work_end); - // Record the debug data - for (sr = 0; sr < NUM_SHADOW_REGS; sr++) { - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].work_end, work_end); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].phase_end, p); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].delay_end, d - 1); - TCLRPT_SET(debug_cal_report->cal_dqsen_margins[sr][grp].vfifo_end, v % VFIFO_SIZE); - } - if (work_end >= work_bgn) { //USER we have a working range } else { @@ -2168,7 +2057,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) dtaps_per_ptap = d - initial_failing_dtap; } - ALTERA_ASSERT(dtaps_per_ptap <= IO_DQS_EN_DELAY_MAX); IOWR_32DIRECT(REG_FILE_DTAPS_PER_PTAP, 0, dtaps_per_ptap); DPRINT(2, "find_dqs_en_phase: dtaps_per_ptap=%lu - %lu = %lu", d, initial_failing_dtap, @@ -2196,12 +2084,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) d++, tmp_delay += IO_DELAY_PER_DQS_EN_DCHAIN_TAP) ; DPRINT(2, "new d %ld, tmp_delay=%ld", d, tmp_delay); - // DQSEN same for all shadow reg - for (sr = 0; sr < NUM_SHADOW_REGS; sr++) { - TCLRPT_SET(debug_cal_report->cal_dqs_in_margins[sr][grp].dqsen_margin, - max_working_cnt - 1); - } - scc_mgr_set_dqs_en_phase_all_ranks(grp, p - 1); scc_mgr_set_dqs_en_delay_all_ranks(grp, d); @@ -2543,8 +2425,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp) t_btfld bit_chk; uint32_t delay_per_ptap_mid; - TRACE_FUNC("%lu", grp); - reg_file_set_sub_stage(CAL_SUBSTAGE_VFIFO_CENTER); scc_mgr_set_dqs_en_delay_all_ranks(grp, 0); @@ -2667,9 +2547,7 @@ static inline uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase_sweep_dq_in_ uint32_t d; uint32_t r; - const uint32_t delay_step = IO_IO_IN_DELAY_MAX / (RW_MGR_MEM_DQ_PER_READ_DQS - 1); /* we start at zero, so have one less dq to devide among */ - - TRACE_FUNC("(%lu,%lu,%lu)", write_group, read_group, test_bgn); + const uint32_t delay_step = IO_IO_IN_DELAY_MAX / (RW_MGR_MEM_DQ_PER_READ_DQS - 1); // try different dq_in_delays since the dq path is shorter than dqs @@ -2725,11 +2603,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_center(uint32_t rank_bgn, uint32_t wr int32_t dq_margin, dqs_margin; uint32_t stop; - TRACE_FUNC("%lu %lu", read_group, test_bgn); - - ALTERA_ASSERT(read_group < RW_MGR_MEM_IF_READ_DQS_WIDTH); - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - start_dqs = READ_SCC_DQS_IN_DELAY(read_group); if (IO_SHIFT_DQS_EN_WHEN_SHIFT_DQS) { start_dqs_en = READ_SCC_DQS_EN_DELAY(read_group); @@ -3041,8 +2914,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_center(uint32_t rank_bgn, uint32_t gr uint32_t dq_margin, dqs_margin; uint32_t start_dqs; - TRACE_FUNC("%lu %lu", grp, test_bgn); - //USER per-bit deskew. //USER start of the per-bit sweep with the minimum working delay setting for //USER all bits. @@ -3177,8 +3048,7 @@ static uint32_t rw_mgr_mem_calibrate_vfifo(uint32_t read_group, uint32_t test_bg uint32_t grp_calibrated; uint32_t write_group, write_test_bgn; uint32_t failed_substage; - - TRACE_FUNC("%lu %lu", read_group, test_bgn); + uint32_t dqs_in_dtaps, orig_start_dqs; //USER update info for sims @@ -3253,33 +3123,65 @@ static uint32_t rw_mgr_mem_calibrate_vfifo(uint32_t read_group, uint32_t test_bg break; } } -// case:56390 - grp_calibrated = 1; - if (rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase_sweep_dq_in_delay - (write_group, read_group, test_bgn)) { - // USER Read per-bit deskew can be done on a per shadow register basis + // Loop over different DQS in delay chains for the purpose of DQS Enable calibration finding one bit working + orig_start_dqs = READ_SCC_DQS_IN_DELAY(read_group); + for (dqs_in_dtaps = orig_start_dqs; + dqs_in_dtaps <= IO_DQS_IN_DELAY_MAX && grp_calibrated == 0; + dqs_in_dtaps++) { + for (rank_bgn = 0, sr = 0; rank_bgn < RW_MGR_MEM_NUMBER_OF_RANKS; rank_bgn += NUM_RANKS_PER_SHADOW_REG, ++sr) { - //USER Determine if this set of ranks should be skipped entirely + if (!param->skip_shadow_regs[sr]) { //USER Select shadow register set select_shadow_regs_for_update(rank_bgn, read_group, 1); - // If doing read after write calibration, do not update FOM now - do it then - if (!rw_mgr_mem_calibrate_vfifo_center - (rank_bgn, write_group, read_group, test_bgn, 1, - 0)) { - grp_calibrated = 0; - failed_substage = CAL_SUBSTAGE_VFIFO_CENTER; + WRITE_SCC_DQS_IN_DELAY(read_group, dqs_in_dtaps); + scc_mgr_load_dqs(read_group); + IOWR_32DIRECT(SCC_MGR_UPD, 0, 0); + } + } + +// case:56390 + grp_calibrated = 1; + if (rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase_sweep_dq_in_delay + (write_group, read_group, test_bgn)) { + // USER Read per-bit deskew can be done on a per shadow register basis + for (rank_bgn = 0, sr = 0; + rank_bgn < RW_MGR_MEM_NUMBER_OF_RANKS; + rank_bgn += NUM_RANKS_PER_SHADOW_REG, ++sr) { + //USER Determine if this set of ranks should be skipped entirely + if (!param->skip_shadow_regs[sr]) { + + //USER Select shadow register set + select_shadow_regs_for_update(rank_bgn, + read_group, + 1); + + // Before doing read deskew, set DQS in back to the reserve value + WRITE_SCC_DQS_IN_DELAY(read_group, + orig_start_dqs); + scc_mgr_load_dqs(read_group); + IOWR_32DIRECT(SCC_MGR_UPD, 0, 0); + + // If doing read after write calibration, do not update FOM now - do it then + if (!rw_mgr_mem_calibrate_vfifo_center + (rank_bgn, write_group, read_group, + test_bgn, 1, 0)) { + grp_calibrated = 0; + failed_substage = + CAL_SUBSTAGE_VFIFO_CENTER; + } } } + } else { + grp_calibrated = 0; + failed_substage = CAL_SUBSTAGE_DQS_EN_PHASE; } - } else { - grp_calibrated = 0; - failed_substage = CAL_SUBSTAGE_DQS_EN_PHASE; } + } } @@ -3307,8 +3209,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo(uint32_t g, uint32_t test_bgn) uint32_t grp_calibrated; uint32_t failed_substage; - TRACE_FUNC("%lu %lu", g, test_bgn); - //USER update info for sims reg_file_set_stage(CAL_STAGE_VFIFO); @@ -3380,8 +3280,6 @@ static uint32_t rw_mgr_mem_calibrate_vfifo_end(uint32_t read_group, uint32_t tes uint32_t grp_calibrated; uint32_t write_group; - TRACE_FUNC("%lu %lu", read_group, test_bgn); - //USER update info for sims reg_file_set_stage(CAL_STAGE_VFIFO_AFTER_WRITES); @@ -3432,9 +3330,6 @@ static uint32_t rw_mgr_mem_calibrate_lfifo(void) uint32_t found_one; t_btfld bit_chk; - TRACE_FUNC(); - BFM_STAGE("lfifo"); - //USER update info for sims reg_file_set_stage(CAL_STAGE_LFIFO); @@ -3588,6 +3483,7 @@ static void rw_mgr_mem_calibrate_write_test_issue(uint32_t group, uint32_t test_ } IOWR_32DIRECT(RW_MGR_RUN_SINGLE_GROUP, (group << 2), mcc_instruction); + } //USER Test writes, can check for a single bit pass or multiple bit pass @@ -3673,7 +3569,7 @@ static inline uint32_t rw_mgr_mem_calibrate_write_test_all_ranks(uint32_t write_ //USER Write Levelling -- Full Calibration static uint32_t rw_mgr_mem_calibrate_wlevel(uint32_t g, uint32_t test_bgn) { - uint32_t p, d, sr; + uint32_t p, d; uint32_t num_additional_fr_cycles = 0; @@ -3683,9 +3579,6 @@ static uint32_t rw_mgr_mem_calibrate_wlevel(uint32_t g, uint32_t test_bgn) uint32_t found_begin; uint32_t dtaps_per_ptap; - TRACE_FUNC("%lu %lu", g, test_bgn); - BFM_STAGE("wlevel"); - //USER update info for sims reg_file_set_stage(CAL_STAGE_WLEVEL); @@ -3864,11 +3757,6 @@ static uint32_t rw_mgr_mem_calibrate_wlevel(uint32_t g, uint32_t test_bgn) BFM_GBL_SET(dqs_wlevel_right_edge[g].d, d - 1); BFM_GBL_SET(dqs_wlevel_right_edge[g].ps, work_end); - for (sr = 0; sr < NUM_SHADOW_REGS; sr++) { - TCLRPT_SET(debug_cal_report->cal_dqs_out_margins[sr][g].dqdqs_start, work_bgn); - TCLRPT_SET(debug_cal_report->cal_dqs_out_margins[sr][g].dqdqs_end, work_end); - } - //USER center work_mid = (work_bgn + work_end) / 2; @@ -3926,8 +3814,6 @@ static uint32_t rw_mgr_mem_calibrate_wlevel(uint32_t g, uint32_t test_bgn) uint32_t work_bgn, work_end, work_mid; uint32_t tmp_delay; - TRACE_FUNC("%lu %lu", g, test_bgn); - //USER update info for sims reg_file_set_stage(CAL_STAGE_WLEVEL); @@ -4071,11 +3957,6 @@ static uint32_t rw_mgr_mem_calibrate_writes_center(uint32_t rank_bgn, uint32_t w int32_t end_best = IO_IO_OUT1_DELAY_MAX + 1; int32_t win_best = 0; - TRACE_FUNC("%lu %lu", write_group, test_bgn); - BFM_STAGE("writes_center"); - - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - dm_margin = 0; start_dqs = READ_SCC_DQS_IO_OUT1_DELAY(); @@ -4302,20 +4183,13 @@ static uint32_t rw_mgr_mem_calibrate_writes_center(uint32_t rank_bgn, uint32_t w IOWR_32DIRECT(SCC_MGR_UPD, 0, 0); } - ////////////////////// - ////////////////////// - //USER Centre DM - ////////////////////// - ////////////////////// - - BFM_STAGE("dm_center"); - DPRINT(2, "write_center: DM"); //USER set the left and right edge of each bit to an illegal value //USER use (IO_IO_OUT1_DELAY_MAX + 1) as an illegal value left_edge[0] = IO_IO_OUT1_DELAY_MAX + 1; right_edge[0] = IO_IO_OUT1_DELAY_MAX + 1; + //USER Search for the/part of the window with DM shift for (d = IO_IO_OUT1_DELAY_MAX; d >= 0; d -= DELTA_D) { scc_mgr_apply_group_dm_out1_delay(write_group, d); @@ -4447,10 +4321,6 @@ static uint32_t rw_mgr_mem_calibrate_writes_center(uint32_t rank_bgn, uint32_t w uint32_t start_dqs; uint32_t stop; - TRACE_FUNC("%lu %lu", write_group, test_bgn); - - ALTERA_ASSERT(write_group < RW_MGR_MEM_IF_WRITE_DQS_WIDTH); - //USER per-bit deskew for (i = 0; i < RW_MGR_MEM_DQ_PER_WRITE_DQS; i++) { @@ -4622,9 +4492,6 @@ static uint32_t rw_mgr_mem_calibrate_writes_center(uint32_t rank_bgn, uint32_t w static uint32_t rw_mgr_mem_calibrate_writes(uint32_t rank_bgn, uint32_t g, uint32_t test_bgn) { - //USER update info for sims - - TRACE_FUNC("%lu %lu", g, test_bgn); reg_file_set_stage(CAL_STAGE_WRITES); reg_file_set_sub_stage(CAL_SUBSTAGE_WRITES_CENTER); @@ -4681,8 +4548,6 @@ static void mem_config(void) uint32_t rw_wl_nop_cycles; uint32_t max_latency; - TRACE_FUNC(); - //USER read in write and read latency wlat = IORD_32DIRECT(MEM_T_WL_ADD, 0); @@ -4771,8 +4636,6 @@ static void mem_skip_calibrate(void) uint32_t vfifo_offset; uint32_t i, j, r; - TRACE_FUNC(); - // Need to update every shadow register set used by the interface for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS; r += NUM_RANKS_PER_SHADOW_REG) { @@ -4857,8 +4720,6 @@ static uint32_t mem_calibrate(void) uint32_t group_failed = 0; uint32_t sr_failed = 0; - TRACE_FUNC(); - // Initialize the data settings DPRINT(1, "Preparing to init data"); DPRINT(1, "Init complete"); @@ -4869,9 +4730,6 @@ static uint32_t mem_calibrate(void) gbl->fom_in = 0; gbl->fom_out = 0; - TCLRPT_SET(debug_summary_report->cal_read_latency, 0); - TCLRPT_SET(debug_summary_report->cal_write_latency, 0); - mem_config(); if (ARRIAV || CYCLONEV) { @@ -4991,10 +4849,6 @@ static uint32_t mem_calibrate(void) } } if (sr_failed == 0) { - TCLRPT_SET(debug_cal_report-> - cal_status_per_group[sr] - [write_group].error_stage, - CAL_STAGE_NIL); } else { group_failed = 1; } @@ -5057,19 +4911,6 @@ static uint32_t mem_calibrate(void) } } - TCLRPT_SET(debug_summary_report->cal_write_latency, IORD_32DIRECT(MEM_T_WL_ADD, 0)); - if (QUARTER_RATE == 1) { - // The read latency is in terms of AFI cycles so we multiply by 4 in quarter - // rate to get the memory cycles. - TCLRPT_SET(debug_summary_report->cal_read_latency, gbl->curr_read_lat * 4); - } else if (HALF_RATE == 1) { - // The read latency is in terms of AFI cycles so we multiply by 2 in half - // rate to get the memory cycles. - TCLRPT_SET(debug_summary_report->cal_read_latency, gbl->curr_read_lat * 2); - } else { - TCLRPT_SET(debug_summary_report->cal_read_latency, gbl->curr_read_lat); - } - //USER Do not remove this line as it makes sure all of our decisions have been applied IOWR_32DIRECT(SCC_MGR_UPD, 0, 0); return 1; @@ -5077,6 +4918,7 @@ static uint32_t mem_calibrate(void) static uint32_t run_mem_calibrate(void) { + uint32_t pass; uint32_t debug_info; uint32_t ctrlcfg = IORD_32DIRECT(CTRL_CONFIG_REG, 0); @@ -5085,10 +4927,6 @@ static uint32_t run_mem_calibrate(void) // This should occur before anything else // Reset pass/fail status shown on afi_cal_success/fail IOWR_32DIRECT(PHY_MGR_CAL_STATUS, 0, PHY_MGR_CAL_RESET); - - TRACE_FUNC(); - - BFM_STAGE("calibrate"); //stop tracking manger IOWR_32DIRECT(CTRL_CONFIG_REG, 0, ctrlcfg & 0xFFBFFFFF); @@ -5106,10 +4944,6 @@ static uint32_t run_mem_calibrate(void) IOWR_32DIRECT(PHY_MGR_CMD_FIFO_RESET, 0, 0); if (pass) { - TCLRPT_SET(debug_summary_report->error_stage, CAL_STAGE_NIL); - - BFM_STAGE("handoff"); - #ifdef TEST_SIZE if (!check_test_mem(0)) { gbl->error_stage = 0x92; @@ -5173,14 +5007,6 @@ static uint32_t run_mem_calibrate(void) } - // Mark the reports as being ready to read - TCLRPT_SET(debug_summary_report->report_flags, debug_summary_report->report_flags |= - DEBUG_REPORT_STATUS_REPORT_READY); - TCLRPT_SET(debug_cal_report->report_flags, debug_cal_report->report_flags |= - DEBUG_REPORT_STATUS_REPORT_READY); - TCLRPT_SET(debug_margin_report->report_flags, debug_margin_report->report_flags |= - DEBUG_REPORT_STATUS_REPORT_READY); - // Set the debug status to show that calibration has ended. // This should occur after everything else return pass; @@ -5349,7 +5175,6 @@ static int socfpga_mem_calibration(void) IPRINT("Preparing to start memory calibration"); - TRACE_FUNC(); DPRINT(1, "%s%s %s ranks=%lu cs/dimm=%lu dq/dqs=%lu,%lu vg/dqs=%lu,%lu dqs=%lu,%lu dq=%lu dm=%lu " "ptap_delay=%lu dtap_delay=%lu dtap_dqsen_delay=%lu, dll=%lu", diff --git a/arch/arm/mach-socfpga/include/mach/sequencer.h b/arch/arm/mach-socfpga/include/mach/sequencer.h index 1671849d6d..dd0378af34 100644 --- a/arch/arm/mach-socfpga/include/mach/sequencer.h +++ b/arch/arm/mach-socfpga/include/mach/sequencer.h @@ -65,6 +65,8 @@ #define RW_MGR_LOOPBACK_MODE BASE_RW_MGR + 0x0200 +#define RW_MGR_ENABLE_REFRESH BASE_RW_MGR + 0x3000 + #define RW_MGR_RANK_NONE 0xFF #define RW_MGR_RANK_ALL 0x00 diff --git a/arch/arm/mach-socfpga/include/mach/socfpga-regs.h b/arch/arm/mach-socfpga/include/mach/socfpga-regs.h index b124ed675c..e88daf7189 100644 --- a/arch/arm/mach-socfpga/include/mach/socfpga-regs.h +++ b/arch/arm/mach-socfpga/include/mach/socfpga-regs.h @@ -2,6 +2,8 @@ #define __MACH_SOCFPGA_REGS_H #define CYCLONE5_SDMMC_ADDRESS 0xff704000 +#define CYCLONE5_QSPI_CTRL_ADDRESS 0xff705000 +#define CYCLONE5_QSPI_DATA_ADDRESS 0xffa00000 #define CYCLONE5_FPGAMGRREGS_ADDRESS 0xff706000 #define CYCLONE5_GPIO0_BASE 0xff708000 #define CYCLONE5_GPIO1_BASE 0xff709000 diff --git a/arch/arm/mach-socfpga/xload.c b/arch/arm/mach-socfpga/xload.c index 3380092168..272896b6bd 100644 --- a/arch/arm/mach-socfpga/xload.c +++ b/arch/arm/mach-socfpga/xload.c @@ -1,3 +1,4 @@ +#include <platform_data/cadence_qspi.h> #include <platform_data/dw_mmc.h> #include <bootsource.h> #include <bootstrap.h> @@ -14,11 +15,19 @@ #include <linux/stat.h> #include <linux/clk.h> +#include <mach/generic.h> #include <mach/system-manager.h> #include <mach/socfpga-regs.h> +struct socfpga_barebox_part *barebox_part; + +static struct socfpga_barebox_part default_part = { + .nor_offset = SZ_256K, + .nor_size = SZ_1M, +}; + enum socfpga_clks { - timer, mmc, uart, clk_max + timer, mmc, qspi_clk, uart, clk_max }; static struct clk *clks[clk_max]; @@ -35,6 +44,43 @@ static void socfpga_mmc_init(void) IORESOURCE_MEM, &mmc_pdata); } +#if defined(CONFIG_SPI_CADENCE_QUADSPI) +static struct cadence_qspi_platform_data qspi_pdata = { + .ext_decoder = 0, + .fifo_depth = 128, +}; + +static __maybe_unused void add_cadence_qspi_device(int id, resource_size_t ctrl, + resource_size_t data, void *pdata) +{ + struct resource *res; + + res = xzalloc(sizeof(struct resource) * 2); + res[0].start = ctrl; + res[0].end = ctrl + 0x100 - 1; + res[0].flags = IORESOURCE_MEM; + res[1].start = data; + res[1].end = data + 0x100 - 1; + res[1].flags = IORESOURCE_MEM; + + add_generic_device_res("cadence_qspi", id, res, 2, pdata); +} + +static __maybe_unused void socfpga_qspi_init(void) +{ + clks[qspi_clk] = clk_fixed("qspi_clk", 370000000); + clkdev_add_physbase(clks[qspi_clk], CYCLONE5_QSPI_CTRL_ADDRESS, NULL); + clkdev_add_physbase(clks[qspi_clk], CYCLONE5_QSPI_DATA_ADDRESS, NULL); + add_cadence_qspi_device(0, CYCLONE5_QSPI_CTRL_ADDRESS, + CYCLONE5_QSPI_DATA_ADDRESS, &qspi_pdata); +} +#else +static void socfpga_qspi_init(void) +{ + return; +} +#endif + static struct NS16550_plat uart_pdata = { .clock = 100000000, .shift = 2, @@ -62,10 +108,19 @@ static __noreturn int socfpga_xload(void) enum bootsource bootsource = bootsource_get(); void *buf; + if (!barebox_part) + barebox_part = &default_part; + switch (bootsource) { case BOOTSOURCE_MMC: + socfpga_mmc_init(); buf = bootstrap_read_disk("disk0.1", "fat"); break; + case BOOTSOURCE_SPI: + socfpga_qspi_init(); + buf = bootstrap_read_devfs("mtd0", false, barebox_part->nor_offset, + barebox_part->nor_size, SZ_1M); + break; default: pr_err("unknown bootsource %d\n", bootsource); hang(); @@ -88,7 +143,6 @@ static int socfpga_devices_init(void) barebox_set_model("SoCFPGA"); socfpga_timer_init(); socfpga_uart_init(); - socfpga_mmc_init(); barebox_main = socfpga_xload; diff --git a/arch/arm/mach-tegra/include/mach/lowlevel.h b/arch/arm/mach-tegra/include/mach/lowlevel.h index f1fea86cf6..0c76b8883c 100644 --- a/arch/arm/mach-tegra/include/mach/lowlevel.h +++ b/arch/arm/mach-tegra/include/mach/lowlevel.h @@ -111,9 +111,9 @@ u32 tegra_get_odmdata(void) return 0; } - bctptr = cpu_readl(TEGRA_IRAM_BASE + bctptr_offset); + bctptr = __raw_readl(TEGRA_IRAM_BASE + bctptr_offset); - return cpu_readl(bctptr + odmdata_offset); + return __raw_readl(bctptr + odmdata_offset); } static __always_inline @@ -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/arm/pbl/Makefile b/arch/arm/pbl/Makefile index 4c1788dd9d..1ff39dbdfe 100644 --- a/arch/arm/pbl/Makefile +++ b/arch/arm/pbl/Makefile @@ -22,7 +22,7 @@ endif $(obj)/zbarebox.bin: $(obj)/zbarebox FORCE $(call if_changed,objcopy) - $(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE)) + $(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE)) $(Q)$(kecho) ' Barebox: fix size' $(Q)$(objtree)/scripts/fix_size -i -f $(objtree)/$@ $(FIX_SIZE) $(Q)$(kecho) ' Barebox: $@ is ready' 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/posix_types.h b/arch/blackfin/include/asm/posix_types.h index 9992929ada..22cae6230c 100644 --- a/arch/blackfin/include/asm/posix_types.h +++ b/arch/blackfin/include/asm/posix_types.h @@ -1,85 +1 @@ -/* - * barebox - posix_types.h - * - * Copyright (c) 2005 blackfin.uclinux.org - * - * (C) Copyright 2000-2004 - * Wolfgang Denk, DENX Software Engineering, 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 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. - * - */ - -#ifndef __ARCH_BLACKFIN_POSIX_TYPES_H -#define __ARCH_BLACKFIN_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned long __kernel_ino_t; -typedef unsigned short __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid_t; -typedef unsigned short __kernel_gid_t; -typedef unsigned long __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_daddr_t; -typedef char *__kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned short __kernel_old_uid_t; -typedef unsigned short __kernel_old_gid_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { -#if defined(__KERNEL__) || defined(__USE_ALL) - int val[2]; -#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ - int __val[2]; -#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ -} __kernel_fsid_t; - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) - -#undef __FD_SET -#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) - -#undef __FD_CLR -#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) - -#undef __FD_ISSET -#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) - -#undef __FD_ZERO -#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) - -#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ - -#endif +#include <asm-generic/posix_types.h> 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/blackfin/include/asm/types.h b/arch/blackfin/include/asm/types.h index 3d2bd35ef4..e9d73377eb 100644 --- a/arch/blackfin/include/asm/types.h +++ b/arch/blackfin/include/asm/types.h @@ -69,14 +69,10 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -/* Dma addresses are 32-bits wide. */ - -typedef u32 dma_addr_t; - #endif #endif /* __ASSEMBLY__ */ -#define BITS_PER_LONG 32 +#include <asm/bitsperlong.h> #endif diff --git a/arch/efi/include/asm/bitsperlong.h b/arch/efi/include/asm/bitsperlong.h new file mode 100644 index 0000000000..00c1fc2625 --- /dev/null +++ b/arch/efi/include/asm/bitsperlong.h @@ -0,0 +1,10 @@ +#ifndef __ASM_BITSPERLONG_H +#define __ASM_BITSPERLONG_H + +#ifdef __x86_64__ +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif + +#endif /* __ASM_BITSPERLONG_H */ diff --git a/arch/efi/include/asm/posix_types.h b/arch/efi/include/asm/posix_types.h index 6985b8eb4a..22cae6230c 100644 --- a/arch/efi/include/asm/posix_types.h +++ b/arch/efi/include/asm/posix_types.h @@ -1,93 +1 @@ -#ifndef __ARCH_I386_POSIX_TYPES_H -#define __ARCH_I386_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned long __kernel_ino_t; -typedef unsigned short __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid_t; -typedef unsigned short __kernel_gid_t; -/* - * Most 32 bit architectures use "unsigned int" size_t, - * and all 64 bit architectures use "unsigned long" size_t. - * - * TODO: It's not clean to use __x86_64__ here. It's better - * to check on __BITS_PER_LONG here. But this is wrong set in - * arch/sandbox/include/asm/types.h. - */ -#ifdef __x86_64__ -typedef unsigned long __kernel_size_t; -typedef long __kernel_ssize_t; -typedef long __kernel_ptrdiff_t; -#else -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -#endif -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_daddr_t; -typedef char * __kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned short __kernel_old_uid_t; -typedef unsigned short __kernel_old_gid_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { -#if defined(__KERNEL__) || defined(__USE_ALL) - int val[2]; -#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ - int __val[2]; -#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ -} __kernel_fsid_t; - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) - -#undef __FD_SET -#define __FD_SET(fd,fdsetp) \ - __asm__ __volatile__("btsl %1,%0": \ - "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) - -#undef __FD_CLR -#define __FD_CLR(fd,fdsetp) \ - __asm__ __volatile__("btrl %1,%0": \ - "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) - -#undef __FD_ISSET -#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ - unsigned char __result; \ - __asm__ __volatile__("btl %1,%2 ; setb %0" \ - :"=q" (__result) :"r" ((int) (fd)), \ - "m" (*(__kernel_fd_set *) (fdsetp))); \ - __result; })) - -#undef __FD_ZERO -#define __FD_ZERO(fdsetp) \ -do { \ - int __d0, __d1; \ - __asm__ __volatile__("cld ; rep ; stosl" \ - :"=m" (*(__kernel_fd_set *) (fdsetp)), \ - "=&c" (__d0), "=&D" (__d1) \ - :"a" (0), "1" (__FDSET_LONGS), \ - "2" ((__kernel_fd_set *) (fdsetp)) : "memory"); \ -} while (0) - -#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ - -#endif +#include <asm-generic/posix_types.h> diff --git a/arch/efi/include/asm/types.h b/arch/efi/include/asm/types.h index 3204448dce..3caac398d8 100644 --- a/arch/efi/include/asm/types.h +++ b/arch/efi/include/asm/types.h @@ -56,15 +56,7 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -#ifdef __x86_64__ -#define BITS_PER_LONG 64 -#else -#define BITS_PER_LONG 32 -#endif - -/* Dma addresses are 32-bits wide. */ - -typedef u32 dma_addr_t; +#include <asm/bitsperlong.h> #endif /* __KERNEL__ */ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ed6e1ab2df..aeb5c04fce 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -269,6 +269,7 @@ config 32BIT config 64BIT bool "64-bit barebox" depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL + select ARCH_DMA_ADDR_T_64BIT help Select this option if you want to build a 64-bit barebox. diff --git a/arch/mips/configs/dlink-dir-320_defconfig b/arch/mips/configs/dlink-dir-320_defconfig index 4c9a06f2b0..61798bf599 100644 --- a/arch/mips/configs/dlink-dir-320_defconfig +++ b/arch/mips/configs/dlink-dir-320_defconfig @@ -2,7 +2,6 @@ CONFIG_BUILTIN_DTB=y CONFIG_BUILTIN_DTB_NAME="dlink-dir-320" CONFIG_MACH_MIPS_BCM47XX=y CONFIG_STACK_SIZE=0x7000 -CONFIG_BROKEN=y CONFIG_EXPERIMENTAL=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y @@ -35,9 +34,9 @@ CONFIG_CMD_PING=y CONFIG_CMD_TFTP=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_EDIT=y +CONFIG_CMD_LOGIN=y CONFIG_CMD_MENU=y CONFIG_CMD_MENU_MANAGEMENT=y -CONFIG_CMD_LOGIN=y CONFIG_CMD_PASSWD=y CONFIG_CMD_READLINE=y CONFIG_CMD_TIMEOUT=y diff --git a/arch/mips/configs/img-ci20_defconfig b/arch/mips/configs/img-ci20_defconfig index 6702c88b65..28319c523f 100644 --- a/arch/mips/configs/img-ci20_defconfig +++ b/arch/mips/configs/img-ci20_defconfig @@ -28,15 +28,18 @@ CONFIG_CMD_UIMAGE=y CONFIG_CMD_MD5SUM=y CONFIG_CMD_GETOPT=y CONFIG_CMD_SLEEP=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y CONFIG_CMD_EDIT=y CONFIG_CMD_GPIO=y CONFIG_CMD_OF_NODE=y CONFIG_CMD_OF_PROPERTY=y CONFIG_CMD_OFTREE=y +CONFIG_NET=y CONFIG_OFDEVICE=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set -CONFIG_CLOCKSOURCE_DUMMY=y CONFIG_CLOCKSOURCE_DUMMY_RATE=3500 -CONFIG_DIGEST_SHA1_GENERIC=y -CONFIG_DIGEST_SHA224_GENERIC=y -CONFIG_DIGEST_SHA256_GENERIC=y +CONFIG_FS_TFTP=y diff --git a/arch/mips/dts/img-ci20.dts b/arch/mips/dts/img-ci20.dts index f2022dd273..da2a5bf625 100644 --- a/arch/mips/dts/img-ci20.dts +++ b/arch/mips/dts/img-ci20.dts @@ -28,6 +28,21 @@ device_type = "memory"; reg = <0x0 0x10000000>; }; + + board { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <>; + + dm9000@16000000 { + compatible = "davicom,dm9000"; + davicom,no-eeprom; + + reg = <0x16000000 1 /* addr */ + 0x16000002 1>; /* data */ + }; + }; }; &uart0 { diff --git a/arch/mips/include/asm/bitsperlong.h b/arch/mips/include/asm/bitsperlong.h index 3e4c10a8e7..41712161bc 100644 --- a/arch/mips/include/asm/bitsperlong.h +++ b/arch/mips/include/asm/bitsperlong.h @@ -1,8 +1,6 @@ #ifndef __ASM_MIPS_BITSPERLONG_H #define __ASM_MIPS_BITSPERLONG_H -#define __BITS_PER_LONG _MIPS_SZLONG - -#include <asm-generic/bitsperlong.h> +#define BITS_PER_LONG _MIPS_SZLONG #endif /* __ASM_MIPS_BITSPERLONG_H */ diff --git a/arch/mips/include/asm/debug_ll_ns16550.h b/arch/mips/include/asm/debug_ll_ns16550.h index a3e1c52f63..4a6562f7c1 100644 --- a/arch/mips/include/asm/debug_ll_ns16550.h +++ b/arch/mips/include/asm/debug_ll_ns16550.h @@ -57,7 +57,7 @@ #include <asm/io.h> -static __inline__ void PUTC_LL(char ch) +static inline void PUTC_LL(char ch) { #ifdef CONFIG_DEBUG_LL while (!(__raw_readb((u8 *)DEBUG_LL_UART_ADDR + UART_LSR) & UART_LSR_THRE)) diff --git a/arch/mips/include/asm/posix_types.h b/arch/mips/include/asm/posix_types.h index bbeb7211f6..c38e24a4b2 100644 --- a/arch/mips/include/asm/posix_types.h +++ b/arch/mips/include/asm/posix_types.h @@ -11,134 +11,6 @@ #include <asm/sgidefs.h> -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned long __kernel_ino_t; -typedef unsigned int __kernel_mode_t; -#if (_MIPS_SZLONG == 32) -typedef unsigned long __kernel_nlink_t; -#endif -#if (_MIPS_SZLONG == 64) -typedef unsigned int __kernel_nlink_t; -#endif -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef int __kernel_ipc_pid_t; -typedef unsigned int __kernel_uid_t; -typedef unsigned int __kernel_gid_t; -#if (_MIPS_SZLONG == 32) -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -#endif -#if (_MIPS_SZLONG == 64) -typedef unsigned long __kernel_size_t; -typedef long __kernel_ssize_t; -typedef long __kernel_ptrdiff_t; -#endif -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_timer_t; -typedef int __kernel_clockid_t; -typedef long __kernel_daddr_t; -typedef char * __kernel_caddr_t; - -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; -typedef __kernel_uid_t __kernel_old_uid_t; -typedef __kernel_gid_t __kernel_old_gid_t; -typedef unsigned int __kernel_old_dev_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { -#if (_MIPS_SZLONG == 32) - long val[2]; -#endif -#if (_MIPS_SZLONG == 64) - int val[2]; -#endif -} __kernel_fsid_t; - -#if defined(__KERNEL__) - -#undef __FD_SET -static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp) -{ - unsigned long __tmp = __fd / __NFDBITS; - unsigned long __rem = __fd % __NFDBITS; - __fdsetp->fds_bits[__tmp] |= (1UL<<__rem); -} - -#undef __FD_CLR -static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp) -{ - unsigned long __tmp = __fd / __NFDBITS; - unsigned long __rem = __fd % __NFDBITS; - __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem); -} - -#undef __FD_ISSET -static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p) -{ - unsigned long __tmp = __fd / __NFDBITS; - unsigned long __rem = __fd % __NFDBITS; - return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0; -} - -/* - * This will unroll the loop for the normal constant case (8 ints, - * for a 256-bit fd_set) - */ -#undef __FD_ZERO -static __inline__ void __FD_ZERO(__kernel_fd_set *__p) -{ - unsigned long *__tmp = __p->fds_bits; - int __i; - - if (__builtin_constant_p(__FDSET_LONGS)) { - switch (__FDSET_LONGS) { - case 16: - __tmp[0] = 0; __tmp[1] = 0; - __tmp[2] = 0; __tmp[3] = 0; - __tmp[4] = 0; __tmp[5] = 0; - __tmp[6] = 0; __tmp[7] = 0; - __tmp[8] = 0; __tmp[9] = 0; - __tmp[10] = 0; __tmp[11] = 0; - __tmp[12] = 0; __tmp[13] = 0; - __tmp[14] = 0; __tmp[15] = 0; - return; - - case 8: - __tmp[0] = 0; __tmp[1] = 0; - __tmp[2] = 0; __tmp[3] = 0; - __tmp[4] = 0; __tmp[5] = 0; - __tmp[6] = 0; __tmp[7] = 0; - return; - - case 4: - __tmp[0] = 0; __tmp[1] = 0; - __tmp[2] = 0; __tmp[3] = 0; - return; - } - } - __i = __FDSET_LONGS; - while (__i) { - __i--; - *__tmp = 0; - __tmp++; - } -} - -#endif /* defined(__KERNEL__) */ +#include <asm-generic/posix_types.h> #endif /* _ASM_POSIX_TYPES_H */ diff --git a/arch/mips/include/asm/types.h b/arch/mips/include/asm/types.h index b63687d37b..4140c92e1a 100644 --- a/arch/mips/include/asm/types.h +++ b/arch/mips/include/asm/types.h @@ -13,18 +13,6 @@ #include <asm-generic/int-ll64.h> -#ifndef __ASSEMBLY__ - -#if (defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) \ - || defined(CONFIG_64BIT) -typedef u64 dma_addr_t; -#else -typedef u32 dma_addr_t; -#endif -typedef u64 dma64_addr_t; - -#endif /* __ASSEMBLY__ */ - /* * We don't use int-l64.h for the kernel anymore but still use it for * userspace to avoid code changes. diff --git a/arch/mips/mach-ath79/include/mach/debug_ll.h b/arch/mips/mach-ath79/include/mach/debug_ll.h index c697318488..64db67499c 100644 --- a/arch/mips/mach-ath79/include/mach/debug_ll.h +++ b/arch/mips/mach-ath79/include/mach/debug_ll.h @@ -41,12 +41,12 @@ static inline void ar933x_debug_ll_writel(u32 b, int offset) { - cpu_writel(b, (u8 *)DEBUG_LL_UART_ADDR + offset); + __raw_writel(b, (u8 *)DEBUG_LL_UART_ADDR + offset); } static inline u32 ar933x_debug_ll_readl(int offset) { - return cpu_readl((u8 *)DEBUG_LL_UART_ADDR + offset); + return __raw_readl((u8 *)DEBUG_LL_UART_ADDR + offset); } static inline void PUTC_LL(int ch) diff --git a/arch/mips/mach-bcm47xx/include/mach/debug_ll.h b/arch/mips/mach-bcm47xx/include/mach/debug_ll.h index 9927b4d945..3e74e0f670 100644 --- a/arch/mips/mach-bcm47xx/include/mach/debug_ll.h +++ b/arch/mips/mach-bcm47xx/include/mach/debug_ll.h @@ -24,16 +24,12 @@ #include <io.h> #include <mach/hardware.h> -#define rbr 0 -#define lsr 5 -#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define DEBUG_LL_UART_SHIFT 0 -static __inline__ void PUTC_LL(char ch) -{ - void *base = (void *)DEBUG_LL_UART_ADDR; +#define DEBUG_LL_UART_CLK (25804800 / 16) +#define DEBUG_LL_UART_BPS CONFIG_BAUDRATE +#define DEBUG_LL_UART_DIVISOR (DEBUG_LL_UART_CLK / DEBUG_LL_UART_BPS) - while (!(__raw_readb(base + lsr) & LSR_THRE)); - __raw_writeb(ch, base + rbr); -} +#include <asm/debug_ll_ns16550.h> #endif /* __INCLUDE_ARCH_DEBUG_LL_H__ */ 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/mips/mach-xburst/Kconfig b/arch/mips/mach-xburst/Kconfig index 2598c41cdf..fd106fefe0 100644 --- a/arch/mips/mach-xburst/Kconfig +++ b/arch/mips/mach-xburst/Kconfig @@ -27,6 +27,7 @@ config BOARD_RZX50 config BOARD_CI20 bool "Imagination Creator CI20" select CPU_JZ4780 + select HAS_DM9000 endchoice diff --git a/arch/mips/pbl/Makefile b/arch/mips/pbl/Makefile index fea1f249bb..b03bca1258 100644 --- a/arch/mips/pbl/Makefile +++ b/arch/mips/pbl/Makefile @@ -15,7 +15,7 @@ extra-y += piggy.gzip piggy.lz4 piggy.lzo piggy.lzma piggy.xzkern piggy.sh $(obj)/zbarebox.bin: $(obj)/zbarebox FORCE $(call if_changed,objcopy) - $(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE)) + $(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE)) $(Q)$(kecho) ' Barebox: $@ is ready' $(obj)/zbarebox.S: $(obj)/zbarebox FORCE diff --git a/arch/nios2/include/asm/posix_types.h b/arch/nios2/include/asm/posix_types.h index 5a901ffe43..22cae6230c 100644 --- a/arch/nios2/include/asm/posix_types.h +++ b/arch/nios2/include/asm/posix_types.h @@ -1,77 +1 @@ -/* - * arch/arm/include/asm/posix_types.h - * - * Copyright (C) 1996-1998 Russell King. - * - * 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. - * - * Changelog: - * 27-06-1996 RMK Created - */ -#ifndef __ARCH_ARM_POSIX_TYPES_H -#define __ARCH_ARM_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned long __kernel_ino_t; -typedef unsigned short __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid_t; -typedef unsigned short __kernel_gid_t; -typedef unsigned long __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_timer_t; -typedef int __kernel_clockid_t; -typedef int __kernel_daddr_t; -typedef char * __kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned short __kernel_old_uid_t; -typedef unsigned short __kernel_old_gid_t; -typedef unsigned short __kernel_old_dev_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { - int val[2]; -} __kernel_fsid_t; - -#if defined(__KERNEL__) - -#undef __FD_SET -#define __FD_SET(fd, fdsetp) \ - (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31))) - -#undef __FD_CLR -#define __FD_CLR(fd, fdsetp) \ - (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31))) - -#undef __FD_ISSET -#define __FD_ISSET(fd, fdsetp) \ - ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0) - -#undef __FD_ZERO -#define __FD_ZERO(fdsetp) \ - (memset(fdsetp, 0, sizeof(*(fd_set *)(fdsetp)))) - -#endif - -#endif +#include <asm-generic/posix_types.h> diff --git a/arch/nios2/include/asm/types.h b/arch/nios2/include/asm/types.h index 21c3415f93..0067ea83c1 100644 --- a/arch/nios2/include/asm/types.h +++ b/arch/nios2/include/asm/types.h @@ -3,7 +3,4 @@ #include <asm/int-ll64.h> -typedef u32 dma_addr_t; - #endif - diff --git a/arch/openrisc/include/asm/bitsperlong.h b/arch/openrisc/include/asm/bitsperlong.h new file mode 100644 index 0000000000..6dc0bb0c13 --- /dev/null +++ b/arch/openrisc/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include <asm-generic/bitsperlong.h> diff --git a/arch/openrisc/include/asm/posix_types.h b/arch/openrisc/include/asm/posix_types.h index 7f4c9423ca..22cae6230c 100644 --- a/arch/openrisc/include/asm/posix_types.h +++ b/arch/openrisc/include/asm/posix_types.h @@ -1,71 +1 @@ -/* - * Based on microblaze implementation: - * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au> - * Copyright (C) 2001,2002 NEC Corporation - * Copyright (C) 2001,2002 Miles Bader <miles@gnu.org> - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of this - * archive for more details. - * - * Written by Miles Bader <miles@gnu.org> - * Microblaze port by John Williams - */ - -#ifndef __ASM_OPENRISC_POSIX_TYPES_H -#define __ASM_OPENRISC_POSIX_TYPES_H - -typedef unsigned long __kernel_ino_t; -typedef unsigned long long __kernel_ino64_t; -typedef unsigned int __kernel_mode_t; -typedef unsigned int __kernel_nlink_t; -typedef long __kernel_off_t; -typedef long long __kernel_loff_t; -typedef int __kernel_pid_t; -typedef unsigned short __kernel_ipc_pid_t; -typedef unsigned int __kernel_uid_t; -typedef unsigned int __kernel_gid_t; -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_daddr_t; -typedef char *__kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned short __kernel_old_uid_t; -typedef unsigned short __kernel_old_gid_t; - - -typedef struct { -#if defined(__KERNEL__) || defined(__USE_ALL) - int val[2]; -#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ - int __val[2]; -#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ -} __kernel_fsid_t; - - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) - -#undef __FD_SET -#define __FD_SET(fd, fd_set) \ - __set_bit(fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) -#undef __FD_CLR -#define __FD_CLR(fd, fd_set) \ - __clear_bit(fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) -#undef __FD_ISSET -#define __FD_ISSET(fd, fd_set) \ - __test_bit(fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) -#undef __FD_ZERO -#define __FD_ZERO(fd_set) \ - memset(fd_set, 0, sizeof(*(fd_set *)fd_set)) - -#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ - -#endif /* __ASM_OPENRISC_POSIX_TYPES_H */ +#include <asm-generic/posix_types.h> diff --git a/arch/openrisc/include/asm/types.h b/arch/openrisc/include/asm/types.h index 3338fcfdeb..5b6391baf0 100644 --- a/arch/openrisc/include/asm/types.h +++ b/arch/openrisc/include/asm/types.h @@ -62,11 +62,7 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -#define BITS_PER_LONG 32 - -/* Dma addresses are 32-bits wide. */ - -typedef u32 dma_addr_t; +#include <asm/bitsperlong.h> #endif /* __KERNEL__ */ 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 c4ed2de65f..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; } @@ -189,67 +189,4 @@ extern __inline__ int ffs(int x) #include <asm-generic/bitops/find.h> -#define _EXT2_HAVE_ASM_BITOPS_ - -#ifdef __KERNEL__ -/* - * test_and_{set,clear}_bit guarantee atomicity without - * disabling interrupts. - */ -#define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x18, addr) -#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x18, addr) - -#else -extern __inline__ int ext2_set_bit(int nr, void * addr) -{ - int mask; - unsigned char *ADDR = (unsigned char *) addr; - int oldbit; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - oldbit = (*ADDR & mask) ? 1 : 0; - *ADDR |= mask; - return oldbit; -} - -extern __inline__ int ext2_clear_bit(int nr, void * addr) -{ - int mask; - unsigned char *ADDR = (unsigned char *) addr; - int oldbit; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - oldbit = (*ADDR & mask) ? 1 : 0; - *ADDR = *ADDR & ~mask; - return oldbit; -} -#endif /* __KERNEL__ */ - -extern __inline__ int ext2_test_bit(int nr, __const__ void * addr) -{ - __const__ unsigned char *ADDR = (__const__ unsigned char *) addr; - - return (ADDR[nr >> 3] >> (nr & 7)) & 1; -} - -/* - * This implementation of ext2_find_{first,next}_zero_bit was stolen from - * Linus' asm-alpha/bitops.h and modified for a big-endian machine. - */ - -#define ext2_find_first_zero_bit(addr, size) \ - ext2_find_next_zero_bit((addr), (size), 0) - -#define ext2_find_next_zero_bit(addr, size, off) \ - generic_find_next_zero_le_bit((unsigned long*)addr, size, off) - -/* Bitmap functions for the minix filesystem. */ -#define minix_test_and_set_bit(nr,addr) ext2_set_bit(nr,addr) -#define minix_set_bit(nr,addr) ((void)ext2_set_bit(nr,addr)) -#define minix_test_and_clear_bit(nr,addr) ext2_clear_bit(nr,addr) -#define minix_test_bit(nr,addr) ext2_test_bit(nr,addr) -#define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size) - #endif /* _PPC_BITOPS_H */ diff --git a/arch/ppc/include/asm/bitsperlong.h b/arch/ppc/include/asm/bitsperlong.h new file mode 100644 index 0000000000..6dc0bb0c13 --- /dev/null +++ b/arch/ppc/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include <asm-generic/bitsperlong.h> 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/posix_types.h b/arch/ppc/include/asm/posix_types.h index a7af4064ee..22cae6230c 100644 --- a/arch/ppc/include/asm/posix_types.h +++ b/arch/ppc/include/asm/posix_types.h @@ -1,108 +1 @@ -#ifndef _PPC_POSIX_TYPES_H -#define _PPC_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned int __kernel_ino_t; -typedef unsigned int __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned int __kernel_uid_t; -typedef unsigned int __kernel_gid_t; -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef long __kernel_ptrdiff_t; -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_daddr_t; -typedef char * __kernel_caddr_t; -typedef short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned int __kernel_old_uid_t; -typedef unsigned int __kernel_old_gid_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { - int val[2]; -} __kernel_fsid_t; - -#ifndef __GNUC__ - -#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) -#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) -#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) -#define __FD_ZERO(set) \ - ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set))) - -#else /* __GNUC__ */ - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \ - || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) -/* With GNU C, use inline functions instead so args are evaluated only once: */ - -#undef __FD_SET -static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - fdsetp->fds_bits[_tmp] |= (1UL<<_rem); -} - -#undef __FD_CLR -static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); -} - -#undef __FD_ISSET -static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; -} - -/* - * This will unroll the loop for the normal constant case (8 ints, - * for a 256-bit fd_set) - */ -#undef __FD_ZERO -static __inline__ void __FD_ZERO(__kernel_fd_set *p) -{ - unsigned int *tmp = (unsigned int *)p->fds_bits; - int i; - - if (__builtin_constant_p(__FDSET_LONGS)) { - switch (__FDSET_LONGS) { - case 8: - tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; - tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; - return; - } - } - i = __FDSET_LONGS; - while (i) { - i--; - *tmp = 0; - tmp++; - } -} - -#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ -#endif /* __GNUC__ */ -#endif /* _PPC_POSIX_TYPES_H */ +#include <asm-generic/posix_types.h> 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/ppc/include/asm/types.h b/arch/ppc/include/asm/types.h index 4ebbb9e028..6eb3877032 100644 --- a/arch/ppc/include/asm/types.h +++ b/arch/ppc/include/asm/types.h @@ -39,10 +39,7 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -#define BITS_PER_LONG 32 - -/* DMA addresses are 32-bits wide */ -typedef u32 dma_addr_t; +#include <asm-generic/bitsperlong.h> #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/arch/sandbox/include/asm/bitsperlong.h b/arch/sandbox/include/asm/bitsperlong.h new file mode 100644 index 0000000000..00c1fc2625 --- /dev/null +++ b/arch/sandbox/include/asm/bitsperlong.h @@ -0,0 +1,10 @@ +#ifndef __ASM_BITSPERLONG_H +#define __ASM_BITSPERLONG_H + +#ifdef __x86_64__ +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif + +#endif /* __ASM_BITSPERLONG_H */ 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/arch/sandbox/include/asm/posix_types.h b/arch/sandbox/include/asm/posix_types.h index 6985b8eb4a..22cae6230c 100644 --- a/arch/sandbox/include/asm/posix_types.h +++ b/arch/sandbox/include/asm/posix_types.h @@ -1,93 +1 @@ -#ifndef __ARCH_I386_POSIX_TYPES_H -#define __ARCH_I386_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned long __kernel_ino_t; -typedef unsigned short __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid_t; -typedef unsigned short __kernel_gid_t; -/* - * Most 32 bit architectures use "unsigned int" size_t, - * and all 64 bit architectures use "unsigned long" size_t. - * - * TODO: It's not clean to use __x86_64__ here. It's better - * to check on __BITS_PER_LONG here. But this is wrong set in - * arch/sandbox/include/asm/types.h. - */ -#ifdef __x86_64__ -typedef unsigned long __kernel_size_t; -typedef long __kernel_ssize_t; -typedef long __kernel_ptrdiff_t; -#else -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -#endif -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_daddr_t; -typedef char * __kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; - -typedef unsigned short __kernel_old_uid_t; -typedef unsigned short __kernel_old_gid_t; - -#ifdef __GNUC__ -typedef long long __kernel_loff_t; -#endif - -typedef struct { -#if defined(__KERNEL__) || defined(__USE_ALL) - int val[2]; -#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ - int __val[2]; -#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ -} __kernel_fsid_t; - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) - -#undef __FD_SET -#define __FD_SET(fd,fdsetp) \ - __asm__ __volatile__("btsl %1,%0": \ - "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) - -#undef __FD_CLR -#define __FD_CLR(fd,fdsetp) \ - __asm__ __volatile__("btrl %1,%0": \ - "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) - -#undef __FD_ISSET -#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ - unsigned char __result; \ - __asm__ __volatile__("btl %1,%2 ; setb %0" \ - :"=q" (__result) :"r" ((int) (fd)), \ - "m" (*(__kernel_fd_set *) (fdsetp))); \ - __result; })) - -#undef __FD_ZERO -#define __FD_ZERO(fdsetp) \ -do { \ - int __d0, __d1; \ - __asm__ __volatile__("cld ; rep ; stosl" \ - :"=m" (*(__kernel_fd_set *) (fdsetp)), \ - "=&c" (__d0), "=&D" (__d1) \ - :"a" (0), "1" (__FDSET_LONGS), \ - "2" ((__kernel_fd_set *) (fdsetp)) : "memory"); \ -} while (0) - -#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ - -#endif +#include <asm-generic/posix_types.h> diff --git a/arch/sandbox/include/asm/types.h b/arch/sandbox/include/asm/types.h index d471d257be..501883f5aa 100644 --- a/arch/sandbox/include/asm/types.h +++ b/arch/sandbox/include/asm/types.h @@ -54,11 +54,7 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -#define BITS_PER_LONG 32 - -/* Dma addresses are 32-bits wide. */ - -typedef u32 dma_addr_t; +#include <asm/bitsperlong.h> #endif /* __KERNEL__ */ diff --git a/arch/x86/include/asm/bitsperlong.h b/arch/x86/include/asm/bitsperlong.h new file mode 100644 index 0000000000..6dc0bb0c13 --- /dev/null +++ b/arch/x86/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include <asm-generic/bitsperlong.h> diff --git a/arch/x86/include/asm/posix_types.h b/arch/x86/include/asm/posix_types.h index 066f159cc9..22cae6230c 100644 --- a/arch/x86/include/asm/posix_types.h +++ b/arch/x86/include/asm/posix_types.h @@ -1,44 +1 @@ -/* - * 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. - * - * - */ - -/** - * @file - * @brief x86 posix types - * - * Minimal set to make all the other header files copied from the Linux kernel happy - */ - -#ifndef _ASM_X86_POSIX_TYPES_H -#define _ASM_X86_POSIX_TYPES_H - -typedef unsigned long __kernel_ino_t; -typedef unsigned short __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; -typedef long __kernel_off_t; -typedef int __kernel_pid_t; -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -typedef long __kernel_time_t; -typedef long __kernel_suseconds_t; -typedef long __kernel_clock_t; -typedef int __kernel_daddr_t; -typedef char * __kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; -typedef long long __kernel_loff_t; - -#endif /* _ASM_X86_POSIX_TYPES_H */ +#include <asm-generic/posix_types.h> diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h index b3fd1f644b..d60612ff74 100644 --- a/arch/x86/include/asm/types.h +++ b/arch/x86/include/asm/types.h @@ -41,7 +41,7 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -#define BITS_PER_LONG 32 +#include <asm-generic/bitsperlong.h> #endif /* __ASSEMBLY__ */ diff --git a/commands/Kconfig b/commands/Kconfig index 25c77a85c5..bb6674e6c2 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1183,6 +1183,7 @@ menu "Network" config CMD_DHCP bool + select NET_DHCP prompt "dhcp" help DHCP client to obtain IP or boot params diff --git a/commands/Makefile b/commands/Makefile index b902f58ec5..36983477be 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -111,3 +111,4 @@ obj-$(CONFIG_CMD_CMP) += cmp.o obj-$(CONFIG_CMD_NV) += nv.o obj-$(CONFIG_CMD_DEFAULTENV) += defaultenv.o obj-$(CONFIG_CMD_STATE) += state.o +obj-$(CONFIG_CMD_DHCP) += dhcp.o 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/dhcp.c b/commands/dhcp.c new file mode 100644 index 0000000000..eb98bfc2a7 --- /dev/null +++ b/commands/dhcp.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 PHYTEC Messtechnik GmbH, + * Author: Wadim Egorov <w.egorov@phytec.de> + * + * Based on work of Sascha Hauer <s.hauer@pengutronix.de>. + * + * 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. + */ + +#include <common.h> +#include <command.h> +#include <complete.h> +#include <environment.h> +#include <getopt.h> +#include <dhcp.h> + +static int do_dhcp(int argc, char *argv[]) +{ + int ret, opt; + int retries = DHCP_DEFAULT_RETRY; + struct dhcp_req_param dhcp_param; + + memset(&dhcp_param, 0, sizeof(struct dhcp_req_param)); + getenv_uint("global.dhcp.retries", &retries); + + while ((opt = getopt(argc, argv, "H:v:c:u:U:r:")) > 0) { + switch (opt) { + case 'H': + dhcp_param.hostname = optarg; + break; + case 'v': + dhcp_param.vendor_id = optarg; + break; + case 'c': + dhcp_param.client_id = optarg; + break; + case 'u': + dhcp_param.client_uuid = optarg; + break; + case 'U': + dhcp_param.user_class = optarg; + break; + case 'r': + retries = simple_strtoul(optarg, NULL, 10); + break; + } + } + + if (!retries) { + printf("retries is set to zero, set it to %d\n", DHCP_DEFAULT_RETRY); + retries = DHCP_DEFAULT_RETRY; + } + + ret = dhcp(retries, &dhcp_param); + + return ret; +} + +BAREBOX_CMD_HELP_START(dhcp) +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-H HOSTNAME", "hostname to send to the DHCP server") +BAREBOX_CMD_HELP_OPT("-v ID\t", "DHCP Vendor ID (code 60) submitted in DHCP requests") +BAREBOX_CMD_HELP_OPT("-c ID\t", "DHCP Client ID (code 61) submitted in DHCP requests") +BAREBOX_CMD_HELP_OPT("-u UUID\t", "DHCP Client UUID (code 97) submitted in DHCP requests") +BAREBOX_CMD_HELP_OPT("-U CLASS", "DHCP User class (code 77) submitted in DHCP requests") +BAREBOX_CMD_HELP_OPT("-r RETRY", "retry limit (default 20)"); +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(dhcp) + .cmd = do_dhcp, + BAREBOX_CMD_DESC("DHCP client to obtain IP or boot params") + BAREBOX_CMD_OPTS("[-HvcuUr]") + BAREBOX_CMD_GROUP(CMD_GRP_NET) + BAREBOX_CMD_HELP(cmd_dhcp_help) + BAREBOX_CMD_COMPLETE(empty_complete) +BAREBOX_CMD_END 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/loadb.c b/commands/loadb.c index 7424bcc08c..be5830da32 100644 --- a/commands/loadb.c +++ b/commands/loadb.c @@ -604,9 +604,8 @@ static int do_load_serial_bin(int argc, char *argv[]) ulong offset = 0; ulong addr; int load_baudrate = 0, current_baudrate; - int rcode = 0; + int rcode = 0, ret; int opt; - int open_mode = O_WRONLY; char *output_file = NULL; struct console_device *cdev = NULL; @@ -621,9 +620,6 @@ static int do_load_serial_bin(int argc, char *argv[]) case 'o': offset = (int)simple_strtoul(optarg, NULL, 10); break; - case 'c': - open_mode |= O_CREAT; - break; default: perror(argv[0]); return 1; @@ -635,7 +631,7 @@ static int do_load_serial_bin(int argc, char *argv[]) printf("%s:No console device with STDIN and STDOUT\n", argv[0]); return -ENODEV; } - current_baudrate = (int)simple_strtoul(dev_get_param(&cdev->class_dev, "baudrate"), NULL, 10); + current_baudrate = console_get_baudrate(cdev); /* Load Defaults */ if (load_baudrate == 0) @@ -644,7 +640,7 @@ static int do_load_serial_bin(int argc, char *argv[]) output_file = DEF_FILE; /* File should exist */ - ofd = open(output_file, open_mode); + ofd = open(output_file, O_WRONLY | O_CREAT); if (ofd < 0) { perror(argv[0]); return 3; @@ -660,17 +656,9 @@ static int do_load_serial_bin(int argc, char *argv[]) } } - if (load_baudrate != current_baudrate) { - printf("## Switch baudrate to %d bps and press ENTER ...\n", - load_baudrate); - udelay(50000); - cdev->setbrg(cdev, load_baudrate); - udelay(50000); - for (;;) { - if (getc() == '\r') - break; - } - } + ret = console_set_baudrate(cdev, load_baudrate); + if (ret) + return ret; printf("## Ready for binary (kermit) download " "to 0x%08lX offset on %s device at %d bps...\n", offset, @@ -681,17 +669,9 @@ static int do_load_serial_bin(int argc, char *argv[]) rcode = 1; } - if (load_baudrate != current_baudrate) { - printf("## Switch baudrate to %d bps and press ESC ...\n", - current_baudrate); - udelay(50000); - cdev->setbrg(cdev, current_baudrate); - udelay(50000); - for (;;) { - if (getc() == 0x1B) /* ESC */ - break; - } - } + ret = console_set_baudrate(cdev, current_baudrate); + if (ret) + return ret; close(ofd); ofd = 0; @@ -704,7 +684,6 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT("-f FILE", "download to FILE (default image.bin") BAREBOX_CMD_HELP_OPT("-o OFFS", "destination file OFFSet (default 0)") BAREBOX_CMD_HELP_OPT("-b BAUD", "baudrate for download (default: console baudrate") -BAREBOX_CMD_HELP_OPT("-c", "create file if not present") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(loadb) diff --git a/commands/loadxy.c b/commands/loadxy.c index 1e65cb6221..a4b1bec94d 100644 --- a/commands/loadxy.c +++ b/commands/loadxy.c @@ -40,45 +40,6 @@ #define DEF_FILE "image.bin" -static int console_change_speed(struct console_device *cdev, int baudrate) -{ - int current_baudrate; - const char *bstr; - - bstr = dev_get_param(&cdev->class_dev, "baudrate"); - current_baudrate = bstr ? (int)simple_strtoul(bstr, NULL, 10) : 0; - if (baudrate && baudrate != current_baudrate) { - printf("## Switch baudrate from %d to %d bps and press ENTER ...\n", - current_baudrate, baudrate); - mdelay(50); - cdev->setbrg(cdev, baudrate); - mdelay(50); - } - return current_baudrate; -} - -static struct console_device *get_named_console(const char *cname) -{ - struct console_device *cdev; - const char *target; - - /* - * Assumption to have BOTH CONSOLE_STDIN AND STDOUT in the - * same output console - */ - for_each_console(cdev) { - target = dev_id(&cdev->class_dev); - if (strlen(target) != strlen(cname)) - continue; - printf("RJK: looking for %s in console name %s\n", - cname, target); - if ((cdev->f_active & (CONSOLE_STDIN | CONSOLE_STDOUT)) - && !strcmp(cname, target)) - return cdev; - } - return NULL; -} - /** * @brief provide the loady(Y-Modem or Y-Modem/G) support * @@ -112,7 +73,7 @@ static int do_loady(int argc, char *argv[]) } if (cname) - cdev = get_named_console(cname); + cdev = console_get_by_name(cname); else cdev = console_get_first_active(); if (!cdev) { @@ -121,7 +82,15 @@ static int do_loady(int argc, char *argv[]) return -ENODEV; } - current_baudrate = console_change_speed(cdev, load_baudrate); + current_baudrate = console_get_baudrate(cdev); + + if (!load_baudrate) + load_baudrate = current_baudrate; + + rc = console_set_baudrate(cdev, load_baudrate); + if (rc) + return rc; + printf("## Ready for binary (ymodem) download at %d bps...\n", load_baudrate ? load_baudrate : current_baudrate); @@ -135,7 +104,9 @@ static int do_loady(int argc, char *argv[]) rcode = 1; } - console_change_speed(cdev, current_baudrate); + rc = console_set_baudrate(cdev, current_baudrate); + if (rc) + return rc; return rcode; } @@ -167,8 +138,7 @@ BAREBOX_CMD_END static int do_loadx(int argc, char *argv[]) { ulong offset = 0; - int load_baudrate = 0, current_baudrate, ofd, opt, rcode = 0; - int open_mode = O_WRONLY; + int load_baudrate = 0, current_baudrate, rc, ofd, opt, rcode = 0; char *output_file = NULL, *cname = NULL; struct console_device *cdev = NULL; @@ -183,9 +153,6 @@ static int do_loadx(int argc, char *argv[]) case 'o': offset = (int)simple_strtoul(optarg, NULL, 10); break; - case 'c': - open_mode |= O_CREAT; - break; case 't': cname = optarg; break; @@ -196,7 +163,7 @@ static int do_loadx(int argc, char *argv[]) } if (cname) - cdev = get_named_console(cname); + cdev = console_get_by_name(cname); else cdev = console_get_first_active(); if (!cdev) { @@ -210,7 +177,7 @@ static int do_loadx(int argc, char *argv[]) output_file = DEF_FILE; /* File should exist */ - ofd = open(output_file, open_mode); + ofd = open(output_file, O_WRONLY | O_CREAT); if (ofd < 0) { perror(argv[0]); return 3; @@ -226,7 +193,15 @@ static int do_loadx(int argc, char *argv[]) } } - current_baudrate = console_change_speed(cdev, load_baudrate); + current_baudrate = console_get_baudrate(cdev); + + if (!load_baudrate) + load_baudrate = current_baudrate; + + rc = console_set_baudrate(cdev, load_baudrate); + if (rc) + return rc; + printf("## Ready for binary (xmodem) download " "to 0x%08lX offset on %s device at %d bps...\n", offset, output_file, load_baudrate ? load_baudrate : current_baudrate); @@ -235,7 +210,10 @@ static int do_loadx(int argc, char *argv[]) printf("## Binary (xmodem) download aborted (%d)\n", rcode); rcode = 1; } - console_change_speed(cdev, current_baudrate); + + rc = console_set_baudrate(cdev, current_baudrate); + if (rc) + return rc; return rcode; } @@ -246,7 +224,6 @@ BAREBOX_CMD_HELP_OPT("-f FILE", "download to FILE (default image.bin") BAREBOX_CMD_HELP_OPT("-o OFFS", "destination file OFFSet (default 0)") BAREBOX_CMD_HELP_OPT("-b BAUD", "baudrate for download (default: console baudrate") BAREBOX_CMD_HELP_OPT("-t NAME", "console name to use (default: current)") -BAREBOX_CMD_HELP_OPT("-c", "create file if not present") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(loadx) 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/md.c b/commands/md.c index 07a03d51f3..c88259a3f8 100644 --- a/commands/md.c +++ b/commands/md.c @@ -49,7 +49,7 @@ static int do_mem_md(int argc, char *argv[]) if (argc < 2) return COMMAND_ERROR_USAGE; - if (mem_parse_options(argc, argv, "bwls:x", &mode, &filename, NULL, + if (mem_parse_options(argc, argv, "bwlqs:x", &mode, &filename, NULL, &swab) < 0) return 1; @@ -105,6 +105,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") BAREBOX_CMD_HELP_OPT ("-w", "word access (16 bit)") BAREBOX_CMD_HELP_OPT ("-l", "long access (32 bit)") +BAREBOX_CMD_HELP_OPT ("-q", "quad access (64 bit)") BAREBOX_CMD_HELP_OPT ("-s FILE", "display file (default /dev/mem)") BAREBOX_CMD_HELP_OPT ("-x", "swap bytes at output") BAREBOX_CMD_HELP_TEXT("") diff --git a/commands/mem.c b/commands/mem.c index 568050d34b..23c703f0b5 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -84,6 +84,9 @@ int mem_parse_options(int argc, char *argv[], char *optstr, int *mode, case 'l': *mode = O_RWSIZE_4; break; + case 'q': + *mode = O_RWSIZE_8; + break; case 's': *sourcefile = optarg; break; diff --git a/commands/memcmp.c b/commands/memcmp.c index d048150672..e079d5f78e 100644 --- a/commands/memcmp.c +++ b/commands/memcmp.c @@ -49,7 +49,7 @@ static int do_memcmp(int argc, char *argv[]) int offset = 0; struct stat statbuf; - if (mem_parse_options(argc, argv, "bwls:d:", &mode, &sourcefile, + if (mem_parse_options(argc, argv, "bwlqs:d:", &mode, &sourcefile, &destfile, NULL) < 0) return 1; @@ -138,6 +138,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") BAREBOX_CMD_HELP_OPT ("-w", "word access (16 bit)") BAREBOX_CMD_HELP_OPT ("-l", "long access (32 bit)") +BAREBOX_CMD_HELP_OPT ("-q", "quad access (64 bit)") BAREBOX_CMD_HELP_OPT ("-s FILE", "source file (default /dev/mem)") BAREBOX_CMD_HELP_OPT ("-d FILE", "destination file (default /dev/mem)") BAREBOX_CMD_HELP_END diff --git a/commands/memcpy.c b/commands/memcpy.c index 78716b1bbc..9c8b64525c 100644 --- a/commands/memcpy.c +++ b/commands/memcpy.c @@ -47,7 +47,7 @@ static int do_memcpy(int argc, char *argv[]) struct stat statbuf; int ret = 0; - if (mem_parse_options(argc, argv, "bwls:d:", &mode, &sourcefile, + if (mem_parse_options(argc, argv, "bwlqs:d:", &mode, &sourcefile, &destfile, NULL) < 0) return 1; @@ -135,6 +135,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") BAREBOX_CMD_HELP_OPT ("-w", "word access (16 bit)") BAREBOX_CMD_HELP_OPT ("-l", "long access (32 bit)") +BAREBOX_CMD_HELP_OPT ("-q", "quad access (64 bit)") BAREBOX_CMD_HELP_OPT ("-s FILE", "source file (default /dev/mem)") BAREBOX_CMD_HELP_OPT ("-d FILE", "write file (default /dev/mem)") BAREBOX_CMD_HELP_END diff --git a/commands/memset.c b/commands/memset.c index bb5f46de7a..fc5b659b9b 100644 --- a/commands/memset.c +++ b/commands/memset.c @@ -44,7 +44,7 @@ static int do_memset(int argc, char *argv[]) int ret = 1; char *file = "/dev/mem"; - if (mem_parse_options(argc, argv, "bwld:", &mode, NULL, &file, + if (mem_parse_options(argc, argv, "bwlqd:", &mode, NULL, &file, NULL) < 0) return 1; @@ -92,6 +92,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") BAREBOX_CMD_HELP_OPT ("-w", "word access (16 bit)") BAREBOX_CMD_HELP_OPT ("-l", "long access (32 bit)") +BAREBOX_CMD_HELP_OPT ("-q", "quad access (64 bit)") BAREBOX_CMD_HELP_OPT ("-d FILE", "write file (default /dev/mem)") BAREBOX_CMD_HELP_END diff --git a/commands/memtest.c b/commands/memtest.c index 9dec0efcba..756123001a 100644 --- a/commands/memtest.c +++ b/commands/memtest.c @@ -62,9 +62,11 @@ static int request_memtest_regions(struct list_head *list) start = PAGE_ALIGN(bank->res->start); size = PAGE_ALIGN_DOWN(bank->res->end - start + 1); - ret = alloc_memtest_region(list, start, size); - if (ret < 0) - return ret; + if (size) { + ret = alloc_memtest_region(list, start, size); + if (ret < 0) + return ret; + } continue; } @@ -95,6 +97,8 @@ static int request_memtest_regions(struct list_head *list) continue; size = PAGE_ALIGN_DOWN(end - start + 1); + if (size == 0) + continue; ret = alloc_memtest_region(list, start, size); if (ret < 0) return ret; @@ -108,7 +112,7 @@ static int request_memtest_regions(struct list_head *list) start = PAGE_ALIGN(r->end); end = bank->res->end; size = PAGE_ALIGN_DOWN(end - start + 1); - if (start < end && start > r->end) { + if (size && start < end && start > r->end) { ret = alloc_memtest_region(list, start, size); if (ret < 0) return ret; diff --git a/commands/mm.c b/commands/mm.c index ff2e746670..7c890a6696 100644 --- a/commands/mm.c +++ b/commands/mm.c @@ -38,9 +38,10 @@ static int do_mem_mm(int argc, char *argv[]) u8 val8; u16 val16; u32 val32; - u32 value, mask; + u64 val64; + u64 value, mask; - if (mem_parse_options(argc, argv, "bwld:", &mode, NULL, &filename, + if (mem_parse_options(argc, argv, "bwlqd:", &mode, NULL, &filename, &swab) < 0) return 1; @@ -48,8 +49,8 @@ static int do_mem_mm(int argc, char *argv[]) return COMMAND_ERROR_USAGE; adr = strtoull_suffix(argv[optind++], NULL, 0); - value = simple_strtoul(argv[optind++], NULL, 0); - mask = simple_strtoul(argv[optind++], NULL, 0); + value = simple_strtoull(argv[optind++], NULL, 0); + mask = simple_strtoull(argv[optind++], NULL, 0); fd = open_and_lseek(filename, mode | O_RDWR, adr); if (fd < 0) @@ -86,6 +87,16 @@ static int do_mem_mm(int argc, char *argv[]) if (ret < 0) goto out_write; break; + case O_RWSIZE_8: + if (ret < 0) + goto out_read; + ret = pread(fd, &val64, 8, adr); + val64 &= ~mask; + val64 |= (value & mask); + ret = pwrite(fd, &val64, 8, adr); + if (ret < 0) + goto out_write; + break; } close(fd); @@ -110,6 +121,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") BAREBOX_CMD_HELP_OPT ("-w", "word access (16 bit)") BAREBOX_CMD_HELP_OPT ("-l", "long access (32 bit)") +BAREBOX_CMD_HELP_OPT ("-q", "quad access (64 bit)") BAREBOX_CMD_HELP_OPT ("-d FILE", "write file (default /dev/mem)") BAREBOX_CMD_HELP_END diff --git a/commands/mount.c b/commands/mount.c index 939e9bc853..aa769d46fe 100644 --- a/commands/mount.c +++ b/commands/mount.c @@ -79,6 +79,8 @@ static int do_mount(int argc, char *argv[]) if (!strncmp(devstr, "/dev/", 5)) devstr += 5; + device_detect_by_name(devstr); + cdev = cdev_by_name(devstr); if (!cdev) return -ENOENT; diff --git a/commands/mw.c b/commands/mw.c index f0384f6435..8ca3c61d7f 100644 --- a/commands/mw.c +++ b/commands/mw.c @@ -42,7 +42,7 @@ static int do_mem_mw(int argc, char *argv[]) loff_t adr; int swab = 0; - if (mem_parse_options(argc, argv, "bwld:x", &mode, NULL, &filename, + if (mem_parse_options(argc, argv, "bwlqd:x", &mode, NULL, &filename, &swab) < 0) return 1; @@ -59,6 +59,7 @@ static int do_mem_mw(int argc, char *argv[]) u8 val8; u16 val16; u32 val32; + u64 val64; switch (mode) { case O_RWSIZE_1: val8 = simple_strtoul(argv[optind], NULL, 0); @@ -76,6 +77,12 @@ static int do_mem_mw(int argc, char *argv[]) val32 = __swab32(val32); ret = write(fd, &val32, 4); break; + case O_RWSIZE_8: + val64 = simple_strtoull(argv[optind], NULL, 0); + if (swab) + val64 = __swab64(val64); + ret = write(fd, &val64, 8); + break; } if (ret < 0) { perror("write"); @@ -97,6 +104,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") BAREBOX_CMD_HELP_OPT ("-w", "word access (16 bit)") BAREBOX_CMD_HELP_OPT ("-l", "long access (32 bit)") +BAREBOX_CMD_HELP_OPT ("-q", "quad access (64 bit)") BAREBOX_CMD_HELP_OPT ("-d FILE", "write file (default /dev/mem)") BAREBOX_CMD_HELP_END 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/ubiformat.c b/commands/ubiformat.c index df0b801da9..e63f16e351 100644 --- a/commands/ubiformat.c +++ b/commands/ubiformat.c @@ -84,7 +84,7 @@ static int parse_opt(int argc, char *argv[]) int key; unsigned long int image_seq; - key = getopt(argc, argv, "nyyqve:x:s:O:f:S:"); + key = getopt(argc, argv, "nyqve:x:s:O:f:S:Q:"); if (key == -1) break; 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 1c5d14c1c0..983d3059fc 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -94,6 +94,17 @@ config EFI_DEVICEPATH config FILE_LIST bool +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 @@ -198,6 +209,16 @@ config BAREBOX_MAX_BARE_INIT_SIZE this will allow your bare_init to fit in SRAM as example ARCH can overwrite it via ARCH_BAREBOX_MAX_BARE_INIT_SIZE +config BAREBOX_MAX_PBLX_SIZE + depends on PBL_MULTI_IMAGES + depends on IMAGE_COMPRESSION + prompt "Maximum PBLX size" + hex + default 0xffffffff + help + Define the maximum size of the PBLX image. + The pblx is a self extracting barebox binary. + config HAVE_CONFIGURABLE_MEMORY_LAYOUT bool diff --git a/common/Makefile b/common/Makefile index 2738238c67..74801f7e28 100644 --- a/common/Makefile +++ b/common/Makefile @@ -52,6 +52,7 @@ lwl-$(CONFIG_IMD) += imd-barebox.o obj-$(CONFIG_IMD) += imd.o obj-$(CONFIG_FILE_LIST) += file-list.o obj-$(CONFIG_FIRMWARE) += firmware.o +obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o quiet_cmd_pwd_h = PWDH $@ ifdef CONFIG_PASSWORD diff --git a/common/bbu.c b/common/bbu.c index 7fb154a230..4d71fa4a87 100644 --- a/common/bbu.c +++ b/common/bbu.c @@ -20,6 +20,12 @@ #include <linux/list.h> #include <errno.h> #include <readkey.h> +#include <filetype.h> +#include <libfile.h> +#include <fs.h> +#include <fcntl.h> +#include <malloc.h> +#include <linux/stat.h> static LIST_HEAD(bbu_image_handlers); @@ -153,3 +159,110 @@ int bbu_register_handler(struct bbu_handler *handler) return 0; } + +struct bbu_std { + struct bbu_handler handler; + enum filetype filetype; +}; + +static int bbu_std_file_handler(struct bbu_handler *handler, + struct bbu_data *data) +{ + struct bbu_std *std = container_of(handler, struct bbu_std, handler); + int fd, ret; + enum filetype filetype; + struct stat s; + unsigned oflags = O_WRONLY; + + filetype = file_detect_type(data->image, data->len); + if (filetype != std->filetype) { + if (!bbu_force(data, "incorrect image type. Expected: %s, got %s", + file_type_to_string(std->filetype), + file_type_to_string(filetype))) + return -EINVAL; + } + + ret = stat(data->devicefile, &s); + if (ret) { + oflags |= O_CREAT; + } else { + if (!S_ISREG(s.st_mode) && s.st_size < data->len) { + printf("Image (%lld) is too big for device (%d)\n", + s.st_size, data->len); + } + } + + ret = bbu_confirm(data); + if (ret) + return ret; + + fd = open(data->devicefile, oflags); + if (fd < 0) + return fd; + + ret = protect(fd, data->len, 0, 0); + if (ret && ret != -ENOSYS) { + printf("unprotecting %s failed with %s\n", data->devicefile, + strerror(-ret)); + goto err_close; + } + + ret = erase(fd, data->len, 0); + if (ret && ret != -ENOSYS) { + printf("erasing %s failed with %s\n", data->devicefile, + strerror(-ret)); + goto err_close; + } + + ret = write_full(fd, data->image, data->len); + if (ret < 0) + goto err_close; + + protect(fd, data->len, 0, 1); + + ret = 0; + +err_close: + close(fd); + + return ret; +} + +/** + * bbu_register_std_file_update() - register a barebox update handler for a + * standard file-to-device-copy operation + * @name: Name of the handler + * @flags: BBU_HANDLER_FLAG_* flags + * @devicefile: the file to write the update image to + * @imagetype: The filetype that the update image must have + * + * This update handler us suitable for a standard file-to-device copy operation. + * The handler checks for a filetype and unprotects/erases the device if + * necessary. If devicefile belongs to a device then the device is checkd for + * enough space before touching it. + * + * Return: 0 if successful, negative error code otherwise + */ +int bbu_register_std_file_update(const char *name, unsigned long flags, + char *devicefile, enum filetype imagetype) +{ + struct bbu_std *std; + struct bbu_handler *handler; + int ret; + + std = xzalloc(sizeof(*std)); + std->filetype = imagetype; + + handler = &std->handler; + + handler->flags = flags; + handler->devicefile = devicefile; + handler->name = name; + handler->handler = bbu_std_file_handler; + + ret = bbu_register_handler(handler); + if (ret) + free(std); + + return ret; +} diff --git a/common/blspec.c b/common/blspec.c index 3506388eb5..7e84ff3cec 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -30,6 +30,7 @@ #include <of.h> #include <linux/stat.h> #include <linux/err.h> +#include <mtd/ubi-user.h> /* * blspec_entry_var_set - set a variable to a value @@ -436,6 +437,35 @@ err_out: } /* + * blspec_scan_ubi - scan over a cdev containing UBI volumes + * + * This function attaches a cdev as UBI devices and collects all blspec + * entries found in the UBI volumes + * + * returns the number of entries found or a negative error code if some unexpected + * error occured. + */ +static int blspec_scan_ubi(struct blspec *blspec, struct cdev *cdev) +{ + struct device_d *child; + int ret, found = 0; + + pr_debug("%s: %s\n", __func__, cdev->name); + + ret = ubi_attach_mtd_dev(cdev->mtd, UBI_DEV_NUM_AUTO, 0, 20); + if (ret && ret != -EEXIST) + return 0; + + device_for_each_child(cdev->dev, child) { + ret = blspec_scan_device(blspec, child); + if (ret > 0) + found += ret; + } + + return found; +} + +/* * blspec_scan_cdev - scan over a cdev * * Given a cdev this function mounts the filesystem and collects all blspec @@ -446,9 +476,9 @@ err_out: */ static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev) { - int ret; + int ret, found = 0; void *buf = xzalloc(512); - enum filetype type; + enum filetype type, filetype; const char *rootpath; pr_debug("%s: %s\n", __func__, cdev->name); @@ -460,16 +490,26 @@ static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev) } type = file_detect_partition_table(buf, 512); + filetype = file_detect_type(buf, 512); free(buf); if (type == filetype_mbr || type == filetype_gpt) return -EINVAL; + if (filetype == filetype_ubi && IS_ENABLED(CONFIG_MTD_UBI)) { + ret = blspec_scan_ubi(blspec, cdev); + if (ret > 0) + found += ret; + } + rootpath = cdev_mount_default(cdev, NULL); - if (IS_ERR(rootpath)) - return PTR_ERR(rootpath); + if (!IS_ERR(rootpath)) { + ret = blspec_scan_directory(blspec, rootpath); + if (ret > 0) + found += ret; + } - return blspec_scan_directory(blspec, rootpath); + return found; } /* @@ -575,17 +615,10 @@ int blspec_scan_devicename(struct blspec *blspec, const char *devname) { struct device_d *dev; struct cdev *cdev; - const char *colon; pr_debug("%s: %s\n", __func__, devname); - colon = strchr(devname, '.'); - if (colon) { - char *name = xstrdup(devname); - *strchr(name, '.') = 0; - device_detect_by_name(name); - free(name); - } + device_detect_by_name(devname); cdev = cdev_by_name(devname); if (cdev) { diff --git a/common/bootsource.c b/common/bootsource.c index 7f3d51fb75..707b07924c 100644 --- a/common/bootsource.c +++ b/common/bootsource.c @@ -35,6 +35,7 @@ static const char *bootsource_str[] = { [BOOTSOURCE_ONENAND] = "onenand", [BOOTSOURCE_HD] = "harddisk", [BOOTSOURCE_USB] = "usb", + [BOOTSOURCE_NET] = "net", }; static enum bootsource bootsource = BOOTSOURCE_UNKNOWN; 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/console.c b/common/console.c index 0c32f06b93..0a6fc3e9bf 100644 --- a/common/console.c +++ b/common/console.c @@ -58,32 +58,14 @@ static struct kfifo __console_output_fifo; static struct kfifo *console_input_fifo = &__console_input_fifo; static struct kfifo *console_output_fifo = &__console_output_fifo; -static int console_std_set(struct device_d *dev, struct param_d *param, - const char *val) +int console_set_active(struct console_device *cdev, unsigned flag) { - struct console_device *cdev = to_console_dev(dev); - char active[4]; - unsigned int flag = 0, i = 0; - int ret; - - if (val) { - if (strchr(val, 'i') && cdev->getc) { - active[i++] = 'i'; - flag |= CONSOLE_STDIN; - } + int ret, i; - if (cdev->putc) { - if (strchr(val, 'o')) { - active[i++] = 'o'; - flag |= CONSOLE_STDOUT; - } - - if (strchr(val, 'e')) { - active[i++] = 'e'; - flag |= CONSOLE_STDERR; - } - } - } + if (!cdev->getc) + flag &= ~CONSOLE_STDIN; + if (!cdev->putc) + flag &= ~(CONSOLE_STDOUT | CONSOLE_STDERR); if (flag && !cdev->f_active) { /* The device is being activated, set its baudrate */ @@ -97,16 +79,25 @@ static int console_std_set(struct device_d *dev, struct param_d *param, return ret; } - active[i] = 0; cdev->f_active = flag; - dev_param_set_generic(dev, param, active); + if (IS_ENABLED(CONFIG_PARAMETER)) { + i = 0; + + if (flag & CONSOLE_STDIN) + cdev->active[i++] = 'i'; + if (flag & CONSOLE_STDOUT) + cdev->active[i++] = 'o'; + if (flag & CONSOLE_STDERR) + cdev->active[i++] = 'e'; + cdev->active[i] = 0; + } if (initialized < CONSOLE_INIT_FULL) { char ch; initialized = CONSOLE_INIT_FULL; puts_ll("Switch to console ["); - puts_ll(dev_name(dev)); + puts_ll(dev_name(&cdev->class_dev)); puts_ll("]\n"); barebox_banner(); while (kfifo_getc(console_output_fifo, &ch) == 0) @@ -116,29 +107,87 @@ static int console_std_set(struct device_d *dev, struct param_d *param, return 0; } -static int console_baudrate_set(struct param_d *param, void *priv) +unsigned console_get_active(struct console_device *cdev) { - struct console_device *cdev = priv; + return cdev->f_active; +} + +static int console_active_set(struct device_d *dev, struct param_d *param, + const char *val) +{ + struct console_device *cdev = to_console_dev(dev); + unsigned int flag = 0; + + if (val) { + if (strchr(val, 'i')) + flag |= CONSOLE_STDIN; + if (strchr(val, 'o')) + flag |= CONSOLE_STDOUT; + if (strchr(val, 'e')) + flag |= CONSOLE_STDERR; + } + + return console_set_active(cdev, flag); +} + +static const char *console_active_get(struct device_d *dev, + struct param_d *param) +{ + struct console_device *cdev = to_console_dev(dev); + + return cdev->active; +} + +int console_set_baudrate(struct console_device *cdev, unsigned baudrate) +{ + int ret; unsigned char c; + if (!cdev->setbrg) + return -ENOSYS; + + if (cdev->baudrate == baudrate) + return 0; + /* * If the device is already active, change its baudrate. * The baudrate of an inactive device will be set at activation time. */ if (cdev->f_active) { - printf("## Switch baudrate to %d bps and press ENTER ...\n", - cdev->baudrate); + printf("## Switch baudrate on console %s to %d bps and press ENTER ...\n", + dev_name(&cdev->class_dev), baudrate); mdelay(50); - cdev->setbrg(cdev, cdev->baudrate); + } + + ret = cdev->setbrg(cdev, baudrate); + if (ret) + return ret; + + if (cdev->f_active) { mdelay(50); do { c = getc(); } while (c != '\r' && c != '\n'); } + cdev->baudrate = baudrate; + cdev->baudrate_param = baudrate; + return 0; } +unsigned console_get_baudrate(struct console_device *cdev) +{ + return cdev->baudrate; +} + +static int console_baudrate_set(struct param_d *param, void *priv) +{ + struct console_device *cdev = priv; + + return console_set_baudrate(cdev, cdev->baudrate_param); +} + static void console_init_early(void) { kfifo_init(console_input_fifo, console_input_buffer, @@ -208,13 +257,13 @@ int console_register(struct console_device *newcdev) if (newcdev->setbrg) { newcdev->baudrate = CONFIG_BAUDRATE; dev_add_param_int(dev, "baudrate", console_baudrate_set, - NULL, &newcdev->baudrate, "%u", newcdev); + NULL, &newcdev->baudrate_param, "%u", newcdev); } if (newcdev->putc && !newcdev->puts) newcdev->puts = __console_puts; - dev_add_param(dev, "active", console_std_set, NULL, 0); + dev_add_param(dev, "active", console_active_set, console_active_get, 0); if (IS_ENABLED(CONFIG_CONSOLE_ACTIVATE_FIRST)) { if (list_empty(&console_list)) @@ -230,12 +279,9 @@ int console_register(struct console_device *newcdev) list_add_tail(&newcdev->list, &console_list); - if (activate) { - if (IS_ENABLED(CONFIG_PARAMETER)) - dev_set_param(dev, "active", "ioe"); - else - console_std_set(dev, NULL, "ioe"); - } + if (activate) + console_set_active(newcdev, CONSOLE_STDIN | + CONSOLE_STDOUT | CONSOLE_STDERR); return 0; } diff --git a/common/console_common.c b/common/console_common.c index 41a6929dba..2c82c6fd46 100644 --- a/common/console_common.c +++ b/common/console_common.c @@ -106,15 +106,23 @@ static void pr_puts(int level, const char *str) log_clean(barebox_log_max_messages - 1); if (barebox_log_max_messages >= 0) { - log = xzalloc(sizeof(*log)); - log->msg = xstrdup(str); + log = malloc(sizeof(*log)); + if (!log) + goto nolog; + + log->msg = strdup(str); + if (!log->msg) { + free(log); + goto nolog; + } + log->timestamp = get_time_ns(); log->level = level; list_add_tail(&log->list, &barebox_logbuf); barebox_logbuf_num_messages++; } } - +nolog: if (level > barebox_loglevel) return; @@ -260,6 +268,19 @@ struct console_device *console_get_by_dev(struct device_d *dev) } EXPORT_SYMBOL(console_get_by_dev); +struct console_device *console_get_by_name(const char *name) +{ + struct console_device *cdev; + + for_each_console(cdev) { + if (!strcmp(cdev->devname, name)) + return cdev; + } + + return NULL; +} +EXPORT_SYMBOL(console_get_by_name); + /* * @brief returns current used console device * 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/memory_display.c b/common/memory_display.c index 7b1d35ec4b..ea91985e5d 100644 --- a/common/memory_display.c +++ b/common/memory_display.c @@ -6,8 +6,8 @@ int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, int swab) { - ulong linebytes, i; - u_char *cp; + unsigned long linebytes, i; + unsigned char *cp; /* Print the lines. * @@ -15,20 +15,34 @@ int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, int * once, and all accesses are with the specified bus width. */ do { - char linebuf[DISP_LINE_LEN]; - uint32_t *uip = (uint *)linebuf; - uint16_t *usp = (ushort *)linebuf; - uint8_t *ucp = (u_char *)linebuf; + unsigned char linebuf[DISP_LINE_LEN]; + uint64_t *ullp = (uint64_t *)linebuf; + uint32_t *uip = (uint32_t *)linebuf; + uint16_t *usp = (uint16_t *)linebuf; + uint8_t *ucp = (uint8_t *)linebuf; unsigned count = 52; printf("%08llx:", offs); linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; for (i = 0; i < linebytes; i += size) { - if (size == 4) { - u32 res; + if (size == 8) { + uint64_t res; data_abort_mask(); - res = *((uint *)addr); + res = *((uint64_t *)addr); + if (swab) + res = __swab64(res); + if (data_abort_unmask()) { + res = 0xffffffffffffffffULL; + count -= printf(" xxxxxxxxxxxxxxxx"); + } else { + count -= printf(" %016llx", res); + } + *ullp++ = res; + } else if (size == 4) { + uint32_t res; + data_abort_mask(); + res = *((uint32_t *)addr); if (swab) res = __swab32(res); if (data_abort_unmask()) { @@ -39,9 +53,9 @@ int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, int } *uip++ = res; } else if (size == 2) { - u16 res; + uint16_t res; data_abort_mask(); - res = *((ushort *)addr); + res = *((uint16_t *)addr); if (swab) res = __swab16(res); if (data_abort_unmask()) { @@ -52,9 +66,9 @@ int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, int } *usp++ = res; } else { - u8 res; + uint8_t res; data_abort_mask(); - res = *((u_char *)addr); + res = *((uint8_t *)addr); if (data_abort_unmask()) { res = 0xff; count -= printf(" xx"); @@ -70,7 +84,7 @@ int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, int while (count--) putchar(' '); - cp = (uint8_t *)linebuf; + cp = linebuf; for (i = 0; i < linebytes; i++) { if ((*cp < 0x20) || (*cp > 0x7e)) putchar('.'); diff --git a/common/memtest.c b/common/memtest.c index 25a97d845c..d8d1154c8b 100644 --- a/common/memtest.c +++ b/common/memtest.c @@ -28,35 +28,33 @@ #include <errno.h> #include <memtest.h> -static const resource_size_t bitpattern[] = { - 0x00000001, /* single bit */ - 0x00000003, /* two adjacent bits */ - 0x00000007, /* three adjacent bits */ - 0x0000000F, /* four adjacent bits */ - 0x00000005, /* two non-adjacent bits */ - 0x00000015, /* three non-adjacent bits */ - 0x00000055, /* four non-adjacent bits */ - 0xAAAAAAAA, /* alternating 1/0 */ -}; +static void mem_test_report_failure(const char *failure_description, + resource_size_t expected_value, + resource_size_t actual_value, + volatile resource_size_t *address) +{ + printf("FAILURE (%s): " + "expected 0x%08x, actual 0x%08x at address 0x%08x.\n", + failure_description, expected_value, actual_value, + (resource_size_t)address); +} -/* - * Perform a memory test. The complete test - * loops until interrupted by ctrl-c. - * - * Prameters: - * start: start address for memory test. - * end: end address of memory test. - * bus_only: skip integrity check and do only a address/data bus - * testing. - * - * Return value can be -EINVAL for invalid parameter or -EINTR - * if memory test was interrupted. - */ -int mem_test(resource_size_t _start, - resource_size_t _end, int bus_only) +int mem_test_bus_integrity(resource_size_t _start, + resource_size_t _end) { - volatile resource_size_t *start, *dummy, val, readback, offset, - offset2, pattern, temp, anti_pattern, num_words; + static const resource_size_t bitpattern[] = { + 0x00000001, /* single bit */ + 0x00000003, /* two adjacent bits */ + 0x00000007, /* three adjacent bits */ + 0x0000000F, /* four adjacent bits */ + 0x00000005, /* two non-adjacent bits */ + 0x00000015, /* three non-adjacent bits */ + 0x00000055, /* four non-adjacent bits */ + 0xAAAAAAAA, /* alternating 1/0 */ + }; + + volatile resource_size_t *start, *dummy, num_words, val, readback, offset, + offset2, pattern, temp, anti_pattern; int i; _start = ALIGN(_start, sizeof(resource_size_t)); @@ -66,7 +64,7 @@ int mem_test(resource_size_t _start, return -EINVAL; start = (resource_size_t *)_start; - /* + /* * Point the dummy to start[1] */ dummy = start + 1; @@ -91,8 +89,7 @@ int mem_test(resource_size_t _start, * '0's and '0' bits through a field of '1's (i.e. * pattern and ~pattern). */ - for (i = 0; i < ARRAY_SIZE(bitpattern)/ - sizeof(resource_size_t); i++) { + for (i = 0; i < ARRAY_SIZE(bitpattern); i++) { val = bitpattern[i]; for (; val != 0; val <<= 1) { @@ -101,9 +98,8 @@ int mem_test(resource_size_t _start, *dummy = ~val; readback = *start; if (readback != val) { - printf("FAILURE (data line): " - "expected 0x%08x, actual 0x%08x at address 0x%08x.\n", - val, readback, (resource_size_t)start); + mem_test_report_failure("data line", + val, readback, start); return -EIO; } @@ -111,10 +107,8 @@ int mem_test(resource_size_t _start, *dummy = val; readback = *start; if (readback != ~val) { - printf("FAILURE (data line): " - "Is 0x%08x, should be 0x%08x at address 0x%08x.\n", - readback, - ~val, (resource_size_t)start); + mem_test_report_failure("data line", + ~val, readback, start); return -EIO; } } @@ -171,6 +165,15 @@ int mem_test(resource_size_t _start, for (offset = 1; offset <= num_words; offset <<= 1) start[offset] = pattern; + /* + * Now write anti-pattern at offset 0. If during the previous + * step one of the address lines got stuck high this + * operation would result in a memory cell at power-of-two + * offset being set to anti-pattern which hopefully would be + * detected byt the loop that follows. + */ + start[0] = anti_pattern; + printf("Check for address bits stuck high.\n"); /* @@ -179,15 +182,17 @@ int mem_test(resource_size_t _start, for (offset = 1; offset <= num_words; offset <<= 1) { temp = start[offset]; if (temp != pattern) { - printf("FAILURE: Address bit " - "stuck high @ 0x%08x:" - " expected 0x%08x, actual 0x%08x.\n", - (resource_size_t)&start[offset], - pattern, temp); + mem_test_report_failure("address bit stuck high", + pattern, temp, &start[offset]); return -EIO; } } + /* + Restore original value + */ + start[0] = pattern; + printf("Check for address bits stuck " "low or shorted.\n"); @@ -197,31 +202,40 @@ int mem_test(resource_size_t _start, for (offset2 = 1; offset2 <= num_words; offset2 <<= 1) { start[offset2] = anti_pattern; - for (offset = 1; offset <= num_words; offset <<= 1) { + for (offset = 0; offset <= num_words; + offset = (offset) ? offset << 1 : 1) { temp = start[offset]; if ((temp != pattern) && (offset != offset2)) { - printf("FAILURE: Address bit stuck" - " low or shorted @" - " 0x%08x: expected 0x%08x, actual 0x%08x.\n", - (resource_size_t)&start[offset], - pattern, temp); + mem_test_report_failure( + "address bit stuck low or shorted", + pattern, temp, &start[offset]); return -EIO; } } start[offset2] = pattern; } - /* - * We tested only the bus if != 0 - * leaving here - */ - if (bus_only) - return 0; + return 0; +} + +int mem_test_dram(resource_size_t _start, + resource_size_t _end) +{ + volatile resource_size_t *start, num_words, offset, temp, anti_pattern; + + _start = ALIGN(_start, sizeof(resource_size_t)); + _end = ALIGN_DOWN(_end, sizeof(resource_size_t)) - 1; + + if (_end <= _start) + return -EINVAL; + + start = (resource_size_t *)_start; + num_words = (_end - _start + 1)/sizeof(resource_size_t); printf("Starting integrity check of physicaly ram.\n" - "Filling ram with patterns...\n"); + "Filling ram with patterns...\n"); /* * Description: Test the integrity of a physical @@ -238,16 +252,17 @@ int mem_test(resource_size_t _start, * Fill memory with a known pattern. */ init_progression_bar(num_words); + for (offset = 0; offset < num_words; offset++) { /* * Every 4K we update the progressbar. */ + if (!(offset & (SZ_4K - 1))) { if (ctrlc()) return -EINTR; show_progress(offset); } - start[offset] = offset + 1; } show_progress(offset); @@ -266,10 +281,10 @@ int mem_test(resource_size_t _start, temp = start[offset]; if (temp != (offset + 1)) { - printf("\nFAILURE (read/write) @ 0x%08x:" - " expected 0x%08x, actual 0x%08x.\n", - (resource_size_t)&start[offset], - (offset + 1), temp); + printf("\n"); + mem_test_report_failure("read/write", + (offset + 1), + temp, &start[offset]); return -EIO; } @@ -294,10 +309,10 @@ int mem_test(resource_size_t _start, temp = start[offset]; if (temp != anti_pattern) { - printf("\nFAILURE (read/write): @ 0x%08x:" - " expected 0x%08x, actual 0x%08x.\n", - (resource_size_t)&start[offset], - anti_pattern, temp); + printf("\n"); + mem_test_report_failure("read/write", + anti_pattern, + temp, &start[offset]); return -EIO; } @@ -312,3 +327,36 @@ int mem_test(resource_size_t _start, return 0; } + +/* + * Perform a memory test. The complete test + * loops until interrupted by ctrl-c. + * + * Prameters: + * start: start address for memory test. + * end: end address of memory test. + * bus_only: skip integrity check and do only a address/data bus + * testing. + * + * Return value can be -EINVAL for invalid parameter or -EINTR + * if memory test was interrupted. + */ +int mem_test(resource_size_t _start, + resource_size_t _end, int bus_only) +{ + int ret; + + ret = mem_test_bus_integrity(_start, _end); + + if (ret < 0) + return ret; + + /* + * We tested only the bus if != 0 + * leaving here + */ + if (!bus_only) + ret = mem_test_dram(_start, _end); + + return ret; +} diff --git a/common/oftree.c b/common/oftree.c index 50fc95b588..f75d7b4bfe 100644 --- a/common/oftree.c +++ b/common/oftree.c @@ -160,6 +160,25 @@ int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context) } /* + * Remove a previously registered fixup. Only the first (if any) is removed. + * Returns 0 if a match was found (and removed), -ENOENT otherwise. + */ +int of_unregister_fixup(int (*fixup)(struct device_node *, void *), + void *context) +{ + struct of_fixup *of_fixup; + + list_for_each_entry(of_fixup, &of_fixup_list, list) { + if (of_fixup->fixup == fixup && of_fixup->context == context) { + list_del(&of_fixup->list); + return 0; + } + } + + return -ENOENT; +} + +/* * Apply registered fixups for the given fdt. The fdt must have * enough free space to apply the fixups. */ 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/startup.c b/common/startup.c index e59b06d533..6178fc5353 100644 --- a/common/startup.c +++ b/common/startup.c @@ -62,6 +62,24 @@ static int mount_root(void) fs_initcall(mount_root); #endif +#ifdef CONFIG_ENV_HANDLING +static int load_environment(void) +{ + const char *default_environment_path; + + default_environment_path = default_environment_path_get(); + + if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT)) + defaultenv_load("/env", 0); + + envfs_load(default_environment_path, "/env", 0); + nvvar_load(); + + return 0; +} +environment_initcall(load_environment); +#endif + int (*barebox_main)(void); void __noreturn start_barebox(void) @@ -84,16 +102,6 @@ void __noreturn start_barebox(void) pr_debug("initcalls done\n"); - if (IS_ENABLED(CONFIG_ENV_HANDLING)) { - char *default_environment_path = default_environment_path_get(); - - if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT)) - defaultenv_load("/env", 0); - - envfs_load(default_environment_path, "/env", 0); - nvvar_load(); - } - if (IS_ENABLED(CONFIG_COMMAND_SUPPORT)) { pr_info("running /env/bin/init...\n"); diff --git a/common/state.c b/common/state.c index b677a9f01d..7076f5764d 100644 --- a/common/state.c +++ b/common/state.c @@ -54,12 +54,14 @@ struct state_backend { int (*load)(struct state_backend *backend, struct state *state); int (*save)(struct state_backend *backend, struct state *state); const char *name; + const char *of_path; const char *path; }; enum state_variable_type { STATE_TYPE_INVALID = 0, STATE_TYPE_ENUM, + STATE_TYPE_U8, STATE_TYPE_U32, STATE_TYPE_MAC, }; @@ -74,12 +76,20 @@ struct state_variable { void *raw; }; +enum state_convert { + STATE_CONVERT_FROM_NODE, + STATE_CONVERT_FROM_NODE_CREATE, + STATE_CONVERT_TO_NODE, + STATE_CONVERT_FIXUP, +}; + /* A variable type (uint32, enum32) */ struct variable_type { enum state_variable_type type; const char *type_name; struct list_head list; - int (*export)(struct state_variable *, struct device_node *); + int (*export)(struct state_variable *, struct device_node *, + enum state_convert); int (*import)(struct state_variable *, const struct device_node *); struct state_variable *(*create)(struct state *state, const char *name, struct device_node *); @@ -126,15 +136,15 @@ static inline struct state_uint32 *to_state_uint32(struct state_variable *s) } static int state_uint32_export(struct state_variable *var, - struct device_node *node) + struct device_node *node, enum state_convert conv) { struct state_uint32 *su32 = to_state_uint32(var); int ret; - if (su32->value_default) { + if (su32->value_default || conv == STATE_CONVERT_FIXUP) { ret = of_property_write_u32(node, "default", su32->value_default); - if (ret) + if (ret || conv == STATE_CONVERT_FIXUP) return ret; } @@ -153,7 +163,7 @@ static int state_uint32_import(struct state_variable *sv, return 0; } -static struct state_variable *state_uint32_create(struct state *state, +static struct state_variable *state_uint8_create(struct state *state, const char *name, struct device_node *node) { struct state_uint32 *su32; @@ -169,6 +179,32 @@ static struct state_variable *state_uint32_create(struct state *state, } su32->param = param; + su32->var.size = sizeof(uint8_t); +#ifdef __LITTLE_ENDIAN + su32->var.raw = &su32->value; +#else + su32->var.raw = &su32->value + 3; +#endif + + return &su32->var; +} + +static struct state_variable *state_uint32_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_uint32 *su32; + struct param_d *param; + + su32 = xzalloc(sizeof(*su32)); + + param = dev_add_param_int(&state->dev, name, state_set_dirty, + NULL, &su32->value, "%u", state); + if (IS_ERR(param)) { + free(su32); + return ERR_CAST(param); + } + + su32->param = param; su32->var.size = sizeof(uint32_t); su32->var.raw = &su32->value; @@ -193,16 +229,16 @@ static inline struct state_enum32 *to_state_enum32(struct state_variable *s) } static int state_enum32_export(struct state_variable *var, - struct device_node *node) + struct device_node *node, enum state_convert conv) { struct state_enum32 *enum32 = to_state_enum32(var); int ret, i, len; char *prop, *str; - if (enum32->value_default) { + if (enum32->value_default || conv == STATE_CONVERT_FIXUP) { ret = of_property_write_u32(node, "default", enum32->value_default); - if (ret) + if (ret || conv == STATE_CONVERT_FIXUP) return ret; } @@ -309,14 +345,14 @@ static inline struct state_mac *to_state_mac(struct state_variable *s) } static int state_mac_export(struct state_variable *var, - struct device_node *node) + struct device_node *node, enum state_convert conv) { 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) + if (ret || conv == STATE_CONVERT_FIXUP) return ret; return of_property_write_u8_array(node, "value", mac->value, @@ -363,6 +399,12 @@ out: static struct variable_type types[] = { { + .type = STATE_TYPE_U8, + .type_name = "uint8", + .export = state_uint32_export, + .import = state_uint32_import, + .create = state_uint8_create, + }, { .type = STATE_TYPE_U32, .type_name = "uint32", .export = state_uint32_export, @@ -426,13 +468,6 @@ static struct state *state_new(const char *name) return state; } -static void state_release(struct state *state) -{ - list_del(&state->list); - unregister_device(&state->dev); - free(state); -} - static struct state_variable *state_find_var(struct state *state, const char *name) { @@ -446,12 +481,6 @@ static struct state_variable *state_find_var(struct state *state, return ERR_PTR(-ENOENT); } -enum state_convert { - STATE_CONVERT_FROM_NODE, - STATE_CONVERT_FROM_NODE_CREATE, - STATE_CONVERT_TO_NODE, -}; - static int state_convert_node_variable(struct state *state, struct device_node *node, struct device_node *parent, const char *parent_name, enum state_convert conv) @@ -476,7 +505,8 @@ static int state_convert_node_variable(struct state *state, parent_name, parent_name[0] ? "." : "", short_name); free(short_name); - if (conv == STATE_CONVERT_TO_NODE) + if ((conv == STATE_CONVERT_TO_NODE) || + (conv == STATE_CONVERT_FIXUP)) new_node = of_new_node(parent, node->name); for_each_child_of_node(node, child) { @@ -489,6 +519,15 @@ static int state_convert_node_variable(struct state *state, /* parents are allowed to have no type */ ret = of_property_read_string(node, "type", &type_name); if (!list_empty(&node->children) && ret == -EINVAL) { + if (conv == STATE_CONVERT_FIXUP) { + ret = of_property_write_u32(new_node, "#address-cells", 1); + if (ret) + goto out_free; + + ret = of_property_write_u32(new_node, "#size-cells", 1); + if (ret) + goto out_free; + } ret = 0; goto out_free; } else if (ret) { @@ -512,13 +551,16 @@ static int state_convert_node_variable(struct state *state, ret = of_property_read_u32_array(node, "reg", start_size, ARRAY_SIZE(start_size)); - if (ret) + if (ret) { + dev_err(&state->dev, + "%s: reg property not found\n", name); goto out_free; + } if (start_size[1] != sv->size) { dev_err(&state->dev, - "size mismatch: type=%s(size=%u) size=%u\n", - type_name, sv->size, start_size[1]); + "%s: size mismatch: type=%s(size=%u) size=%u\n", + name, type_name, sv->size, start_size[1]); ret = -EOVERFLOW; goto out_free; } @@ -539,7 +581,8 @@ static int state_convert_node_variable(struct state *state, } free(name); - if (conv == STATE_CONVERT_TO_NODE) { + if ((conv == STATE_CONVERT_TO_NODE) || + (conv == STATE_CONVERT_FIXUP)) { ret = of_set_property(new_node, "type", vtype->type_name, strlen(vtype->type_name) + 1, 1); @@ -556,8 +599,9 @@ static int state_convert_node_variable(struct state *state, } } - if (conv == STATE_CONVERT_TO_NODE) - ret = vtype->export(sv, new_node); + if ((conv == STATE_CONVERT_TO_NODE) || + (conv == STATE_CONVERT_FIXUP)) + ret = vtype->export(sv, new_node, conv); else ret = vtype->import(sv, node); @@ -571,20 +615,21 @@ out: return ret; } -static struct device_node *state_to_node(struct state *state) +static struct device_node *state_to_node(struct state *state, struct device_node *parent, + enum state_convert conv) { struct device_node *child; struct device_node *root; int ret; - root = of_new_node(NULL, NULL); + root = of_new_node(parent, state->root->name); ret = of_property_write_u32(root, "magic", state->magic); if (ret) goto out; for_each_child_of_node(state->root, child) { ret = state_convert_node_variable(state, child, root, "", - STATE_CONVERT_TO_NODE); + conv); if (ret) goto out; } @@ -657,6 +702,101 @@ static int state_from_node(struct state *state, struct device_node *node, return ret; } +static int of_state_fixup(struct device_node *root, void *ctx) +{ + struct state *state = ctx; + const char *compatible = "barebox,state"; + struct device_node *new_node, *node, *parent, *backend_node; + struct property *p; + int ret; + phandle phandle; + + node = of_find_node_by_path_from(root, state->root->full_name); + if (node) { + /* replace existing node - it will be deleted later */ + parent = node->parent; + } else { + char *of_path, *c; + + /* look for parent, remove last '/' from path */ + of_path = xstrdup(state->root->full_name); + c = strrchr(of_path, '/'); + if (!c) + return -ENODEV; + *c = '0'; + parent = of_find_node_by_path(of_path); + if (!parent) + parent = root; + + free(of_path); + } + + /* serialize variable definitions */ + new_node = state_to_node(state, parent, STATE_CONVERT_FIXUP); + if (IS_ERR(new_node)) + return PTR_ERR(new_node); + + /* compatible */ + p = of_new_property(new_node, "compatible", compatible, + strlen(compatible) + 1); + if (!p) { + ret = -ENOMEM; + goto out; + } + + /* backend-type */ + if (!state->backend) { + ret = -ENODEV; + goto out; + } + + p = of_new_property(new_node, "backend-type", state->backend->name, + strlen(state->backend->name) + 1); + if (!p) { + ret = -ENOMEM; + goto out; + } + + /* backend phandle */ + backend_node = of_find_node_by_path_from(root, state->backend->of_path); + if (!backend_node) { + ret = -ENODEV; + goto out; + } + + phandle = of_node_create_phandle(backend_node); + ret = of_property_write_u32(new_node, "backend", phandle); + if (ret) + goto out; + + /* address-cells + size-cells */ + ret = of_property_write_u32(new_node, "#address-cells", 1); + if (ret) + goto out; + + ret = of_property_write_u32(new_node, "#size-cells", 1); + if (ret) + goto out; + + /* delete existing node */ + if (node) + of_delete_node(node); + + return 0; + + out: + of_delete_node(new_node); + return ret; +} + +void state_release(struct state *state) +{ + of_unregister_fixup(of_state_fixup, state); + list_del(&state->list); + unregister_device(&state->dev); + free(state); +} + /* * state_new_from_node - create a new state instance from a device_node * @@ -678,27 +818,11 @@ struct state *state_new_from_node(const char *name, struct device_node *node) return ERR_PTR(ret); } - return state; -} - -/* - * state_new_from_fdt - create a new state instance from a fdt binary blob - * - * @name The name of the new state instance - * @fdt The fdt binary blob describing the new state instance - */ -struct state *state_new_from_fdt(const char *name, void *fdt) -{ - struct state *state; - struct device_node *root; - - root = of_unflatten_dtb(fdt); - if (!root) - return ERR_PTR(-EINVAL); - - state = state_new_from_node(name, root); - - of_delete_node(root); + ret = of_register_fixup(of_state_fixup, state); + if (ret) { + state_release(state); + return ERR_PTR(ret); + } return state; } @@ -757,10 +881,13 @@ int state_load(struct state *state) return -ENOSYS; ret = state->backend->load(state->backend, state); - if (ret) + if (ret) { + dev_warn(&state->dev, "load failed\n"); state->dirty = 1; - else + } else { + dev_info(&state->dev, "load successful\n"); state->dirty = 0; + } return ret; } @@ -809,7 +936,7 @@ static int mtd_get_meminfo(const char *path, struct mtd_info_user *meminfo) { int fd, ret; - fd = open(path, O_RDWR); + fd = open(path, O_RDONLY); if (fd < 0) return fd; @@ -863,7 +990,7 @@ static int state_backend_dtb_save(struct state_backend *backend, struct device_node *root; struct fdt_header *fdt; - root = state_to_node(state); + root = state_to_node(state, NULL, STATE_CONVERT_TO_NODE); if (IS_ERR(root)) return PTR_ERR(root); @@ -906,7 +1033,7 @@ out: * @state The state instance to work on * @path The path where the state will be stored to */ -int state_backend_dtb_file(struct state *state, const char *path) +int state_backend_dtb_file(struct state *state, const char *of_path, const char *path) { struct state_backend_dtb *backend_dtb; struct state_backend *backend; @@ -921,13 +1048,14 @@ int state_backend_dtb_file(struct state *state, const char *path) backend->load = state_backend_dtb_load; backend->save = state_backend_dtb_save; + backend->of_path = xstrdup(of_path); backend->path = xstrdup(path); backend->name = "dtb"; state->backend = backend; ret = mtd_get_meminfo(backend->path, &meminfo); - if (!ret && !(meminfo.mtd->flags & MTD_NO_ERASE)) + if (!ret && !(meminfo.flags & MTD_NO_ERASE)) backend_dtb->need_erase = true; return 0; @@ -938,9 +1066,9 @@ int state_backend_dtb_file(struct state *state, const char *path) */ struct state_backend_raw { struct state_backend backend; - unsigned long size_data; /* The raw data size (without magic and crc) */ - unsigned long size_full; - unsigned long step; /* The step in bytes between two copies */ + unsigned long size_data; /* The raw data size (without header) */ + unsigned long size_full; /* The size header + raw data */ + unsigned long stride; /* The stride size in bytes of the copies */ off_t offset; /* offset in the storage file */ size_t size; /* size of the storage area */ int num_copy_read; /* The first successfully read copy */ @@ -961,16 +1089,23 @@ static int backend_raw_load_one(struct state_backend_raw *backend_raw, uint32_t crc; struct state_variable *sv; struct backend_raw_header header = {}; + unsigned long max_len; int ret; void *buf; + max_len = backend_raw->stride; + ret = lseek(fd, offset, SEEK_SET); if (ret < 0) return ret; ret = read_full(fd, &header, sizeof(header)); - if (ret < 0) + max_len -= sizeof(header); + if (ret < 0) { + dev_err(&state->dev, + "cannot read header from backend device"); return ret; + } crc = crc32(0, &header, sizeof(header) - sizeof(uint32_t)); if (crc != header.header_crc) { @@ -987,6 +1122,13 @@ static int backend_raw_load_one(struct state_backend_raw *backend_raw, return -EINVAL; } + if (header.data_len > max_len) { + dev_err(&state->dev, + "invalid data_len %u in header, max is %lu\n", + header.data_len, max_len); + return -EINVAL; + } + buf = xzalloc(header.data_len); ret = read_full(fd, buf, header.data_len); @@ -1024,11 +1166,13 @@ static int state_backend_raw_load(struct state_backend *backend, int ret = 0, fd, i; fd = open(backend->path, O_RDONLY); - if (fd < 0) + if (fd < 0) { + dev_err(&state->dev, "cannot open %s\n", backend->path); return fd; + } for (i = 0; i < RAW_BACKEND_COPIES; i++) { - off_t offset = backend_raw->offset + i * backend_raw->step; + off_t offset = backend_raw->offset + i * backend_raw->stride; ret = backend_raw_load_one(backend_raw, state, fd, offset); if (!ret) { @@ -1044,11 +1188,11 @@ static int state_backend_raw_load(struct state_backend *backend, return ret; } -static int backend_raw_write_one(struct state_backend_raw *backend_raw, +static int backend_raw_save_one(struct state_backend_raw *backend_raw, struct state *state, int fd, int num, void *buf, size_t size) { int ret; - off_t offset = backend_raw->offset + num * backend_raw->step; + off_t offset = backend_raw->offset + num * backend_raw->stride; dev_dbg(&state->dev, "%s: 0x%08lx 0x%08zx\n", __func__, offset, size); @@ -1058,7 +1202,7 @@ static int backend_raw_write_one(struct state_backend_raw *backend_raw, return ret; if (backend_raw->need_erase) { - ret = erase(fd, backend_raw->size_full, offset); + ret = erase(fd, backend_raw->stride, offset); if (ret) return ret; } @@ -1075,14 +1219,12 @@ static int state_backend_raw_save(struct state_backend *backend, { struct state_backend_raw *backend_raw = container_of(backend, struct state_backend_raw, backend); - int ret = 0, size, fd; + int ret = 0, fd, i; void *buf, *data; struct backend_raw_header *header; struct state_variable *sv; - size = backend_raw->size_data + sizeof(struct backend_raw_header); - - buf = xzalloc(size); + buf = xzalloc(backend_raw->size_full); header = buf; data = buf + sizeof(*header); @@ -1100,13 +1242,20 @@ static int state_backend_raw_save(struct state_backend *backend, if (fd < 0) goto out_free; - ret = backend_raw_write_one(backend_raw, state, fd, - !backend_raw->num_copy_read, buf, size); - if (ret) - goto out_close; + /* save other slots first */ + for (i = 0; i < RAW_BACKEND_COPIES; i++) { + if (i == backend_raw->num_copy_read) + continue; - ret = backend_raw_write_one(backend_raw, state, fd, - backend_raw->num_copy_read, buf, size); + ret = backend_raw_save_one(backend_raw, state, fd, + i, buf, backend_raw->size_full); + if (ret) + goto out_close; + + } + + ret = backend_raw_save_one(backend_raw, state, fd, + backend_raw->num_copy_read, buf, backend_raw->size_full); if (ret) goto out_close; @@ -1119,6 +1268,60 @@ out_free: return ret; } +#ifdef __BAREBOX__ +#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode) || S_ISCHR(s.st_mode)) +#define BLKGET_GIVES_SIZE(s) 0 +#ifndef BLKGETSIZE64 +#define BLKGETSIZE64 -1 +#endif +#else +#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode)) +#define BLKGET_GIVES_SIZE(s) (S_ISBLK(s.st_mode)) +#endif + +static int state_backend_raw_file_get_size(const char *path, size_t *out_size) +{ + struct mtd_info_user meminfo; + struct stat s; + int ret; + + ret = stat(path, &s); + if (ret) + return -errno; + + /* + * under Linux, stat() gives the size only on regular files + * under barebox, it works on char dev, too + */ + if (STAT_GIVES_SIZE(s)) { + *out_size = s.st_size; + return 0; + } + + /* this works under Linux on block devs */ + if (BLKGET_GIVES_SIZE(s)) { + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + ret = ioctl(fd, BLKGETSIZE64, out_size); + close(fd); + if (!ret) + return 0; + } + + /* try mtd next */ + ret = mtd_get_meminfo(path, &meminfo); + if (!ret) { + *out_size = meminfo.size; + return 0; + } + + return ret; +} + /* * state_backend_raw_file - create a raw file backend store for a state instance * @@ -1136,32 +1339,34 @@ out_free: * device @size may be 0. The two copies are spread to different * eraseblocks if approriate for this device. */ -int state_backend_raw_file(struct state *state, const char *path, off_t offset, - size_t size) +int state_backend_raw_file(struct state *state, const char *of_path, + const char *path, off_t offset, size_t size) { struct state_backend_raw *backend_raw; struct state_backend *backend; struct state_variable *sv; - int ret; - struct stat s; struct mtd_info_user meminfo; + size_t path_size = 0; + int ret; if (state->backend) return -EBUSY; - ret = stat(path, &s); - if (!ret && S_ISCHR(s.st_mode)) { - if (size == 0) - size = s.st_size; - else if (offset + size > s.st_size) - return -EINVAL; - } + ret = state_backend_raw_file_get_size(path, &path_size); + if (ret) + return ret; + + if (size == 0) + size = path_size; + else if (offset + size > path_size) + return -EINVAL; backend_raw = xzalloc(sizeof(*backend_raw)); backend = &backend_raw->backend; backend->load = state_backend_raw_load; backend->save = state_backend_raw_save; + backend->of_path = xstrdup(of_path); backend->path = xstrdup(path); backend->name = "raw"; @@ -1175,18 +1380,21 @@ int state_backend_raw_file(struct state *state, const char *path, off_t offset, state->backend = backend; ret = mtd_get_meminfo(backend->path, &meminfo); - if (!ret && !(meminfo.mtd->flags & MTD_NO_ERASE)) { + if (!ret && !(meminfo.flags & MTD_NO_ERASE)) { backend_raw->need_erase = true; - backend_raw->step = ALIGN(backend_raw->size_full, - meminfo.erasesize); + backend_raw->size_full = ALIGN(backend_raw->size_full, + meminfo.writesize); + backend_raw->stride = ALIGN(backend_raw->size_full, + meminfo.erasesize); dev_dbg(&state->dev, "is a mtd, adjust stepsize to %ld\n", - backend_raw->step); + backend_raw->stride); } else { - backend_raw->step = backend_raw->size_full; + backend_raw->stride = backend_raw->size_full; } - if (backend_raw->size / backend_raw->step < RAW_BACKEND_COPIES) { - dev_err(&state->dev, "not enough space for two copies\n"); + if (backend_raw->size / backend_raw->stride < RAW_BACKEND_COPIES) { + dev_err(&state->dev, "not enough space for two copies (%lu each)\n", + backend_raw->stride); ret = -ENOSPC; goto err; } diff --git a/common/tlsfbits.h b/common/tlsfbits.h index 93466e46a8..edbac80636 100644 --- a/common/tlsfbits.h +++ b/common/tlsfbits.h @@ -3,6 +3,10 @@ #include <linux/bitops.h> +#ifdef CONFIG_64BIT +#define TLSF_64BIT +#endif + /* ** Architecture-specific bit manipulation routines. ** @@ -33,7 +37,7 @@ static int tlsf_fls(unsigned int word) /* Possibly 64-bit version of tlsf_fls. */ #if defined (TLSF_64BIT) -tlsf_decl int tlsf_fls_sizet(size_t size) +static int tlsf_fls_sizet(size_t size) { int high = (int)(size >> 32); int bits = 0; diff --git a/crypto/crc16.c b/crypto/crc16.c index d22b656379..0b08e9ccde 100644 --- a/crypto/crc16.c +++ b/crypto/crc16.c @@ -90,7 +90,7 @@ static const uint16_t crc16_tab[] = { }; uint16_t -cyg_crc16(unsigned char *buf, int len) +cyg_crc16(const unsigned char *buf, int len) { int i; uint16_t cksum; diff --git a/crypto/digest.c b/crypto/digest.c index b3f514c8ad..a90e4ff79f 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -172,7 +172,7 @@ EXPORT_SYMBOL_GPL(digest_free); int digest_file_window(struct digest *d, const char *filename, unsigned char *hash, - unsigned char *sig, + const unsigned char *sig, ulong start, ulong size) { ulong len = 0; @@ -249,8 +249,8 @@ out: EXPORT_SYMBOL_GPL(digest_file_window); int digest_file(struct digest *d, const char *filename, - unsigned char *hash, - unsigned char *sig) + unsigned char *hash, + const unsigned char *sig) { struct stat st; int ret; @@ -265,8 +265,8 @@ int digest_file(struct digest *d, const char *filename, EXPORT_SYMBOL_GPL(digest_file); int digest_file_by_name(const char *algo, const char *filename, - unsigned char *hash, - unsigned char *sig) + unsigned char *hash, + const unsigned char *sig) { struct digest *d; int ret; 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/i2c/i2c.c b/drivers/i2c/i2c.c index 7a6bde0f67..5d0fa06bb5 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -183,7 +183,7 @@ int i2c_read_reg(struct i2c_client *client, u32 addr, u8 *buf, u16 count) msg->len = i; status = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); - dev_dbg(&client->dev, "%s: %zu@%u --> %d\n", __func__, + dev_dbg(&client->dev, "%s: %u@%u --> %d\n", __func__, count, addr, status); if (status == ARRAY_SIZE(msg)) 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/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 8b45500a09..6caf165616 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -60,9 +60,10 @@ static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data) if (data) { xfertyp |= COMMAND_DPSEL; -#ifndef CONFIG_MCI_IMX_ESDHC_PIO - xfertyp |= TRANSFER_MODE_DMAEN; -#endif + + if (!IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) + xfertyp |= TRANSFER_MODE_DMAEN; + if (data->blocks > 1) { xfertyp |= TRANSFER_MODE_MSBSEL; xfertyp |= TRANSFER_MODE_BCEN; @@ -89,11 +90,10 @@ static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data) return COMMAND_CMD(cmd->cmdidx) | xfertyp; } -#ifdef CONFIG_MCI_IMX_ESDHC_PIO /* * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. */ -static void +static int esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); @@ -115,8 +115,8 @@ esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data) while (!(esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_BREN) && --timeout); if (timeout <= 0) { - printf("\nData Read Failed in PIO Mode."); - return; + dev_err(host->dev, "Data Read Failed\n"); + return -ETIMEDOUT; } while (size && (!(irqstat & IRQSTAT_TC))) { udelay(100); /* Wait before last byte transfer complete */ @@ -138,8 +138,8 @@ esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data) while (!(esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_BWEN) && --timeout); if (timeout <= 0) { - printf("\nData Write Failed in PIO Mode."); - return; + dev_err(host->dev, "Data Write Failed\n"); + return -ETIMEDOUT; } while (size && (!(irqstat & IRQSTAT_TC))) { udelay(100); /* Wait before last byte transfer complete */ @@ -152,53 +152,85 @@ esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data) blocks--; } } + + return 0; } -#endif static int esdhc_setup_data(struct mci_host *mci, struct mci_data *data) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); void __iomem *regs = host->regs; -#ifndef CONFIG_MCI_IMX_ESDHC_PIO u32 wml_value; - wml_value = data->blocksize/4; - - if (data->flags & MMC_DATA_READ) { - if (wml_value > 0x10) - wml_value = 0x10; - - esdhc_clrsetbits32(regs + IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value); - esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->dest); + if (IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) { + if (!(data->flags & MMC_DATA_READ)) { + if ((esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL) == 0) + goto err_locked; + esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->src); + } else { + esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->dest); + } } else { - if (wml_value > 0x80) - wml_value = 0x80; - if ((esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL) == 0) { - printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); - return -ETIMEDOUT; + wml_value = data->blocksize/4; + + if (data->flags & MMC_DATA_READ) { + if (wml_value > 0x10) + wml_value = 0x10; + + esdhc_clrsetbits32(regs + IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value); + esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->dest); + } else { + if (wml_value > 0x80) + wml_value = 0x80; + if ((esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL) == 0) + goto err_locked; + + esdhc_clrsetbits32(regs + IMX_SDHCI_WML, WML_WR_WML_MASK, + wml_value << 16); + esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->src); } - - esdhc_clrsetbits32(regs + IMX_SDHCI_WML, WML_WR_WML_MASK, - wml_value << 16); - esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->src); } -#else /* CONFIG_MCI_IMX_ESDHC_PIO */ - if (!(data->flags & MMC_DATA_READ)) { - if ((esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_WPSPL) == 0) { - printf("\nThe SD card is locked. " - "Can not write to a locked card.\n\n"); - return -ETIMEDOUT; - } - esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->src); - } else - esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->dest); -#endif /* CONFIG_MCI_IMX_ESDHC_PIO */ esdhc_write32(regs + SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize); return 0; + +err_locked: + dev_err(host->dev, "Can not write to locked card.\n\n"); + + return -ETIMEDOUT; } +static int esdhc_do_data(struct mci_host *mci, struct mci_data *data) +{ + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + void __iomem *regs = host->regs; + unsigned int num_bytes = data->blocks * data->blocksize; + u32 irqstat; + + if (IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO)) + return esdhc_pio_read_write(mci, data); + + do { + irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); + + if (irqstat & DATA_ERR) + return -EIO; + + if (irqstat & IRQSTAT_DTOE) + return -ETIMEDOUT; + } while (!(irqstat & IRQSTAT_TC) && + (esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); + + if (data->flags & MMC_DATA_WRITE) + dma_sync_single_for_cpu((unsigned long)data->src, + num_bytes, DMA_TO_DEVICE); + else + dma_sync_single_for_cpu((unsigned long)data->dest, + num_bytes, DMA_FROM_DEVICE); + + return 0; +} /* * Sends a command out on the bus. Takes the mci pointer, @@ -303,27 +335,9 @@ esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) /* Wait until all of the blocks are transferred */ if (data) { -#ifdef CONFIG_MCI_IMX_ESDHC_PIO - esdhc_pio_read_write(mci, data); -#else - do { - irqstat = esdhc_read32(regs + SDHCI_INT_STATUS); - - if (irqstat & DATA_ERR) - return -EIO; - - if (irqstat & IRQSTAT_DTOE) - return -ETIMEDOUT; - } while (!(irqstat & IRQSTAT_TC) && - (esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_DLA)); - - if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_cpu((unsigned long)data->src, - num_bytes, DMA_TO_DEVICE); - else - dma_sync_single_for_cpu((unsigned long)data->dest, - num_bytes, DMA_FROM_DEVICE); -#endif + ret = esdhc_do_data(mci, data); + if (ret) + return ret; } esdhc_write32(regs + SDHCI_INT_STATUS, -1); @@ -498,8 +512,9 @@ static int esdhc_init(struct mci_host *mci, struct device_d *dev) return ret; } -static int esdhc_reset(void __iomem *regs) +static int esdhc_reset(struct fsl_esdhc_host *host) { + void __iomem *regs = host->regs; uint64_t start; /* reset the controller */ @@ -513,7 +528,7 @@ static int esdhc_reset(void __iomem *regs) & SYSCTL_RSTA)) break; if (is_timeout(start, 100 * MSECOND)) { - printf("MMC/SD: Reset never completed.\n"); + dev_err(host->dev, "Reset never completed.\n"); return -EIO; } } @@ -550,7 +565,7 @@ static int fsl_esdhc_probe(struct device_d *dev) return PTR_ERR(host->regs); /* First reset the eSDHC controller */ - ret = esdhc_reset(host->regs); + ret = esdhc_reset(host); if (ret) { free(host); return ret; diff --git a/drivers/misc/state.c b/drivers/misc/state.c index 3b07bb93d7..f3e366480f 100644 --- a/drivers/misc/state.c +++ b/drivers/misc/state.c @@ -24,10 +24,12 @@ static int state_probe(struct device_d *dev) { struct device_node *np = dev->device_node; + struct device_node *partition_node; struct state *state; const char *alias; const char *backend_type = NULL; - int ret; + int len, ret; + const char *of_path; char *path; if (!np) @@ -41,28 +43,70 @@ static int state_probe(struct device_d *dev) if (IS_ERR(state)) return PTR_ERR(state); - ret = of_find_path(np, "backend", &path, 0); - if (ret) - return ret; + of_path = of_get_property(np, "backend", &len); + if (!of_path) { + ret = -ENODEV; + goto out_release; + } + + /* guess if of_path is a path, not a phandle */ + if (of_path[0] == '/' && len > 1) { + ret = of_find_path(np, "backend", &path, 0); + if (ret) + goto out_release; + } else { + struct device_d *dev; + struct cdev *cdev; + + partition_node = of_parse_phandle(np, "backend", 0); + if (!partition_node) { + ret = -ENODEV; + goto out_release; + } + + dev = of_find_device_by_node(partition_node); + if (!list_is_singular(&dev->cdevs)) { + ret = -ENODEV; + goto out_release; + } + + cdev = list_first_entry(&dev->cdevs, struct cdev, devices_list); + if (!cdev) { + ret = -ENODEV; + goto out_release; + } - dev_info(dev, "outpath: %s\n", path); + path = asprintf("/dev/%s", cdev->name); + of_path = partition_node->full_name; + } ret = of_property_read_string(np, "backend-type", &backend_type); - if (ret) - return ret; - else if (!strcmp(backend_type, "raw")) - ret = state_backend_raw_file(state, path, 0, 0); - else if (!strcmp(backend_type, "dtb")) - ret = state_backend_dtb_file(state, path); - else + if (ret) { + goto out_free; + } else if (!strcmp(backend_type, "raw")) { + ret = state_backend_raw_file(state, of_path, path, 0, 0); + } else if (!strcmp(backend_type, "dtb")) { + ret = state_backend_dtb_file(state, of_path, path); + } else { dev_warn(dev, "invalid backend type: %s\n", backend_type); + ret = -ENODEV; + goto out_free; + } if (ret) - return ret; + goto out_free; - state_load(state); + dev_info(dev, "backend: %s, path: %s, of_path: %s\n", backend_type, path, of_path); + free(path); + state_load(state); return 0; + + out_free: + free(path); + out_release: + state_release(state); + return ret; } static __maybe_unused struct of_device_id state_ids[] = { diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index e94e6b1f63..ea1be556b4 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -20,9 +20,20 @@ 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" +source "drivers/mtd/spi-nor/Kconfig" source "drivers/mtd/ubi/Kconfig" endif diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 9c7725742e..d3ae7fca3e 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -1,7 +1,9 @@ obj-$(CONFIG_NAND) += nand/ obj-$(CONFIG_DRIVER_CFI) += nor/ +obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ obj-$(CONFIG_MTD_UBI) += ubi/ 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 1755e7680f..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> @@ -191,7 +193,7 @@ static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset) return 0; } -static ssize_t mtd_op_protect(struct cdev *cdev, size_t count, loff_t offset, int prot) +static int mtd_op_protect(struct cdev *cdev, size_t count, loff_t offset, int prot) { struct mtd_info *mtd = cdev->priv; @@ -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 7f9c306258..9c3925bde1 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -22,6 +22,7 @@ config MTD_DATAFLASH_WRITE_VERIFY config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" 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 efef98490b..794c9dbd82 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -25,775 +25,202 @@ #include <errno.h> #include <linux/err.h> #include <clock.h> -#include <linux/math64.h> -#include <linux/mtd/cfi.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/spi-nor.h> +#include <linux/mod_devicetable.h> -/* Flash opcodes. */ -#define OPCODE_WREN 0x06 /* Write enable */ -#define OPCODE_RDSR 0x05 /* Read status register */ -#define OPCODE_WRSR 0x01 /* Write status register 1 byte */ -#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ -#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ -#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ -#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ -#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ -#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ -#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ -#define OPCODE_RDID 0x9f /* Read JEDEC ID */ - -/* Used for SST flashes only. */ -#define OPCODE_BP 0x02 /* Byte program */ -#define OPCODE_WRDI 0x04 /* Write disable */ -#define OPCODE_AAI_WP 0xad /* Auto address increment word program */ - -/* Used for Macronix flashes only. */ -#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */ -#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */ - -/* Used for Spansion flashes only. */ -#define OPCODE_BRWR 0x17 /* Bank register write */ - -/* Status Register bits. */ -#define SR_WIP 1 /* Write in progress */ -#define SR_WEL 2 /* Write enable latch */ -/* meaning of other SR_* bits may differ between vendors */ -#define SR_BP0 4 /* Block protect 0 */ -#define SR_BP1 8 /* Block protect 1 */ -#define SR_BP2 0x10 /* Block protect 2 */ -#define SR_SRWD 0x80 /* SR write protect */ - -/* Define max times to check status register before we give up. */ -#define MAX_READY_WAIT 40 /* M25P16 specs 40s max chip erase */ #define MAX_CMD_SIZE 6 -#define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) - -/****************************************************************************/ - -#define SPI_NAME_SIZE 32 - struct m25p { struct spi_device *spi; + struct spi_nor spi_nor; struct mtd_info mtd; - u16 page_size; - unsigned sector_size; - u16 addr_width; - u8 erase_opcode; - u8 erase_opcode_4k; - u8 *command; + u8 command[MAX_CMD_SIZE]; }; -static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) -{ - return container_of(mtd, struct m25p, mtd); -} - -/****************************************************************************/ - -/* - * Internal helper functions - */ - -/* - * Read the status register, returning its value in the location - * Return the status register value. - * Returns negative if error occurred. - */ -static int read_sr(struct m25p *flash) -{ - ssize_t retval; - u8 code = OPCODE_RDSR; - u8 val; - - retval = spi_write_then_read(flash->spi, &code, 1, &val, 1); - - if (retval < 0) { - dev_err(&flash->spi->dev, "error %d reading SR\n", - (int) retval); - return retval; - } - - return val; -} - -/* - * Write status register 1 byte - * Returns negative if error occurred. - */ -static int write_sr(struct m25p *flash, u8 val) -{ - flash->command[0] = OPCODE_WRSR; - flash->command[1] = val; - - return spi_write(flash->spi, flash->command, 2); -} - -/* - * Set write enable latch with Write Enable command. - * Returns negative if error occurred. - */ -static inline int write_enable(struct m25p *flash) -{ - u8 code = OPCODE_WREN; - - return spi_write_then_read(flash->spi, &code, 1, NULL, 0); -} - -/* - * Send write disble instruction to the chip. - */ -static inline int write_disable(struct m25p *flash) -{ - u8 code = OPCODE_WRDI; - - return spi_write_then_read(flash->spi, &code, 1, NULL, 0); -} - -/* - * Enable/disable 4-byte addressing mode. - */ -static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable) -{ - switch (JEDEC_MFR(jedec_id)) { - case CFI_MFR_MACRONIX: - flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B; - return spi_write(flash->spi, flash->command, 1); - default: - /* Spansion style */ - flash->command[0] = OPCODE_BRWR; - flash->command[1] = enable << 7; - return spi_write(flash->spi, flash->command, 2); - } -} - -/* - * Service routine to read status register until ready, or timeout occurs. - * Returns non-zero if error. - */ -static int wait_till_ready(struct m25p *flash) -{ - int sr; - uint64_t timer_start; - - timer_start = get_time_ns(); - - do { - if ((sr = read_sr(flash)) < 0) - break; - else if (!(sr & SR_WIP)) - return 0; - - } while (!(is_timeout(timer_start, MAX_READY_WAIT * SECOND))); - - return -ETIMEDOUT; -} - -/* - * Erase the whole flash memory - * - * Returns 0 if successful, non-zero otherwise. - */ -static int erase_chip(struct m25p *flash) +static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len) { - dev_dbg(&flash->spi->dev, "%s %lldKiB\n", - __func__, (long long)(flash->mtd.size >> 10)); - - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) - return -ETIMEDOUT; - - /* Send write enable, then erase commands. */ - write_enable(flash); + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; + int ret; - /* Set up command buffer. */ - flash->command[0] = OPCODE_CHIP_ERASE; - - spi_write(flash->spi, flash->command, 1); + ret = spi_write_then_read(spi, &code, 1, val, len); + if (ret < 0) + dev_err(&spi->dev, "error %d reading %x\n", ret, code); - return 0; + return ret; } -static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd) +static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd) { /* opcode is in cmd[0] */ - cmd[1] = addr >> (flash->addr_width * 8 - 8); - cmd[2] = addr >> (flash->addr_width * 8 - 16); - cmd[3] = addr >> (flash->addr_width * 8 - 24); - cmd[4] = addr >> (flash->addr_width * 8 - 32); -} - -static int m25p_cmdsz(struct m25p *flash) -{ - return 1 + flash->addr_width; + cmd[1] = addr >> (nor->addr_width * 8 - 8); + cmd[2] = addr >> (nor->addr_width * 8 - 16); + cmd[3] = addr >> (nor->addr_width * 8 - 24); + cmd[4] = addr >> (nor->addr_width * 8 - 32); } -/* - * Erase one sector of flash memory at offset ``offset'' which is any - * address within the sector which should be erased. - * - * Returns 0 if successful, non-zero otherwise. - */ -static int erase_sector(struct m25p *flash, u32 offset, u32 command) +static int m25p_cmdsz(struct spi_nor *nor) { - dev_dbg(&flash->spi->dev, "%s %dKiB at 0x%08x\n", - __func__, flash->mtd.erasesize / 1024, offset); - - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) - return -ETIMEDOUT; - - /* Send write enable, then erase commands. */ - write_enable(flash); - - /* Set up command buffer. */ - flash->command[0] = command; - m25p_addr2cmd(flash, offset, flash->command); - - spi_write(flash->spi, flash->command, m25p_cmdsz(flash)); - - return 0; + return 1 + nor->addr_width; } -/****************************************************************************/ - -/* - * MTD implementation - */ - -/* - * Erase an address range on the flash chip. The address range may extend - * one or more erase sectors. Return an error is there is a problem erasing. - */ -static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) +static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len, + int wr_en) { - struct m25p *flash = mtd_to_m25p(mtd); - u32 addr; - uint32_t rem; - uint64_t len; - - dev_dbg(&flash->spi->dev, "%s at 0x%llx, len %lld\n", - __func__, (long long)instr->addr, - (long long)instr->len); - - div_u64_rem(instr->len, mtd->erasesize, &rem); - if (rem) - return -EINVAL; - - addr = instr->addr; - len = instr->len; - - /* whole-chip erase? */ - if (len == flash->mtd.size) { - if (erase_chip(flash)) { - instr->state = MTD_ERASE_FAILED; - return -EIO; - } - return 0; - } - - if (flash->erase_opcode_4k) { - while (len && (addr & (flash->sector_size - 1))) { - if (ctrlc()) - return -EINTR; - if (erase_sector(flash, addr, flash->erase_opcode_4k)) - return -EIO; - addr += mtd->erasesize; - len -= mtd->erasesize; - } - - while (len >= flash->sector_size) { - if (ctrlc()) - return -EINTR; - if (erase_sector(flash, addr, flash->erase_opcode)) - return -EIO; - addr += flash->sector_size; - len -= flash->sector_size; - } - - while (len) { - if (ctrlc()) - return -EINTR; - if (erase_sector(flash, addr, flash->erase_opcode_4k)) - return -EIO; - addr += mtd->erasesize; - len -= mtd->erasesize; - } - } else { - while (len) { - if (ctrlc()) - return -EINTR; - if (erase_sector(flash, addr, flash->erase_opcode)) - return -EIO; - - if (len <= mtd->erasesize) - break; - addr += mtd->erasesize; - len -= mtd->erasesize; - } - } - - if (wait_till_ready(flash)) - return -ETIMEDOUT; + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); + flash->command[0] = opcode; + if (buf) + memcpy(&flash->command[1], buf, len); - return 0; + return spi_write(spi, flash->command, len + 1); } -/* - * Read an address range from the flash chip. The address range - * may be any size provided it is within the physical boundaries. - */ -static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { - struct m25p *flash = mtd_to_m25p(mtd); - struct spi_transfer t[2]; + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; + struct spi_transfer t[2] = {}; struct spi_message m; - int fast_read = 0; - - if (flash->spi->max_speed_hz >= 25000000) - fast_read = 1; + int cmd_sz = m25p_cmdsz(nor); spi_message_init(&m); - memset(t, 0, (sizeof t)); - /* NOTE: - * OPCODE_FAST_READ (if available) is faster. - * Should add 1 byte DUMMY_BYTE. - */ + if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) + cmd_sz = 1; + + flash->command[0] = nor->program_opcode; + m25p_addr2cmd(nor, to, flash->command); + t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash) + fast_read; + t[0].len = cmd_sz; spi_message_add_tail(&t[0], &m); - t[1].rx_buf = buf; + t[1].tx_buf = buf; t[1].len = len; spi_message_add_tail(&t[1], &m); - /* Wait till previous write/erase is done. */ - if (wait_till_ready(flash)) - return -ETIMEDOUT; - - /* FIXME switch to OPCODE_FAST_READ. It's required for higher - * clocks; and at this writing, every chip this driver handles - * supports that opcode. - */ - - /* Set up the write data buffer. */ - flash->command[0] = fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ; - m25p_addr2cmd(flash, from, flash->command); - - spi_sync(flash->spi, &m); - - *retlen = m.actual_length - m25p_cmdsz(flash) - fast_read; + spi_sync(spi, &m); - return 0; + *retlen += m.actual_length - cmd_sz; } /* - * Write an address range to the flash chip. Data must be written in - * FLASH_PAGESIZE chunks. The address range may be any size provided - * it is within the physical boundaries. + * Read an address range from the nor chip. The address range + * may be any size provided it is within the physical boundaries. */ -static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, + size_t *retlen, u_char *buf) { - struct m25p *flash = mtd_to_m25p(mtd); - u32 page_offset, page_size; + struct m25p *flash = nor->priv; + struct spi_device *spi = flash->spi; struct spi_transfer t[2]; struct spi_message m; + unsigned int dummy = nor->read_dummy; - dev_dbg(&flash->spi->dev, "m25p80_write %ld bytes at 0x%08llx\n", - (unsigned long)len, to); + /* convert the dummy cycles to the number of bytes */ + dummy /= 8; spi_message_init(&m); memset(t, 0, (sizeof t)); + flash->command[0] = nor->read_opcode; + m25p_addr2cmd(nor, from, flash->command); + t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash); + t[0].len = m25p_cmdsz(nor) + dummy; spi_message_add_tail(&t[0], &m); - t[1].tx_buf = buf; + t[1].rx_buf = buf; + t[1].len = len; spi_message_add_tail(&t[1], &m); - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) - return -ETIMEDOUT; - - write_enable(flash); - - /* Set up the opcode in the write buffer. */ - flash->command[0] = OPCODE_PP; - m25p_addr2cmd(flash, to, flash->command); - - page_offset = to & (flash->page_size - 1); - - /* do all the bytes fit onto one page? */ - if (page_offset + len <= flash->page_size) { - t[1].len = len; - - spi_sync(flash->spi, &m); - - *retlen = m.actual_length - m25p_cmdsz(flash); - } else { - u32 i; - - /* the size of data remaining on the first page */ - page_size = flash->page_size - page_offset; - - t[1].len = page_size; - spi_sync(flash->spi, &m); - - *retlen = m.actual_length - m25p_cmdsz(flash); - - /* write everything in flash->page_size chunks */ - for (i = page_size; i < len; i += page_size) { - page_size = len - i; - if (page_size > flash->page_size) - page_size = flash->page_size; - - /* write the next page to flash */ - m25p_addr2cmd(flash, to + i, flash->command); - - t[1].tx_buf = buf + i; - t[1].len = page_size; - - wait_till_ready(flash); - - write_enable(flash); - - spi_sync(flash->spi, &m); - - *retlen += m.actual_length - m25p_cmdsz(flash); - } - } + spi_sync(spi, &m); + *retlen = m.actual_length - m25p_cmdsz(nor) - dummy; return 0; } -static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int m25p80_erase(struct spi_nor *nor, loff_t offset) { - struct m25p *flash = mtd_to_m25p(mtd); - struct spi_transfer t[2]; - struct spi_message m; - size_t actual; - int cmd_sz, ret; - - dev_dbg(&flash->spi->dev, "%s to 0x%08x, len %zd\n", - __func__, (u32)to, len); - - spi_message_init(&m); - memset(t, 0, (sizeof t)); + struct m25p *flash = nor->priv; - t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash); - spi_message_add_tail(&t[0], &m); + dev_dbg(nor->dev, "%dKiB at 0x%08x\n", + flash->mtd.erasesize / 1024, (u32)offset); - t[1].tx_buf = buf; - spi_message_add_tail(&t[1], &m); + /* Set up command buffer. */ + flash->command[0] = nor->erase_opcode; + m25p_addr2cmd(nor, offset, flash->command); - /* Wait until finished previous write command. */ - ret = wait_till_ready(flash); - if (ret) - goto time_out; - - write_enable(flash); - - actual = to % 2; - /* Start write from odd address. */ - if (actual) { - flash->command[0] = OPCODE_BP; - m25p_addr2cmd(flash, to, flash->command); - - /* write one byte. */ - t[1].len = 1; - spi_sync(flash->spi, &m); - ret = wait_till_ready(flash); - if (ret) - goto time_out; - *retlen += m.actual_length - m25p_cmdsz(flash); - } - to += actual; - - flash->command[0] = OPCODE_AAI_WP; - m25p_addr2cmd(flash, to, flash->command); - - /* Write out most of the data here. */ - cmd_sz = m25p_cmdsz(flash); - for (; actual < len - 1; actual += 2) { - t[0].len = cmd_sz; - /* write two bytes. */ - t[1].len = 2; - t[1].tx_buf = buf + actual; - - spi_sync(flash->spi, &m); - ret = wait_till_ready(flash); - if (ret) - goto time_out; - *retlen += m.actual_length - cmd_sz; - cmd_sz = 1; - to += 2; - } - write_disable(flash); - ret = wait_till_ready(flash); - if (ret) - goto time_out; - - /* Write out trailing byte if it exists. */ - if (actual != len) { - write_enable(flash); - flash->command[0] = OPCODE_BP; - m25p_addr2cmd(flash, to, flash->command); - t[0].len = m25p_cmdsz(flash); - t[1].len = 1; - t[1].tx_buf = buf + actual; - - spi_sync(flash->spi, &m); - ret = wait_till_ready(flash); - if (ret) - goto time_out; - *retlen += m.actual_length - m25p_cmdsz(flash); - write_disable(flash); - } + spi_write(flash->spi, flash->command, m25p_cmdsz(nor)); -time_out: - return ret; + return 0; } -/****************************************************************************/ - /* - * SPI device driver setup and teardown - */ - -struct flash_info { - /* JEDEC id zero means "no ID" (most older chips); otherwise it has - * a high byte of zero plus three data bytes: the manufacturer id, - * then a two byte device id. - */ - u32 jedec_id; - u16 ext_id; - - /* The size listed here is what works with OPCODE_SE, which isn't - * necessarily called a "sector" by the vendor. - */ - unsigned sector_size; - u16 n_sectors; - - u16 page_size; - u16 addr_width; - - u16 flags; -#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ -#define M25P_NO_ERASE 0x02 /* No erase command needed */ -}; - -#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - ((unsigned long)&(struct flash_info) { \ - .jedec_id = (_jedec_id), \ - .ext_id = (_ext_id), \ - .sector_size = (_sector_size), \ - .n_sectors = (_n_sectors), \ - .page_size = 256, \ - .flags = (_flags), \ - }) - -#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width) \ - ((unsigned long)&(struct flash_info) { \ - .sector_size = (_sector_size), \ - .n_sectors = (_n_sectors), \ - .page_size = (_page_size), \ - .addr_width = (_addr_width), \ - .flags = M25P_NO_ERASE, \ - }) - -/* NOTE: double check command sets and memory organization when you add - * more flash chips. This current list focusses on newer chips, which - * have been converging on command sets which including JEDEC ID. + * Do NOT add to this array without reading the following: + * + * Historically, many flash devices are bound to this driver by their name. But + * since most of these flash are compatible to some extent, and their + * differences can often be differentiated by the JEDEC read-ID command, we + * encourage new users to add support to the spi-nor library, and simply bind + * against a generic string here (e.g., "nor-jedec"). + * + * Many flash names are kept here in this list (as well as in spi-nor.c) to + * keep them available as module aliases for existing platforms. */ static const struct platform_device_id m25p_ids[] = { - /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, - { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, - - { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, - { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, - { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, - - { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, - { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, - { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, - { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, - - { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, - - /* EON -- en25xxx */ - { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, - { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, - { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, - { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - - /* Everspin */ - { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) }, - - /* Intel/Numonyx -- xxxs33b */ - { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, - { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, - { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, - - /* Macronix */ - { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, - { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, - { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, - { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, - { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, - { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, - { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, - { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - - /* Micron */ - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, - { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, - { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, - { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, - - /* Spansion -- single (large) sector size only, at least - * for the chips listed here (without boot sectors). + {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, + {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"}, + {"at26df321"}, {"at45db081d"}, + {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"}, + {"en25q64"}, {"en25qh128"}, {"en25qh256"}, + {"f25l32pa"}, + {"mr25h256"}, {"mr25h10"}, + {"gd25q32"}, {"gd25q64"}, + {"160s33b"}, {"320s33b"}, {"640s33b"}, + {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"}, + {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"}, + {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"}, + {"mx66l1g55g"}, + {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"}, + {"n25q512a"}, {"n25q512ax3"}, {"n25q00"}, + {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"}, + {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"}, + {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, + {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, + {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, + {"s25fl016k"}, {"s25fl064k"}, {"s25fl132k"}, + {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, + {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, + {"sst25wf040"}, + {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"}, + {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"}, + {"m25p128"}, {"n25q032"}, + {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, + {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, + {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, + {"m45pe10"}, {"m45pe80"}, {"m45pe16"}, + {"m25pe20"}, {"m25pe80"}, {"m25pe16"}, + {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, + {"m25px64"}, {"m25px80"}, + {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, + {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, + {"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"}, + {"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. */ - { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) }, - { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, - { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, 0) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, - { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, - { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, - { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, - { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, - { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, - { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, - { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, - { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, - { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, - { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, - { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - - /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K) }, - { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K) }, - { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K) }, - { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K) }, - { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K) }, - { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K) }, - { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K) }, - { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K) }, - - /* ST Microelectronics -- newer production may have feature updates */ - { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, - { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, - { "m25p20", INFO(0x202012, 0, 64 * 1024, 4, 0) }, - { "m25p40", INFO(0x202013, 0, 64 * 1024, 8, 0) }, - { "m25p80", INFO(0x202014, 0, 64 * 1024, 16, 0) }, - { "m25p16", INFO(0x202015, 0, 64 * 1024, 32, 0) }, - { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, - { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, - { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, - { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, - - { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, - { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, - { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, - { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8, 0) }, - { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16, 0) }, - { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32, 0) }, - { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64, 0) }, - { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128, 0) }, - { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64, 0) }, - - { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2, 0) }, - { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, - { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, - - { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, - { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, - { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, - - { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, - - /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, - { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, - { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, - { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, - { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, - - /* Catalyst / On Semiconductor -- non-JEDEC */ - { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, - { "cat25c03", CAT25_INFO( 32, 8, 16, 2) }, - { "cat25c09", CAT25_INFO( 128, 8, 32, 2) }, - { "cat25c17", CAT25_INFO( 256, 8, 32, 2) }, - { "cat25128", CAT25_INFO(2048, 8, 64, 2) }, + {"nor-jedec"}, { }, }; -static const struct platform_device_id *jedec_probe(struct spi_device *spi) -{ - int tmp; - u8 code = OPCODE_RDID; - u8 id[5]; - u32 jedec; - u16 ext_jedec; - struct flash_info *info; - - /* JEDEC also defines an optional "extended device information" - * string for after vendor-specific data, after the three bytes - * we use here. Supporting some chips might require using it. - */ - tmp = spi_write_then_read(spi, &code, 1, id, 5); - if (tmp < 0) { - dev_dbg(&spi->dev, "%s: error %d reading JEDEC ID\n", - dev_name(&spi->dev), tmp); - return ERR_PTR(tmp); - } - jedec = id[0]; - jedec = jedec << 8; - jedec |= id[1]; - jedec = jedec << 8; - jedec |= id[2]; - - ext_jedec = id[3] << 8 | id[4]; - - for (tmp = 0; tmp < ARRAY_SIZE(m25p_ids) - 1; tmp++) { - info = (void *)m25p_ids[tmp].driver_data; - if (info->jedec_id == jedec) { - if (info->ext_id != 0 && info->ext_id != ext_jedec) - continue; - return &m25p_ids[tmp]; - } - } - dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); - return ERR_PTR(-ENODEV); -} - - /* * board specific setup should have ensured the SPI clock used here * matches what the READ command supports, at least until this driver @@ -802,164 +229,65 @@ static const struct platform_device_id *jedec_probe(struct spi_device *spi) static int m25p_probe(struct device_d *dev) { struct spi_device *spi = (struct spi_device *)dev->type_data; - const struct platform_device_id *id = NULL; struct flash_platform_data *data; struct m25p *flash; - struct flash_info *info = NULL; - unsigned i; - unsigned do_jdec_probe = 1; - char *flashname = NULL; - const char *typename = NULL; + struct spi_nor *nor; + enum read_mode mode = SPI_NOR_NORMAL; + const char *flash_name = NULL; int device_id; + int ret; - /* Platform data helps sort out which chip type we have, as - * well as how this board partitions it. If we don't have - * a chip ID, try the JEDEC id commands; they'll work for most - * newer chips, even if we don't recognize the particular chip. - */ data = dev->platform_data; - if (data && data->type) - typename = data->type; - else if (dev->id_entry) - typename = dev->id_entry->name; - - if (typename) { - const struct platform_device_id *plat_id; - - for (i = 0; i < ARRAY_SIZE(m25p_ids) - 1; i++) { - plat_id = &m25p_ids[i]; - if (strcmp(typename, plat_id->name)) - continue; - break; - } - - if (i < ARRAY_SIZE(m25p_ids) - 1) { - id = plat_id; - info = (void *)id->driver_data; - /* If flash type is provided but the memory is not - * JEDEC compliant, don't try to probe the JEDEC id */ - if (!info->jedec_id) - do_jdec_probe = 0; - } else - dev_warn(&spi->dev, "unrecognized id %s\n", typename); - } - - if (do_jdec_probe) { - const struct platform_device_id *jid; - - jid = jedec_probe(spi); - if (IS_ERR(jid)) { - return PTR_ERR(jid); - } else if (jid != id) { - /* - * JEDEC knows better, so overwrite platform ID. We - * can't trust partitions any longer, but we'll let - * mtd apply them anyway, since some partitions may be - * marked read-only, and we don't want to lose that - * information, even if it's not 100% accurate. - */ - if (id) - dev_warn(dev, "found %s, expected %s\n", - jid->name, id->name); - - id = jid; - info = (void *)jid->driver_data; - } - } flash = xzalloc(sizeof *flash); - flash->command = xmalloc(MAX_CMD_SIZE); - flash->spi = spi; - dev->priv = (void *)flash; - /* - * Atmel, SST and Intel/Numonyx serial flash tend to power - * up with the software protection bits set - */ + nor = &flash->spi_nor; - if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL || - JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL || - JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) { - write_enable(flash); - write_sr(flash, 0); - } + /* install the hooks */ + nor->read = m25p80_read; + nor->write = m25p80_write; + nor->erase = m25p80_erase; + nor->write_reg = m25p80_write_reg; + nor->read_reg = m25p80_read_reg; - device_id = DEVICE_ID_SINGLE; - if (dev->device_node) { - const char *alias = of_alias_get(dev->device_node); - if (alias) - flashname = xstrdup(alias); - } else if (data && data->name) { - flashname = data->name; - } + nor->dev = dev; + nor->mtd = &flash->mtd; + nor->priv = flash; - if (!flashname) { - device_id = DEVICE_ID_DYNAMIC; - flashname = "m25p"; - } + flash->mtd.priv = nor; + flash->mtd.parent = &spi->dev; + flash->spi = spi; + + dev->priv = (void *)flash; - flash->mtd.type = MTD_NORFLASH; - flash->mtd.writesize = 1; - flash->mtd.flags = MTD_CAP_NORFLASH; - flash->mtd.size = (uint64_t)info->sector_size * info->n_sectors; - flash->mtd.erase = m25p80_erase; - flash->mtd.read = m25p80_read; + if (data && data->name) + flash->mtd.name = data->name; - /* sst flash chips use AAI word program */ - if (IS_ENABLED(CONFIG_MTD_SST25L) && JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) - flash->mtd.write = sst_write; + if (data && data->type) + flash_name = data->type; + else if (data && data->name) + flash_name = data->name; + else if (dev->id_entry) + flash_name = dev->id_entry->name; else - flash->mtd.write = m25p80_write; - - /* prefer "small sector" erase if possible */ - if (info->flags & SECT_4K) { - flash->erase_opcode_4k = OPCODE_BE_4K; - flash->erase_opcode = OPCODE_SE; - flash->mtd.erasesize = 4096; - } else { - flash->erase_opcode = OPCODE_SE; - flash->mtd.erasesize = info->sector_size; - } + flash_name = NULL; /* auto-detect */ - if (info->flags & M25P_NO_ERASE) - flash->mtd.flags |= MTD_NO_ERASE; + ret = spi_nor_scan(nor, flash_name, mode); + if (ret) + return ret; - flash->mtd.parent = &spi->dev; - flash->page_size = info->page_size; - flash->sector_size = info->sector_size; - - if (info->addr_width) - flash->addr_width = info->addr_width; - else { - /* enable 4-byte addressing if the device exceeds 16MiB */ - if (flash->mtd.size > 0x1000000) { - flash->addr_width = 4; - set_4byte(flash, info->jedec_id, 1); - } else - flash->addr_width = 3; + device_id = DEVICE_ID_SINGLE; + 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; + flash_name = "m25p"; } - dev_info(dev, "%s (%lld Kbytes)\n", id->name, - (long long)flash->mtd.size >> 10); - - dev_dbg(dev, "mtd .name = %s, .size = 0x%llx (%lldMiB) " - ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", - flash->mtd.name, - (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), - flash->mtd.erasesize, flash->mtd.erasesize / 1024, - flash->mtd.numeraseregions); - - if (flash->mtd.numeraseregions) - for (i = 0; i < flash->mtd.numeraseregions; i++) - dev_dbg(dev, "mtd.eraseregions[%d] = { .offset = 0x%llx, " - ".erasesize = 0x%.8x (%uKiB), " - ".numblocks = %d }\n", - i, (long long)flash->mtd.eraseregions[i].offset, - flash->mtd.eraseregions[i].erasesize, - flash->mtd.eraseregions[i].erasesize / 1024, - flash->mtd.eraseregions[i].numblocks); - - return add_mtd_device(&flash->mtd, flashname, device_id); + return add_mtd_device(&flash->mtd, flash_name, device_id); } static __maybe_unused struct of_device_id m25p80_dt_ids[] = { 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/nand/nand-bb.c b/drivers/mtd/nand/nand-bb.c index 539c685482..8e4600ab03 100644 --- a/drivers/mtd/nand/nand-bb.c +++ b/drivers/mtd/nand/nand-bb.c @@ -54,7 +54,7 @@ static ssize_t nand_bb_read(struct cdev *cdev, void *buf, size_t count, size_t retlen; int ret, bytes = 0, now; - debug("%s offset: 0x%08llx (raw: 0x%08llx) count: 0x%08x\n", + debug("%s offset: 0x%08llx (raw: 0x%08llx) count: 0x%08zx\n", __func__, offset, bb->offset, count); while (count) { @@ -132,7 +132,7 @@ static ssize_t nand_bb_write(struct cdev *cdev, const void *buf, size_t count, struct nand_bb *bb = cdev->priv; int bytes = count, now, wroffs, ret; - debug("%s offset: 0x%08llx (raw: 0x%08llx) count: 0x%08x\n", + debug("%s offset: 0x%08llx (raw: 0x%08llx) count: 0x%08zx\n", __func__, offset, bb->offset, count); while (count) { 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 9aad5c41f6..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,32 +243,32 @@ 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) { - cpu_writeb(value, addr); + __raw_writeb(value, addr); } static inline void flash_write16(u16 value, void *addr) { - cpu_writew(value, addr); + __raw_writew(value, addr); } static inline void flash_write32(u32 value, void *addr) { - cpu_writel(value, addr); + __raw_writel(value, addr); } static inline void flash_write64(u64 value, void *addr) @@ -276,17 +278,17 @@ static inline void flash_write64(u64 value, void *addr) static inline u8 flash_read8(void *addr) { - return cpu_readb(addr); + return __raw_readb(addr); } static inline u16 flash_read16(void *addr) { - return cpu_readw(addr); + return __raw_readw(addr); } static inline u32 flash_read32(void *addr) { - return cpu_readl(addr); + return __raw_readl(addr); } static inline u64 flash_read64(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/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig new file mode 100644 index 0000000000..a84591fdd1 --- /dev/null +++ b/drivers/mtd/spi-nor/Kconfig @@ -0,0 +1,15 @@ +menuconfig MTD_SPI_NOR + tristate "SPI-NOR device support" + depends on MTD + help + This is the framework for the SPI NOR which can be used by the SPI + device drivers and the SPI-NOR device driver. + +if MTD_SPI_NOR + +config SPI_CADENCE_QUADSPI + tristate "Cadence Quad SPI controller" + help + This enables support for the Cadence Quad SPI controller and NOR flash. + +endif diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile new file mode 100644 index 0000000000..4e00f38a7d --- /dev/null +++ b/drivers/mtd/spi-nor/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o +obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c new file mode 100644 index 0000000000..dce29ca0ea --- /dev/null +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -0,0 +1,1211 @@ +/* + * Copyright (C) 2015 Pengutronix, Steffen Trumtrar <s.trumtrar@pengutronix.de> + * + * derived from Linux kernel driver by + * + * Driver for Cadence QSPI Controller + * + * Copyright Altera Corporation (C) 2012-2014. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ + +#include <clock.h> +#include <common.h> +#include <driver.h> +#include <errno.h> +#include <init.h> +#include <io.h> +#include <linux/clk.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/spi-nor.h> +#include <of.h> +#include <platform_data/cadence_qspi.h> +#include <spi/spi.h> + +#define CQSPI_MAX_CHIPSELECT 16 + +struct cqspi_flash_pdata { + struct mtd_info mtd; + struct spi_nor nor; + u32 clk_rate; + unsigned int block_size; + unsigned int read_delay; + unsigned int tshsl_ns; + unsigned int tsd2d_ns; + unsigned int tchsh_ns; + unsigned int tslch_ns; +}; + +struct cqspi_st { + struct device_d *dev; + struct clk *l4_mp_clk; + struct clk *qspi_clk; + unsigned int sclk; + + void __iomem *iobase; + void __iomem *ahb_base; + unsigned int irq_mask; + int current_cs; + unsigned int master_ref_clk_hz; + unsigned int ext_decoder; + unsigned int fifo_depth; + struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT]; + bool no_reconfig; +}; + +/* Operation timeout value */ +#define CQSPI_TIMEOUT_MS 800 * MSECOND +#define CQSPI_READ_TIMEOUT_MS 100 * MSECOND +#define CQSPI_POLL_IDLE_RETRY 3 + +#define CQSPI_FIFO_WIDTH 4 + +#define CQSPI_REG_SRAM_THRESHOLD_BYTES 50 + +/* Instruction type */ +#define CQSPI_INST_TYPE_SINGLE 0 +#define CQSPI_INST_TYPE_DUAL 1 +#define CQSPI_INST_TYPE_QUAD 2 + +#define CQSPI_DUMMY_CLKS_PER_BYTE 8 +#define CQSPI_DUMMY_BYTES_MAX 4 + +#define CQSPI_STIG_DATA_LEN_MAX 8 + +#define CQSPI_INDIRECTTRIGGER_ADDR_MASK 0xFFFFF + +/* Register map */ +#define CQSPI_REG_CONFIG 0x00 +#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0) +#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9) +#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10 +#define CQSPI_REG_CONFIG_DMA_MASK BIT(15) +#define CQSPI_REG_CONFIG_BAUD_LSB 19 +#define CQSPI_REG_CONFIG_IDLE_LSB 31 +#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF +#define CQSPI_REG_CONFIG_BAUD_MASK 0xF + +#define CQSPI_REG_RD_INSTR 0x04 +#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0 +#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8 +#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12 +#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16 +#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20 +#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24 +#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3 +#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3 +#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3 +#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F + +#define CQSPI_REG_WR_INSTR 0x08 +#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0 +#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12 +#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16 + +#define CQSPI_REG_DELAY 0x0C +#define CQSPI_REG_DELAY_TSLCH_LSB 0 +#define CQSPI_REG_DELAY_TCHSH_LSB 8 +#define CQSPI_REG_DELAY_TSD2D_LSB 16 +#define CQSPI_REG_DELAY_TSHSL_LSB 24 +#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF +#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF +#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF +#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF + +#define CQSPI_REG_READCAPTURE 0x10 +#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0 +#define CQSPI_REG_READCAPTURE_DELAY_LSB 1 +#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF + +#define CQSPI_REG_SIZE 0x14 +#define CQSPI_REG_SIZE_ADDRESS_LSB 0 +#define CQSPI_REG_SIZE_PAGE_LSB 4 +#define CQSPI_REG_SIZE_BLOCK_LSB 16 +#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF +#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF +#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F + +#define CQSPI_REG_SRAMPARTITION 0x18 +#define CQSPI_REG_INDIRECTTRIGGER 0x1C + +#define CQSPI_REG_DMA 0x20 +#define CQSPI_REG_DMA_SINGLE_LSB 0 +#define CQSPI_REG_DMA_BURST_LSB 8 +#define CQSPI_REG_DMA_SINGLE_MASK 0xFF +#define CQSPI_REG_DMA_BURST_MASK 0xFF + +#define CQSPI_REG_REMAP 0x24 +#define CQSPI_REG_MODE_BIT 0x28 + +#define CQSPI_REG_SRAMLEVEL 0x2C +#define CQSPI_REG_SRAMLEVEL_RD_LSB 0 +#define CQSPI_REG_SRAMLEVEL_WR_LSB 16 +#define CQSPI_REG_SRAMLEVEL_RD_MASK 0xFFFF +#define CQSPI_REG_SRAMLEVEL_WR_MASK 0xFFFF + +#define CQSPI_REG_IRQSTATUS 0x40 +#define CQSPI_REG_IRQMASK 0x44 + +#define CQSPI_REG_INDIRECTRD 0x60 +#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0) +#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1) +#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5) + +#define CQSPI_REG_INDIRECTRDWATERMARK 0x64 +#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68 +#define CQSPI_REG_INDIRECTRDBYTES 0x6C + +#define CQSPI_REG_CMDCTRL 0x90 +#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0) +#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1) +#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12 +#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15 +#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16 +#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19 +#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20 +#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23 +#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24 +#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7 +#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3 +#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7 + +#define CQSPI_REG_INDIRECTWR 0x70 +#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0) +#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1) +#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5) + +#define CQSPI_REG_INDIRECTWRWATERMARK 0x74 +#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78 +#define CQSPI_REG_INDIRECTWRBYTES 0x7C + +#define CQSPI_REG_CMDADDRESS 0x94 +#define CQSPI_REG_CMDREADDATALOWER 0xA0 +#define CQSPI_REG_CMDREADDATAUPPER 0xA4 +#define CQSPI_REG_CMDWRITEDATALOWER 0xA8 +#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC + +/* Interrupt status bits */ +#define CQSPI_REG_IRQ_MODE_ERR BIT(0) +#define CQSPI_REG_IRQ_UNDERFLOW BIT(1) +#define CQSPI_REG_IRQ_IND_COMP BIT(2) +#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3) +#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4) +#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5) +#define CQSPI_REG_IRQ_WATERMARK BIT(6) +#define CQSPI_REG_IRQ_IND_RD_OVERFLOW BIT(12) + +#define CQSPI_IRQ_STATUS_ERR (CQSPI_REG_IRQ_MODE_ERR | \ + CQSPI_REG_IRQ_IND_RD_REJECT | \ + CQSPI_REG_IRQ_WR_PROTECTED_ERR | \ + CQSPI_REG_IRQ_ILLEGAL_AHB_ERR) + +#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \ + CQSPI_REG_IRQ_IND_RD_OVERFLOW | \ + CQSPI_REG_IRQ_IND_COMP) + +#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \ + CQSPI_REG_IRQ_WATERMARK | \ + CQSPI_REG_IRQ_UNDERFLOW) + +#define CQSPI_IRQ_STATUS_MASK 0x1FFFE + +#define CQSPI_REG_IS_IDLE(base) \ + ((readl(base + CQSPI_REG_CONFIG) >> \ + CQSPI_REG_CONFIG_IDLE_LSB) & 0x1) + +#define CQSPI_GET_RD_SRAM_LEVEL(reg_base) \ + (((readl(reg_base + CQSPI_REG_SRAMLEVEL)) >> \ + CQSPI_REG_SRAMLEVEL_RD_LSB) & CQSPI_REG_SRAMLEVEL_RD_MASK) + +static void cqspi_fifo_read(void *dest, const void *src_ahb_addr, + unsigned int bytes) +{ + unsigned int temp; + int remaining = bytes; + unsigned int *dest_ptr = (unsigned int *)dest; + unsigned int *src_ptr = (unsigned int *)src_ahb_addr; + + while (remaining > CQSPI_FIFO_WIDTH) { + *dest_ptr = readl(src_ptr); + dest_ptr++; + remaining -= CQSPI_FIFO_WIDTH; + } + if (remaining > 0) { + /* dangling bytes */ + temp = readl(src_ptr); + memcpy(dest_ptr, &temp, remaining); + } +} + +static void cqspi_fifo_write(void *dest_ahb_addr, + const void *src, unsigned int bytes) +{ + unsigned int temp; + int remaining = bytes; + unsigned int *dest_ptr = (unsigned int *)dest_ahb_addr; + unsigned int *src_ptr = (unsigned int *)src; + + while (remaining > CQSPI_FIFO_WIDTH) { + writel(*src_ptr, dest_ptr); + src_ptr++; + remaining -= CQSPI_FIFO_WIDTH; + } + if (remaining > 0) { + /* dangling bytes */ + memcpy(&temp, src_ptr, remaining); + writel(temp, dest_ptr); + } +} + +static int cqspi_find_chipselect(struct spi_nor *nor) +{ + int cs = -1; + struct cqspi_st *cqspi = nor->priv; + + for (cs = 0; cs < CQSPI_MAX_CHIPSELECT; cs++) + if (nor == &cqspi->f_pdata[cs].nor) + break; + return cs; +} + +static unsigned int cqspi_calc_rdreg(struct spi_nor *nor, u8 opcode) +{ + unsigned int rdreg = 0; + struct cqspi_st *cqspi = nor->priv; + struct cqspi_flash_pdata *f_pdata; + + f_pdata = &cqspi->f_pdata[cqspi->current_cs]; + + if (nor->flash_read == SPI_NOR_QUAD) + rdreg |= (CQSPI_INST_TYPE_QUAD + << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB); + return rdreg; +} + +static unsigned int cqspi_wait_idle(struct cqspi_st *cqspi) +{ + void __iomem *reg_base = cqspi->iobase; + + if (wait_on_timeout(CQSPI_TIMEOUT_MS, + CQSPI_REG_IS_IDLE(reg_base))) { + /* Timeout, in busy mode. */ + dev_err(cqspi->dev, "QSPI is still busy after %llums timeout.\n", + CQSPI_TIMEOUT_MS); + return -ETIMEDOUT; + } + + return 0; +} + +static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg) +{ + void __iomem *reg_base = cqspi->iobase; + + /* Write the CMDCTRL without start execution. */ + writel(reg, reg_base + CQSPI_REG_CMDCTRL); + /* Start execute */ + reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK; + writel(reg, reg_base + CQSPI_REG_CMDCTRL); + + if (wait_on_timeout(CQSPI_TIMEOUT_MS, + (readl(reg_base + CQSPI_REG_CMDCTRL) & + CQSPI_REG_CMDCTRL_INPROGRESS_MASK) == 0)) { + dev_err(cqspi->dev, "flash cmd execute time out (0x%08x)\n", + readl(reg_base + CQSPI_REG_CMDCTRL)); + return -EIO; + } + + /* Polling QSPI idle status. */ + return cqspi_wait_idle(cqspi); +} + +static int cqspi_command_read(struct spi_nor *nor, + const u8 *txbuf, unsigned n_tx, + u8 *rxbuf, unsigned n_rx) +{ + unsigned int reg; + unsigned int read_len; + int status; + struct cqspi_st *cqspi = nor->priv; + void __iomem *reg_base = cqspi->iobase; + unsigned int rdreg; + + if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) { + dev_err(nor->dev, + "Invalid input argument, len %d rxbuf 0x%08x\n", n_rx, + (unsigned int)rxbuf); + return -EINVAL; + } + + reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB; + + rdreg = cqspi_calc_rdreg(nor, txbuf[0]); + writel(rdreg, reg_base + CQSPI_REG_RD_INSTR); + + reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); + + /* 0 means 1 byte. */ + reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) + << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); + status = cqspi_exec_flash_cmd(cqspi, reg); + if (status != 0) + return status; + + reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER); + + /* Put the read value into rx_buf */ + read_len = (n_rx > 4) ? 4 : n_rx; + memcpy(rxbuf, ®, read_len); + rxbuf += read_len; + + if (n_rx > 4) { + reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER); + + read_len = n_rx - read_len; + memcpy(rxbuf, ®, read_len); + } + + return 0; +} + +static __maybe_unused int cqspi_command_write(struct spi_nor *nor, + u8 opcode, const u8 *txbuf, unsigned n_tx) +{ + unsigned int reg; + unsigned int data; + struct cqspi_st *cqspi = nor->priv; + void __iomem *reg_base = cqspi->iobase; + + if (n_tx > 4 || (n_tx && txbuf == NULL)) { + dev_err(nor->dev, + "Invalid input argument, cmdlen %d txbuf 0x%08x\n", + n_tx, (unsigned int)txbuf); + return -EINVAL; + } + + reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; + if (n_tx) { + reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB); + reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) + << CQSPI_REG_CMDCTRL_WR_BYTES_LSB; + data = 0; + memcpy(&data, txbuf, n_tx); + writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER); + } + + return cqspi_exec_flash_cmd(cqspi, reg); +} + +static int cqspi_command_write_addr(struct spi_nor *nor, + u8 opcode, unsigned int addr) +{ + unsigned int reg; + struct cqspi_st *cqspi = nor->priv; + void __iomem *reg_base = cqspi->iobase; + + reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; + reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); + reg |= ((nor->addr_width - 1) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) + << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; + + writel(addr, reg_base + CQSPI_REG_CMDADDRESS); + + return cqspi_exec_flash_cmd(cqspi, reg); +} + +static int cqspi_indirect_read_setup(struct spi_nor *nor, + unsigned int from_addr) +{ + struct cqspi_st *cqspi = nor->priv; + unsigned int ahb_base = (unsigned int) cqspi->ahb_base; + void __iomem *reg_base = cqspi->iobase; + unsigned int dummy_clk = 0; + unsigned int dummy_bytes; + unsigned int reg = 0; + + writel(ahb_base & CQSPI_INDIRECTTRIGGER_ADDR_MASK, + reg_base + CQSPI_REG_INDIRECTTRIGGER); + writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); + + reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB; + reg |= cqspi_calc_rdreg(nor, nor->read_opcode); + + /* Setup dummy clock cycles */ + dummy_bytes = nor->read_dummy / 8; + + if (dummy_bytes) { + struct cqspi_flash_pdata *f_pdata; + + f_pdata = &cqspi->f_pdata[cqspi->current_cs]; + + if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX) + dummy_bytes = CQSPI_DUMMY_BYTES_MAX; + + reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB); + /* Set mode bits high to ensure chip doesn't enter XIP */ + writel(0xFF, reg_base + CQSPI_REG_MODE_BIT); + + /* Convert to clock cycles. */ + dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE; + /* Need to subtract the mode byte (8 clocks). */ + dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE; + + if (dummy_clk) + reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK) + << CQSPI_REG_RD_INSTR_DUMMY_LSB; + } + + writel(reg, reg_base + CQSPI_REG_RD_INSTR); + + /* Set address width */ + reg = readl(reg_base + CQSPI_REG_SIZE); + reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; + reg |= (nor->addr_width) - 1; + writel(reg, reg_base + CQSPI_REG_SIZE); + return 0; +} + +static int cqspi_indirect_read_execute(struct spi_nor *nor, + u8 *rxbuf, unsigned n_rx) +{ + int ret = 0; + unsigned int reg = 0; + unsigned int bytes_to_read = 0; + unsigned int watermark; + struct cqspi_st *cqspi = nor->priv; + void __iomem *reg_base = cqspi->iobase; + void __iomem *ahb_base = cqspi->ahb_base; + int remaining = (int)n_rx; + + watermark = cqspi->fifo_depth * CQSPI_FIFO_WIDTH / 2; + writel(watermark, reg_base + CQSPI_REG_INDIRECTRDWATERMARK); + writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES); + + /* Clear all interrupts. */ + writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); + + cqspi->irq_mask = CQSPI_IRQ_MASK_RD; + writel(cqspi->irq_mask, reg_base + CQSPI_REG_IRQMASK); + + writel(CQSPI_REG_INDIRECTRD_START_MASK, + reg_base + CQSPI_REG_INDIRECTRD); + + while (remaining > 0) { + unsigned int irq_status; + + ret = wait_on_timeout(CQSPI_READ_TIMEOUT_MS, + readl(reg_base + CQSPI_REG_IRQSTATUS) & cqspi->irq_mask); + + irq_status = readl(reg_base + CQSPI_REG_IRQSTATUS); + bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base); + + /* Clear all interrupts. */ + writel(irq_status, reg_base + CQSPI_REG_IRQSTATUS); + + if (!ret && bytes_to_read == 0) { + dev_err(nor->dev, "Indirect read timeout, no bytes\n"); + ret = -ETIMEDOUT; + goto failrd; + } + + while (bytes_to_read != 0) { + bytes_to_read *= CQSPI_FIFO_WIDTH; + bytes_to_read = bytes_to_read > remaining + ? remaining : bytes_to_read; + cqspi_fifo_read(rxbuf, ahb_base, bytes_to_read); + rxbuf += bytes_to_read; + remaining -= bytes_to_read; + bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base); + } + } + + /* Check indirect done status */ + if (wait_on_timeout(CQSPI_TIMEOUT_MS, + readl(reg_base + CQSPI_REG_INDIRECTRD) & + CQSPI_REG_INDIRECTRD_DONE_MASK)) { + dev_err(nor->dev, + "Indirect read completion error 0x%08x\n", reg); + ret = -ETIMEDOUT; + goto failrd; + } + + /* Disable interrupt */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Clear indirect completion status */ + writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD); + + return 0; + + failrd: + /* Disable interrupt */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Cancel the indirect read */ + writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, + reg_base + CQSPI_REG_INDIRECTRD); + return ret; +} + +static __maybe_unused int cqspi_indirect_write_setup(struct spi_nor *nor, + unsigned int to_addr) +{ + unsigned int reg; + struct cqspi_st *cqspi = nor->priv; + void __iomem *reg_base = cqspi->iobase; + + /* Set opcode. */ + reg = nor->program_opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB; + writel(reg, reg_base + CQSPI_REG_WR_INSTR); + reg = cqspi_calc_rdreg(nor, nor->program_opcode); + writel(reg, reg_base + CQSPI_REG_RD_INSTR); + + writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR); + + reg = readl(reg_base + CQSPI_REG_SIZE); + reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; + reg |= (nor->addr_width - 1); + writel(reg, reg_base + CQSPI_REG_SIZE); + return 0; +} + +static __maybe_unused int cqspi_indirect_write_execute(struct spi_nor *nor, + const u8 *txbuf, unsigned n_tx) +{ + int ret; + unsigned int reg = 0; + struct cqspi_st *cqspi = nor->priv; + void __iomem *reg_base = cqspi->iobase; + void __iomem *ahb_base = cqspi->ahb_base; + int remaining = (int)n_tx; + unsigned int page_size; + unsigned int write_bytes; + + page_size = nor->page_size; + + writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES); + + writel(CQSPI_REG_SRAM_THRESHOLD_BYTES, reg_base + + CQSPI_REG_INDIRECTWRWATERMARK); + + /* Clear all interrupts. */ + writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); + + cqspi->irq_mask = CQSPI_IRQ_MASK_WR; + writel(cqspi->irq_mask, reg_base + CQSPI_REG_IRQMASK); + + writel(CQSPI_REG_INDIRECTWR_START_MASK, + reg_base + CQSPI_REG_INDIRECTWR); + + /* Write a page or remaining bytes. */ + write_bytes = remaining > page_size ? page_size : remaining; + /* Fill up the data at the beginning */ + cqspi_fifo_write(ahb_base, txbuf, write_bytes); + txbuf += write_bytes; + remaining -= write_bytes; + + while (remaining > 0) { + ret = wait_on_timeout(CQSPI_READ_TIMEOUT_MS, + readl(reg_base + CQSPI_REG_IRQSTATUS) & cqspi->irq_mask); + + /* Clear all interrupts. */ + writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); + + if (ret < 0) { + dev_err(nor->dev, "Indirect write timeout\n"); + ret = -ETIMEDOUT; + goto failwr; + } + + write_bytes = remaining > page_size ? page_size : remaining; + cqspi_fifo_write(ahb_base, txbuf, write_bytes); + txbuf += write_bytes; + remaining -= write_bytes; + + writel(cqspi->irq_mask, reg_base + CQSPI_REG_IRQMASK); + } + ret = wait_on_timeout(CQSPI_READ_TIMEOUT_MS, + readl(reg_base + CQSPI_REG_IRQSTATUS) & cqspi->irq_mask); + + /* Clear all interrupts. */ + writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); + if (ret < 0) { + dev_err(nor->dev, "Indirect write timeout\n"); + ret = -ETIMEDOUT; + goto failwr; + } + + /* Check indirect done status */ + if (wait_on_timeout(CQSPI_TIMEOUT_MS, + readl(reg_base + CQSPI_REG_INDIRECTWR) + & CQSPI_REG_INDIRECTWR_DONE_MASK)) { + dev_err(nor->dev, + "Indirect write completion error 0x%08x\n", reg); + ret = -ETIMEDOUT; + goto failwr; + } + + /* Disable interrupt. */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Clear indirect completion status */ + writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR); + + cqspi_wait_idle(cqspi); + + return 0; + +failwr: + /* Disable interrupt. */ + writel(0, reg_base + CQSPI_REG_IRQMASK); + + /* Cancel the indirect write */ + writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, + reg_base + CQSPI_REG_INDIRECTWR); + return ret; +} + +static void cqspi_write(struct spi_nor *nor, loff_t to, + size_t len, size_t *retlen, const u_char *buf) +{ + int ret; + + if (!IS_ENABLED(CONFIG_MTD_WRITE)) + return; + + ret = cqspi_indirect_write_setup(nor, to); + if (ret == 0) { + ret = cqspi_indirect_write_execute(nor, buf, len); + if (ret == 0) + *retlen += len; + } +} + +static int cqspi_read(struct spi_nor *nor, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + int ret; + + ret = cqspi_indirect_read_setup(nor, from); + if (ret == 0) { + ret = cqspi_indirect_read_execute(nor, buf, len); + if (ret == 0) + *retlen += len; + } + return ret; +} + +static int cqspi_erase(struct spi_nor *nor, loff_t offs) +{ + int ret; + + /* Send write enable, then erase commands. */ + ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0); + if (ret) + return ret; + + /* Set up command buffer. */ + ret = cqspi_command_write_addr(nor, nor->erase_opcode, offs); + if (ret) + return ret; + + return 0; +} + +static unsigned int calculate_ticks_for_ns(unsigned int ref_clk_hz, + unsigned int ns_val) +{ + unsigned int ticks; + + ticks = ref_clk_hz; + ticks /= 1000; + ticks *= ns_val; + ticks += 999999; + ticks /= 1000000; + return ticks; +} + +static void cqspi_delay(struct cqspi_st *cqspi, + unsigned int ref_clk_hz, unsigned int sclk_hz) +{ + void __iomem *reg_base = cqspi->iobase; + struct cqspi_flash_pdata *f_pdata; + unsigned int ref_clk_ns; + unsigned int sclk_ns; + unsigned int tshsl, tchsh, tslch, tsd2d; + unsigned int reg; + unsigned int tsclk; + + if (cqspi->no_reconfig) + return; + + f_pdata = &cqspi->f_pdata[cqspi->current_cs]; + + /* Convert to ns. */ + ref_clk_ns = NSEC_PER_SEC / ref_clk_hz; + + /* Convert to ns. */ + sclk_ns = NSEC_PER_SEC / sclk_hz; + + /* calculate the number of ref ticks for one sclk tick */ + tsclk = (ref_clk_hz + sclk_hz - 1) / sclk_hz; + + tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns); + /* this particular value must be at least one sclk */ + if (tshsl < tsclk) + tshsl = tsclk; + + tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns); + tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns); + tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns); + + reg = ((tshsl & CQSPI_REG_DELAY_TSHSL_MASK) + << CQSPI_REG_DELAY_TSHSL_LSB); + reg |= ((tchsh & CQSPI_REG_DELAY_TCHSH_MASK) + << CQSPI_REG_DELAY_TCHSH_LSB); + reg |= ((tslch & CQSPI_REG_DELAY_TSLCH_MASK) + << CQSPI_REG_DELAY_TSLCH_LSB); + reg |= ((tsd2d & CQSPI_REG_DELAY_TSD2D_MASK) + << CQSPI_REG_DELAY_TSD2D_LSB); + writel(reg, reg_base + CQSPI_REG_DELAY); +} + +static void cqspi_config_baudrate_div(struct cqspi_st *cqspi, + unsigned int ref_clk_hz, + unsigned int sclk_hz) +{ + void __iomem *reg_base = cqspi->iobase; + unsigned int reg; + unsigned int div; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB); + + div = ref_clk_hz / sclk_hz; + + /* Recalculate the baudrate divisor based on QSPI specification. */ + if (div > 32) + div = 32; + + /* Check if even number. */ + if (div & 1) + div = (div / 2); + else + div = (div / 2) - 1; + + div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB; + reg |= div; + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + +static void cqspi_readdata_capture(struct cqspi_st *cqspi, + unsigned int bypass, unsigned int delay) +{ + void __iomem *reg_base = cqspi->iobase; + unsigned int reg; + + if (cqspi->no_reconfig) + return; + + reg = readl(reg_base + CQSPI_REG_READCAPTURE); + + if (bypass) + reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); + else + reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); + + reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK + << CQSPI_REG_READCAPTURE_DELAY_LSB); + + reg |= ((delay & CQSPI_REG_READCAPTURE_DELAY_MASK) + << CQSPI_REG_READCAPTURE_DELAY_LSB); + + writel(reg, reg_base + CQSPI_REG_READCAPTURE); +} + +static void cqspi_chipselect(struct cqspi_st *cqspi, + unsigned int chip_select, + unsigned int decoder_enable) +{ + void __iomem *reg_base = cqspi->iobase; + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + if (decoder_enable) { + reg |= CQSPI_REG_CONFIG_DECODE_MASK; + } else { + reg &= ~CQSPI_REG_CONFIG_DECODE_MASK; + + /* Convert CS if without decoder. + * CS0 to 4b'1110 + * CS1 to 4b'1101 + * CS2 to 4b'1011 + * CS3 to 4b'0111 + */ + chip_select = 0xF & ~(1 << chip_select); + } + + reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK + << CQSPI_REG_CONFIG_CHIPSELECT_LSB); + reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK) + << CQSPI_REG_CONFIG_CHIPSELECT_LSB; + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + +static void cqspi_controller_enable(struct cqspi_st *cqspi) +{ + void __iomem *reg_base = cqspi->iobase; + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + reg |= CQSPI_REG_CONFIG_ENABLE_MASK; + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + +static void cqspi_controller_disable(struct cqspi_st *cqspi) +{ + void __iomem *reg_base = cqspi->iobase; + unsigned int reg; + + reg = readl(reg_base + CQSPI_REG_CONFIG); + reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK; + writel(reg, reg_base + CQSPI_REG_CONFIG); +} + +static void cqspi_switch_cs(struct cqspi_st *cqspi, unsigned int cs) +{ + unsigned int reg; + struct cqspi_flash_pdata *f_pdata = &cqspi->f_pdata[cs]; + void __iomem *reg_base = cqspi->iobase; + struct spi_nor *nor = &f_pdata->nor; + + cqspi_controller_disable(cqspi); + + /* configure page size and block size. */ + reg = readl(reg_base + CQSPI_REG_SIZE); + reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB); + reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB); + reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB); + reg |= (f_pdata->block_size << CQSPI_REG_SIZE_BLOCK_LSB); + reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; + reg |= (nor->addr_width - 1); + writel(reg, reg_base + CQSPI_REG_SIZE); + + /* configure the chip select */ + cqspi_chipselect(cqspi, cs, cqspi->ext_decoder); + + cqspi_controller_enable(cqspi); +} + +static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + struct cqspi_st *cqspi = nor->priv; + int cs = cqspi_find_chipselect(nor); + struct cqspi_flash_pdata *f_pdata; + unsigned int sclk; + + /* Switch chip select. */ + if (cqspi->current_cs != cs) { + cqspi->current_cs = cs; + cqspi_switch_cs(cqspi, cs); + } + + /* Setup baudrate divisor and delays */ + f_pdata = &cqspi->f_pdata[cqspi->current_cs]; + sclk = f_pdata->clk_rate; + if (cqspi->sclk != sclk) { + cqspi->sclk = sclk; + cqspi_controller_disable(cqspi); + cqspi_config_baudrate_div(cqspi, + cqspi->master_ref_clk_hz, sclk); + cqspi_delay(cqspi, cqspi->master_ref_clk_hz, sclk); + cqspi_readdata_capture(cqspi, 1, f_pdata->read_delay); + cqspi_controller_enable(cqspi); + } + return 0; +} + +static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +{ + int ret; + + cqspi_prep(nor, SPI_NOR_OPS_READ); + + ret = cqspi_command_read(nor, &opcode, 1, buf, len); + return ret; +} + +static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len, + int write_enable) +{ + int ret = 0; + + if (!IS_ENABLED(CONFIG_MTD_WRITE)) + return -ENOTSUPP; + + cqspi_prep(nor, SPI_NOR_OPS_WRITE); + + ret = cqspi_command_write(nor, opcode, buf, len); + return ret; +} + +static int cqspi_of_get_flash_pdata(struct device_d *dev, + struct cqspi_flash_pdata *f_pdata, + struct device_node *np) +{ + struct cqspi_st *cqspi = dev->priv; + void __iomem *reg_base = cqspi->iobase; + + if (!np) { + f_pdata->block_size = (readl(reg_base + CQSPI_REG_SIZE) >> + CQSPI_REG_SIZE_BLOCK_LSB) & + CQSPI_REG_SIZE_BLOCK_MASK; + + cqspi->no_reconfig = true; + + return 0; + } + + if (of_property_read_u32(np, "cdns,block-size", &f_pdata->block_size)) { + dev_err(dev, "couldn't determine block-size\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) { + dev_err(dev, "couldn't determine read-delay\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) { + dev_err(dev, "couldn't determine tshsl-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) { + dev_err(dev, "couldn't determine tsd2d-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) { + dev_err(dev, "couldn't determine tchsh-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) { + dev_err(dev, "couldn't determine tslch-ns\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) { + dev_err(dev, "couldn't determine spi-max-frequency\n"); + return -ENXIO; + } + + return 0; +} + +static int cqspi_parse_dt(struct cqspi_st *cqspi) +{ + struct device_node *np = cqspi->dev->device_node; + struct device_d *dev = cqspi->dev; + + if (of_property_read_u32(np, "ext-decoder", &cqspi->ext_decoder)) { + dev_err(dev, "couldn't determine ext-decoder\n"); + return -ENXIO; + } + + if (of_property_read_u32(np, "fifo-depth", &cqspi->fifo_depth)) { + dev_err(dev, "couldn't determine fifo-depth\n"); + return -ENXIO; + } + + return 0; +} + +static int cqspi_setup_flash(struct device_d *dev, + struct cqspi_flash_pdata *f_pdata, + struct device_node *np) +{ + struct cqspi_st *cqspi = dev->priv; + struct mtd_info *mtd; + struct spi_nor *nor; + int ret; + + ret = cqspi_of_get_flash_pdata(dev, f_pdata, np); + if (ret) + goto probe_failed; + + nor = &f_pdata->nor; + mtd = &f_pdata->mtd; + + nor->mtd = mtd; + + if (np) { + nor->dev = xzalloc(sizeof(*nor->dev)); + + strcpy(nor->dev->name, np->name); + + nor->dev->device_node = np; + nor->dev->id = DEVICE_ID_SINGLE; + nor->dev->parent = dev; + ret = register_device(nor->dev); + + if (ret) + return ret; + + mtd->parent = nor->dev; + } else { + nor->dev = dev; + } + + nor->priv = cqspi; + mtd->priv = nor; + + nor->read_reg = cqspi_read_reg; + nor->write_reg = cqspi_write_reg; + nor->read = cqspi_read; + nor->write = cqspi_write; + nor->erase = cqspi_erase; + + ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD); + if (ret) + goto probe_failed; + + ret = add_mtd_device(mtd, NULL, DEVICE_ID_DYNAMIC); + if (ret) + goto probe_failed; + + return 0; + +probe_failed: + dev_err(dev, "probing for flashchip failed\n"); + return ret; + +} + +static void cqspi_controller_init(struct cqspi_st *cqspi) +{ + cqspi_controller_disable(cqspi); + + /* Configure the remap address register, no remap */ + writel(0, cqspi->iobase + CQSPI_REG_REMAP); + + /* Disable all interrupts */ + writel(0, cqspi->iobase + CQSPI_REG_IRQMASK); + + cqspi_controller_enable(cqspi); +} + +static int cqspi_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct cqspi_st *cqspi; + struct cadence_qspi_platform_data *pdata = dev->platform_data; + int ret; + + cqspi = kzalloc(sizeof(*cqspi), GFP_KERNEL); + if (!cqspi) + return -ENOMEM; + + cqspi->dev = dev; + dev->priv = cqspi; + + if (pdata) { + cqspi->ext_decoder = pdata->ext_decoder; + cqspi->fifo_depth = pdata->fifo_depth; + } else { + ret = cqspi_parse_dt(cqspi); + if (ret) { + dev_err(dev, "Get platform data failed.\n"); + return -ENODEV; + } + } + + cqspi->qspi_clk = clk_get(dev, "qspi_clk"); + if (IS_ERR(cqspi->qspi_clk)) { + dev_err(dev, "cannot get qspi clk\n"); + ret = PTR_ERR(cqspi->qspi_clk); + goto probe_failed; + } + cqspi->master_ref_clk_hz = clk_get_rate(cqspi->qspi_clk); + + clk_enable(cqspi->qspi_clk); + + cqspi->iobase = dev_request_mem_region(dev, 0); + if (IS_ERR(cqspi->iobase)) { + dev_err(dev, "dev_request_mem_region 0 failed\n"); + ret = PTR_ERR(cqspi->iobase); + goto probe_failed; + } + + cqspi->ahb_base = dev_request_mem_region(dev, 1); + if (IS_ERR(cqspi->ahb_base)) { + dev_err(dev, "dev_request_mem_region 0 failed\n"); + ret = PTR_ERR(cqspi->ahb_base); + goto probe_failed; + } + + cqspi_wait_idle(cqspi); + cqspi_controller_init(cqspi); + cqspi->current_cs = -1; + cqspi->sclk = 0; + + if (!dev->device_node) { + struct cqspi_flash_pdata *f_pdata; + + f_pdata = &cqspi->f_pdata[0]; + + ret = cqspi_setup_flash(dev, f_pdata, NULL); + if (ret) + goto probe_failed; + } else { + /* Get flash device data */ + for_each_available_child_of_node(dev->device_node, np) { + struct cqspi_flash_pdata *f_pdata; + unsigned int cs; + if (of_property_read_u32(np, "reg", &cs)) { + dev_err(dev, "couldn't determine chip select\n"); + return -ENXIO; + } + if (cs > CQSPI_MAX_CHIPSELECT) { + dev_err(dev, "chip select %d out of range\n", cs); + return -ENXIO; + } + f_pdata = &cqspi->f_pdata[cs]; + + ret = cqspi_setup_flash(dev, f_pdata, np); + if (ret) + goto probe_failed; + } + } + + dev_info(dev, "Cadence QSPI NOR flash driver\n"); + return 0; + +probe_failed: + dev_err(dev, "Cadence QSPI NOR probe failed\n"); + return ret; +} + +static __maybe_unused struct of_device_id cqspi_dt_ids[] = { + {.compatible = "cdns,qspi-nor",}, + { /* end of table */ } +}; + +static struct driver_d cqspi_driver = { + .name = "cadence_qspi", + .probe = cqspi_probe, + .of_compatible = DRV_OF_COMPAT(cqspi_dt_ids), +}; +device_platform_driver(cqspi_driver); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c new file mode 100644 index 0000000000..c85ed34e06 --- /dev/null +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -0,0 +1,1148 @@ +/* + * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with + * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c + * + * Copyright (C) 2005, Intec Automation Inc. + * Copyright (C) 2014, Freescale Semiconductor, Inc. + * + * This code 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. + */ + +#include <clock.h> +#include <common.h> +#include <driver.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/math64.h> +#include <linux/mod_devicetable.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/cfi.h> +#include <linux/mtd/spi-nor.h> +#include <of.h> +#include <spi/flash.h> + +#define SPI_NOR_MAX_ID_LEN 6 + +struct flash_info { + /* + * This array stores the ID bytes. + * The first three bytes are the JEDIC ID. + * JEDEC ID zero means "no ID" (mostly older chips). + */ + u8 id[SPI_NOR_MAX_ID_LEN]; + u8 id_len; + + /* The size listed here is what works with SPINOR_OP_SE, which isn't + * necessarily called a "sector" by the vendor. + */ + unsigned sector_size; + u16 n_sectors; + + u16 page_size; + u16 addr_width; + + u16 flags; +#define SECT_4K 0x01 /* SPINOR_OP_BE_4K works uniformly */ +#define SPI_NOR_NO_ERASE 0x02 /* No erase command needed */ +#define SST_WRITE 0x04 /* use SST byte programming */ +#define SPI_NOR_NO_FR 0x08 /* Can't do fastread */ +#define SECT_4K_PMC 0x10 /* SPINOR_OP_BE_4K_PMC works uniformly */ +#define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */ +#define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */ +#define USE_FSR 0x80 /* use flag status register */ +}; + +#define JEDEC_MFR(info) ((info)->id[0]) + +static const struct spi_device_id *spi_nor_match_id(const char *name); + +/* + * Read the status register, returning its value in the location + * Return the status register value. + * Returns negative if error occurred. + */ +static int read_sr(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1); + if (ret < 0) { + pr_err("error %d reading SR\n", (int) ret); + return ret; + } + + return val; +} + +/* + * Read the flag status register, returning its value in the location + * Return the status register value. + * Returns negative if error occurred. + */ +static int read_fsr(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1); + if (ret < 0) { + pr_err("error %d reading FSR\n", ret); + return ret; + } + + return val; +} + +/* + * Read configuration register, returning its value in the + * location. Return the configuration register value. + * Returns negative if error occured. + */ +static int read_cr(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading CR\n", ret); + return ret; + } + + return val; +} + +/* + * Dummy Cycle calculation for different type of read. + * It can be used to support more commands with + * different dummy cycle requirements. + */ +static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor) +{ + switch (nor->flash_read) { + case SPI_NOR_FAST: + case SPI_NOR_DUAL: + case SPI_NOR_QUAD: + return 8; + case SPI_NOR_NORMAL: + return 0; + } + return 0; +} + +/* + * Write status register 1 byte + * Returns negative if error occurred. + */ +static inline int write_sr(struct spi_nor *nor, u8 val) +{ + nor->cmd_buf[0] = val; + return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0); +} + +/* + * Set write enable latch with Write Enable command. + * Returns negative if error occurred. + */ +static inline int write_enable(struct spi_nor *nor) +{ + return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0); +} + +/* + * Send write disble instruction to the chip. + */ +static inline int write_disable(struct spi_nor *nor) +{ + return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0); +} + +static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) +{ + return mtd->priv; +} + +/* Enable/disable 4-byte addressing mode. */ +static inline int set_4byte(struct spi_nor *nor, struct flash_info *info, + int enable) +{ + int status; + bool need_wren = false; + u8 cmd; + + switch (JEDEC_MFR(info)) { + case CFI_MFR_ST: /* Micron, actually */ + /* Some Micron need WREN command; all will accept it */ + need_wren = true; + case CFI_MFR_MACRONIX: + case 0xEF /* winbond */: + if (need_wren) + write_enable(nor); + + cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; + status = nor->write_reg(nor, cmd, NULL, 0, 0); + if (need_wren) + write_disable(nor); + + return status; + default: + /* Spansion style */ + nor->cmd_buf[0] = enable << 7; + return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0); + } +} +static inline int spi_nor_sr_ready(struct spi_nor *nor) +{ + int sr = read_sr(nor); + if (sr < 0) + return sr; + else + return !(sr & SR_WIP); +} + +static inline int spi_nor_fsr_ready(struct spi_nor *nor) +{ + int fsr = read_fsr(nor); + if (fsr < 0) + return fsr; + else + return fsr & FSR_READY; +} + +static int spi_nor_ready(struct spi_nor *nor) +{ + int sr, fsr; + sr = spi_nor_sr_ready(nor); + if (sr < 0) + return sr; + fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1; + if (fsr < 0) + return fsr; + return sr && fsr; +} + +/* + * Service routine to read status register until ready, or timeout occurs. + * Returns non-zero if error. + */ +static int spi_nor_wait_till_ready(struct spi_nor *nor) +{ + uint64_t start = get_time_ns(); + int timeout = 0; + int ret; + + while (!timeout) { + if (is_timeout(start, 40 * SECOND)) + timeout = 1; + + ret = spi_nor_ready(nor); + if (ret < 0) + return ret; + if (ret) + return 0; + } + + dev_err(nor->dev, "flash operation timed out\n"); + + return -ETIMEDOUT; +} + +/* + * Erase the whole flash memory + * + * Returns 0 if successful, non-zero otherwise. + */ +static int erase_chip(struct spi_nor *nor) +{ + dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10)); + + return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0); +} + +static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + int ret = 0; + + mutex_lock(&nor->lock); + + if (nor->prepare) { + ret = nor->prepare(nor, ops); + if (ret) { + dev_err(nor->dev, "failed in the preparation.\n"); + mutex_unlock(&nor->lock); + return ret; + } + } + return ret; +} + +static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + if (nor->unprepare) + nor->unprepare(nor, ops); + mutex_unlock(&nor->lock); +} + +/* + * Erase an address range on the nor chip. The address range may extend + * one or more erase sectors. Return an error is there is a problem erasing. + */ +static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + u32 addr, len; + uint32_t rem; + int ret; + + dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, + (long long)instr->len); + + div_u64_rem(instr->len, mtd->erasesize, &rem); + if (rem) + return -EINVAL; + + addr = instr->addr; + len = instr->len; + + /* Assure previous operations are completed */ + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto erase_err; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE); + if (ret) + return ret; + + /* whole-chip erase? */ + if (len == mtd->size) { + write_enable(nor); + + if (erase_chip(nor)) { + ret = -EIO; + goto erase_err; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto erase_err; + + /* REVISIT in some cases we could speed up erasing large regions + * by using SPINOR_OP_SE instead of SPINOR_OP_BE_4K. We may have set up + * to use "small sector erase", but that's not always optimal. + */ + + /* "sector"-at-a-time erase */ + } else { + while (len) { + write_enable(nor); + + if (nor->erase(nor, addr)) { + ret = -EIO; + goto erase_err; + } + + addr += mtd->erasesize; + len -= mtd->erasesize; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto erase_err; + } + } + + write_disable(nor); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return ret; + +erase_err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); + instr->state = MTD_ERASE_FAILED; + return ret; +} + +static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + uint32_t offset = ofs; + uint8_t status_old, status_new; + int ret = 0; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); + if (ret) + return ret; + + status_old = read_sr(nor); + + if (offset < mtd->size - (mtd->size / 2)) + status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0; + else if (offset < mtd->size - (mtd->size / 4)) + status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; + else if (offset < mtd->size - (mtd->size / 8)) + status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; + else if (offset < mtd->size - (mtd->size / 16)) + status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2; + else if (offset < mtd->size - (mtd->size / 32)) + status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; + else if (offset < mtd->size - (mtd->size / 64)) + status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1; + else + status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0; + + /* Only modify protection if it will not unlock other areas */ + if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) > + (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { + write_enable(nor); + ret = write_sr(nor, status_new); + if (ret) + goto err; + } + +err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + return ret; +} + +static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + uint32_t offset = ofs; + uint8_t status_old, status_new; + int ret = 0; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); + if (ret) + return ret; + + status_old = read_sr(nor); + + if (offset+len > mtd->size - (mtd->size / 64)) + status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0); + else if (offset+len > mtd->size - (mtd->size / 32)) + status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0; + else if (offset+len > mtd->size - (mtd->size / 16)) + status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1; + else if (offset+len > mtd->size - (mtd->size / 8)) + status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; + else if (offset+len > mtd->size - (mtd->size / 4)) + status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2; + else if (offset+len > mtd->size - (mtd->size / 2)) + status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; + else + status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; + + /* Only modify protection if it will not lock other areas */ + if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) < + (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { + write_enable(nor); + ret = write_sr(nor, status_new); + if (ret) + goto err; + } + +err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); + return ret; +} + +/* Used when the "_ext_id" is two bytes at most */ +#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + ((unsigned long)&(struct flash_info) { \ + .id = { \ + ((_jedec_id) >> 16) & 0xff, \ + ((_jedec_id) >> 8) & 0xff, \ + (_jedec_id) & 0xff, \ + ((_ext_id) >> 8) & 0xff, \ + (_ext_id) & 0xff, \ + }, \ + .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \ + .sector_size = (_sector_size), \ + .n_sectors = (_n_sectors), \ + .page_size = 256, \ + .flags = (_flags), \ + }) + +#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + ((unsigned long)&(struct flash_info) { \ + .id = { \ + ((_jedec_id) >> 16) & 0xff, \ + ((_jedec_id) >> 8) & 0xff, \ + (_jedec_id) & 0xff, \ + ((_ext_id) >> 16) & 0xff, \ + ((_ext_id) >> 8) & 0xff, \ + (_ext_id) & 0xff, \ + }, \ + .id_len = 6, \ + .sector_size = (_sector_size), \ + .n_sectors = (_n_sectors), \ + .page_size = 256, \ + .flags = (_flags), \ + }) + +#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ + ((unsigned long)&(struct flash_info) { \ + .sector_size = (_sector_size), \ + .n_sectors = (_n_sectors), \ + .page_size = (_page_size), \ + .addr_width = (_addr_width), \ + .flags = (_flags), \ + }) + +/* NOTE: double check command sets and memory organization when you add + * more nor chips. This current list focusses on newer chips, which + * have been converging on command sets which including JEDEC ID. + */ +static const struct spi_device_id spi_nor_ids[] = { + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, + { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, + + { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, + { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, + { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, + + { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, + { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, + { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, + { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + + { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, + + /* EON -- en25xxx */ + { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, + { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, + { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, + { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, + + /* ESMT */ + { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, + + /* Everspin */ + { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + + /* Fujitsu */ + { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) }, + + /* GigaDevice */ + { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, + { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, + + /* Intel/Numonyx -- xxxs33b */ + { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, + { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + + /* Macronix */ + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, + { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, + { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, + { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, + { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, + { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, + { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, + { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, + { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, + { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, + { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, + { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, + + /* Micron */ + { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, + { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, + { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, + { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, + { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) }, + { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR | SPI_NOR_QUAD_READ) }, + + /* PMC */ + { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, + { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, + { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, + { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, + { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, + { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, + { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, + { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, + { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, + { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, + { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, + { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, + { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, + { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, + { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, + { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, 0) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, + { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, + { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, + { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, + { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, + { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, + { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + + /* ST Microelectronics -- newer production may have feature updates */ + { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, + { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, + { "m25p20", INFO(0x202012, 0, 64 * 1024, 4, 0) }, + { "m25p40", INFO(0x202013, 0, 64 * 1024, 8, 0) }, + { "m25p80", INFO(0x202014, 0, 64 * 1024, 16, 0) }, + { "m25p16", INFO(0x202015, 0, 64 * 1024, 32, 0) }, + { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, + { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, + { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, + + { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, + { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, + { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, + { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8, 0) }, + { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16, 0) }, + { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32, 0) }, + { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64, 0) }, + { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128, 0) }, + { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64, 0) }, + + { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2, 0) }, + { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, + { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, + + { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, + { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, + { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, + + { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, + { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, + { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, + { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, + { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, + { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, + + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, + { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, + { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, + { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, + { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, + { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, + { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, + { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, + { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, + + /* Catalyst / On Semiconductor -- non-JEDEC */ + { "cat25c11", CAT25_INFO( 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25c03", CAT25_INFO( 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { }, +}; + +static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) +{ + int tmp; + u8 id[SPI_NOR_MAX_ID_LEN]; + struct flash_info *info; + + tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); + if (tmp < 0) { + dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp); + return ERR_PTR(tmp); + } + + for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { + info = (void *)spi_nor_ids[tmp].driver_data; + if (info->id_len) { + if (!memcmp(info->id, id, info->id_len)) + return &spi_nor_ids[tmp]; + } + } + dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %2x, %2x\n", + id[0], id[1], id[2]); + return ERR_PTR(-ENODEV); +} + +static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ); + if (ret) + return ret; + + ret = nor->read(nor, from, len, retlen, buf); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); + return ret; +} + +static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + size_t actual; + int ret; + + dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); + if (ret) + return ret; + + write_enable(nor); + + nor->sst_write_second = false; + + actual = to % 2; + /* Start write from odd address. */ + if (actual) { + nor->program_opcode = SPINOR_OP_BP; + + /* write one byte. */ + nor->write(nor, to, 1, retlen, buf); + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto time_out; + } + to += actual; + + /* Write out most of the data here. */ + for (; actual < len - 1; actual += 2) { + nor->program_opcode = SPINOR_OP_AAI_WP; + + /* write two bytes. */ + nor->write(nor, to, 2, retlen, buf + actual); + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto time_out; + to += 2; + nor->sst_write_second = true; + } + nor->sst_write_second = false; + + write_disable(nor); + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto time_out; + + /* Write out trailing byte if it exists. */ + if (actual != len) { + write_enable(nor); + + nor->program_opcode = SPINOR_OP_BP; + nor->write(nor, to, 1, retlen, buf + actual); + + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto time_out; + write_disable(nor); + } +time_out: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + return ret; +} + +/* + * Write an address range to the nor chip. Data must be written in + * FLASH_PAGESIZE chunks. The address range may be any size provided + * it is within the physical boundaries. + */ +static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + u32 page_offset, page_size, i; + int ret; + + dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); + if (ret) + return ret; + + write_enable(nor); + + page_offset = to & (nor->page_size - 1); + + /* do all the bytes fit onto one page? */ + if (page_offset + len <= nor->page_size) { + nor->write(nor, to, len, retlen, buf); + } else { + /* the size of data remaining on the first page */ + page_size = nor->page_size - page_offset; + nor->write(nor, to, page_size, retlen, buf); + + /* write everything in nor->page_size chunks */ + for (i = page_size; i < len; i += page_size) { + page_size = len - i; + if (page_size > nor->page_size) + page_size = nor->page_size; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto write_err; + + write_enable(nor); + + nor->write(nor, to + i, page_size, retlen, buf + i); + } + } + + ret = spi_nor_wait_till_ready(nor); +write_err: + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + return ret; +} + +static int macronix_quad_enable(struct spi_nor *nor) +{ + int ret, val; + + val = read_sr(nor); + write_enable(nor); + + nor->cmd_buf[0] = val | SR_QUAD_EN_MX; + nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0); + + if (spi_nor_wait_till_ready(nor)) + return 1; + + ret = read_sr(nor); + if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { + dev_err(nor->dev, "Macronix Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +/* + * Write status Register and configuration register with 2 bytes + * The first byte will be written to the status register, while the + * second byte will be written to the configuration register. + * Return negative if error occured. + */ +static int write_sr_cr(struct spi_nor *nor, u16 val) +{ + nor->cmd_buf[0] = val & 0xff; + nor->cmd_buf[1] = (val >> 8); + + return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0); +} + +static int spansion_quad_enable(struct spi_nor *nor) +{ + int ret; + int quad_en = CR_QUAD_EN_SPAN << 8; + + write_enable(nor); + + ret = write_sr_cr(nor, quad_en); + if (ret < 0) { + dev_err(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* read back and check it */ + ret = read_cr(nor); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_err(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) +{ + int status; + + switch (JEDEC_MFR(info)) { + case CFI_MFR_MACRONIX: + status = macronix_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Macronix quad-read not enabled\n"); + return -EINVAL; + } + return status; + default: + status = spansion_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Spansion quad-read not enabled\n"); + return -EINVAL; + } + return status; + } +} + +static int spi_nor_check(struct spi_nor *nor) +{ + if (!nor->dev || !nor->read || !nor->write || + !nor->read_reg || !nor->write_reg || !nor->erase) { + pr_err("spi-nor: please fill all the necessary fields!\n"); + return -EINVAL; + } + + return 0; +} + +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) +{ + const struct spi_device_id *id = NULL; + struct flash_info *info; + struct device_d *dev = nor->dev; + struct mtd_info *mtd = nor->mtd; + struct device_node *np = dev->device_node; + int ret; + int i; + + ret = spi_nor_check(nor); + if (ret) + return ret; + + /* Try to auto-detect if chip name wasn't specified */ + if (!name) + id = spi_nor_read_id(nor); + else + id = spi_nor_match_id(name); + if (IS_ERR_OR_NULL(id)) + return -ENOENT; + + info = (void *)id->driver_data; + + /* + * If caller has specified name of flash model that can normally be + * detected using JEDEC, let's verify it. + */ + if (name && info->id_len) { + const struct spi_device_id *jid; + + jid = spi_nor_read_id(nor); + if (IS_ERR(jid)) { + return PTR_ERR(jid); + } else if (jid != id) { + /* + * JEDEC knows better, so overwrite platform ID. We + * can't trust partitions any longer, but we'll let + * mtd apply them anyway, since some partitions may be + * marked read-only, and we don't want to lose that + * information, even if it's not 100% accurate. + */ + dev_warn(dev, "found %s, expected %s\n", + jid->name, id->name); + id = jid; + info = (void *)jid->driver_data; + } + } + + mutex_init(&nor->lock); + + /* + * Atmel, SST and Intel/Numonyx serial nor tend to power + * up with the software protection bits set + */ + + if (JEDEC_MFR(info) == CFI_MFR_ATMEL || + JEDEC_MFR(info) == CFI_MFR_INTEL || + JEDEC_MFR(info) == CFI_MFR_SST) { + write_enable(nor); + write_sr(nor, 0); + } + + if (!mtd->name) + mtd->name = (char *) dev_name(dev); + mtd->type = MTD_NORFLASH; + mtd->writesize = 1; + mtd->flags = MTD_CAP_NORFLASH; + mtd->size = info->sector_size * info->n_sectors; + mtd->erase = spi_nor_erase; + mtd->read = spi_nor_read; + + /* nor protection support for STmicro chips */ + if (JEDEC_MFR(info) == CFI_MFR_ST) { + mtd->lock = spi_nor_lock; + mtd->unlock = spi_nor_unlock; + } + + /* sst nor chips use AAI word program */ + if (info->flags & SST_WRITE) + mtd->write = sst_write; + else + mtd->write = spi_nor_write; + + if (info->flags & USE_FSR) + nor->flags |= SNOR_F_USE_FSR; + +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + /* prefer "small sector" erase if possible */ + if (info->flags & SECT_4K) { + nor->erase_opcode = SPINOR_OP_BE_4K; + mtd->erasesize = 4096; + } else if (info->flags & SECT_4K_PMC) { + nor->erase_opcode = SPINOR_OP_BE_4K_PMC; + mtd->erasesize = 4096; + } else +#endif + { + nor->erase_opcode = SPINOR_OP_SE; + mtd->erasesize = info->sector_size; + } + + if (info->flags & SPI_NOR_NO_ERASE) + mtd->flags |= MTD_NO_ERASE; + + nor->page_size = info->page_size; + mtd->writebufsize = nor->page_size; + + if (np) { + /* If we were instantiated by DT, use it */ + if (of_property_read_bool(np, "m25p,fast-read")) + nor->flash_read = SPI_NOR_FAST; + else + nor->flash_read = SPI_NOR_NORMAL; + } else { + /* If we weren't instantiated by DT, default to fast-read */ + nor->flash_read = SPI_NOR_FAST; + } + + /* Some devices cannot do fast-read, no matter what DT tells us */ + if (info->flags & SPI_NOR_NO_FR) + nor->flash_read = SPI_NOR_NORMAL; + + /* Quad/Dual-read mode takes precedence over fast/normal */ + if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { + ret = set_quad_mode(nor, info); + if (ret) { + dev_err(dev, "quad mode not supported\n"); + return ret; + } + nor->flash_read = SPI_NOR_QUAD; + } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) { + nor->flash_read = SPI_NOR_DUAL; + } + + /* Default commands */ + switch (nor->flash_read) { + case SPI_NOR_QUAD: + nor->read_opcode = SPINOR_OP_READ_1_1_4; + break; + case SPI_NOR_DUAL: + nor->read_opcode = SPINOR_OP_READ_1_1_2; + break; + case SPI_NOR_FAST: + nor->read_opcode = SPINOR_OP_READ_FAST; + break; + case SPI_NOR_NORMAL: + nor->read_opcode = SPINOR_OP_READ; + break; + default: + dev_err(dev, "No Read opcode defined\n"); + return -EINVAL; + } + + nor->program_opcode = SPINOR_OP_PP; + + if (info->addr_width) + nor->addr_width = info->addr_width; + else if (mtd->size > 0x1000000) { + /* enable 4-byte addressing if the device exceeds 16MiB */ + nor->addr_width = 4; + if (JEDEC_MFR(info) == CFI_MFR_AMD) { + /* Dedicated 4-byte command set */ + switch (nor->flash_read) { + case SPI_NOR_QUAD: + nor->read_opcode = SPINOR_OP_READ4_1_1_4; + break; + case SPI_NOR_DUAL: + nor->read_opcode = SPINOR_OP_READ4_1_1_2; + break; + case SPI_NOR_FAST: + nor->read_opcode = SPINOR_OP_READ4_FAST; + break; + case SPI_NOR_NORMAL: + nor->read_opcode = SPINOR_OP_READ4; + break; + } + nor->program_opcode = SPINOR_OP_PP_4B; + /* No small sector erase for 4-byte command set */ + nor->erase_opcode = SPINOR_OP_SE_4B; + mtd->erasesize = info->sector_size; + } else + set_4byte(nor, info, 1); + } else { + nor->addr_width = 3; + } + + nor->read_dummy = spi_nor_read_dummy_cycles(nor); + + dev_info(dev, "%s (%lld Kbytes)\n", id->name, + (long long)mtd->size >> 10); + + dev_dbg(dev, + "mtd .name = %s, .size = 0x%llx (%lldMiB), " + ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", + mtd->name, (long long)mtd->size, (long long)(mtd->size >> 20), + mtd->erasesize, mtd->erasesize / 1024, mtd->numeraseregions); + + if (mtd->numeraseregions) + for (i = 0; i < mtd->numeraseregions; i++) + dev_dbg(dev, + "mtd.eraseregions[%d] = { .offset = 0x%llx, " + ".erasesize = 0x%.8x (%uKiB), " + ".numblocks = %d }\n", + i, (long long)mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].erasesize / 1024, + mtd->eraseregions[i].numblocks); + return 0; +} +EXPORT_SYMBOL_GPL(spi_nor_scan); + +static const struct spi_device_id *spi_nor_match_id(const char *name) +{ + const struct spi_device_id *id = spi_nor_ids; + + while (id->name[0]) { + if (!strcmp(name, id->name)) + return id; + id++; + } + return NULL; +} 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 abcb7ee65f..1f1938d977 100644 --- a/drivers/net/dm9k.c +++ b/drivers/net/dm9k.c @@ -48,6 +48,7 @@ # define NCR_FCOL (1 << 4) # define NCR_FDX (1 << 3) # define NCR_LBK (3 << 1) +# define NCR_MAC_LBK (1 << 1) # define NCR_RST (1 << 0) #define DM9K_NSR 0x01 @@ -359,6 +360,11 @@ static int dm9k_phy_read(struct mii_bus *bus, int addr, int reg) struct dm9k *priv = bus->priv; struct device_d *dev = &bus->dev; + /* only internal phy supported by now, so show only one phy on miibus */ + if (addr != 0) { + return 0xffff; + } + /* Fill the phyxcer register into REG_0C */ dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg); dm9k_iow(priv, DM9K_EPCR, 0xc); /* Issue phyxcer read command */ @@ -378,6 +384,11 @@ static int dm9k_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) struct dm9k *priv = bus->priv; struct device_d *dev = &bus->dev; + /* only internal phy supported by now, so show only one phy on miibus */ + if (addr != 0) { + return 0; + } + /* Fill the phyxcer register into REG_0C */ dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg); @@ -462,8 +473,28 @@ static void dm9k_reset(struct dm9k *priv) struct device_d *dev = priv->miibus.parent; dev_dbg(dev, "%s\n", __func__); - dm9k_iow(priv, DM9K_NCR, NCR_RST); - udelay(1000); /* delay 1ms */ + + /* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 + * The essential point is that we have to do a double reset, and the + * instruction is to set LBK into MAC internal loopback mode. + */ + + /* Make all GPIO pins outputs */ + dm9k_iow(priv, DM9K_GPCR, 0x0F); + /* Power internal PHY by writing 0 to GPIO0 pin */ + dm9k_iow(priv, DM9K_GPR, 0); + + dm9k_iow(priv, DM9K_NCR, NCR_RST | NCR_MAC_LBK); + udelay(100); /* Application note says at least 20 us */ + if (dm9k_ior(priv, DM9K_NCR) & NCR_RST) + dev_err(dev, "dm9000 did not respond to first reset\n"); + + dm9k_iow(priv, DM9K_NCR, 0); + dm9k_iow(priv, DM9K_NCR, NCR_RST | NCR_MAC_LBK); + udelay(100); + + if (dm9k_ior(priv, DM9K_NCR) & NCR_RST) + dev_err(dev, "dm9000 did not respond to second reset\n"); } static int dm9k_eth_open(struct eth_device *edev) @@ -680,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; @@ -698,17 +729,66 @@ static int dm9k_init_dev(struct eth_device *edev) return 0; } +static int dm9000_setup_buswidth(struct device_d *dev, struct dm9k *priv, uint32_t width) +{ + switch (width) { + case 1: + priv->buswidth = IORESOURCE_MEM_8BIT; + break; + case 2: + priv->buswidth = IORESOURCE_MEM_16BIT; + break; + case 4: + priv->buswidth = IORESOURCE_MEM_32BIT; + break; + default: + dev_err(dev, "Wrong io resource size\n"); + return -EINVAL; + } + + return 0; +} + +static int dm9000_parse_dt(struct device_d *dev, struct dm9k *priv) +{ + struct device_node *np = dev->device_node; + uint32_t prop; + + if (!IS_ENABLED(CONFIG_OFDEVICE) || !np) + return -ENODEV; + + if (of_find_property(np, "davicom,no-eeprom", NULL)) { + priv->srom = 0; + } else { + priv->srom = 1; + } + + if (of_property_read_u32(np, "reg-io-width", &prop)) { + /* Use 8-bit registers by default */ + prop = 1; + } + + return dm9000_setup_buswidth(dev, priv, prop); +} + +static int dm9000_parse_pdata(struct device_d *dev, struct dm9k *priv) +{ + struct dm9000_platform_data *pdata = dev->platform_data; + uint32_t width; + + priv->srom = pdata->srom; + + width = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; + + return dm9000_setup_buswidth(dev, priv, width); +} + static int dm9k_probe(struct device_d *dev) { unsigned io_mode; struct eth_device *edev; struct dm9k *priv; - struct dm9000_platform_data *pdata; - - if (!dev->platform_data) { - dev_err(dev, "No platform_data\n"); - return -ENODEV; - } + int ret; if (dev->num_resources < 2) { dev_err(dev, "Need 2 resources base and data"); @@ -717,19 +797,28 @@ static int dm9k_probe(struct device_d *dev) edev = xzalloc(sizeof(struct eth_device) + sizeof(struct dm9k)); edev->priv = (struct dm9k *)(edev + 1); + priv = edev->priv; - pdata = dev->platform_data; + if (dev->platform_data) { + ret = dm9000_parse_pdata(dev, priv); + } else { + ret = dm9000_parse_dt(dev, priv); + } - priv = edev->priv; + if (ret) + goto err; - priv->buswidth = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; priv->iodata = dev_request_mem_region(dev, 1); - if (!priv->iodata) - return -EBUSY; + if (!priv->iodata) { + ret = -EBUSY; + goto err; + } + priv->iobase = dev_request_mem_region(dev, 0); - if (!priv->iobase) - return -EBUSY; - priv->srom = pdata->srom; + if (!priv->iobase) { + ret = -EBUSY; + goto err; + } edev->init = dm9k_init_dev; edev->open = dm9k_eth_open; @@ -747,8 +836,10 @@ static int dm9k_probe(struct device_d *dev) /* RESET device */ dm9k_reset(priv); - if(dm9k_check_id(priv)) - return -ENODEV; + if (dm9k_check_id(priv)) { + ret = -ENODEV; + goto err; + } io_mode = dm9k_ior(priv, DM9K_ISR) >> 6; switch (io_mode) { @@ -780,10 +871,21 @@ static int dm9k_probe(struct device_d *dev) eth_register(edev); return 0; + +err: + free(edev); + + return ret; } +static struct of_device_id dm9000_of_matches[] = { + { .compatible = "davicom,dm9000", }, + { /* sentinel */ } +}; + static struct driver_d dm9k_driver = { .name = "dm9000", .probe = dm9k_probe, + .of_compatible = DRV_OF_COMPAT(dm9000_of_matches), }; device_platform_driver(dm9k_driver); 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/fdt.c b/drivers/of/fdt.c index dfa95c38c8..88f0523260 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -48,7 +48,6 @@ static inline char *dt_string(struct fdt_header *f, char *strstart, uint32_t ofs /** * of_unflatten_dtb - unflatten a dtb binary blob - * @root - node in which the fdt blob should be merged into or NULL * @infdt - the fdt blob to unflatten * * Parse a flat device tree binary blob and return a pointer to the diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 3a0e7a5f4e..191561da03 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -129,10 +129,24 @@ static struct pci_dev *alloc_pci_dev(void) return dev; } +static u32 pci_size(u32 base, u32 maxbase, u32 mask) +{ + u32 size = maxbase & mask; + if (!size) + return 0; + + size = (size & ~(size-1)) - 1; + + if (base == maxbase && ((base | size) & mask) != mask) + return 0; + + return size + 1; +} + + static void setup_device(struct pci_dev *dev, int max_bar) { - int bar, size; - u32 mask; + int bar; u8 cmd; pci_read_config_byte(dev, PCI_COMMAND, &cmd); @@ -141,9 +155,12 @@ static void setup_device(struct pci_dev *dev, int max_bar) for (bar = 0; bar < max_bar; bar++) { resource_size_t last_addr; + u32 orig, mask, size; + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &orig); pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, 0xfffffffe); pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &mask); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, orig); if (mask == 0 || mask == 0xffffffff) { pr_debug("pbar%d set bad mask\n", bar); @@ -151,7 +168,11 @@ static void setup_device(struct pci_dev *dev, int max_bar) } if (mask & 0x01) { /* IO */ - size = ((~(mask & 0xfffffffe)) & 0xffff) + 1; + size = pci_size(orig, mask, 0xfffffffe); + if (!size) { + pr_debug("pbar%d bad IO mask\n", bar); + continue; + } pr_debug("pbar%d: mask=%08x io %d bytes\n", bar, mask, size); if (last_io + size > dev->bus->resource[PCI_BUS_RESOURCE_IO]->end) { @@ -164,7 +185,11 @@ static void setup_device(struct pci_dev *dev, int max_bar) last_io += size; } else if ((mask & PCI_BASE_ADDRESS_MEM_PREFETCH) && last_mem_pref) /* prefetchable MEM */ { - size = (~(mask & 0xfffffff0)) + 1; + size = pci_size(orig, mask, 0xfffffff0); + if (!size) { + pr_debug("pbar%d bad P-MEM mask\n", bar); + continue; + } pr_debug("pbar%d: mask=%08x P memory %d bytes\n", bar, mask, size); if (last_mem_pref + size > @@ -178,7 +203,11 @@ static void setup_device(struct pci_dev *dev, int max_bar) last_addr = last_mem_pref; last_mem_pref += size; } else { /* non-prefetch MEM */ - size = (~(mask & 0xfffffff0)) + 1; + size = pci_size(orig, mask, 0xfffffff0); + if (!size) { + pr_debug("pbar%d bad NP-MEM mask\n", bar); + continue; + } pr_debug("pbar%d: mask=%08x NP memory %d bytes\n", bar, mask, size); if (last_mem + size > @@ -391,11 +420,6 @@ unsigned int pci_scan_bus(struct pci_bus *bus) bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type); continue; } - - if (class == PCI_CLASS_BRIDGE_HOST) { - pr_debug("skip pci host bridge\n"); - continue; - } } /* diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c index 51184aaae5..59bb5b2ecf 100644 --- a/drivers/serial/serial_ar933x.c +++ b/drivers/serial/serial_ar933x.c @@ -40,7 +40,7 @@ static inline void ar933x_serial_writel(struct console_device *cdev, { struct ar933x_uart_priv *priv = cdev->dev->priv; - cpu_writel(b, priv->base + offset); + __raw_writel(b, priv->base + offset); } static inline u32 ar933x_serial_readl(struct console_device *cdev, @@ -48,7 +48,7 @@ static inline u32 ar933x_serial_readl(struct console_device *cdev, { struct ar933x_uart_priv *priv = cdev->dev->priv; - return cpu_readl(priv->base + offset); + return __raw_readl(priv->base + offset); } /* diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c index f075c50fc2..68b438b0bb 100644 --- a/drivers/serial/serial_imx.c +++ b/drivers/serial/serial_imx.c @@ -23,113 +23,7 @@ #include <of.h> #include <linux/err.h> #include <linux/clk.h> - -#define URXD0 0x0 /* Receiver Register */ -#define URTX0 0x40 /* Transmitter Register */ -#define UCR1 0x80 /* Control Register 1 */ -#define UCR2 0x84 /* Control Register 2 */ -#define UCR3 0x88 /* Control Register 3 */ -#define UCR4 0x8c /* Control Register 4 */ -#define UFCR 0x90 /* FIFO Control Register */ -#define USR1 0x94 /* Status Register 1 */ -#define USR2 0x98 /* Status Register 2 */ -#define UESC 0x9c /* Escape Character Register */ -#define UTIM 0xa0 /* Escape Timer Register */ -#define UBIR 0xa4 /* BRM Incremental Register */ -#define UBMR 0xa8 /* BRM Modulator Register */ -#define UBRC 0xac /* Baud Rate Count Register */ - -/* UART Control Register Bit Fields.*/ -#define URXD_CHARRDY (1<<15) -#define URXD_ERR (1<<14) -#define URXD_OVRRUN (1<<13) -#define URXD_FRMERR (1<<12) -#define URXD_BRK (1<<11) -#define URXD_PRERR (1<<10) -#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ -#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ -#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ -#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ -#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ -#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ -#define UCR1_IREN (1<<7) /* Infrared interface enable */ -#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ -#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ -#define UCR1_SNDBRK (1<<4) /* Send break */ -#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ -#define UCR1_DOZE (1<<1) /* Doze */ -#define UCR1_UARTEN (1<<0) /* UART enabled */ -#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ -#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ -#define UCR2_CTSC (1<<13) /* CTS pin control */ -#define UCR2_CTS (1<<12) /* Clear to send */ -#define UCR2_ESCEN (1<<11) /* Escape enable */ -#define UCR2_PREN (1<<8) /* Parity enable */ -#define UCR2_PROE (1<<7) /* Parity odd/even */ -#define UCR2_STPB (1<<6) /* Stop */ -#define UCR2_WS (1<<5) /* Word size */ -#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ -#define UCR2_TXEN (1<<2) /* Transmitter enabled */ -#define UCR2_RXEN (1<<1) /* Receiver enabled */ -#define UCR2_SRST (1<<0) /* SW reset */ -#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ -#define UCR3_PARERREN (1<<12) /* Parity enable */ -#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ -#define UCR3_DSR (1<<10) /* Data set ready */ -#define UCR3_DCD (1<<9) /* Data carrier detect */ -#define UCR3_RI (1<<8) /* Ring indicator */ -#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */ -#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ -#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ -#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz (i.MXL / i.MX1) */ -#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz (i.MXL / i.MX1) */ -#define UCR3_RXDMUXSEL (1<<2) /* RXD Muxed input select (i.MX27) */ -#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ -#define UCR3_BPEN (1<<0) /* Preset registers enable */ -#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */ -#define UCR4_INVR (1<<9) /* Inverted infrared reception */ -#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ -#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ -#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ -#define UCR4_IRSC (1<<5) /* IR special case */ -#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ -#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ -#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ -#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ -#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ -#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ -#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ -#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ -#define USR1_RTSS (1<<14) /* RTS pin status */ -#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ -#define USR1_RTSD (1<<12) /* RTS delta */ -#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ -#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ -#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ -#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ -#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ -#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ -#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ -#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ -#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ -#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ -#define USR2_IDLE (1<<12) /* Idle condition */ -#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ -#define USR2_WAKE (1<<7) /* Wake */ -#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ -#define USR2_TXDC (1<<3) /* Transmitter complete */ -#define USR2_BRCD (1<<2) /* Break condition */ -#define USR2_ORE (1<<1) /* Overrun error */ -#define USR2_RDR (1<<0) /* Recv data ready */ -#define UTS_FRCPERR (1<<13) /* Force parity error */ -#define UTS_LOOP (1<<12) /* Loop tx and rx */ -#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ -#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ -#define UTS_TXFULL (1<<4) /* TxFIFO full */ -#define UTS_RXFULL (1<<3) /* RxFIFO full */ -#define UTS_SOFTRST (1<<0) /* Software reset */ +#include <serial/imx-uart.h> /* * create default values for different platforms @@ -219,10 +113,10 @@ static int imx_serial_init_port(struct console_device *cdev) writel(val, regs + USR2); /* Clear status flags */ - val = readl(regs + USR2); + val = readl(regs + USR1); val |= USR1_PARITYERR | USR1_RTSD | USR1_ESCF | USR1_FRAMERR | USR1_AIRINT | USR1_AWAKE; - writel(val, regs + USR2); + writel(val, regs + USR1); return 0; } @@ -284,9 +178,9 @@ static int imx_serial_setbaudrate(struct console_device *cdev, int baudrate) writel(val, regs + UCR1); /* Set the numerator value minus one of the BRM ratio */ - writel((baudrate / 100) - 1, regs + UBIR); + writel(baudrate_to_ubir(baudrate), regs + UBIR); /* Set the denominator value minus one of the BRM ratio */ - writel((imx_serial_reffreq(priv) / 1600) - 1, regs + UBMR); + writel(refclock_to_ubmr(imx_serial_reffreq(priv)), regs + UBMR); writel(ucr1, regs + UCR1); 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/spi/ath79_spi.c b/drivers/spi/ath79_spi.c index 4d71eba695..bdb39ef0cb 100644 --- a/drivers/spi/ath79_spi.c +++ b/drivers/spi/ath79_spi.c @@ -48,12 +48,12 @@ struct ath79_spi { static inline u32 ath79_spi_rr(struct ath79_spi *sp, int reg) { - return cpu_readl(sp->regs + reg); + return __raw_readl(sp->regs + reg); } static inline void ath79_spi_wr(struct ath79_spi *sp, u32 val, int reg) { - cpu_writel(val, sp->regs + reg); + __raw_writel(val, sp->regs + reg); } static inline void setbits(struct ath79_spi *sp, int bits, int on) 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/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 1e5e8093c0..2b0faf3303 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -536,7 +536,8 @@ int gserial_connect(struct gserial *gser, u8 port_num) if (status) goto fail_out; - dev_set_param(&cdev->class_dev, "active", "ioe"); + console_set_active(cdev, CONSOLE_STDIN | CONSOLE_STDOUT | + CONSOLE_STDERR); /* REVISIT if waiting on "carrier detect", signal. */ diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ccb702980f..84a05c4f96 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -119,8 +119,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" MUSB_DRIVER_NAME); -#define MUSB_HOST_TIMEOUT 0x5fffff - /*-------------------------------------------------------------------------*/ #ifndef CONFIG_BLACKFIN @@ -1025,17 +1023,18 @@ int musb_init(struct usb_host *host) { struct musb *musb = to_musb(host); void *mbase; - int timeout = MUSB_HOST_TIMEOUT; + u64 start; u8 power; musb_start(musb); mbase = musb->mregs; - do { + start = get_time_ns(); + while (1) { if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM) break; - } while (--timeout); - if (!timeout) - return -ENODEV; + if (is_timeout(start, 4 * SECOND)) + return -ENODEV; + } power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); diff --git a/dts/Bindings/arm/omap/l3-noc.txt b/dts/Bindings/arm/omap/l3-noc.txt index 974624ea68..161448da95 100644 --- a/dts/Bindings/arm/omap/l3-noc.txt +++ b/dts/Bindings/arm/omap/l3-noc.txt @@ -6,6 +6,7 @@ provided by Arteris. Required properties: - compatible : Should be "ti,omap3-l3-smx" for OMAP3 family Should be "ti,omap4-l3-noc" for OMAP4 family + Should be "ti,omap5-l3-noc" for OMAP5 family Should be "ti,dra7-l3-noc" for DRA7 family Should be "ti,am4372-l3-noc" for AM43 family - reg: Contains L3 register address range for each noc domain. 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/dma/fsl-mxs-dma.txt b/dts/Bindings/dma/fsl-mxs-dma.txt index a4873e5e3e..e30e184f50 100644 --- a/dts/Bindings/dma/fsl-mxs-dma.txt +++ b/dts/Bindings/dma/fsl-mxs-dma.txt @@ -38,7 +38,7 @@ dma_apbx: dma-apbx@80024000 { 80 81 68 69 70 71 72 73 74 75 76 77>; - interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", + interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty", "saif0", "saif1", "i2c0", "i2c1", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; 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/rtc/abracon,abx80x.txt b/dts/Bindings/rtc/abracon,abx80x.txt new file mode 100644 index 0000000000..be789685a1 --- /dev/null +++ b/dts/Bindings/rtc/abracon,abx80x.txt @@ -0,0 +1,30 @@ +Abracon ABX80X I2C ultra low power RTC/Alarm chip + +The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801, +ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805 +is the superset of ab180x. + +Required properties: + + - "compatible": should one of: + "abracon,abx80x" + "abracon,ab0801" + "abracon,ab0803" + "abracon,ab0804" + "abracon,ab0805" + "abracon,ab1801" + "abracon,ab1803" + "abracon,ab1804" + "abracon,ab1805" + Using "abracon,abx80x" will enable chip autodetection. + - "reg": I2C bus address of the device + +Optional properties: + +The abx804 and abx805 have a trickle charger that is able to charge the +connected battery or supercap. Both the following properties have to be defined +and valid to enable charging: + + - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V) + - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output + resistor, the other values are in ohm. 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/am437x-sk-evm.dts b/dts/src/arm/am437x-sk-evm.dts index 8ae29c955c..c17097d2c1 100644 --- a/dts/src/arm/am437x-sk-evm.dts +++ b/dts/src/arm/am437x-sk-evm.dts @@ -49,7 +49,7 @@ pinctrl-0 = <&matrix_keypad_pins>; debounce-delay-ms = <5>; - col-scan-delay-us = <1500>; + col-scan-delay-us = <5>; row-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH /* Bank5, pin5 */ &gpio5 6 GPIO_ACTIVE_HIGH>; /* Bank5, pin6 */ @@ -473,7 +473,7 @@ interrupt-parent = <&gpio0>; interrupts = <31 0>; - wake-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>; touchscreen-size-x = <480>; touchscreen-size-y = <272>; diff --git a/dts/src/arm/am57xx-beagle-x15.dts b/dts/src/arm/am57xx-beagle-x15.dts index 15f198e486..7128fad991 100644 --- a/dts/src/arm/am57xx-beagle-x15.dts +++ b/dts/src/arm/am57xx-beagle-x15.dts @@ -18,6 +18,7 @@ aliases { rtc0 = &mcp_rtc; rtc1 = &tps659038_rtc; + rtc2 = &rtc; }; memory { @@ -83,7 +84,7 @@ gpio_fan: gpio_fan { /* Based on 5v 500mA AFB02505HHB */ compatible = "gpio-fan"; - gpios = <&tps659038_gpio 1 GPIO_ACTIVE_HIGH>; + gpios = <&tps659038_gpio 2 GPIO_ACTIVE_HIGH>; gpio-fan,speed-map = <0 0>, <13000 1>; #cooling-cells = <2>; @@ -130,8 +131,8 @@ uart3_pins_default: uart3_pins_default { pinctrl-single,pins = < - 0x248 (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd.rxd */ - 0x24c (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd.txd */ + 0x3f8 (PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */ + 0x3fc (PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */ >; }; @@ -455,7 +456,7 @@ mcp_rtc: rtc@6f { compatible = "microchip,mcp7941x"; reg = <0x6f>; - interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */ + interrupts = <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>; /* IRQ_SYS_1N */ pinctrl-names = "default"; pinctrl-0 = <&mcp79410_pins_default>; @@ -478,7 +479,7 @@ &uart3 { status = "okay"; interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>, - <&dra7_pmx_core 0x248>; + <&dra7_pmx_core 0x3f8>; pinctrl-names = "default"; pinctrl-0 = <&uart3_pins_default>; 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/armada-xp-openblocks-ax3-4.dts b/dts/src/arm/armada-xp-openblocks-ax3-4.dts index e3b08fb959..990e8a2100 100644 --- a/dts/src/arm/armada-xp-openblocks-ax3-4.dts +++ b/dts/src/arm/armada-xp-openblocks-ax3-4.dts @@ -105,6 +105,10 @@ }; internal-regs { + rtc@10300 { + /* No crystal connected to the internal RTC */ + status = "disabled"; + }; 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/dra7.dtsi b/dts/src/arm/dra7.dtsi index 5332b57b49..f03a091cd0 100644 --- a/dts/src/arm/dra7.dtsi +++ b/dts/src/arm/dra7.dtsi @@ -911,7 +911,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07ddc 0x4>, <0x4ae07de0 0x4>, - <0x4ae06014 0x4>, <0x4a003b20 0x8>, + <0x4ae06014 0x4>, <0x4a003b20 0xc>, <0x4ae0c158 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -944,7 +944,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07e34 0x4>, <0x4ae07e24 0x4>, - <0x4ae06010 0x4>, <0x4a0025cc 0x8>, + <0x4ae06010 0x4>, <0x4a0025cc 0xc>, <0x4a002470 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -977,7 +977,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07e30 0x4>, <0x4ae07e20 0x4>, - <0x4ae06010 0x4>, <0x4a0025e0 0x8>, + <0x4ae06010 0x4>, <0x4a0025e0 0xc>, <0x4a00246c 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -1010,7 +1010,7 @@ ti,clock-cycles = <16>; reg = <0x4ae07de4 0x4>, <0x4ae07de8 0x4>, - <0x4ae06010 0x4>, <0x4a003b08 0x8>, + <0x4ae06010 0x4>, <0x4a003b08 0xc>, <0x4ae0c154 0x4>; reg-names = "setup-address", "control-address", "int-address", "efuse-address", @@ -1203,7 +1203,7 @@ status = "disabled"; }; - rtc@48838000 { + rtc: rtc@48838000 { compatible = "ti,am3352-rtc"; reg = <0x48838000 0x100>; interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, diff --git a/dts/src/arm/exynos4412-odroid-common.dtsi b/dts/src/arm/exynos4412-odroid-common.dtsi index 8de12af7c2..d6b49e5b32 100644 --- a/dts/src/arm/exynos4412-odroid-common.dtsi +++ b/dts/src/arm/exynos4412-odroid-common.dtsi @@ -9,6 +9,7 @@ #include <dt-bindings/sound/samsung-i2s.h> #include <dt-bindings/input/input.h> +#include <dt-bindings/clock/maxim,max77686.h> #include "exynos4412.dtsi" / { @@ -105,6 +106,8 @@ rtc@10070000 { status = "okay"; + clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>; + clock-names = "rtc", "rtc_src"; }; g2d@10800000 { 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/exynos5250-snow.dts b/dts/src/arm/exynos5250-snow.dts index 2657e842e5..1eca97ee4b 100644 --- a/dts/src/arm/exynos5250-snow.dts +++ b/dts/src/arm/exynos5250-snow.dts @@ -567,6 +567,7 @@ num-slots = <1>; broken-cd; cap-sdio-irq; + keep-power-in-suspend; card-detect-delay = <200>; samsung,dw-mshc-ciu-div = <3>; samsung,dw-mshc-sdr-timing = <2 3>; 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/exynos5420-trip-points.dtsi b/dts/src/arm/exynos5420-trip-points.dtsi index 5d31fc1408..2180a0152c 100644 --- a/dts/src/arm/exynos5420-trip-points.dtsi +++ b/dts/src/arm/exynos5420-trip-points.dtsi @@ -28,7 +28,7 @@ trips { type = "active"; }; cpu-crit-0 { - temperature = <1200000>; /* millicelsius */ + temperature = <120000>; /* millicelsius */ hysteresis = <0>; /* millicelsius */ type = "critical"; }; diff --git a/dts/src/arm/exynos5420.dtsi b/dts/src/arm/exynos5420.dtsi index f67b23f303..45317538bb 100644 --- a/dts/src/arm/exynos5420.dtsi +++ b/dts/src/arm/exynos5420.dtsi @@ -536,6 +536,7 @@ clock-names = "dp"; phys = <&dp_phy>; phy-names = "dp"; + power-domains = <&disp_pd>; }; mipi_phy: video-phy@10040714 { diff --git a/dts/src/arm/exynos5440-trip-points.dtsi b/dts/src/arm/exynos5440-trip-points.dtsi index 48adfa8f43..356e963edf 100644 --- a/dts/src/arm/exynos5440-trip-points.dtsi +++ b/dts/src/arm/exynos5440-trip-points.dtsi @@ -18,7 +18,7 @@ trips { type = "active"; }; cpu-crit-0 { - temperature = <1050000>; /* millicelsius */ + temperature = <105000>; /* millicelsius */ hysteresis = <0>; /* millicelsius */ type = "critical"; }; 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/imx23-olinuxino.dts b/dts/src/arm/imx23-olinuxino.dts index 7e6eef2488..82045398bf 100644 --- a/dts/src/arm/imx23-olinuxino.dts +++ b/dts/src/arm/imx23-olinuxino.dts @@ -12,6 +12,7 @@ */ /dts-v1/; +#include <dt-bindings/gpio/gpio.h> #include "imx23.dtsi" / { @@ -93,6 +94,7 @@ ahb@80080000 { usb0: usb@80080000 { + dr_mode = "host"; vbus-supply = <®_usb0_vbus>; status = "okay"; }; @@ -122,7 +124,7 @@ user { label = "green"; - gpios = <&gpio2 1 1>; + gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; }; }; }; diff --git a/dts/src/arm/imx25.dtsi b/dts/src/arm/imx25.dtsi index e4d3aecc4e..677f81d9dc 100644 --- a/dts/src/arm/imx25.dtsi +++ b/dts/src/arm/imx25.dtsi @@ -428,6 +428,7 @@ pwm4: pwm@53fc8000 { compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; + #pwm-cells = <2>; reg = <0x53fc8000 0x4000>; clocks = <&clks 108>, <&clks 52>; clock-names = "ipg", "per"; 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/imx28.dtsi b/dts/src/arm/imx28.dtsi index 25e25f82fb..4e073e8547 100644 --- a/dts/src/arm/imx28.dtsi +++ b/dts/src/arm/imx28.dtsi @@ -913,7 +913,7 @@ 80 81 68 69 70 71 72 73 74 75 76 77>; - interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", + interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty", "saif0", "saif1", "i2c0", "i2c1", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; diff --git a/dts/src/arm/imx6qdl-phytec-pfla02.dtsi b/dts/src/arm/imx6qdl-phytec-pfla02.dtsi index 19cc269a08..1ce6133b67 100644 --- a/dts/src/arm/imx6qdl-phytec-pfla02.dtsi +++ b/dts/src/arm/imx6qdl-phytec-pfla02.dtsi @@ -31,6 +31,7 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio4 15 0>; + enable-active-high; }; reg_usb_h1_vbus: regulator@1 { @@ -40,6 +41,7 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&gpio1 0 0>; + enable-active-high; }; }; diff --git a/dts/src/arm/imx6qdl-sabreauto.dtsi b/dts/src/arm/imx6qdl-sabreauto.dtsi index 46b2fed7c3..3b24b12651 100644 --- a/dts/src/arm/imx6qdl-sabreauto.dtsi +++ b/dts/src/arm/imx6qdl-sabreauto.dtsi @@ -185,7 +185,6 @@ &i2c3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; - pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>; status = "okay"; max7310_a: gpio@30 { 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 a29315833e..5f5e0f3d5b 100644 --- a/dts/src/arm/omap3-n900.dts +++ b/dts/src/arm/omap3-n900.dts @@ -498,6 +498,8 @@ DRVDD-supply = <&vmmc2>; IOVDD-supply = <&vio>; DVDD-supply = <&vio>; + + ai3x-micbias-vg = <1>; }; tlv320aic3x_aux: tlv320aic3x@19 { @@ -509,6 +511,8 @@ DRVDD-supply = <&vmmc2>; IOVDD-supply = <&vio>; DVDD-supply = <&vio>; + + ai3x-micbias-vg = <2>; }; tsl2563: tsl2563@29 { @@ -828,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/omap3.dtsi b/dts/src/arm/omap3.dtsi index d18a90f5ec..69a40cfc1f 100644 --- a/dts/src/arm/omap3.dtsi +++ b/dts/src/arm/omap3.dtsi @@ -456,6 +456,7 @@ }; mmu_isp: mmu@480bd400 { + #iommu-cells = <0>; compatible = "ti,omap2-iommu"; reg = <0x480bd400 0x80>; interrupts = <24>; @@ -464,6 +465,7 @@ }; mmu_iva: mmu@5d000000 { + #iommu-cells = <0>; compatible = "ti,omap2-iommu"; reg = <0x5d000000 0x80>; interrupts = <28>; diff --git a/dts/src/arm/omap5.dtsi b/dts/src/arm/omap5.dtsi index efe5f737f3..7d24ae0306 100644 --- a/dts/src/arm/omap5.dtsi +++ b/dts/src/arm/omap5.dtsi @@ -128,7 +128,7 @@ * hierarchy. */ ocp { - compatible = "ti,omap4-l3-noc", "simple-bus"; + compatible = "ti,omap5-l3-noc", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges; diff --git a/dts/src/arm/r8a7791-koelsch.dts b/dts/src/arm/r8a7791-koelsch.dts index 74c3212f1f..824ddab9c3 100644 --- a/dts/src/arm/r8a7791-koelsch.dts +++ b/dts/src/arm/r8a7791-koelsch.dts @@ -545,7 +545,7 @@ compatible = "adi,adv7511w"; reg = <0x39>; interrupt-parent = <&gpio3>; - interrupts = <29 IRQ_TYPE_EDGE_FALLING>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; adi,input-depth = <8>; adi,input-colorspace = "rgb"; diff --git a/dts/src/arm/ste-dbx5x0.dtsi b/dts/src/arm/ste-dbx5x0.dtsi index bfd3f1c734..2201cd5da3 100644 --- a/dts/src/arm/ste-dbx5x0.dtsi +++ b/dts/src/arm/ste-dbx5x0.dtsi @@ -1017,23 +1017,6 @@ status = "disabled"; }; - vmmci: regulator-gpio { - compatible = "regulator-gpio"; - - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2900000>; - regulator-name = "mmci-reg"; - regulator-type = "voltage"; - - startup-delay-us = <100>; - enable-active-high; - - states = <1800000 0x1 - 2900000 0x0>; - - status = "disabled"; - }; - mcde@a0350000 { compatible = "stericsson,mcde"; reg = <0xa0350000 0x1000>, /* MCDE */ diff --git a/dts/src/arm/ste-href.dtsi b/dts/src/arm/ste-href.dtsi index bf8f0eddc2..744c1e3a74 100644 --- a/dts/src/arm/ste-href.dtsi +++ b/dts/src/arm/ste-href.dtsi @@ -111,6 +111,21 @@ pinctrl-1 = <&i2c3_sleep_mode>; }; + vmmci: regulator-gpio { + compatible = "regulator-gpio"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-name = "mmci-reg"; + regulator-type = "voltage"; + + startup-delay-us = <100>; + enable-active-high; + + states = <1800000 0x1 + 2900000 0x0>; + }; + // External Micro SD slot sdi0_per1@80126000 { arm,primecell-periphid = <0x10480180>; diff --git a/dts/src/arm/ste-snowball.dts b/dts/src/arm/ste-snowball.dts index 206826a855..1bc84ebdcc 100644 --- a/dts/src/arm/ste-snowball.dts +++ b/dts/src/arm/ste-snowball.dts @@ -146,8 +146,21 @@ }; vmmci: regulator-gpio { + compatible = "regulator-gpio"; + gpios = <&gpio7 4 0x4>; enable-gpio = <&gpio6 25 0x4>; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-name = "mmci-reg"; + regulator-type = "voltage"; + + startup-delay-us = <100>; + enable-active-high; + + states = <1800000 0x1 + 2900000 0x0>; }; // External Micro SD slot 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); - @@ -1564,14 +1564,11 @@ out: } EXPORT_SYMBOL(rmdir); -static void memcpy_sz(void *_dst, const void *_src, ulong count, ulong rwsize) +static void memcpy_sz(void *dst, const void *src, size_t count, int rwsize) { - ulong dst = (ulong)_dst; - ulong src = (ulong)_src; - /* no rwsize specification given. Do whatever memcpy likes best */ if (!rwsize) { - memcpy(_dst, _src, count); + memcpy(dst, src, count); return; } @@ -1582,13 +1579,16 @@ static void memcpy_sz(void *_dst, const void *_src, ulong count, ulong rwsize) while (count-- > 0) { switch (rwsize) { case 1: - *((u_char *)dst) = *((u_char *)src); + *((u8 *)dst) = *((u8 *)src); break; case 2: - *((ushort *)dst) = *((ushort *)src); + *((u16 *)dst) = *((u16 *)src); break; case 4: - *((ulong *)dst) = *((ulong *)src); + *((u32 *)dst) = *((u32 *)src); + break; + case 8: + *((u64 *)dst) = *((u64 *)src); break; } dst += rwsize; 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); - diff --git a/images/Makefile b/images/Makefile index 587cb2651f..6ee1dccac0 100644 --- a/images/Makefile +++ b/images/Makefile @@ -75,6 +75,8 @@ quiet_cmd_pblx ?= PBLX $@ $(obj)/%.pblx: $(obj)/%.pblb $(obj)/barebox.z FORCE $(call if_changed,pblx,$(@F)) + $(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_PBLX_SIZE)) + $(obj)/%.s: $(obj)/% FORCE $(call if_changed,disasm) diff --git a/images/Makefile.am33xx b/images/Makefile.am33xx index eae2a6a6e1..657aeb0e28 100644 --- a/images/Makefile.am33xx +++ b/images/Makefile.am33xx @@ -7,13 +7,23 @@ quiet_cmd_mlo_image = MLO $@ $(obj)/%.mlo: $(obj)/% FORCE $(call if_changed,mlo_image) +# %.mlospi - convert MLO image for SPI loading +# ---------------------------------------------------------------- +quiet_cmd_mlo_spi_image = SPI-IMG $@ + cmd_mlo_spi_image = scripts/mk-omap-image -s -a 0x402f0400 $<.mlo > $@ + +$(obj)/%.mlospi: $(obj)/% $(obj)/%.mlo FORCE + $(call if_changed,mlo_spi_image) + pblx-$(CONFIG_MACH_AFI_GF) += start_am33xx_afi_gf_sdram FILE_barebox-am33xx-afi-gf.img = start_am33xx_afi_gf_sdram.pblx am33xx-barebox-$(CONFIG_MACH_AFI_GF) += barebox-am33xx-afi-gf.img pblx-$(CONFIG_MACH_AFI_GF) += start_am33xx_afi_gf_sram FILE_barebox-am33xx-afi-gf-mlo.img = start_am33xx_afi_gf_sram.pblx.mlo +FILE_barebox-am33xx-afi-gf-mlo.spi.img = start_am33xx_afi_gf_sram.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_AFI_GF) += barebox-am33xx-afi-gf-mlo.img +am33xx-mlospi-$(CONFIG_MACH_AFI_GF) += barebox-am33xx-afi-gf-mlo.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sdram FILE_barebox-am33xx-phytec-phycore.img = start_am33xx_phytec_phycore_sdram.pblx @@ -25,19 +35,27 @@ am33xx-barebox-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_256mb FILE_barebox-am33xx-phytec-phycore-mlo-256mb.img = start_am33xx_phytec_phycore_sram_256mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-256mb.spi.img = start_am33xx_phytec_phycore_sram_256mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-256mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-256mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_128mb FILE_barebox-am33xx-phytec-phycore-mlo-128mb.img = start_am33xx_phytec_phycore_sram_128mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-128mb.spi.img = start_am33xx_phytec_phycore_sram_128mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-128mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-128mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_512mb FILE_barebox-am33xx-phytec-phycore-mlo-512mb.img = start_am33xx_phytec_phycore_sram_512mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-512mb.spi.img = start_am33xx_phytec_phycore_sram_512mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-512mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-512mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_2x512mb FILE_barebox-am33xx-phytec-phycore-mlo-2x512mb.img = start_am33xx_phytec_phycore_sram_2x512mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycore-mlo-2x512mb.spi.img = start_am33xx_phytec_phycore_sram_2x512mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-2x512mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-2x512mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phyflex_sdram FILE_barebox-am33xx-phytec-phyflex.img = start_am33xx_phytec_phyflex_sdram.pblx @@ -45,11 +63,15 @@ am33xx-barebox-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phyflex_sram_256mb FILE_barebox-am33xx-phytec-phyflex-mlo-256mb.img = start_am33xx_phytec_phyflex_sram_256mb.pblx.mlo +FILE_barebox-am33xx-phytec-phyflex-mlo-256mb.spi.img = start_am33xx_phytec_phyflex_sram_256mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-256mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-256mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phyflex_sram_512mb FILE_barebox-am33xx-phytec-phyflex-mlo-512mb.img = start_am33xx_phytec_phyflex_sram_512mb.pblx.mlo +FILE_barebox-am33xx-phytec-phyflex-mlo-512mb.spi.img = start_am33xx_phytec_phyflex_sram_512mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-512mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phyflex-mlo-512mb.spi.img pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycard_sdram FILE_barebox-am33xx-phytec-phycard.img = start_am33xx_phytec_phycard_sdram.pblx @@ -57,7 +79,9 @@ am33xx-barebox-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycard pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycard_sram_256mb FILE_barebox-am33xx-phytec-phycard-mlo-256mb.img = start_am33xx_phytec_phycard_sram_256mb.pblx.mlo +FILE_barebox-am33xx-phytec-phycard-mlo-256mb.spi.img = start_am33xx_phytec_phycard_sram_256mb.pblx.mlospi am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycard-mlo-256mb.img +am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycard-mlo-256mb.spi.img pblx-$(CONFIG_MACH_BEAGLEBONE) += start_am33xx_beaglebone_sdram FILE_barebox-am33xx-beaglebone.img = start_am33xx_beaglebone_sdram.pblx @@ -72,3 +96,7 @@ image-y += $(am33xx-mlo-y) else image-y += $(am33xx-barebox-y) endif + +ifdef CONFIG_OMAP_BUILD_SPI +image-y += $(am33xx-mlospi-y) +endif diff --git a/images/Makefile.imx b/images/Makefile.imx index 415b294e85..6b44958157 100644 --- a/images/Makefile.imx +++ b/images/Makefile.imx @@ -4,8 +4,15 @@ # %.imximg - convert into i.MX image # ---------------------------------------------------------------- + +ifdef CONFIG_ARCH_IMX_XLOAD +$(obj)/%.imximg: $(obj)/% FORCE + $(call cmd,check_file_size,$<,$(CONFIG_ARCH_IMX_UNUSED_IRAM_SIZE)) + $(call if_changed,imx_image) +else $(obj)/%.imximg: $(obj)/% FORCE $(call if_changed,imx_image) +endif # ----------------------- i.MX25 based boards --------------------------- pblx-$(CONFIG_MACH_TX25) += start_imx25_karo_tx25 @@ -29,7 +36,18 @@ image-$(CONFIG_MACH_PCM038) += barebox-phytec-phycore-imx27.img pblx-$(CONFIG_MACH_FREESCALE_MX51_PDK) += start_imx51_babbage CFG_start_imx51_babbage.pblx.imximg = $(board)/freescale-mx51-babbage/flash-header-imx51-babbage.imxcfg FILE_barebox-freescale-imx51-babbage.img = start_imx51_babbage.pblx.imximg -image-$(CONFIG_MACH_FREESCALE_MX51_PDK) += barebox-freescale-imx51-babbage.img +imx-barebox-$(CONFIG_MACH_FREESCALE_MX51_PDK) += barebox-freescale-imx51-babbage.img + +pblx-$(CONFIG_MACH_FREESCALE_MX51_PDK) += start_imx51_babbage_xload +CFG_start_imx51_babbage_xload.pblx.imximg = $(board)/freescale-mx51-babbage/flash-header-imx51-babbage-xload.imxcfg +FILE_barebox-freescale-imx51-babbage-xload.img = start_imx51_babbage_xload.pblx.imximg +imx-xload-$(CONFIG_MACH_FREESCALE_MX51_PDK) += barebox-freescale-imx51-babbage-xload.img + +ifdef CONFIG_ARCH_IMX_XLOAD +image-y += $(imx-xload-y) +else +image-y += $(imx-barebox-y) +endif pblx-$(CONFIG_MACH_EFIKA_MX_SMARTBOOK) += start_imx51_genesi_efikasb CFG_start_imx51_genesi_efikasb.pblx.imximg = $(board)/efika-mx-smartbook/flash-header-imx51-genesi-efikasb.imxcfg diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h index e359187d7f..00d6ecaf54 100644 --- a/include/asm-generic/barebox.lds.h +++ b/include/asm-generic/barebox.lds.h @@ -34,7 +34,9 @@ KEEP(*(.initcall.9)) \ KEEP(*(.initcall.10)) \ KEEP(*(.initcall.11)) \ - KEEP(*(.initcall.12)) + KEEP(*(.initcall.12)) \ + KEEP(*(.initcall.13)) \ + KEEP(*(.initcall.14)) #define BAREBOX_CMDS KEEP(*(SORT_BY_NAME(.barebox_cmd*))) @@ -45,7 +47,8 @@ #define BAREBOX_CLK_TABLE() \ . = ALIGN(8); \ __clk_of_table_start = .; \ - KEEP(*(.__clk_of_table_*)); \ + KEEP(*(.__clk_of_table)); \ + KEEP(*(.__clk_of_table_end)); \ __clk_of_table_end = .; #define BAREBOX_DTB() \ diff --git a/include/asm-generic/bitsperlong.h b/include/asm-generic/bitsperlong.h index 4ae54e07de..bb98650298 100644 --- a/include/asm-generic/bitsperlong.h +++ b/include/asm-generic/bitsperlong.h @@ -1,32 +1,10 @@ #ifndef __ASM_GENERIC_BITS_PER_LONG #define __ASM_GENERIC_BITS_PER_LONG -/* - * There seems to be no way of detecting this automatically from user - * space, so 64 bit architectures should override this in their - * bitsperlong.h. In particular, an architecture that supports - * both 32 and 64 bit user space must not rely on CONFIG_64BIT - * to decide it, but rather check a compiler provided macro. - */ -#ifndef __BITS_PER_LONG -#define __BITS_PER_LONG 32 -#endif - -#ifdef __KERNEL__ - #ifdef CONFIG_64BIT #define BITS_PER_LONG 64 #else #define BITS_PER_LONG 32 #endif /* CONFIG_64BIT */ -/* - * FIXME: The check currently breaks x86-64 build, so it's - * temporarily disabled. Please fix x86-64 and reenable - */ -#if 0 && BITS_PER_LONG != __BITS_PER_LONG -#error Inconsistent word size. Check asm/bitsperlong.h -#endif - -#endif /* __KERNEL__ */ #endif /* __ASM_GENERIC_BITS_PER_LONG */ diff --git a/include/asm-generic/posix_types.h b/include/asm-generic/posix_types.h new file mode 100644 index 0000000000..136f161e15 --- /dev/null +++ b/include/asm-generic/posix_types.h @@ -0,0 +1,90 @@ +#ifndef __ASM_GENERIC_POSIX_TYPES_H +#define __ASM_GENERIC_POSIX_TYPES_H + +#include <asm/bitsperlong.h> +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. + * + * First the types that are often defined in different ways across + * architectures, so that you can override them. + */ + +#ifndef __kernel_long_t +typedef long __kernel_long_t; +typedef unsigned long __kernel_ulong_t; +#endif + +#ifndef __kernel_ino_t +typedef __kernel_ulong_t __kernel_ino_t; +#endif + +#ifndef __kernel_mode_t +typedef unsigned int __kernel_mode_t; +#endif + +#ifndef __kernel_pid_t +typedef int __kernel_pid_t; +#endif + +#ifndef __kernel_ipc_pid_t +typedef int __kernel_ipc_pid_t; +#endif + +#ifndef __kernel_uid_t +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +#endif + +#ifndef __kernel_suseconds_t +typedef __kernel_long_t __kernel_suseconds_t; +#endif + +#ifndef __kernel_daddr_t +typedef int __kernel_daddr_t; +#endif + +#ifndef __kernel_uid32_t +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; +#endif + +#ifndef __kernel_old_uid_t +typedef __kernel_uid_t __kernel_old_uid_t; +typedef __kernel_gid_t __kernel_old_gid_t; +#endif + +#ifndef __kernel_old_dev_t +typedef unsigned int __kernel_old_dev_t; +#endif + +/* + * Most 32 bit architectures use "unsigned int" size_t, + * and all 64 bit architectures use "unsigned long" size_t. + */ +#ifndef __kernel_size_t +#if BITS_PER_LONG != 64 +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +#else +typedef __kernel_ulong_t __kernel_size_t; +typedef __kernel_long_t __kernel_ssize_t; +typedef __kernel_long_t __kernel_ptrdiff_t; +#endif +#endif + +/* + * anything below here should be completely generic + */ +typedef __kernel_long_t __kernel_off_t; +typedef long long __kernel_loff_t; +typedef __kernel_long_t __kernel_time_t; +typedef __kernel_long_t __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; + +#endif /* __ASM_GENERIC_POSIX_TYPES_H */ diff --git a/include/asm-generic/swab.h b/include/asm-generic/swab.h index a8e9029d9e..3ab5add54f 100644 --- a/include/asm-generic/swab.h +++ b/include/asm-generic/swab.h @@ -9,7 +9,7 @@ * valid if the compiler supports 64 bit data types. */ -#if __BITS_PER_LONG == 32 +#if BITS_PER_LONG == 32 #if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) #define __SWAB_64_THRU_32__ #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/bootsource.h b/include/bootsource.h index 4bca9b99ad..c6d3b3a98b 100644 --- a/include/bootsource.h +++ b/include/bootsource.h @@ -15,6 +15,7 @@ enum bootsource { BOOTSOURCE_ONENAND, BOOTSOURCE_HD, BOOTSOURCE_USB, + BOOTSOURCE_NET, }; #define BOOTSOURCE_INSTANCE_UNKNOWN -1 diff --git a/include/console.h b/include/console.h index 72b4a440e7..839ec17e50 100644 --- a/include/console.h +++ b/include/console.h @@ -52,8 +52,10 @@ struct console_device { struct list_head list; unsigned char f_active; + char active[4]; unsigned int baudrate; + unsigned int baudrate_param; const char *linux_console_name; }; @@ -62,6 +64,7 @@ int console_register(struct console_device *cdev); int console_unregister(struct console_device *cdev); struct console_device *console_get_by_dev(struct device_d *dev); +struct console_device *console_get_by_name(const char *name); extern struct list_head console_list; #define for_each_console(console) list_for_each_entry(console, &console_list, list) @@ -75,4 +78,9 @@ extern int barebox_loglevel; struct console_device *console_get_first_active(void); +int console_set_active(struct console_device *cdev, unsigned active); +unsigned console_get_active(struct console_device *cdev); +int console_set_baudrate(struct console_device *cdev, unsigned baudrate); +unsigned console_get_baudrate(struct console_device *cdev); + #endif diff --git a/include/crc.h b/include/crc.h index 10560c9fa9..4290f41c57 100644 --- a/include/crc.h +++ b/include/crc.h @@ -95,6 +95,6 @@ cyg_ether_crc32_accumulate(uint32_t crc, unsigned char *s, int len); /* 16 bit CRC with polynomial x^16+x^12+x^5+1 */ -extern uint16_t cyg_crc16(unsigned char *s, int len); +extern uint16_t cyg_crc16(const unsigned char *s, int len); #endif /* _SERVICES_CRC_CRC_H_ */ diff --git a/include/dhcp.h b/include/dhcp.h new file mode 100644 index 0000000000..0796b30cf1 --- /dev/null +++ b/include/dhcp.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015 PHYTEC Messtechnik GmbH, + * Author: Wadim Egorov <w.egorov@phytec.de> + * + * 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. + */ + +#ifndef __DHCP_H__ +#define __DHCP_H__ + +#define DHCP_DEFAULT_RETRY 20 + +struct dhcp_req_param { + char *hostname; + char *vendor_id; + char *client_id; + char *user_class; + char *client_uuid; +}; + +int dhcp(int retries, struct dhcp_req_param *param); + +#endif diff --git a/include/digest.h b/include/digest.h index 7f8d696eb6..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); @@ -68,14 +69,24 @@ void digest_free(struct digest *d); int digest_file_window(struct digest *d, const char *filename, unsigned char *hash, - unsigned char *sig, + const unsigned char *sig, ulong start, ulong size); int digest_file(struct digest *d, const char *filename, - unsigned char *hash, - unsigned char *sig); + unsigned char *hash, + const unsigned char *sig); int digest_file_by_name(const char *algo, const char *filename, - unsigned char *hash, - unsigned char *sig); + 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/fcntl.h b/include/fcntl.h index aed741e584..501b415035 100644 --- a/include/fcntl.h +++ b/include/fcntl.h @@ -17,11 +17,12 @@ #define O_NOFOLLOW 00400000 /* don't follow links */ /* barebox additional flags */ -#define O_RWSIZE_MASK 00000070 +#define O_RWSIZE_MASK 00000170 #define O_RWSIZE_SHIFT 3 #define O_RWSIZE_1 00000010 #define O_RWSIZE_2 00000020 #define O_RWSIZE_4 00000040 +#define O_RWSIZE_8 00000100 #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ 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/habv4.h b/include/habv4.h index fb6ed99d82..f9bf74f3b9 100644 --- a/include/habv4.h +++ b/include/habv4.h @@ -21,7 +21,7 @@ #ifdef CONFIG_HABV4 int habv4_get_status(void); #else -static inline int habv4_get_status() +static inline int habv4_get_status(void) { return -EPERM; } diff --git a/include/init.h b/include/init.h index 37c7eedf67..f619c951d3 100644 --- a/include/init.h +++ b/include/init.h @@ -39,6 +39,8 @@ typedef int (*initcall_t)(void); #define device_initcall(fn) __define_initcall("10",fn,10) #define crypto_initcall(fn) __define_initcall("11",fn,11) #define late_initcall(fn) __define_initcall("12",fn,12) +#define environment_initcall(fn) __define_initcall("13",fn,13) +#define postenvironment_initcall(fn) __define_initcall("14",fn,14) /* section for code used very early when * - we're not running from where we linked at diff --git a/include/io.h b/include/io.h index 8d885de68f..8eb56b061f 100644 --- a/include/io.h +++ b/include/io.h @@ -3,12 +3,4 @@ #include <asm/io.h> -/* cpu_read/cpu_write: cpu native io accessors */ -#define cpu_readb(a) __raw_readb(a) -#define cpu_readw(a) __raw_readw(a) -#define cpu_readl(a) __raw_readl(a) -#define cpu_writeb(v, a) __raw_writeb((v), (a)) -#define cpu_writew(v, a) __raw_writew((v), (a)) -#define cpu_writel(v, a) __raw_writel((v), (a)) - #endif /* __IO_H */ 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/clk.h b/include/linux/clk.h index 4aeec63a84..7a0ee110e4 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -321,7 +321,7 @@ struct of_phandle_args; #define CLK_OF_DECLARE(name, compat, fn) \ const struct of_device_id __clk_of_table_##name \ -__attribute__ ((unused,section (".__clk_of_table_" __stringify(name)))) \ +__attribute__ ((unused,section (".__clk_of_table"))) \ = { .compatible = compat, .data = fn } #if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER) diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index c822075688..d8125214a0 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -17,4 +17,11 @@ struct pci_device_id { __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ }; +#define SPI_NAME_SIZE 32 + +struct spi_device_id { + char name[SPI_NAME_SIZE]; + unsigned long driver_data; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ 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/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h new file mode 100644 index 0000000000..f099406c53 --- /dev/null +++ b/include/linux/mtd/spi-nor.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * 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. + */ + +#ifndef __LINUX_MTD_SPI_NOR_H +#define __LINUX_MTD_SPI_NOR_H + +/* + * Note on opcode nomenclature: some opcodes have a format like + * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number + * of I/O lines used for the opcode, address, and data (respectively). The + * FUNCTION has an optional suffix of '4', to represent an opcode which + * requires a 4-byte (32-bit) address. + */ + +/* Flash opcodes. */ +#define SPINOR_OP_WREN 0x06 /* Write enable */ +#define SPINOR_OP_RDSR 0x05 /* Read status register */ +#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */ +#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */ +#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ +#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */ +#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */ +#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ +#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */ +#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ +#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */ +#define SPINOR_OP_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define SPINOR_OP_SE 0xd8 /* Sector erase (usually 64KiB) */ +#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */ +#define SPINOR_OP_RDCR 0x35 /* Read configuration register */ +#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ + +/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ +#define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */ +#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ +#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */ +#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ +#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ +#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ + +/* Used for SST flashes only. */ +#define SPINOR_OP_BP 0x02 /* Byte program */ +#define SPINOR_OP_WRDI 0x04 /* Write disable */ +#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */ + +/* Used for Macronix and Winbond flashes. */ +#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ +#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ + +/* Used for Spansion flashes only. */ +#define SPINOR_OP_BRWR 0x17 /* Bank register write */ + +/* Status Register bits. */ +#define SR_WIP 1 /* Write in progress */ +#define SR_WEL 2 /* Write enable latch */ +/* meaning of other SR_* bits may differ between vendors */ +#define SR_BP0 4 /* Block protect 0 */ +#define SR_BP1 8 /* Block protect 1 */ +#define SR_BP2 0x10 /* Block protect 2 */ +#define SR_SRWD 0x80 /* SR write protect */ + +#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ + +/* Flag Status Register bits */ +#define FSR_READY 0x80 + +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ + +enum read_mode { + SPI_NOR_NORMAL = 0, + SPI_NOR_FAST, + SPI_NOR_DUAL, + SPI_NOR_QUAD, +}; + +/** + * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer + * @wren: command for "Write Enable", or 0x00 for not required + * @cmd: command for operation + * @cmd_pins: number of pins to send @cmd (1, 2, 4) + * @addr: address for operation + * @addr_pins: number of pins to send @addr (1, 2, 4) + * @addr_width: number of address bytes + * (3,4, or 0 for address not required) + * @mode: mode data + * @mode_pins: number of pins to send @mode (1, 2, 4) + * @mode_cycles: number of mode cycles (0 for mode not required) + * @dummy_cycles: number of dummy cycles (0 for dummy not required) + */ +struct spi_nor_xfer_cfg { + u8 wren; + u8 cmd; + u8 cmd_pins; + u32 addr; + u8 addr_pins; + u8 addr_width; + u8 mode; + u8 mode_pins; + u8 mode_cycles; + u8 dummy_cycles; +}; + +#define SPI_NOR_MAX_CMD_SIZE 8 +enum spi_nor_ops { + SPI_NOR_OPS_READ = 0, + SPI_NOR_OPS_WRITE, + SPI_NOR_OPS_ERASE, + SPI_NOR_OPS_LOCK, + SPI_NOR_OPS_UNLOCK, +}; + +enum spi_nor_option_flags { + SNOR_F_USE_FSR = BIT(0), +}; + +/** + * struct spi_nor - Structure for defining a the SPI NOR layer + * @mtd: point to a mtd_info structure + * @lock: the lock for the read/write/erase/lock/unlock operations + * @dev: point to a spi device, or a spi nor controller device. + * @page_size: the page size of the SPI NOR + * @addr_width: number of address bytes + * @erase_opcode: the opcode for erasing a sector + * @read_opcode: the read opcode + * @read_dummy: the dummy needed by the read operation + * @program_opcode: the program opcode + * @flash_read: the mode of the read + * @sst_write_second: used by the SST write operation + * @flags: flag options for the current SPI-NOR (SNOR_F_*) + * @cfg: used by the read_xfer/write_xfer + * @cmd_buf: used by the write_reg + * @prepare: [OPTIONAL] do some preparations for the + * read/write/erase/lock/unlock operations + * @unprepare: [OPTIONAL] do some post work after the + * read/write/erase/lock/unlock operations + * @read_xfer: [OPTIONAL] the read fundamental primitive + * @write_xfer: [OPTIONAL] the writefundamental primitive + * @read_reg: [DRIVER-SPECIFIC] read out the register + * @write_reg: [DRIVER-SPECIFIC] write data to the register + * @read: [DRIVER-SPECIFIC] read data from the SPI NOR + * @write: [DRIVER-SPECIFIC] write data to the SPI NOR + * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR + * at the offset @offs + * @priv: the private data + */ +struct spi_nor { + struct mtd_info *mtd; + struct mutex lock; + struct device_d *dev; + u32 page_size; + u8 addr_width; + u8 erase_opcode; + u8 read_opcode; + u8 read_dummy; + u8 program_opcode; + enum read_mode flash_read; + bool sst_write_second; + u32 flags; + struct spi_nor_xfer_cfg cfg; + u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; + + int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); + void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops); + int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg, + u8 *buf, size_t len); + int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg, + u8 *buf, size_t len); + int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); + int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len, + int write_enable); + + int (*read)(struct spi_nor *nor, loff_t from, + size_t len, size_t *retlen, u_char *read_buf); + void (*write)(struct spi_nor *nor, loff_t to, + size_t len, size_t *retlen, const u_char *write_buf); + int (*erase)(struct spi_nor *nor, loff_t offs); + + void *priv; +}; + +/** + * spi_nor_scan() - scan the SPI NOR + * @nor: the spi_nor structure + * @name: the chip type name + * @mode: the read mode supported by the driver + * + * The drivers can use this fuction to scan the SPI NOR. + * In the scanning, it will try to get all the necessary information to + * fill the mtd_info{} and the spi_nor{}. + * + * The chip type name can be provided through the @name parameter. + * + * Return: 0 for success, others for failure. + */ +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); + +#endif diff --git a/include/linux/types.h b/include/linux/types.h index c11e148c90..ce1a0ec84c 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -15,7 +15,6 @@ typedef __kernel_fd_set fd_set; typedef __kernel_dev_t dev_t; typedef __kernel_ino_t ino_t; typedef __kernel_mode_t mode_t; -typedef __kernel_nlink_t nlink_t; typedef __kernel_off_t off_t; typedef __kernel_pid_t pid_t; typedef __kernel_daddr_t daddr_t; @@ -158,6 +157,13 @@ typedef __u32 __bitwise __wsum; #define __aligned_be64 __be64 __attribute__((aligned(8))) #define __aligned_le64 __le64 __attribute__((aligned(8))) +/* A dma_addr_t can hold any valid DMA or bus address for the platform */ +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +typedef u64 dma_addr_t; +#else +typedef u32 dma_addr_t; +#endif /* dma_addr_t */ + #ifdef CONFIG_PHYS_ADDR_T_64BIT typedef u64 phys_addr_t; typedef u64 phys_size_t; 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 e73cd7a446..c02f5f49ab 100644 --- a/include/of.h +++ b/include/of.h @@ -243,6 +243,7 @@ struct device_d *of_find_device_by_node_path(const char *path); #define OF_FIND_PATH_FLAGS_BB 1 /* return .bb device if available */ int of_find_path(struct device_node *node, const char *propname, char **outpath, unsigned flags); int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context); +int of_unregister_fixup(int (*fixup)(struct device_node *, void *), void *context); struct device_node *of_find_node_by_alias(struct device_node *root, const char *alias); struct device_node *of_find_node_by_path_or_alias(struct device_node *root, diff --git a/include/platform_data/cadence_qspi.h b/include/platform_data/cadence_qspi.h new file mode 100644 index 0000000000..4930edce50 --- /dev/null +++ b/include/platform_data/cadence_qspi.h @@ -0,0 +1,9 @@ +#ifndef __INCLUDE_PLATFORM_DATA_CADENCE_QSPI_H +#define __INCLUDE_PLATFORM_DATA_CADENCE_QSPI_H + +struct cadence_qspi_platform_data { + unsigned int ext_decoder; + unsigned int fifo_depth; +}; + +#endif /* __INCLUDE_PLATFORM_DATA_CADENCE_QSPI_H */ diff --git a/include/serial/imx-uart.h b/include/serial/imx-uart.h new file mode 100644 index 0000000000..7275e6ac38 --- /dev/null +++ b/include/serial/imx-uart.h @@ -0,0 +1,128 @@ +#ifndef __IMX_UART_H__ +#define __IMX_UART_H__ + +#define URXD0 0x0 /* Receiver Register */ +#define URTX0 0x40 /* Transmitter Register */ +#define UCR1 0x80 /* Control Register 1 */ +#define UCR2 0x84 /* Control Register 2 */ +#define UCR3 0x88 /* Control Register 3 */ +#define UCR4 0x8c /* Control Register 4 */ +#define UFCR 0x90 /* FIFO Control Register */ +#define USR1 0x94 /* Status Register 1 */ +#define USR2 0x98 /* Status Register 2 */ +#define UESC 0x9c /* Escape Character Register */ +#define UTIM 0xa0 /* Escape Timer Register */ +#define UBIR 0xa4 /* BRM Incremental Register */ +#define UBMR 0xa8 /* BRM Modulator Register */ +#define UBRC 0xac /* Baud Rate Count Register */ + +/* UART Control Register Bit Fields.*/ +#define URXD_CHARRDY (1<<15) +#define URXD_ERR (1<<14) +#define URXD_OVRRUN (1<<13) +#define URXD_FRMERR (1<<12) +#define URXD_BRK (1<<11) +#define URXD_PRERR (1<<10) +#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ +#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ +#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ +#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ +#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ +#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_IREN (1<<7) /* Infrared interface enable */ +#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ +#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ +#define UCR1_SNDBRK (1<<4) /* Send break */ +#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ +#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ +#define UCR1_DOZE (1<<1) /* Doze */ +#define UCR1_UARTEN (1<<0) /* UART enabled */ +#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ +#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ +#define UCR2_CTSC (1<<13) /* CTS pin control */ +#define UCR2_CTS (1<<12) /* Clear to send */ +#define UCR2_ESCEN (1<<11) /* Escape enable */ +#define UCR2_PREN (1<<8) /* Parity enable */ +#define UCR2_PROE (1<<7) /* Parity odd/even */ +#define UCR2_STPB (1<<6) /* Stop */ +#define UCR2_WS (1<<5) /* Word size */ +#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ +#define UCR2_TXEN (1<<2) /* Transmitter enabled */ +#define UCR2_RXEN (1<<1) /* Receiver enabled */ +#define UCR2_SRST (1<<0) /* SW reset */ +#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ +#define UCR3_PARERREN (1<<12) /* Parity enable */ +#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ +#define UCR3_DSR (1<<10) /* Data set ready */ +#define UCR3_DCD (1<<9) /* Data carrier detect */ +#define UCR3_RI (1<<8) /* Ring indicator */ +#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */ +#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ +#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ +#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ +#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz (i.MXL / i.MX1) */ +#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz (i.MXL / i.MX1) */ +#define UCR3_RXDMUXSEL (1<<2) /* RXD Muxed input select (i.MX27) */ +#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ +#define UCR3_BPEN (1<<0) /* Preset registers enable */ +#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */ +#define UCR4_INVR (1<<9) /* Inverted infrared reception */ +#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ +#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ +#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ +#define UCR4_IRSC (1<<5) /* IR special case */ +#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ +#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ +#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ +#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ +#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV6 (0b000<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV5 (0b001<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV4 (0b010<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV3 (0b011<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV2 (0b100<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV1 (0b101<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV7 (0b110<<7) /* Reference freq divider mask */ +#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ +#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ +#define USR1_RTSS (1<<14) /* RTS pin status */ +#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ +#define USR1_RTSD (1<<12) /* RTS delta */ +#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ +#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ +#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ +#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ +#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ +#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ +#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ +#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ +#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ +#define USR2_IDLE (1<<12) /* Idle condition */ +#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ +#define USR2_WAKE (1<<7) /* Wake */ +#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ +#define USR2_TXDC (1<<3) /* Transmitter complete */ +#define USR2_BRCD (1<<2) /* Break condition */ +#define USR2_ORE (1<<1) /* Overrun error */ +#define USR2_RDR (1<<0) /* Recv data ready */ +#define UTS_FRCPERR (1<<13) /* Force parity error */ +#define UTS_LOOP (1<<12) /* Loop tx and rx */ +#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ +#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ +#define UTS_TXFULL (1<<4) /* TxFIFO full */ +#define UTS_RXFULL (1<<3) /* RxFIFO full */ +#define UTS_SOFTRST (1<<0) /* Software reset */ + +static inline int baudrate_to_ubir(int baudrate) +{ + return baudrate / 100 - 1; +} + +static inline int refclock_to_ubmr(int clock_hz) +{ + return clock_hz / 1600 - 1; +} + +#endif /* __IMX_UART_H__ */ diff --git a/include/state.h b/include/state.h index e96d3bfb2e..08c4e8654b 100644 --- a/include/state.h +++ b/include/state.h @@ -5,12 +5,13 @@ struct state; -int state_backend_dtb_file(struct state *state, const char *path); -int state_backend_raw_file(struct state *state, const char *path, - off_t offset, size_t size); +int state_backend_dtb_file(struct state *state, const char *of_path, + const char *path); +int state_backend_raw_file(struct state *state, const char *of_path, + const char *path, off_t offset, size_t size); -struct state *state_new_from_fdt(const char *name, void *fdt); struct state *state_new_from_node(const char *name, struct device_node *node); +void state_release(struct state *state); struct state *state_by_name(const char *name); struct state *state_by_node(const struct device_node *node); diff --git a/include/watchdog.h b/include/watchdog.h index 3e2d08e876..7e37b7c22a 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -17,8 +17,25 @@ struct watchdog { int (*set_timeout)(struct watchdog *, unsigned); }; +#ifdef CONFIG_WATCHDOG int watchdog_register(struct watchdog *); int watchdog_deregister(struct watchdog *); int watchdog_set_timeout(unsigned); +#else +static inline int watchdog_register(struct watchdog *w) +{ + return 0; +} + +int watchdog_deregister(struct watchdog *w) +{ + return 0; +} + +int watchdog_set_timeout(unsigned t) +{ + return 0; +} +#endif #endif /* INCLUDE_WATCHDOG_H */ diff --git a/lib/bootstrap/devfs.c b/lib/bootstrap/devfs.c index 704680a4c9..5a64477eed 100644 --- a/lib/bootstrap/devfs.c +++ b/lib/bootstrap/devfs.c @@ -35,7 +35,7 @@ static void *read_image_head(const char *name) cdev = cdev_open(name, O_RDONLY); if (!cdev) { bootstrap_err("failed to open partition\n"); - return NULL; + goto free_header; } ret = cdev_read(cdev, header, BAREBOX_HEAD_SIZE, 0, 0); @@ -43,10 +43,14 @@ static void *read_image_head(const char *name) if (ret != BAREBOX_HEAD_SIZE) { bootstrap_err("failed to read from partition\n"); - return NULL; + goto free_header; } return header; + +free_header: + free(header); + return NULL; } static unsigned int get_image_size(void *head) @@ -54,8 +58,12 @@ static unsigned int get_image_size(void *head) unsigned int ret = 0; unsigned int *psize = head + BAREBOX_HEAD_SIZE_OFFSET; - if (is_barebox_head(head)) + if (is_barebox_head(head)) { ret = *psize; + if (!ret) + bootstrap_err( + "image has correct magic, but the length is zero\n"); + } debug("Detected barebox image size %u\n", ret); return ret; @@ -77,13 +85,27 @@ void* bootstrap_read_devfs(char *devname, bool use_bb, int offset, { int ret; int size = 0; - void *to, *header; - struct cdev *cdev; + void *to, *header, *result = NULL; + struct cdev *cdev, *partition; char *partname = "x"; - devfs_add_partition(devname, offset, max_size, DEVFS_PARTITION_FIXED, partname); + partition = devfs_add_partition(devname, offset, max_size, + DEVFS_PARTITION_FIXED, partname); + if (IS_ERR(partition)) { + bootstrap_err("%s: failed to add partition (%ld)\n", + devname, PTR_ERR(partition)); + return NULL; + } + if (use_bb) { - dev_add_bb_dev(partname, "bbx"); + ret = dev_add_bb_dev(partname, "bbx"); + if (ret) { + bootstrap_err( + "%s: failed to add bad block aware partition (%d)\n", + devname, ret); + goto delete_devfs_partition; + } + partname = "bbx"; } @@ -105,14 +127,29 @@ void* bootstrap_read_devfs(char *devname, bool use_bb, int offset, cdev = cdev_open(partname, O_RDONLY); if (!cdev) { bootstrap_err("%s: failed to open %s\n", devname, partname); - return NULL; + goto free_memory; } ret = cdev_read(cdev, to, size, 0, 0); - if (ret != size) { + cdev_close(cdev); + + if (ret != size) bootstrap_err("%s: failed to read from %s\n", devname, partname); - return NULL; + else + result = to; + +free_memory: + free(header); + if (!result) + free(to); + + if (use_bb) { + dev_remove_bb_dev(partname); + partname = "x"; } - return to; +delete_devfs_partition: + devfs_del_partition(partname); + + return result; } diff --git a/lib/fnmatch.c b/lib/fnmatch.c index 1a5e8d0d3d..0ab530d3b1 100644 --- a/lib/fnmatch.c +++ b/lib/fnmatch.c @@ -218,4 +218,3 @@ int fnmatch(const char *pattern, const char *string, int flags) # undef FOLD } - diff --git a/lib/gui/bmp.c b/lib/gui/bmp.c index 6943a1c8e0..d457c01d84 100644 --- a/lib/gui/bmp.c +++ b/lib/gui/bmp.c @@ -7,6 +7,7 @@ #include <gui/graphic_utils.h> #include <init.h> #include <gui/image_renderer.h> +#include <asm/unaligned.h> struct image *bmp_open(char *inbuf, int insize) { @@ -19,9 +20,9 @@ struct image *bmp_open(char *inbuf, int insize) } img->data = inbuf; - img->height = le32_to_cpu(bmp->header.height); - img->width = le32_to_cpu(bmp->header.width); - img->bits_per_pixel = le16_to_cpu(bmp->header.bit_count); + img->height = get_unaligned_le32(&bmp->header.height); + img->width = get_unaligned_le32(&bmp->header.width); + img->bits_per_pixel = get_unaligned_le16(&bmp->header.bit_count); pr_debug("bmp: %d x %d x %d data@0x%p\n", img->width, img->height, img->bits_per_pixel, img->data); @@ -76,7 +77,7 @@ static int bmp_renderer(struct screen *sc, struct surface *s, struct image *img) for (y = 0; y < height; y++) { image = (char *)bmp + - le32_to_cpu(bmp->header.data_offset); + get_unaligned_le32(&bmp->header.data_offset); image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3); adr = buf + (y + starty) * sc->info.line_length + startx * (sc->info.bits_per_pixel >> 3); @@ -98,7 +99,7 @@ static int bmp_renderer(struct screen *sc, struct surface *s, struct image *img) for (y = 0; y < height; y++) { image = (char *)bmp + - le32_to_cpu(bmp->header.data_offset); + get_unaligned_le32(&bmp->header.data_offset); image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3); adr = buf + (y + starty) * sc->info.line_length + startx * (sc->info.bits_per_pixel >> 3); diff --git a/lib/gui/image_renderer.c b/lib/gui/image_renderer.c index dd29389baa..9bef99a7b0 100644 --- a/lib/gui/image_renderer.c +++ b/lib/gui/image_renderer.c @@ -37,10 +37,10 @@ struct image *image_renderer_open(const char* file) struct image *img; int ret; - data = read_file(file, &size); - if (!data) { - printf("unable to read %s\n", file); - return ERR_PTR(-ENOMEM); + ret = read_file_2(file, &size, &data, FILESIZE_MAX); + if (ret) { + printf("unable to read %s: %s\n", file, strerror(-ret)); + return ERR_PTR(ret); } ir = get_renderer(data, size); diff --git a/lib/libfile.c b/lib/libfile.c index 8acff042c8..ba03700aba 100644 --- a/lib/libfile.c +++ b/lib/libfile.c @@ -184,8 +184,8 @@ again: if (read_size < s.st_size) return -EFBIG; - else - return 0; + + return 0; err_out1: close(fd); diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index 3c0f512634..6e8c822b3a 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -258,4 +258,3 @@ lookbehind_overrun: } EXPORT_SYMBOL(lzo1x_decompress_safe); - diff --git a/lib/parameter.c b/lib/parameter.c index 865ad9f431..60642f001b 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -122,6 +122,14 @@ static const char *param_get_generic(struct device_d *dev, struct param_d *p) return p->value ? p->value : ""; } +static int compare(struct list_head *a, struct list_head *b) +{ + char *na = (char*)list_entry(a, struct param_d, list)->name; + char *nb = (char*)list_entry(b, struct param_d, list)->name; + + return strcmp(na, nb); +} + static int __dev_add_param(struct param_d *param, struct device_d *dev, const char *name, int (*set)(struct device_d *dev, struct param_d *p, const char *val), const char *(*get)(struct device_d *dev, struct param_d *p), @@ -145,7 +153,7 @@ static int __dev_add_param(struct param_d *param, struct device_d *dev, const ch param->flags = flags; param->dev = dev; - list_add_tail(¶m->list, &dev->parameters); + list_add_sort(¶m->list, &dev->parameters, compare); return 0; } @@ -575,7 +583,6 @@ struct param_d *dev_add_param_llint_ro(struct device_d *dev, const char *name, return &piro->param; } -#ifdef CONFIG_NET struct param_ip { struct param_d param; IPaddr_t *ip; @@ -739,7 +746,6 @@ struct param_d *dev_add_param_mac(struct device_d *dev, const char *name, return &pm->param; } -#endif /** * dev_remove_param - remove a parameter from a device and free its diff --git a/lib/random.c b/lib/random.c index 14c7da119d..210fea9946 100644 --- a/lib/random.c +++ b/lib/random.c @@ -25,4 +25,3 @@ void get_random_bytes(void *_buf, int len) while (len--) *buf++ = rand() % 256; } - diff --git a/lib/strtox.c b/lib/strtox.c index 882865b45d..cfe61240cc 100644 --- a/lib/strtox.c +++ b/lib/strtox.c @@ -65,4 +65,3 @@ unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int ba return result; } EXPORT_SYMBOL(simple_strtoull); - diff --git a/lib/xfuncs.c b/lib/xfuncs.c index 86d0013787..0e78b670a5 100644 --- a/lib/xfuncs.c +++ b/lib/xfuncs.c @@ -30,8 +30,6 @@ void *xmalloc(size_t size) if (!(p = malloc(size))) panic("ERROR: out of memory\n"); - debug("xmalloc %p (size %zu)\n", p, size); - return p; } EXPORT_SYMBOL(xmalloc); @@ -43,8 +41,6 @@ void *xrealloc(void *ptr, size_t size) if (!(p = realloc(ptr, size))) panic("ERROR: out of memory\n"); - debug("xrealloc %p -> %p (size %zu)\n", ptr, p, size); - return p; } EXPORT_SYMBOL(xrealloc); diff --git a/net/Kconfig b/net/Kconfig index 918d77653e..a89049201d 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -22,4 +22,8 @@ config NET_IFUP default y bool +config NET_DHCP + bool + prompt "dhcp support" + endif diff --git a/net/Makefile b/net/Makefile index 907dc28b99..8d564e7299 100644 --- a/net/Makefile +++ b/net/Makefile @@ -1,7 +1,8 @@ +obj-y += lib.o obj-$(CONFIG_NET) += eth.o obj-$(CONFIG_NET) += net.o obj-$(CONFIG_NET_NFS) += nfs.o -obj-$(CONFIG_CMD_DHCP) += dhcp.o +obj-$(CONFIG_NET_DHCP) += dhcp.o obj-$(CONFIG_CMD_PING) += ping.o obj-$(CONFIG_NET_RESOLV)+= dns.o obj-$(CONFIG_NET_NETCONSOLE) += netconsole.o diff --git a/net/dhcp.c b/net/dhcp.c index 19a846270e..e1625ec9cd 100644 --- a/net/dhcp.c +++ b/net/dhcp.c @@ -21,8 +21,7 @@ #include <getopt.h> #include <globalvar.h> #include <init.h> - -#define DHCP_DEFAULT_RETRY 20 +#include <dhcp.h> #define OPT_SIZE 312 /* Minimum DHCP Options size per RFC2131 - results in 576 byte pkt */ @@ -142,7 +141,8 @@ static void env_ip_handle(struct dhcp_opt *opt, unsigned char *popt, int optlen) IPaddr_t ip; ip = net_read_ip(popt); - setenv_ip(opt->barebox_var_name, ip); + if (IS_ENABLED(CONFIG_ENVIRONMENT_VARIABLES)) + setenv_ip(opt->barebox_var_name, ip); } static void env_str_handle(struct dhcp_opt *opt, unsigned char *popt, int optlen) @@ -158,10 +158,9 @@ static void env_str_handle(struct dhcp_opt *opt, unsigned char *popt, int optlen if (opt->copy_only_if_valid && !strlen(tmp)) return; - - if (opt->barebox_var_name) + if (opt->barebox_var_name && IS_ENABLED(EVIRONMENT_VARIABLES)) setenv(opt->barebox_var_name, tmp); - if (opt->barebox_dhcp_global) + if (opt->barebox_dhcp_global && IS_ENABLED(CONFIG_GLOBALVAR)) dhcp_set_barebox_global(opt->barebox_dhcp_global, tmp); } @@ -263,10 +262,10 @@ static int dhcp_set_string_options(struct dhcp_param *param, u8 *e) int str_len; char* str = param->data; - if (!str && param->barebox_var_name) + if (!str && param->barebox_var_name && IS_ENABLED(CONFIG_ENVIRONMENT_VARIABLES)) str = (char*)getenv(param->barebox_var_name); - if (!str && param->barebox_dhcp_global) + if (!str && param->barebox_dhcp_global && IS_ENABLED(CONFIG_GLOBALVAR)) str = (char*)dhcp_get_barebox_global(param->barebox_dhcp_global); if (!str) @@ -391,8 +390,10 @@ static void bootp_copy_net_params(struct bootp *bp) net_set_serverip(tmp_ip); if (strlen(bp->bp_file) > 0) { - setenv("bootfile", bp->bp_file); - dhcp_set_barebox_global("bootfile", bp->bp_file); + if (IS_ENABLED(CONFIG_ENVIRONMENT_VARIABLES)) + setenv("bootfile", bp->bp_file); + if (IS_ENABLED(CONFIG_GLOBALVAR)) + dhcp_set_barebox_global("bootfile", bp->bp_file); } debug("bootfile: %s\n", bp->bp_file); @@ -651,87 +652,27 @@ static void dhcp_reset_env(void) if (!opt->barebox_var_name || opt->copy_only_if_valid) continue; - setenv(opt->barebox_var_name,""); - if (opt->barebox_dhcp_global) - dhcp_set_barebox_global(opt->barebox_dhcp_global,""); - } -} - -static void dhcp_global_add(const char *var) -{ - char * var_global = asprintf("dhcp.%s", var); - - if (!var_global) - return; - - globalvar_add_simple(var_global, NULL); - free(var_global); -} - -static int dhcp_global_init(void) -{ - struct dhcp_opt *opt; - struct dhcp_param *param; - int i; - - for (i = 0; i < ARRAY_SIZE(dhcp_options); i++) { - opt = &dhcp_options[i]; - - if (!opt->barebox_dhcp_global) - continue; - - dhcp_global_add(opt->barebox_dhcp_global); - } - - for (i = 0; i < ARRAY_SIZE(dhcp_params); i++) { - param = &dhcp_params[i]; - - if (!param->barebox_dhcp_global) - continue; - - dhcp_global_add(param->barebox_dhcp_global); + if (IS_ENABLED(CONFIG_ENVIRONMENT_VARIABLES)) + setenv(opt->barebox_var_name, ""); + if (opt->barebox_dhcp_global && IS_ENABLED(CONFIG_GLOBALVAR)) + dhcp_set_barebox_global(opt->barebox_dhcp_global, ""); } - - return 0; } -late_initcall(dhcp_global_init); -static int do_dhcp(int argc, char *argv[]) +int dhcp(int retries, struct dhcp_req_param *param) { - int ret, opt; - int retries = DHCP_DEFAULT_RETRY; + int ret = 0; dhcp_reset_env(); - getenv_uint("global.dhcp.retries", &retries); - - while((opt = getopt(argc, argv, "H:v:c:u:U:r:")) > 0) { - switch(opt) { - case 'H': - dhcp_set_param_data(DHCP_HOSTNAME, optarg); - break; - case 'v': - dhcp_set_param_data(DHCP_VENDOR_ID, optarg); - break; - case 'c': - dhcp_set_param_data(DHCP_CLIENT_ID, optarg); - break; - case 'u': - dhcp_set_param_data(DHCP_CLIENT_UUID, optarg); - break; - case 'U': - dhcp_set_param_data(DHCP_USER_CLASS, optarg); - break; - case 'r': - retries = simple_strtoul(optarg, NULL, 10); - break; - } - } + dhcp_set_param_data(DHCP_HOSTNAME, param->hostname); + dhcp_set_param_data(DHCP_VENDOR_ID, param->vendor_id); + dhcp_set_param_data(DHCP_CLIENT_ID, param->client_id); + dhcp_set_param_data(DHCP_USER_CLASS, param->user_class); + dhcp_set_param_data(DHCP_CLIENT_UUID, param->client_uuid); - if (!retries) { - printf("retries is set to zero, set it to %d\n", DHCP_DEFAULT_RETRY); + if (!retries) retries = DHCP_DEFAULT_RETRY; - } dhcp_con = net_udp_new(0xffffffff, PORT_BOOTPS, dhcp_handler, NULL); if (IS_ERR(dhcp_con)) { @@ -781,29 +722,50 @@ out1: net_unregister(dhcp_con); out: if (ret) - printf("dhcp failed: %s\n", strerror(-ret)); + debug("dhcp failed: %s\n", strerror(-ret)); return ret; } -BAREBOX_CMD_HELP_START(dhcp) -BAREBOX_CMD_HELP_TEXT("Options:") -BAREBOX_CMD_HELP_OPT ("-H HOSTNAME", "hostname to send to the DHCP server") -BAREBOX_CMD_HELP_OPT ("-v ID\t", "DHCP Vendor ID (code 60) submitted in DHCP requests") -BAREBOX_CMD_HELP_OPT ("-c ID\t", "DHCP Client ID (code 61) submitted in DHCP requests") -BAREBOX_CMD_HELP_OPT ("-u UUID\t", "DHCP Client UUID (code 97) submitted in DHCP requests") -BAREBOX_CMD_HELP_OPT ("-U CLASS", "DHCP User class (code 77) submitted in DHCP requests") -BAREBOX_CMD_HELP_OPT ("-r RETRY", "retry limit (default 20)"); -BAREBOX_CMD_HELP_END - -BAREBOX_CMD_START(dhcp) - .cmd = do_dhcp, - BAREBOX_CMD_DESC("DHCP client to obtain IP or boot params") - BAREBOX_CMD_OPTS("[-HvcuUr]") - BAREBOX_CMD_GROUP(CMD_GRP_NET) - BAREBOX_CMD_HELP(cmd_dhcp_help) - BAREBOX_CMD_COMPLETE(empty_complete) -BAREBOX_CMD_END +#ifdef CONFIG_GLOBALVAR +static void dhcp_global_add(const char *var) +{ + char *var_global = asprintf("dhcp.%s", var); + + if (!var_global) + return; + + globalvar_add_simple(var_global, NULL); + free(var_global); +} + +static int dhcp_global_init(void) +{ + struct dhcp_opt *opt; + struct dhcp_param *param; + int i; + + for (i = 0; i < ARRAY_SIZE(dhcp_options); i++) { + opt = &dhcp_options[i]; + + if (!opt->barebox_dhcp_global) + continue; + + dhcp_global_add(opt->barebox_dhcp_global); + } + + for (i = 0; i < ARRAY_SIZE(dhcp_params); i++) { + param = &dhcp_params[i]; + + if (!param->barebox_dhcp_global) + continue; + + dhcp_global_add(param->barebox_dhcp_global); + } + + return 0; +} +late_initcall(dhcp_global_init); BAREBOX_MAGICVAR_NAMED(global_dhcp_bootfile, global.dhcp.bootfile, "bootfile returned from DHCP request"); BAREBOX_MAGICVAR_NAMED(global_dhcp_rootpath, global.dhcp.rootpath, "rootpath returned from DHCP request"); @@ -814,3 +776,4 @@ BAREBOX_MAGICVAR_NAMED(global_dhcp_user_class, global.dhcp.user_class, "user cla BAREBOX_MAGICVAR_NAMED(global_dhcp_tftp_server_name, global.dhcp.tftp_server_name, "TFTP server Name returned from DHCP request"); BAREBOX_MAGICVAR_NAMED(global_dhcp_oftree_file, global.dhcp.oftree_file, "OF tree returned from DHCP request (option 224)"); BAREBOX_MAGICVAR_NAMED(global_dhcp_retries, global.dhcp.retries, "retry limit"); +#endif @@ -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/.gitignore b/scripts/.gitignore index 6203589fe3..533bffd97d 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -24,3 +24,4 @@ bareboxstate-target mk-am35xx-spi-image mxsimage mxsboot +mxs-usb-loader diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 57426d0302..e991f33691 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -388,10 +388,10 @@ quiet_cmd_ln = LN $@ cmd_ln = ln -sf $< $@ # Check size of a file -quiet_cmd_check_file_size = CHKSIZE $@ +quiet_cmd_check_file_size = CHKSIZE $2 cmd_check_file_size = set -e; \ - size=`stat -c%s $@`; \ - max_size=`printf "%d" $2`; \ + size=`stat -c%s $2`; \ + max_size=`printf "%d" $3`; \ if [ $$size -gt $$max_size ] ; \ then \ echo "$@ size $$size > of the maximum size $$max_size" >&2; \ diff --git a/scripts/coccinelle/misc/altera_sequencer.cocci b/scripts/coccinelle/misc/altera_sequencer.cocci index 9fea239c0c..2350e841c0 100644 --- a/scripts/coccinelle/misc/altera_sequencer.cocci +++ b/scripts/coccinelle/misc/altera_sequencer.cocci @@ -1,7 +1,8 @@ @r_shadow@ +type T; @@ -- ...curr_shadow_reg = 0; +- static T curr_shadow_reg = 0; @r_out2_delay@ type T; diff --git a/scripts/imx/Makefile b/scripts/imx/Makefile index be0b490108..ee0acc1514 100644 --- a/scripts/imx/Makefile +++ b/scripts/imx/Makefile @@ -6,5 +6,7 @@ always := $(hostprogs-y) HOSTCFLAGS_imx-usb-loader.o = `pkg-config --cflags libusb-1.0` HOSTLOADLIBES_imx-usb-loader = `pkg-config --libs libusb-1.0` +HOSTCFLAGS_imx-image.o = -I$(srctree) + imx-usb-loader-objs := imx-usb-loader.o imx-image-objs := imx-image.o diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index 25ea4d8d1b..e765c1d3d6 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -27,6 +27,8 @@ #include <fcntl.h> #include <endian.h> +#include <include/filetype.h> + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) @@ -91,9 +93,12 @@ static int add_header_v1(void *buf, int offset, uint32_t loadaddr, uint32_t imag { struct imx_flash_header *hdr; int dcdsize = curdcd * sizeof(uint32_t); + uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET; - if (add_barebox_header) + if (add_barebox_header) { memcpy(buf, bb_header, sizeof(bb_header)); + *psize = imagesize; + } buf += offset; hdr = buf; @@ -177,6 +182,7 @@ static int add_header_v2(void *buf, int offset, uint32_t loadaddr, uint32_t imag { struct imx_flash_header_v2 *hdr; int dcdsize = curdcd * sizeof(uint32_t); + uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET; if (add_barebox_header) memcpy(buf, bb_header, sizeof(bb_header)); @@ -201,6 +207,9 @@ static int add_header_v2(void *buf, int offset, uint32_t loadaddr, uint32_t imag hdr->boot_data.size += CSF_LEN; } + if (add_barebox_header) + *psize = hdr->boot_data.size; + hdr->dcd_header.tag = TAG_DCD_HEADER; hdr->dcd_header.length = htobe16(sizeof(uint32_t) + dcdsize); hdr->dcd_header.version = DCD_VERSION; diff --git a/scripts/omap_signGP.c b/scripts/omap_signGP.c index 482cfac925..ac47fdf089 100644 --- a/scripts/omap_signGP.c +++ b/scripts/omap_signGP.c @@ -317,8 +317,15 @@ int main(int argc, char *argv[]) if (fwrite(&config_header, 1, 512, ofile) <= 0) pdie("fwrite"); + /* The size field in the header needs to include the + * size of the gp_header */ + len += sizeof(struct gp_header); + if (fwrite(&len, 1, 4, ofile) <= 0) pdie("fwrite"); + + len -= sizeof(struct gp_header); + if (fwrite(&loadaddr, 1, 4, ofile) <= 0) pdie("fwrite"); for (i = 0; i < len; i++) { diff --git a/scripts/socfpga_get_sequencer b/scripts/socfpga_get_sequencer index 5e4eb2d0c4..fb0ea6628b 100755 --- a/scripts/socfpga_get_sequencer +++ b/scripts/socfpga_get_sequencer @@ -49,6 +49,14 @@ copy_source() { echo " Running coccinelle cleanups..." spatch -sp_file scripts/coccinelle/misc/altera_sequencer.cocci -in_place arch/arm/mach-socfpga/include/mach + + echo " Cleanup header..." + sed -i 's/^static void rw_mgr_mem_calibrate_eye_diag_aid(void);$//g' $tgt + sed -i 's/^static void rw_mgr_load_mrs_calib(void);$//g' $tgt + sed -i 's/^static void rw_mgr_load_mrs_exec(void);$//g' $tgt + sed -i 's/^static void scc_mgr_set_group_dqs_io_and_oct_out2_gradual(uint32_t write_group, uint32_t delay);$//g' $tgt + sed -i 's/^static void rw_mgr_incr_vfifo_auto(uint32_t grp);$//g' $tgt + sed -i 's/^static void rw_mgr_decr_vfifo_auto(uint32_t grp);$//g' $tgt } copy_source ${ubootsrc}/board/altera/socfpga/sdram/sequencer.c arch/arm/mach-socfpga/include/mach/sequencer.c diff --git a/scripts/socfpga_sequencer_defines_defaults b/scripts/socfpga_sequencer_defines_defaults index 19b12b1142..3ad1f588f6 100755 --- a/scripts/socfpga_sequencer_defines_defaults +++ b/scripts/socfpga_sequencer_defines_defaults @@ -33,6 +33,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define DYNAMIC_CALIBRATION_MODE 0 #define DISABLE_GUARANTEED_READ 0 +#define AP_MODE 0 +#define ADVANCED_ODT_CONTROL 0 #define ARRIAVGZ 0 #define ARRIAV 0 #define AVL_CLK_FREQ 67 @@ -56,6 +58,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define ENABLE_INST_ROM_WRITE 1 #define ENABLE_MARGIN_REPORT_GEN 0 #define ENABLE_NON_DESTRUCTIVE_CALIB 0 +#define ENABLE_NON_DES_CAL 0 +#define ENABLE_NON_DES_CAL_TEST 0 #define ENABLE_SUPER_QUICK_CALIBRATION 0 #define ENABLE_TCL_DEBUG 0 #define FAKE_CAL_FAIL 0 |