From sha at pengutronix.de  Mon Jan  3 00:06:37 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 3 Jan 2022 09:06:37 +0100
Subject: [PATCH v2 0/8] video: ssd1307fb: Add SPI support
In-Reply-To: <20211223160404.119970-1-m.tretter@pengutronix.de>
References: <20211223160404.119970-1-m.tretter@pengutronix.de>
Message-ID: <20220103080637.GD6003@pengutronix.de>

On Thu, Dec 23, 2021 at 05:03:56PM +0100, Michael Tretter wrote:
> Hello,
> 
> The Solomon single-chip CMOS OLED/PLED driver with controller can be connected
> to I2C or SPI. The driver already supports I2C. This series adds support for
> SPI connected displays to the driver.
> 
> The bindings for the SPI connected display are still not documented. The
> driver uses the (undocumented) solomon,ssd1306 compatible of the staging
> driver in Linux, but uses properties defined for the solomon,ssd1306fb-i2c
> compatible of the I2C driver. I moved the warning about the compatible from
> the commit message into the driver to have it in the same place as the use of
> the compatible and to allow to eventually remove it.
> 
> The driver still allows to use SPI and I2C with its own hand-rolled
> abstraction, because the controller does not actually expose registers, but
> simply accepts commands or data. I followed Ahmad's suggestions how to remove
> the ugly #ifdefs and the driver looks a lot nicer now.
> 
> Patches 1-3 adjust the SPI and I2C frameworks to make them nicer to use for
> drivers that support devices that may be connected via SPI or I2C.
> 
> Patches 4-7 refactor the driver to have fewer locations that refer to I2C to
> simplify disabling the I2C support.
> 
> Patch 8 actually adds the SPI support and makes I2C optional.
> 
> Michael
> 
> ---
> 
> Changelog:
> 
> v2:
> 
> - add new Patches 1-3 for the SPI and I2C frameworks
> - use new SPI and I2C helpers to get rid of use of config macros
> - move warning about undocumented compatible into driver
> 
> Michael Tretter (8):
>   spi: stub device_spi_driver if SPI is disabled
>   spi: add to_spi_device helper
>   i2c: stub device_i2c_driver if I2C is disabled
>   video: ssd1307fb: pass par instead of i2c client to write
>   video: ssd1307fb: don't use i2c client for logging
>   video: ssd1307fb: move i2c setup to single place
>   video: ssd1307fb: use function pointer for write
>   video: ssd1307fb: add spi support

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan  3 00:07:54 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 3 Jan 2022 09:07:54 +0100
Subject: [PATCH] arm: mvebu: Replace license and copyright boilerplate by
 SPDX identifiers
In-Reply-To: <20211230143145.68650-1-u.kleine-koenig@pengutronix.de>
References: <20211230143145.68650-1-u.kleine-koenig@pengutronix.de>
Message-ID: <20220103080754.GE6003@pengutronix.de>

On Thu, Dec 30, 2021 at 03:31:45PM +0100, Uwe Kleine-K?nig wrote:
> Converts the files that licensecheck can determine to be licensed under
> GPL-2.0-only or GPL-2.0-or-later and also convert their copyright
> statements to SPDX.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig at pengutronix.de>
> ---
>  arch/arm/mach-mvebu/armada-370-xp.c           | 17 ++---------------
>  arch/arm/mach-mvebu/common.c                  | 19 +++----------------
>  arch/arm/mach-mvebu/dove.c                    | 17 ++---------------
>  .../include/mach/armada-370-xp-regs.h         | 17 ++---------------
>  arch/arm/mach-mvebu/include/mach/common.h     | 19 +++----------------
>  arch/arm/mach-mvebu/include/mach/debug_ll.h   | 17 ++---------------
>  arch/arm/mach-mvebu/include/mach/dove-regs.h  | 17 ++---------------
>  .../mach-mvebu/include/mach/kirkwood-regs.h   | 17 ++---------------
>  arch/arm/mach-mvebu/include/mach/lowlevel.h   | 19 +++----------------
>  arch/arm/mach-mvebu/include/mach/socid.h      | 17 +++--------------
>  arch/arm/mach-mvebu/kirkwood.c                | 16 ++--------------
>  11 files changed, 26 insertions(+), 166 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Mon Jan  3 00:10:39 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 3 Jan 2022 09:10:39 +0100
Subject: [PATCH] rtc: import pcf85363 support from linux-5.12
In-Reply-To: <20211226163755.204465-1-antonynpavlov@gmail.com>
References: <20211226163755.204465-1-antonynpavlov@gmail.com>
Message-ID: <20220103081039.GF6003@pengutronix.de>

On Sun, Dec 26, 2021 at 07:37:55PM +0300, Antony Pavlov wrote:
> Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
> ---
>  drivers/rtc/Kconfig        |   6 ++
>  drivers/rtc/Makefile       |   1 +
>  drivers/rtc/rtc-pcf85363.c | 169 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 176 insertions(+)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan  3 01:05:45 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 3 Jan 2022 10:05:45 +0100
Subject: [PATCH] watchdog: imxwd: suspend watchdog timer in low power mode
In-Reply-To: <20211216122653.2335949-1-andrej.picej@norik.com>
References: <20211216122653.2335949-1-andrej.picej@norik.com>
Message-ID: <20220103090545.GG6003@pengutronix.de>

On Thu, Dec 16, 2021 at 01:26:53PM +0100, Andrej Picej wrote:
> Watchdog timer should be disabled in low power mode. The problem that
> was observed was that when the watchdog is started from barebox, kernel
> driver doesn't do its own setup again and in turn this bit is left
> unset. Moreover, this bit is write-once and has to be set before
> enabling the watchdog, leaving responsibility for proper setup to a
> party first using the watchdog timer (e.g. bootloader). Issue manifests
> itself later on, when device enters low power mode (e.g. suspend) for
> more amount of time than what is maximum watchdog timeout (128s). After
> that period of time, device will not recover ever as there is no service
> patting the watchdog (CPU is suspended). This means that the device can
> hang in suspend mode or it performs an unexpected reset.
> 
> Thus to avoid suspend/resume problems when watchdog is started already
> in the bootloader, align bootloader driver settings with kernel settings.
> Kernel driver has been already setting this bit since 2014.
> 
> Signed-off-by: Andrej Picej <andrej.picej at norik.com>
> ---
>  drivers/watchdog/imxwd.c | 4 ++++
>  1 file changed, 4 insertions(+)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan  3 02:25:47 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 3 Jan 2022 11:25:47 +0100
Subject: [PATCH master] RISC-V: cpu: fix build with
 CONFIG_RISCV_EXCEPTIONS=n
In-Reply-To: <20211207090615.GF28260@pengutronix.de>
References: <20211204130854.1624493-1-ahmad@a3f.at>
 <20211207090615.GF28260@pengutronix.de>
Message-ID: <d7b38b7a-e6ef-d96d-557d-1fa25a979276@pengutronix.de>

Hello Sascha,

On 07.12.21 10:06, Sascha Hauer wrote:
> On Sat, Dec 04, 2021 at 02:08:54PM +0100, Ahmad Fatoum wrote:
>> Building without CONFIG_RISCV_EXCEPTIONS causes a compile error, because
>> of a definition mismatch. data_abort_mask is a no-op without exception
>> support, but interrupt.c defines it as a different type of symbol. Skip
>> interrupt.c compilation to fix the build error.

I don't find this patch in either master or next.
Can you push it?

Thanks,
Ahmad

>>
>> Reported-by: Yann Sionneau <ysionneau at kalray.eu>
>> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
>> ---
>>  arch/riscv/cpu/Makefile | 2 ++
>>  1 file changed, 2 insertions(+)
> 
> Applied, thanks
> 
> Sascha
> 
>>
>> diff --git a/arch/riscv/cpu/Makefile b/arch/riscv/cpu/Makefile
>> index 717baaaaa727..d79bafc6f142 100644
>> --- a/arch/riscv/cpu/Makefile
>> +++ b/arch/riscv/cpu/Makefile
>> @@ -2,6 +2,8 @@
>>  
>>  obj-y += core.o time.o
>>  obj-$(CONFIG_HAS_DMA) += dma.o
>> +ifeq ($(CONFIG_RISCV_EXCEPTIONS),y)
>>  obj-pbl-$(CONFIG_RISCV_M_MODE) += mtrap.o
>>  obj-pbl-$(CONFIG_RISCV_S_MODE) += strap.o
>>  obj-pbl-y += interrupts.o
>> +endif
>> -- 
>> 2.33.0
>>
>>
>> _______________________________________________
>> barebox mailing list
>> barebox at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/barebox
>>
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan  3 02:27:54 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 3 Jan 2022 11:27:54 +0100
Subject: [PATCH] state: make first boot with uninitialized legacy state
 less verbose
In-Reply-To: <93265eaa-3a16-9253-b6f5-35dae8a9f3ab@pengutronix.de>
References: <20211129072235.2016324-1-ahmad@a3f.at>
 <20211130102302.GP28260@pengutronix.de>
 <93265eaa-3a16-9253-b6f5-35dae8a9f3ab@pengutronix.de>
Message-ID: <2ed28579-71e0-a0ec-e36a-c83c81bd97c2@pengutronix.de>

Hello Sascha,

On 30.11.21 11:39, Ahmad Fatoum wrote:
> Hello Sascha,
> 
> On 30.11.21 11:23, Sascha Hauer wrote:
>> On Mon, Nov 29, 2021 at 08:22:35AM +0100, Ahmad Fatoum wrote:
>>> With non-legacy state, barebox checks a header for a specific magic
>>> signature. This can be all zero on an uninitialized state, so in that
>>> particular case, bump down the log message severity.
>>>
>>> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
>>> ---
>>> Applies on top of https://lore.barebox.org/barebox/20211125161042.3829996-3-a.fatoum at pengutronix.de/
> 
> Yes, please see ^ first.

Is this ok for next?

Cheers,
Ahmad

> 
>>> ---
>>>  common/state/backend_bucket_direct.c | 4 ++--
>>>  common/state/backend_storage.c       | 7 +++++--
>>>  2 files changed, 7 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c
>>> index 517aec60634b..117cdfb46c9e 100644
>>> --- a/common/state/backend_bucket_direct.c
>>> +++ b/common/state/backend_bucket_direct.c
>>> @@ -76,9 +76,9 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket
>>>  		if (meta.magic != ~0 && !!meta.magic)
>>>  			bucket->wrong_magic = 1;
>>>  		if (!IS_ENABLED(CONFIG_STATE_BACKWARD_COMPATIBLE)) {
>>> -			dev_err(direct->dev, "No meta data header found\n");
>>>  			dev_dbg(direct->dev, "Enable backward compatibility or increase stride size\n");
>>> -			return -EINVAL;
>>> +			return dev_err_state_init(direct->dev, meta.magic ? -EINVAL : -ENOMEDIUM,
>>> +						  "No meta data header found\n");
>>
>> What is dev_err_state_init()? I don't have that in my tree.
>>
>>>  		}
>>>  		read_len = direct->max_size;
>>>  		if (lseek(direct->fd, direct->offset, SEEK_SET) !=
>>> diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c
>>> index 72f8bcf521ad..c55d22e37f70 100644
>>> --- a/common/state/backend_storage.c
>>> +++ b/common/state/backend_storage.c
>>> @@ -156,10 +156,13 @@ int state_storage_read(struct state_backend_storage *storage,
>>>  		totalbuckets++;
>>>  
>>>  		ret = bucket->read(bucket, &bucket->buf, &bucket->len);
>>> -		if (ret == -EUCLEAN)
>>> +		if (ret == -EUCLEAN) {
>>>  			bucket->needs_refresh = 1;
>>> -		else if (ret)
>>> +		} else if (ret) {
>>> +			if (ret == -ENOMEDIUM)
>>> +				zerobuckets++;
>>
>> This variable also does not exist. Does this patch depend on other
>> patches?
> 
> It does. I
> 
>>
>> Sascha
>>
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan  3 02:40:57 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 3 Jan 2022 11:40:57 +0100
Subject: [PATCH 1/3] vsprintf: add support for printing raw buffers as hex
 (%*ph)
In-Reply-To: <20211214072747.GM6003@pengutronix.de>
References: <20211209105708.3517684-1-a.fatoum@pengutronix.de>
 <20211213222808.GL6003@pengutronix.de>
 <6780849f-e1f9-fdae-ffb6-02cdde4cdb55@pengutronix.de>
 <20211214072747.GM6003@pengutronix.de>
Message-ID: <92020314-afcc-e694-e12c-07399f0747c8@pengutronix.de>

Hello Sascha,

On 14.12.21 08:27, Sascha Hauer wrote:
> On Tue, Dec 14, 2021 at 07:57:01AM +0100, Ahmad Fatoum wrote:
>> On 13.12.21 23:28, Sascha Hauer wrote:
>>> On Thu, Dec 09, 2021 at 11:57:06AM +0100, Ahmad Fatoum wrote:
>>>> Import from Linux support for printing buffers as a hex string
>>>> with a certain separator. For larger buffers consider using
>>>> print_hex_dump(). Examples:
>>>>
>>>>   %*ph	00 01 02  ...  3f
>>>>   %*phC	00:01:02: ... :3f
>>>>   %*phD	00-01-02- ... -3f
>>>>   %*phN	000102 ... 3f
>>>>
>>>> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
>>>> ---
>>>>  lib/Kconfig    |  3 +++
>>>>  lib/vsprintf.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  2 files changed, 53 insertions(+)
>>>>
>>>> diff --git a/lib/Kconfig b/lib/Kconfig
>>>> index 718033e56e64..27e7bea6852f 100644
>>>> --- a/lib/Kconfig
>>>> +++ b/lib/Kconfig
>>>> @@ -166,6 +166,9 @@ config PRINTF_UUID
>>>>  config PRINTF_WCHAR
>>>>  	bool
>>>>  
>>>> +config PRINTF_HEXSTR
>>>> +	bool
>>>
>>> So hexdumps are silently ignored when this option is disabled. Not sure
>>> if this should really be configurable, but I think when it is
>>> configurable it should be default y to avoid surprises.
>>
>> It will be printed as a raw pointer when the option is disabled.
>> There's no code in-tree that uses this format specifier yet,
>> so I prefer to not make this the default and increase binary size.
> 
> Ok for now, but we should revise it once this actually gets used.

This is still left after a rebase.

Cheers,
Ahmad

> 
> Sascha
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan  3 03:57:13 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:57:13 +0100
Subject: [PATCH master 0/5] misc fixes
Message-ID: <20220103115718.1723730-1-a.fatoum@pengutronix.de>

Collection of fixes for master.

Ahmad Fatoum (4):
  pwm: atmel: point MMIO accesses at correct address
  clk: fixed: record parent name in clk_register_fixed_rate
  imx-bbu-nand-fcb: suppress compiler warning about uninitialized use
  regulator: fix broken reference counting on disable

Enrico Jorns (1):
  regulator: respect "regulator-always-on" property

 common/imx-bbu-nand-fcb.c | 2 +-
 drivers/clk/clk-fixed.c   | 4 ++++
 drivers/pwm/pwm-atmel.c   | 2 +-
 drivers/regulator/core.c  | 8 +++++++-
 include/regulator.h       | 3 ++-
 5 files changed, 15 insertions(+), 4 deletions(-)

-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:57:15 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:57:15 +0100
Subject: [PATCH master 2/5] clk: fixed: record parent name in
 clk_register_fixed_rate
In-Reply-To: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115718.1723730-3-a.fatoum@pengutronix.de>

parent_names is allocated, but only populated with zeroes. Fix this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk-fixed.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/clk/clk-fixed.c b/drivers/clk/clk-fixed.c
index b961c382ec22..e813f31d76d9 100644
--- a/drivers/clk/clk-fixed.c
+++ b/drivers/clk/clk-fixed.c
@@ -45,6 +45,10 @@ struct clk *clk_register_fixed_rate(const char *name,
 		if (!parent_names)
 			return ERR_PTR(-ENOMEM);
 
+		parent_names[0] = strdup(parent_name);
+		if (!parent_names[0])
+			return ERR_PTR(-ENOMEM);
+
 		fix->hw.clk.parent_names = parent_names;
 		fix->hw.clk.num_parents = 1;
 	}
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:57:14 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:57:14 +0100
Subject: [PATCH master 1/5] pwm: atmel: point MMIO accesses at correct address
In-Reply-To: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115718.1723730-2-a.fatoum@pengutronix.de>

The base address for MMIO writes was the address of the resource struct,
not the start address pointed at by it.

Change untested, but it doesn't look like this driver could ever have
worked.

Cc: Sam Ravnborg <sam at ravnborg.org>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/pwm/pwm-atmel.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 7819d321d387..648f75fb7292 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -256,7 +256,7 @@ static int atmel_pwm_probe(struct device_d *dev)
 	if (IS_ERR(res))
 		return PTR_ERR(res);
 
-	atmel_pwm->base = IOMEM(res);
+	atmel_pwm->base = IOMEM(res->start);
 
 	for (i = 0; i < PWM_CHANNELS; i++) {
 		struct atmel_pwm_chip *chip = &atmel_pwm->atmel_pwm_chip[i];
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:57:18 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:57:18 +0100
Subject: [PATCH master 5/5] regulator: respect "regulator-always-on" property
In-Reply-To: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115718.1723730-6-a.fatoum@pengutronix.de>

From: Enrico Jorns <ejo at pengutronix.de>

As barebox ignored this property, a regulator could have been disabled
even if it should not have been.
By taking the same path as for 'regulator-boot-on', we ensure always
holding an enable count > 0 on the regulator.

Signed-off-by: Enrico Jorns <ejo at pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/regulator/core.c | 3 ++-
 include/regulator.h      | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ac4141c1cdbf..b2e5f8caa2ca 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -130,7 +130,7 @@ static struct regulator_internal * __regulator_register(struct regulator_dev *rd
 	if (name)
 		ri->name = xstrdup(name);
 
-	if (rd->boot_on) {
+	if (rd->boot_on && rd->always_on) {
 		ret = regulator_enable_internal(ri);
 		if (ret && ret != -ENOSYS)
 			goto err;
@@ -163,6 +163,7 @@ int of_regulator_register(struct regulator_dev *rd, struct device_node *node)
 		return -EINVAL;
 
 	rd->boot_on = of_property_read_bool(node, "regulator-boot-on");
+	rd->always_on = of_property_read_bool(node, "regulator-always-on");
 
 	name = of_get_property(node, "regulator-name", NULL);
 
diff --git a/include/regulator.h b/include/regulator.h
index bbe8dd91d84b..dfdfbf033262 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -84,7 +84,8 @@ struct regulator_desc {
 struct regulator_dev {
 	const struct regulator_desc *desc;
 	struct regmap *regmap;
-	int boot_on;
+	bool boot_on;
+	bool always_on;
 	/* the device this regulator device belongs to */
 	struct device_d *dev;
 };
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:57:16 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:57:16 +0100
Subject: [PATCH master 3/5] imx-bbu-nand-fcb: suppress compiler warning about
 uninitialized use
In-Reply-To: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115718.1723730-4-a.fatoum@pengutronix.de>

fw_orig_len is selectively initialized in read_firmware_all. In case
it's left uninitialized, fw_orig will keep it's initial value of NULL.
fw_orig is checked before fw_orig_len use, so there is no use of an
uninitialized variable in practice, but GCC 11.1.1 warns about it
anyway. Give it an initial value of 0 to silence the warning.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/imx-bbu-nand-fcb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index 3b07d539ee6e..bde0b227f81c 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -1155,7 +1155,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 	enum filetype filetype;
 	unsigned num_blocks_fw, fw_size;
 	int used = 0;
-	int fw_orig_len;
+	int fw_orig_len = 0;
 	int used_refresh = 0, unused_refresh = 0;
 
 	if (data->image) {
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:57:17 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:57:17 +0100
Subject: [PATCH master 4/5] regulator: fix broken reference counting on disable
In-Reply-To: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115718.1723730-5-a.fatoum@pengutronix.de>

Reference count is maintained correctly when enabling, but the very
first disable will ignore the reference count and disable the regulator
unconditionally. Make disable with an enable_count > 1 a no-op to fix
this.

Reported-by: Enrico Jorns <ejo at pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/regulator/core.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index d1d3a36dfc8d..ac4141c1cdbf 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -71,6 +71,11 @@ static int regulator_disable_internal(struct regulator_internal *ri)
 	if (!ri->enable_count)
 		return -EINVAL;
 
+	if (ri->enable_count > 1) {
+		ri->enable_count--;
+		return 0;
+	}
+
 	if (!ri->rdev->desc->ops->disable)
 		return -ENOSYS;
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:58:22 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:58:22 +0100
Subject: [PATCH 2/4] include: spinlock.h: define dummy for DEFINE_SPINLOCK
In-Reply-To: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
References: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115824.1725086-3-a.fatoum@pengutronix.de>

This allows easier porting of code that uses spinlocks.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/linux/spinlock.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index b32114f4f070..7d011785eda7 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -8,4 +8,6 @@ typedef int   spinlock_t;
 #define spin_lock_irqsave(lock, flags) do { flags = 0; } while (0)
 #define spin_unlock_irqrestore(lock, flags) do { flags = flags; } while (0)
 
+#define DEFINE_SPINLOCK(lock) spinlock_t lock
+
 #endif /* __LINUX_SPINLOCK_H */
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:58:23 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:58:23 +0100
Subject: [PATCH 3/4] include: <linux/compiler.h>: delete __ADDRESSABLE macro
In-Reply-To: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
References: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115824.1725086-4-a.fatoum@pengutronix.de>

The macro is non-functional, because it requires linker script changes.
Instead of doing those and risking breakage, just drop it. These can be
done when the macro is actually needed.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/linux/compiler.h | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index f61a45841470..6654c164f594 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -276,16 +276,6 @@ unsigned long read_word_at_a_time(const void *addr)
 
 #endif /* __KERNEL__ */
 
-/*
- * Force the compiler to emit 'sym' as a symbol, so that we can reference
- * it from inline assembler. Necessary in case 'sym' could be inlined
- * otherwise, or eliminated entirely due to lack of references that are
- * visible to the compiler.
- */
-#define __ADDRESSABLE(sym) \
-	static void * __attribute__((section(".discard.addressable"), used)) \
-		__PASTE(__addressable_##sym, __LINE__) = (void *)&sym;
-
 /**
  * offset_to_ptr - convert a relative memory offset to an absolute pointer
  * @off:	the address of the 32-bit offset value
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:58:20 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:58:20 +0100
Subject: [PATCH 0/4] include: misc clean up
Message-ID: <20220103115824.1725086-1-a.fatoum@pengutronix.de>

Ahmad Fatoum (4):
  include: <linux/overflow.h>: add missing include
  include: spinlock.h: define dummy for DEFINE_SPINLOCK
  include: <linux/compiler.h>: delete __ADDRESSABLE macro
  x86: remove reference to empty file

 arch/x86/mach-efi/include/mach/barebox.lds.h |  1 -
 include/asm-generic/barebox.lds.h            |  3 +--
 include/linux/compiler.h                     | 10 ----------
 include/linux/overflow.h                     |  1 +
 include/linux/spinlock.h                     |  2 ++
 5 files changed, 4 insertions(+), 13 deletions(-)
 delete mode 100644 arch/x86/mach-efi/include/mach/barebox.lds.h

-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:58:21 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:58:21 +0100
Subject: [PATCH 1/4] include: <linux/overflow.h>: add missing include
In-Reply-To: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
References: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115824.1725086-2-a.fatoum@pengutronix.de>

SIZE_MAX needs to be defined for functions defined inline within the
header. Include appropriate header.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/linux/overflow.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/overflow.h b/include/linux/overflow.h
index 659045046468..50c93ca0c3d6 100644
--- a/include/linux/overflow.h
+++ b/include/linux/overflow.h
@@ -3,6 +3,7 @@
 #define __LINUX_OVERFLOW_H
 
 #include <linux/compiler.h>
+#include <linux/limits.h>
 
 /*
  * In the fallback code below, we need to compute the minimum and
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 03:58:24 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 12:58:24 +0100
Subject: [PATCH 4/4] x86: remove reference to empty file
In-Reply-To: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
References: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
Message-ID: <20220103115824.1725086-5-a.fatoum@pengutronix.de>

This might have been needed in the past when there was legacy boot
machine support. Now there isn't, so we can just delete it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/x86/mach-efi/include/mach/barebox.lds.h | 1 -
 include/asm-generic/barebox.lds.h            | 3 +--
 2 files changed, 1 insertion(+), 3 deletions(-)
 delete mode 100644 arch/x86/mach-efi/include/mach/barebox.lds.h

diff --git a/arch/x86/mach-efi/include/mach/barebox.lds.h b/arch/x86/mach-efi/include/mach/barebox.lds.h
deleted file mode 100644
index 40a8c178f10d..000000000000
--- a/arch/x86/mach-efi/include/mach/barebox.lds.h
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h
index c5f9d975472a..a03655d41cc4 100644
--- a/include/asm-generic/barebox.lds.h
+++ b/include/asm-generic/barebox.lds.h
@@ -6,8 +6,7 @@
 #define STRUCT_ALIGNMENT 32
 #define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
 
-#if defined CONFIG_X86 || \
-	defined CONFIG_ARCH_EP93XX
+#if defined CONFIG_ARCH_EP93XX
 #include <mach/barebox.lds.h>
 #endif
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:00:15 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:00:15 +0100
Subject: [PATCH] i2c: add Rockchip i2c controller support
Message-ID: <20220103120015.1727051-1-a.fatoum@pengutronix.de>

For addressing the PMIC on Rockchip platforms, add an i2c controller
driver. Tested with rk3399 and rk808.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/i2c/busses/Kconfig        |   8 +
 drivers/i2c/busses/Makefile       |   1 +
 drivers/i2c/busses/i2c-rockchip.c | 472 ++++++++++++++++++++++++++++++
 3 files changed, 481 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-rockchip.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c1e76a04096e..a551df537a69 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -62,4 +62,12 @@ config I2C_STM32
 	depends on HAVE_CLK
 	depends on ARCH_STM32MP || COMPILE_TEST
 
+config I2C_RK3X
+	tristate "Rockchip RK3xxx I2C adapter"
+	depends on HAVE_CLK
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	help
+	  Say Y here to include support for the I2C adapter in Rockchip RK3xxx
+	  SoCs.
+
 endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 34a12fcbea96..d6273f3d8679 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
 obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o
 obj-$(CONFIG_I2C_STM32)		+= i2c-stm32.o
+obj-$(CONFIG_I2C_RK3X)		+= i2c-rockchip.o
diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
new file mode 100644
index 000000000000..ba7397b19967
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rockchip.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ * Peter, Software Engineering, <superpeter.cai at gmail.com>.
+ */
+
+#include <common.h>
+#include <i2c/i2c.h>
+#include <linux/iopoll.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <driver.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+#include <linux/sizes.h>
+
+struct i2c_regs {
+	u32 con;
+	u32 clkdiv;
+	u32 mrxaddr;
+	u32 mrxraddr;
+	u32 mtxcnt;
+	u32 mrxcnt;
+	u32 ien;
+	u32 ipd;
+	u32 fcnt;
+	u32 reserved0[0x37];
+	u32 txdata[8];
+	u32 reserved1[0x38];
+	u32 rxdata[8];
+};
+
+/* Control register */
+#define I2C_CON_EN		(1 << 0)
+#define I2C_CON_MOD(mod)	((mod) << 1)
+#define I2C_MODE_TX		0x00
+#define I2C_MODE_TRX		0x01
+#define I2C_MODE_RX		0x02
+#define I2C_MODE_RRX		0x03
+#define I2C_CON_MASK		(3 << 1)
+
+#define I2C_CON_START		(1 << 3)
+#define I2C_CON_STOP		(1 << 4)
+#define I2C_CON_LASTACK		(1 << 5)
+#define I2C_CON_ACTACK		(1 << 6)
+
+/* Clock dividor register */
+#define I2C_CLKDIV_VAL(divl, divh) \
+	(((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))
+
+/* the slave address accessed  for master rx mode */
+#define I2C_MRXADDR_SET(vld, addr)	(((vld) << 24) | (addr))
+
+/* the slave register address accessed  for master rx mode */
+#define I2C_MRXRADDR_SET(vld, raddr)	(((vld) << 24) | (raddr))
+
+/* interrupt enable register */
+#define I2C_BTFIEN		(1 << 0)
+#define I2C_BRFIEN		(1 << 1)
+#define I2C_MBTFIEN		(1 << 2)
+#define I2C_MBRFIEN		(1 << 3)
+#define I2C_STARTIEN		(1 << 4)
+#define I2C_STOPIEN		(1 << 5)
+#define I2C_NAKRCVIEN		(1 << 6)
+
+/* interrupt pending register */
+#define I2C_BTFIPD              (1 << 0)
+#define I2C_BRFIPD              (1 << 1)
+#define I2C_MBTFIPD             (1 << 2)
+#define I2C_MBRFIPD             (1 << 3)
+#define I2C_STARTIPD            (1 << 4)
+#define I2C_STOPIPD             (1 << 5)
+#define I2C_NAKRCVIPD           (1 << 6)
+#define I2C_IPD_ALL_CLEAN       0x7f
+
+/* i2c timerout */
+#define I2C_TIMEOUT		(100 * MSECOND)
+#define I2C_RETRY_COUNT		3
+
+/* rk i2c fifo max transfer bytes */
+#define RK_I2C_FIFO_SIZE	32
+
+struct rk_i2c {
+	struct i2c_adapter	adapter;
+	struct clk *clk;
+	struct i2c_regs *regs;
+	unsigned int speed;
+};
+
+static inline struct rk_i2c *to_rk_i2c(struct i2c_adapter *adapter)
+{
+	return container_of(adapter, struct rk_i2c, adapter);
+}
+
+static inline void rk_i2c_get_div(int div, int *divh, int *divl)
+{
+	*divl = div / 2;
+	if (div % 2 == 0)
+		*divh = div / 2;
+	else
+		*divh = DIV_ROUND_UP(div, 2);
+}
+
+/*
+ * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
+ * SCL = PCLK / SCLK Divisor
+ * i2c_rate = PCLK
+ */
+static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
+{
+	struct device_d *dev = i2c->adapter.dev.parent;
+	uint32_t i2c_rate;
+	int div, divl, divh;
+
+	/* First get i2c rate from pclk */
+	i2c_rate = clk_get_rate(i2c->clk);
+
+	div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
+	divh = 0;
+	divl = 0;
+	if (div >= 0)
+		rk_i2c_get_div(div, &divh, &divl);
+	writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
+
+	dev_dbg(dev, "rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
+		scl_rate);
+	dev_dbg(dev, "set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
+	dev_dbg(dev, "set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
+}
+
+static void rk_i2c_show_regs(struct rk_i2c *i2c)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	int i;
+
+	dev_dbg(dev, "i2c_con: 0x%08x\n", readl(&regs->con));
+	dev_dbg(dev, "i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
+	dev_dbg(dev, "i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
+	dev_dbg(dev, "i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
+	dev_dbg(dev, "i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
+	dev_dbg(dev, "i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
+	dev_dbg(dev, "i2c_ien: 0x%08x\n", readl(&regs->ien));
+	dev_dbg(dev, "i2c_ipd: 0x%08x\n", readl(&regs->ipd));
+	dev_dbg(dev, "i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
+
+	for (i = 0; i < 8; i++)
+		dev_dbg(dev, "i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
+	for (i = 0; i < 8; i++)
+		dev_dbg(dev, "i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
+}
+
+static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	u64 start;
+
+	dev_dbg(dev, "I2c Send Start bit.\n");
+	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
+
+	writel(I2C_CON_EN | I2C_CON_START, &regs->con);
+	writel(I2C_STARTIEN, &regs->ien);
+
+	for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
+		if (readl(&regs->ipd) & I2C_STARTIPD) {
+			writel(I2C_STARTIPD, &regs->ipd);
+			return 0;
+		}
+		udelay(1);
+	}
+
+	dev_dbg(dev, "I2C Send Start Bit Timeout\n");
+	rk_i2c_show_regs(i2c);
+	return -ETIMEDOUT;
+}
+
+static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	u64 start;
+
+	dev_dbg(dev, "I2c Send Stop bit.\n");
+	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
+
+	writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
+	writel(I2C_CON_STOP, &regs->ien);
+
+	for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
+		if (readl(&regs->ipd) & I2C_STOPIPD) {
+			writel(I2C_STOPIPD, &regs->ipd);
+			return 0;
+		}
+		udelay(1);
+	}
+
+	dev_dbg(dev, "I2C Send Start Bit Timeout\n");
+	rk_i2c_show_regs(i2c);
+	return -ETIMEDOUT;
+}
+
+static inline void rk_i2c_disable(struct rk_i2c *i2c)
+{
+	writel(0, &i2c->regs->con);
+}
+
+static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
+		       uchar *buf, uint b_len)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	uchar *pbuf = buf;
+	uint bytes_remain_len = b_len;
+	uint bytes_xferred = 0;
+	uint words_xferred = 0;
+	u64 start;
+	uint con = 0;
+	uint rxdata;
+	uint i, j;
+	int err;
+	bool snd_chunk = false;
+
+	dev_dbg(dev, "rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
+	      chip, reg, r_len, b_len);
+
+	err = rk_i2c_send_start_bit(i2c);
+	if (err)
+		return err;
+
+	writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
+	if (r_len == 0) {
+		writel(0, &regs->mrxraddr);
+	} else if (r_len < 4) {
+		writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
+	} else {
+		dev_dbg(dev, "I2C Read: addr len %d not supported\n", r_len);
+		return -EIO;
+	}
+
+	while (bytes_remain_len) {
+		if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
+			con = I2C_CON_EN;
+			bytes_xferred = 32;
+		} else {
+			/*
+			 * The hw can read up to 32 bytes at a time. If we need
+			 * more than one chunk, send an ACK after the last byte.
+			 */
+			con = I2C_CON_EN | I2C_CON_LASTACK;
+			bytes_xferred = bytes_remain_len;
+		}
+		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
+
+		/*
+		 * make sure we are in plain RX mode if we read a second chunk
+		 */
+		if (snd_chunk)
+			con |= I2C_CON_MOD(I2C_MODE_RX);
+		else
+			con |= I2C_CON_MOD(I2C_MODE_TRX);
+
+		writel(con, &regs->con);
+		writel(bytes_xferred, &regs->mrxcnt);
+		writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
+
+		err = -ETIMEDOUT;
+		for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
+			if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
+				writel(I2C_NAKRCVIPD, &regs->ipd);
+				err = -EREMOTEIO;
+			}
+			if (readl(&regs->ipd) & I2C_MBRFIPD) {
+				writel(I2C_MBRFIPD, &regs->ipd);
+				err = 0;
+				break;
+			}
+			udelay(1);
+		}
+
+		if (err) {
+			dev_dbg(dev, "I2C Read Data Timeout\n");
+			rk_i2c_show_regs(i2c);
+			goto i2c_exit;
+		}
+
+		for (i = 0; i < words_xferred; i++) {
+			rxdata = readl(&regs->rxdata[i]);
+			dev_dbg(dev, "I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
+			for (j = 0; j < 4; j++) {
+				if ((i * 4 + j) == bytes_xferred)
+					break;
+				*pbuf++ = (rxdata >> (j * 8)) & 0xff;
+			}
+		}
+
+		bytes_remain_len -= bytes_xferred;
+		snd_chunk = true;
+		dev_dbg(dev, "I2C Read bytes_remain_len %d\n", bytes_remain_len);
+	}
+
+i2c_exit:
+	rk_i2c_disable(i2c);
+
+	return err;
+}
+
+static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
+			uchar *buf, uint b_len)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	int err;
+	uchar *pbuf = buf;
+	uint bytes_remain_len = b_len + r_len + 1;
+	uint bytes_xferred = 0;
+	uint words_xferred = 0;
+	u64 start;
+	uint txdata;
+	uint i, j;
+
+	dev_dbg(dev, "rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
+	      chip, reg, r_len, b_len);
+	err = rk_i2c_send_start_bit(i2c);
+	if (err)
+		return err;
+
+	while (bytes_remain_len) {
+		if (bytes_remain_len > RK_I2C_FIFO_SIZE)
+			bytes_xferred = RK_I2C_FIFO_SIZE;
+		else
+			bytes_xferred = bytes_remain_len;
+		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
+
+		for (i = 0; i < words_xferred; i++) {
+			txdata = 0;
+			for (j = 0; j < 4; j++) {
+				if ((i * 4 + j) == bytes_xferred)
+					break;
+
+				if (i == 0 && j == 0 && pbuf == buf) {
+					txdata |= (chip << 1);
+				} else if (i == 0 && j <= r_len && pbuf == buf) {
+					txdata |= (reg &
+						(0xff << ((j - 1) * 8))) << 8;
+				} else {
+					txdata |= (*pbuf++)<<(j * 8);
+				}
+			}
+			writel(txdata, &regs->txdata[i]);
+			dev_dbg(dev, "I2c Write TXDATA[%d] = 0x%08x\n", i, txdata);
+		}
+
+		writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
+		writel(bytes_xferred, &regs->mtxcnt);
+		writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
+
+		err = -ETIMEDOUT;
+		for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
+			if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
+				writel(I2C_NAKRCVIPD, &regs->ipd);
+				err = -EREMOTEIO;
+			}
+			if (readl(&regs->ipd) & I2C_MBTFIPD) {
+				writel(I2C_MBTFIPD, &regs->ipd);
+				err = 0;
+				break;
+			}
+			udelay(1);
+		}
+
+		if (err) {
+			dev_dbg(dev, "I2C Write Data Timeout\n");
+			rk_i2c_show_regs(i2c);
+			goto i2c_exit;
+		}
+
+		bytes_remain_len -= bytes_xferred;
+		dev_dbg(dev, "I2C Write bytes_remain_len %d\n", bytes_remain_len);
+	}
+
+i2c_exit:
+	rk_i2c_disable(i2c);
+
+	return err;
+}
+
+static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+			     int nmsgs)
+{
+	struct rk_i2c *i2c = to_rk_i2c(adapter);
+	struct device_d *dev = &adapter->dev;
+	int ret;
+
+	dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+		if (msg->flags & I2C_M_RD) {
+			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
+					  msg->len);
+		} else {
+			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
+					   msg->len);
+		}
+		if (ret) {
+			dev_dbg(dev, "i2c_write: error sending\n");
+			return -EREMOTEIO;
+		}
+	}
+
+	rk_i2c_send_stop_bit(i2c);
+	rk_i2c_disable(i2c);
+
+	return 0;
+}
+
+static int rk_i2c_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	struct resource *iores;
+	struct rk_i2c *i2c;
+	unsigned bitrate;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	i2c = kzalloc(sizeof(struct rk_i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	dev->priv = i2c;
+	i2c->regs = IOMEM(iores->start);
+
+	/* Only one clock to use for bus clock and peripheral clock */
+	i2c->clk = clk_get(dev, NULL);
+	if (IS_ERR(i2c->clk))
+		return dev_err_probe(dev, PTR_ERR(i2c->clk), "Can't get bus clk\n");
+
+	/* Setup i2c_fsl driver structure */
+	i2c->adapter.master_xfer = rockchip_i2c_xfer;
+	i2c->adapter.nr = dev->id;
+	i2c->adapter.dev.parent = dev;
+	i2c->adapter.dev.device_node = np;
+
+	/* Set up clock divider */
+	bitrate = 100000;
+	of_property_read_u32(np, "clock-frequency", &bitrate);
+
+	rk_i2c_set_clk(i2c, bitrate);
+
+	return i2c_add_numbered_adapter(&i2c->adapter);
+}
+
+static const struct of_device_id rk_i2c_match[] = {
+	{ .compatible = "rockchip,rv1108-i2c" },
+	{ .compatible = "rockchip,rk3228-i2c" },
+	{ .compatible = "rockchip,rk3288-i2c" },
+	{ .compatible = "rockchip,rk3399-i2c" },
+	{},
+};
+
+static struct driver_d rk_i2c_driver = {
+	.name  = "rk3x-i2c",
+	.of_compatible = rk_i2c_match,
+	.probe   = rk_i2c_probe,
+};
+coredevice_platform_driver(rk_i2c_driver);
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:02:05 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:02:05 +0100
Subject: [PATCH] parseopt: drop unused, duplicate, parseopt_u16
Message-ID: <20220103120205.1728778-1-a.fatoum@pengutronix.de>

We always have sizeof(unsigned short) == sizeof(uint16_t), so
parseopt_u16() is exactly equivalent to parseopt_hu().

The former is unused anyway, so just drop it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/parseopt.h |  1 -
 lib/parseopt.c     | 31 -------------------------------
 2 files changed, 32 deletions(-)

diff --git a/include/parseopt.h b/include/parseopt.h
index 5a40bdc219fe..a944c3655f77 100644
--- a/include/parseopt.h
+++ b/include/parseopt.h
@@ -6,7 +6,6 @@ void parseopt_llu_suffix(const char *options, const char *opt,
 
 void parseopt_b(const char *options, const char *opt, bool *val);
 void parseopt_hu(const char *options, const char *opt, unsigned short *val);
-void parseopt_u16(const char *options, const char *opt, uint16_t *val);
 void parseopt_str(const char *options, const char *opt, char **val);
 
 #endif /* __PARSEOPT_H__ */
diff --git a/lib/parseopt.c b/lib/parseopt.c
index 70983066d952..d0a27d8bf372 100644
--- a/lib/parseopt.c
+++ b/lib/parseopt.c
@@ -59,37 +59,6 @@ again:
 		*val = v;
 }
 
-void parseopt_u16(const char *options, const char *opt, uint16_t *val)
-{
-	const char *start;
-	size_t optlen = strlen(opt);
-	ulong v;
-	char *endp;
-
-again:
-	start = strstr(options, opt);
-
-	if (!start)
-		return;
-
-	if (start > options && start[-1] != ',') {
-		options = start;
-		goto again;
-	}
-
-	if (start[optlen] != '=') {
-		options = start;
-		goto again;
-	}
-
-	v = simple_strtoul(start + optlen + 1, &endp, 0);
-	if (v > U16_MAX)
-		return;
-
-	if (*endp == ',' || *endp == '\0')
-		*val = v;
-}
-
 void parseopt_str(const char *options, const char *opt, char **val)
 {
 	const char *start;
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:03:10 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:03:10 +0100
Subject: [PATCH] commands: time: add -n option for nanoseconds output
Message-ID: <20220103120310.1729050-1-a.fatoum@pengutronix.de>

The current millisecond output may be too coarse for debugging timing
of barebox functionality. Add an optional nanosecond output.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/time.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/commands/time.c b/commands/time.c
index 25ba2da15ed5..2d9fb75e7a8c 100644
--- a/commands/time.c
+++ b/commands/time.c
@@ -9,7 +9,7 @@ static int do_time(int argc, char *argv[])
 	int i;
 	unsigned char *buf;
 	u64 start, end, diff64;
-	unsigned long diff;
+	bool nanoseconds = false;
 	int len = 1; /* '\0' */
 
 	if (argc < 2)
@@ -20,7 +20,13 @@ static int do_time(int argc, char *argv[])
 
 	buf = xzalloc(len);
 
-	for (i = 1; i < argc; i++) {
+	i = 1;
+	if (!strcmp(argv[i], "-n")) {
+		nanoseconds = true;
+		i++;
+	}
+
+	for (; i < argc; i++) {
 		strcat(buf, argv[i]);
 		strcat(buf, " ");
 	}
@@ -33,11 +39,10 @@ static int do_time(int argc, char *argv[])
 
 	diff64 = end - start;
 
-	do_div(diff64, 1000000);
-
-	diff = diff64;
+	if (!nanoseconds)
+		do_div(diff64, 1000000);
 
-	printf("time: %lums\n", diff);
+	printf("time: %llu%cs\n", diff64, nanoseconds ? 'n' : 'm');
 
 	free(buf);
 
@@ -47,12 +52,14 @@ static int do_time(int argc, char *argv[])
 BAREBOX_CMD_HELP_START(time)
 BAREBOX_CMD_HELP_TEXT("Note: This command depends on COMMAND being interruptible,")
 BAREBOX_CMD_HELP_TEXT("otherwise the timer may overrun resulting in incorrect results")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-n",     "output elapsed time in nanoseconds")
 BAREBOX_CMD_HELP_END
 
 BAREBOX_CMD_START(time)
 	.cmd		= do_time,
 	BAREBOX_CMD_DESC("measure execution duration of a command")
-	BAREBOX_CMD_OPTS("COMMAND")
+	BAREBOX_CMD_OPTS("[-n] COMMAND")
 	BAREBOX_CMD_GROUP(CMD_GRP_MISC)
 	BAREBOX_CMD_HELP(cmd_time_help)
 BAREBOX_CMD_END
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:03:36 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:03:36 +0100
Subject: [PATCH] commands: regulator: add support for enabling/disabling
 regulators
Message-ID: <20220103120336.1729791-1-a.fatoum@pengutronix.de>

For testing regulator drivers, it can be handy to enable/disable them
from the shell prompt. Extend the regulator command to support this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/regulator.c     | 38 +++++++++++++++++++++++++++++++++++---
 drivers/regulator/core.c |  8 ++++++++
 include/regulator.h      |  1 +
 3 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/commands/regulator.c b/commands/regulator.c
index 3e2595f8bfc1..e6b2f4852db4 100644
--- a/commands/regulator.c
+++ b/commands/regulator.c
@@ -6,16 +6,48 @@
 #include <common.h>
 #include <command.h>
 #include <regulator.h>
+#include <getopt.h>
 
 static int do_regulator(int argc, char *argv[])
 {
-	regulators_print();
+	struct regulator *chosen;
+	int opt, ret;
+
+	while ((opt = getopt(argc, argv, "e:d:")) > 0) {
+		switch (opt) {
+		case 'e':
+		case 'd':
+			chosen = regulator_get_name(optarg);
+			if (IS_ERR_OR_NULL(chosen)) {
+				printf("regulator not found\n");
+				return COMMAND_ERROR;
+			}
+
+			ret = opt == 'e' ? regulator_enable(chosen)
+				         : regulator_disable(chosen);
+			regulator_put(chosen);
+			return ret;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
 
+	regulators_print();
 	return 0;
 }
 
+BAREBOX_CMD_HELP_START(regulator)
+	BAREBOX_CMD_HELP_TEXT("List and control regulators.")
+	BAREBOX_CMD_HELP_TEXT("Without options, displays regulator info")
+	BAREBOX_CMD_HELP_TEXT("Options:")
+	BAREBOX_CMD_HELP_OPT("-e REGULATOR\t", "enable REGULATOR")
+	BAREBOX_CMD_HELP_OPT("-d REGULATOR\t", "disable REGULATOR")
+BAREBOX_CMD_HELP_END
+
 BAREBOX_CMD_START(regulator)
 	.cmd		= do_regulator,
-	BAREBOX_CMD_DESC("list regulators")
-	BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+	BAREBOX_CMD_DESC("list and control regulators")
+	BAREBOX_CMD_OPTS("[-ed] [REGULATOR]")
+	BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
+	BAREBOX_CMD_HELP(cmd_regulator_help)
 BAREBOX_CMD_END
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index b2e5f8caa2ca..35567100c5af 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -355,6 +355,14 @@ struct regulator *regulator_get(struct device_d *dev, const char *supply)
 	return r;
 }
 
+void regulator_put(struct regulator *r)
+{
+	if (IS_ERR_OR_NULL(r))
+		return;
+	list_del(&r->list);
+	free(r);
+}
+
 static struct regulator_internal *regulator_by_name(const char *name)
 {
 	struct regulator_internal *ri;
diff --git a/include/regulator.h b/include/regulator.h
index dfdfbf033262..f4cf6726c2ad 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -148,6 +148,7 @@ void regulators_print(void);
 #ifdef CONFIG_REGULATOR
 
 struct regulator *regulator_get(struct device_d *, const char *);
+void regulator_put(struct regulator *r);
 struct regulator *regulator_get_name(const char *name);
 int regulator_enable(struct regulator *);
 int regulator_disable(struct regulator *);
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:29 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:29 +0100
Subject: [PATCH 01/11] commands: set SPDX-License-Identifier for files without
 license statement
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-2-a.fatoum@pengutronix.de>

In absence of a dual licensing statement, this is GPL-2.0-only as the
barebox project as a whole. Add a SPDX-License-Identifier to make this
clear.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/Kconfig            | 2 ++
 commands/Makefile           | 2 ++
 commands/clk.c              | 2 ++
 commands/fbtest.c           | 2 ++
 commands/hwclock.c          | 2 ++
 commands/hwmon.c            | 2 ++
 commands/insmod.c           | 2 ++
 commands/internal.h         | 2 ++
 commands/keystore.c         | 2 ++
 commands/lsmod.c            | 2 ++
 commands/magicvar.c         | 2 ++
 commands/memtester/Makefile | 2 ++
 commands/mmc.c              | 2 ++
 commands/readf.c            | 2 ++
 commands/rmdir.c            | 2 ++
 commands/splash.c           | 2 ++
 commands/time.c             | 2 ++
 commands/ubi.c              | 2 ++
 commands/uimage.c           | 2 ++
 19 files changed, 38 insertions(+)

diff --git a/commands/Kconfig b/commands/Kconfig
index 22375360885b..e2c36949347e 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config REGINFO
 	bool
 
diff --git a/commands/Makefile b/commands/Makefile
index ba5ea19eb202..0b7c1563b534 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_STDDEV)		+= stddev.o
 obj-$(CONFIG_CMD_DIGEST)	+= digest.o
 obj-$(CONFIG_COMPILE_HASH)	+= hashsum.o
diff --git a/commands/clk.c b/commands/clk.c
index 4d124807bd73..0f7d7422e9b2 100644
--- a/commands/clk.c
+++ b/commands/clk.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <getopt.h>
diff --git a/commands/fbtest.c b/commands/fbtest.c
index 30d96f6af41f..be1540d3d170 100644
--- a/commands/fbtest.c
+++ b/commands/fbtest.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <errno.h>
diff --git a/commands/hwclock.c b/commands/hwclock.c
index 7a5600c456c9..abb0500e6a5d 100644
--- a/commands/hwclock.c
+++ b/commands/hwclock.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <getopt.h>
diff --git a/commands/hwmon.c b/commands/hwmon.c
index ace4503c0b4d..04c3e728c636 100644
--- a/commands/hwmon.c
+++ b/commands/hwmon.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <getopt.h>
diff --git a/commands/insmod.c b/commands/insmod.c
index 735dde022253..8f962b62d30d 100644
--- a/commands/insmod.c
+++ b/commands/insmod.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <module.h>
diff --git a/commands/internal.h b/commands/internal.h
index 21d1408c911f..63c10af28e76 100644
--- a/commands/internal.h
+++ b/commands/internal.h
@@ -1,2 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 int __do_digest(struct digest *d, unsigned char *sig,
 		       int argc, char *argv[]);
diff --git a/commands/keystore.c b/commands/keystore.c
index 4f6a7ef190ea..4922cf1bebe9 100644
--- a/commands/keystore.c
+++ b/commands/keystore.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <getopt.h>
diff --git a/commands/lsmod.c b/commands/lsmod.c
index 711c1c66dc3d..3d7ce40430bd 100644
--- a/commands/lsmod.c
+++ b/commands/lsmod.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <complete.h>
diff --git a/commands/magicvar.c b/commands/magicvar.c
index 8740784ed2c2..01acc741ac5d 100644
--- a/commands/magicvar.c
+++ b/commands/magicvar.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <getopt.h>
diff --git a/commands/memtester/Makefile b/commands/memtester/Makefile
index 17a2429276bb..b410813af7c8 100644
--- a/commands/memtester/Makefile
+++ b/commands/memtester/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += tests.o memtester.o
diff --git a/commands/mmc.c b/commands/mmc.c
index c696e7b8817b..cbbb9d615145 100644
--- a/commands/mmc.c
+++ b/commands/mmc.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <command.h>
 #include <mci.h>
 #include <stdio.h>
diff --git a/commands/readf.c b/commands/readf.c
index 8dd5a2b55a79..d9d1b5124349 100644
--- a/commands/readf.c
+++ b/commands/readf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <fs.h>
diff --git a/commands/rmdir.c b/commands/rmdir.c
index e1cd5dc54852..9b2938a5563c 100644
--- a/commands/rmdir.c
+++ b/commands/rmdir.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <fs.h>
diff --git a/commands/splash.c b/commands/splash.c
index f1cc8c83bd97..2eb7c5dc39e5 100644
--- a/commands/splash.c
+++ b/commands/splash.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <errno.h>
diff --git a/commands/time.c b/commands/time.c
index 2d9fb75e7a8c..5b8933ea6553 100644
--- a/commands/time.c
+++ b/commands/time.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <clock.h>
diff --git a/commands/ubi.c b/commands/ubi.c
index f866f00160b0..6abd054af393 100644
--- a/commands/ubi.c
+++ b/commands/ubi.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <fs.h>
diff --git a/commands/uimage.c b/commands/uimage.c
index fb4df780bdd0..588519e3f3a7 100644
--- a/commands/uimage.c
+++ b/commands/uimage.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <image.h>
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:31 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:31 +0100
Subject: [PATCH 03/11] treewide: add SPDX-License-Identifier for .gitignore
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-4-a.fatoum@pengutronix.de>

Makes the files not appear when searching for files that lack
SPDX-License-Identifier.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 .gitignore                                   | 1 +
 Documentation/.gitignore                     | 2 ++
 arch/arm/boards/nxp-imx8mq-evk/.gitignore    | 2 ++
 arch/arm/boards/phytec-som-imx8mq/.gitignore | 2 ++
 arch/arm/boards/qemu-virt/.gitignore         | 2 ++
 arch/arm/crypto/.gitignore                   | 2 ++
 arch/arm/lib32/.gitignore                    | 2 ++
 arch/arm/lib64/.gitignore                    | 2 ++
 arch/mips/lib/.gitignore                     | 2 ++
 arch/mips/pbl/.gitignore                     | 2 ++
 arch/openrisc/cpu/.gitignore                 | 2 ++
 arch/powerpc/boards/.gitignore               | 2 ++
 arch/powerpc/mach-mpc85xx/.gitignore         | 2 ++
 arch/riscv/lib/.gitignore                    | 2 ++
 arch/sandbox/board/.gitignore                | 2 ++
 arch/x86/mach-efi/.gitignore                 | 2 ++
 common/.gitignore                            | 2 ++
 crypto/.gitignore                            | 2 ++
 defaultenv/.gitignore                        | 2 ++
 firmware/.gitignore                          | 2 ++
 images/.gitignore                            | 2 ++
 include/.gitignore                           | 2 ++
 lib/logo/.gitignore                          | 2 ++
 scripts/.gitignore                           | 2 ++
 scripts/dtc/.gitignore                       | 2 ++
 scripts/imx/.gitignore                       | 2 ++
 scripts/mod/.gitignore                       | 2 ++
 scripts/tegra/.gitignore                     | 2 ++
 test/.gitignore                              | 2 ++
 29 files changed, 57 insertions(+)

diff --git a/.gitignore b/.gitignore
index 529bcfc2128e..d551a610d4c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # NOTE! Don't add files that are generated in specific
 # subdirectories here. Add them in the ".gitignore" file
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
index 5c36dc3ec5de..e8b2851d2552 100644
--- a/Documentation/.gitignore
+++ b/Documentation/.gitignore
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 build
 commands
 html
diff --git a/arch/arm/boards/nxp-imx8mq-evk/.gitignore b/arch/arm/boards/nxp-imx8mq-evk/.gitignore
index ef13747c92ee..cafa52b2079a 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/.gitignore
+++ b/arch/arm/boards/nxp-imx8mq-evk/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 *.ddr-phy-fw*
diff --git a/arch/arm/boards/phytec-som-imx8mq/.gitignore b/arch/arm/boards/phytec-som-imx8mq/.gitignore
index ef13747c92ee..cafa52b2079a 100644
--- a/arch/arm/boards/phytec-som-imx8mq/.gitignore
+++ b/arch/arm/boards/phytec-som-imx8mq/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 *.ddr-phy-fw*
diff --git a/arch/arm/boards/qemu-virt/.gitignore b/arch/arm/boards/qemu-virt/.gitignore
index 5d65b54bf17a..3e3932a3bfba 100644
--- a/arch/arm/boards/qemu-virt/.gitignore
+++ b/arch/arm/boards/qemu-virt/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 *.dtb*
diff --git a/arch/arm/crypto/.gitignore b/arch/arm/crypto/.gitignore
index b22a068f76f2..545a1b084d4e 100644
--- a/arch/arm/crypto/.gitignore
+++ b/arch/arm/crypto/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 /sha256-core.S
diff --git a/arch/arm/lib32/.gitignore b/arch/arm/lib32/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/arm/lib32/.gitignore
+++ b/arch/arm/lib32/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/arm/lib64/.gitignore b/arch/arm/lib64/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/arm/lib64/.gitignore
+++ b/arch/arm/lib64/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/mips/lib/.gitignore b/arch/mips/lib/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/mips/lib/.gitignore
+++ b/arch/mips/lib/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/mips/pbl/.gitignore b/arch/mips/pbl/.gitignore
index be604a81bf86..667b44eaf356 100644
--- a/arch/mips/pbl/.gitignore
+++ b/arch/mips/pbl/.gitignore
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 piggy.gzip
 piggy.lzo
 piggy.lz4
diff --git a/arch/openrisc/cpu/.gitignore b/arch/openrisc/cpu/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/openrisc/cpu/.gitignore
+++ b/arch/openrisc/cpu/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/powerpc/boards/.gitignore b/arch/powerpc/boards/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/powerpc/boards/.gitignore
+++ b/arch/powerpc/boards/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/powerpc/mach-mpc85xx/.gitignore b/arch/powerpc/mach-mpc85xx/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/powerpc/mach-mpc85xx/.gitignore
+++ b/arch/powerpc/mach-mpc85xx/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/riscv/lib/.gitignore b/arch/riscv/lib/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/riscv/lib/.gitignore
+++ b/arch/riscv/lib/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/sandbox/board/.gitignore b/arch/sandbox/board/.gitignore
index d1165788c9ab..03987a700942 100644
--- a/arch/sandbox/board/.gitignore
+++ b/arch/sandbox/board/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox.lds
diff --git a/arch/x86/mach-efi/.gitignore b/arch/x86/mach-efi/.gitignore
index 847e317701f6..0dae36ae58e6 100644
--- a/arch/x86/mach-efi/.gitignore
+++ b/arch/x86/mach-efi/.gitignore
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 elf_x86_64_efi.lds
 elf_ia32_efi.lds
diff --git a/common/.gitignore b/common/.gitignore
index 8e0d6c160e8c..e3e3d504dc4b 100644
--- a/common/.gitignore
+++ b/common/.gitignore
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 module.lds
 barebox_default_env*
diff --git a/crypto/.gitignore b/crypto/.gitignore
index 92d8af3cf491..3d5e57e7dd37 100644
--- a/crypto/.gitignore
+++ b/crypto/.gitignore
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 rsa-keys.h
 rsa-keys.h.tmp
diff --git a/defaultenv/.gitignore b/defaultenv/.gitignore
index 7c338505990d..e2ef3c4205cb 100644
--- a/defaultenv/.gitignore
+++ b/defaultenv/.gitignore
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox_default_env*
 barebox_zero_env
diff --git a/firmware/.gitignore b/firmware/.gitignore
index a8a0dcec4472..4f3e56d8b719 100644
--- a/firmware/.gitignore
+++ b/firmware/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 *.bin
diff --git a/images/.gitignore b/images/.gitignore
index 3a9a77dad16e..1aa9620a42d8 100644
--- a/images/.gitignore
+++ b/images/.gitignore
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 *.pbl
 *.pblb
 *.img
diff --git a/include/.gitignore b/include/.gitignore
index 18e58a752ad7..3ac630625dc7 100644
--- a/include/.gitignore
+++ b/include/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 /config.h
diff --git a/lib/logo/.gitignore b/lib/logo/.gitignore
index 0d5475cb7878..800a44c41472 100644
--- a/lib/logo/.gitignore
+++ b/lib/logo/.gitignore
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 barebox-logo-w64.bblogo
 barebox-logo-w64.bblogo.S
 barebox-logo-w240.bblogo
diff --git a/scripts/.gitignore b/scripts/.gitignore
index ae70c92af8a3..6ef43640b79f 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 bin2c
 mkimage
 fix_size
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore
index 2c0d6a1bf3e1..0079e3f1b516 100644
--- a/scripts/dtc/.gitignore
+++ b/scripts/dtc/.gitignore
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 dtc
 fdtget
diff --git a/scripts/imx/.gitignore b/scripts/imx/.gitignore
index 341aec9ee435..dce5c3306c26 100644
--- a/scripts/imx/.gitignore
+++ b/scripts/imx/.gitignore
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 imx-usb-loader
 imx-usb-loader-target
 imx-image
diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore
index a6dd5e27e2f5..f507ef8560eb 100644
--- a/scripts/mod/.gitignore
+++ b/scripts/mod/.gitignore
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 elfconfig.h
 mk_elfconfig
 modpost
diff --git a/scripts/tegra/.gitignore b/scripts/tegra/.gitignore
index 5d5891b24389..96cc56e4a790 100644
--- a/scripts/tegra/.gitignore
+++ b/scripts/tegra/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 cbootimage
diff --git a/test/.gitignore b/test/.gitignore
index bee8a64b79a9..1a4103cb05f7 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 __pycache__
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:33 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:33 +0100
Subject: [PATCH 05/11] fs: jffs2: add SPDX-License-Identifier: GPL-2.0-only
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-6-a.fatoum@pengutronix.de>

The files refer to the (Linux) top-level LICENSE file. Replace that with
GPL-2.0-only.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/jffs2/acl.h         | 4 +---
 fs/jffs2/build.c       | 4 +---
 fs/jffs2/compr.c       | 4 +---
 fs/jffs2/compr.h       | 4 +---
 fs/jffs2/compr_lzo.c   | 4 +---
 fs/jffs2/compr_rtime.c | 5 +----
 fs/jffs2/compr_rubin.c | 4 +---
 fs/jffs2/compr_zlib.c  | 4 +---
 fs/jffs2/debug.c       | 4 +---
 fs/jffs2/debug.h       | 5 ++---
 fs/jffs2/dir.c         | 4 +---
 fs/jffs2/fs.c          | 4 +---
 fs/jffs2/jffs2_fs_i.h  | 5 ++---
 fs/jffs2/jffs2_fs_sb.h | 5 ++---
 fs/jffs2/malloc.c      | 4 +---
 fs/jffs2/nodelist.c    | 4 +---
 fs/jffs2/nodelist.h    | 4 +---
 fs/jffs2/os-linux.h    | 5 ++---
 fs/jffs2/read.c        | 4 +---
 fs/jffs2/readinode.c   | 4 +---
 fs/jffs2/scan.c        | 4 +---
 fs/jffs2/summary.h     | 4 +---
 fs/jffs2/super.c       | 5 ++---
 fs/jffs2/xattr.h       | 4 +---
 24 files changed, 29 insertions(+), 73 deletions(-)

diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
index 12d0271bdde3..2e1794f5aee4 100644
--- a/fs/jffs2/acl.h
+++ b/fs/jffs2/acl.h
@@ -1,12 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai at ak.jp.nec.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 struct jffs2_acl_entry {
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index f3fc0ade207c..d5757d100bf5 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index 1c5a7d9137e2..04b014199fde 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -7,9 +8,6 @@
  *		    University of Szeged, Hungary
  *
  * Created by Arjan van de Ven <arjan at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <common.h>
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h
index 2e3c368acee5..20267beeca8e 100644
--- a/fs/jffs2/compr.h
+++ b/fs/jffs2/compr.h
@@ -1,12 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2004   Ferenc Havasi <havasi at inf.u-szeged.hu>,
  *		      University of Szeged, Hungary
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef __JFFS2_COMPR_H__
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c
index 1be30dc60443..643b83fa7474 100644
--- a/fs/jffs2/compr_lzo.c
+++ b/fs/jffs2/compr_lzo.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by Richard Purdie <rpurdie at openedhand.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #include <common.h>
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
index d74d7d3d794a..f8bc4ab1142e 100644
--- a/fs/jffs2/compr_rtime.c
+++ b/fs/jffs2/compr_rtime.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -6,10 +7,6 @@
  *
  * Created by Arjan van de Ven <arjanv at redhat.com>
  *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- *
- *
  * Very simple lz77-ish encoder.
  *
  * Theory of operation: Both encoder and decoder have a list of "last
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c
index 3e4faa739a3e..91a500f4fb29 100644
--- a/fs/jffs2/compr_rubin.c
+++ b/fs/jffs2/compr_rubin.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by Arjan van de Ven <arjanv at redhat.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index 222e0d6e5fcf..2b7914f1f5d2 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <common.h>
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c
index 536a1786c163..edf853976223 100644
--- a/fs/jffs2/debug.c
+++ b/fs/jffs2/debug.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index 97733ecca72f..d40569e6fed9 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +7,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef _JFFS2_DEBUG_H_
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 4d28d2b5531c..34f8d141f289 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <common.h>
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index a267ec0669cc..f3f472d6876c 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <common.h>
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h
index 2d4b03040fad..5d420a926dd0 100644
--- a/fs/jffs2/jffs2_fs_i.h
+++ b/fs/jffs2/jffs2_fs_i.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +7,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef _JFFS2_FS_I
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index 84d118c2e9de..20fa9a26a4ff 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +7,6 @@
  * Copyright ? 2004-2010 David Woodhouse <dwmw2 at infradead.org>
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef _JFFS2_FS_SB
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 7e3e0797b3b8..202191be944a 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 446407e1380e..94753e1995cb 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 26afb7ccd789..b5f7716ce2d0 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -1,12 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef __JFFS2_NODELIST_H__
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index b86a55e482bc..3f6af905829d 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -1,12 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef __JFFS2_OS_LINUX_H__
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c
index 2848e4d1d86d..a1c3b9d47bb4 100644
--- a/fs/jffs2/read.c
+++ b/fs/jffs2/read.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 0fe67cbb6b30..aaf26196135b 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 64a5e02c216c..0d74a8f51f97 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h
index a4b4747825e5..87a782f11ec3 100644
--- a/fs/jffs2/summary.h
+++ b/fs/jffs2/summary.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
@@ -5,9 +6,6 @@
  *		     Zoltan Sogor <weth at inf.u-szeged.hu>,
  *		     Patrik Kluba <pajko at halom.u-szeged.hu>,
  *		     University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef JFFS2_SUMMARY_H
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index d9bb6d0bff9c..6001be8e1038 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -1,12 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2 at infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <common.h>
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index dced8737669e..e348190bd3d1 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -1,12 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright ? 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai at ak.jp.nec.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
  */
 
 #ifndef _JFFS2_FS_XATTR_H_
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:39 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:39 +0100
Subject: [PATCH 11/11] treewide: add SPDX-License-Identifier for files without
 explicit license
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-12-a.fatoum@pengutronix.de>

Record GPL-2.0-only as license for all files lacking an explicit license
statement.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 MAKEALL                                      | 2 ++
 arch/arm/tools/gen-mach-types                | 2 ++
 common/boards/qemu-virt/overlay-of-flash.dts | 2 ++
 common/calloc.c                              | 2 ++
 common/console_simple.c                      | 2 ++
 common/globalvar.c                           | 2 ++
 common/imd-barebox.c                         | 2 ++
 common/kallsyms.c                            | 2 ++
 common/meminfo.c                             | 2 ++
 common/memory_display.c                      | 4 +++-
 common/oftree.c                              | 2 ++
 common/parser.c                              | 2 ++
 common/serdev.c                              | 1 +
 common/state/state.h                         | 2 ++
 common/tlsf.c                                | 2 ++
 common/tlsfbits.h                            | 2 ++
 common/version.c                             | 2 ++
 crypto/md5.c                                 | 1 +
 fs/cramfs/uncompress.c                       | 2 ++
 fs/fat/diskio.h                              | 2 ++
 fs/fat/ffconf.h                              | 2 ++
 fs/fat/integer.h                             | 2 ++
 fs/pstore/internal.h                         | 2 ++
 fs/squashfs/squashfs.c                       | 2 ++
 lib/bcd.c                                    | 2 ++
 lib/fdt.c                                    | 1 +
 lib/fdt_empty_tree.c                         | 2 ++
 lib/fdt_ro.c                                 | 2 ++
 lib/fdt_rw.c                                 | 2 ++
 lib/fdt_strerror.c                           | 1 +
 lib/fdt_sw.c                                 | 2 ++
 lib/fdt_wip.c                                | 2 ++
 lib/fonts/font_6x8.c                         | 2 ++
 lib/fonts/font_7x14.c                        | 2 ++
 lib/fonts/font_8x16.c                        | 2 ++
 lib/fonts/font_8x8.c                         | 2 ++
 lib/fonts/font_custom_16x.c                  | 2 ++
 lib/fonts/font_mini_4x6.c                    | 2 ++
 lib/gcd.c                                    | 2 ++
 lib/gui/2d-primitives.c                      | 2 ++
 lib/gui/bmp.c                                | 2 ++
 lib/gui/graphic_utils.c                      | 2 ++
 lib/gui/picopng.h                            | 2 ++
 lib/gui/png.c                                | 2 ++
 lib/gui/png_lode.c                           | 2 ++
 lib/gui/png_pico.c                           | 2 ++
 lib/list_sort.c                              | 2 ++
 lib/make_directory.c                         | 1 +
 lib/nls_base.c                               | 2 ++
 lib/notifier.c                               | 2 ++
 lib/parseopt.c                               | 2 ++
 lib/random.c                                 | 2 ++
 lib/readline.c                               | 2 ++
 lib/readline_simple.c                        | 2 ++
 lib/string.c                                 | 1 +
 lib/stringlist.c                             | 2 ++
 lib/strtox.c                                 | 2 ++
 lib/unlink-recursive.c                       | 2 ++
 lib/vsprintf.c                               | 2 ++
 net/nfs.c                                    | 2 ++
 net/ping.c                                   | 2 ++
 pbl/console.c                                | 2 ++
 pbl/misc.c                                   | 2 ++
 pbl/string.c                                 | 2 ++
 64 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/MAKEALL b/MAKEALL
index 3548739e37f4..b4cf4c649b9c 100755
--- a/MAKEALL
+++ b/MAKEALL
@@ -1,4 +1,6 @@
 #!/usr/bin/env bash
+#
+# SPDX-License-Identifier: GPL-2.0-only
 
 # Print statistics when we exit
 trap exit 1 2 3 15
diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
index 04fef71d7be9..fcfc0ed192e1 100644
--- a/arch/arm/tools/gen-mach-types
+++ b/arch/arm/tools/gen-mach-types
@@ -1,5 +1,7 @@
 #!/bin/awk
 #
+# SPDX-License-Identifier: GPL-2.0-only
+#
 # Awk script to generate include/generated/mach-types.h
 #
 BEGIN	{ nr = 0 }
diff --git a/common/boards/qemu-virt/overlay-of-flash.dts b/common/boards/qemu-virt/overlay-of-flash.dts
index a271a455105f..b3cdf6893f8a 100644
--- a/common/boards/qemu-virt/overlay-of-flash.dts
+++ b/common/boards/qemu-virt/overlay-of-flash.dts
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /dts-v1/;
 /plugin/;
 
diff --git a/common/calloc.c b/common/calloc.c
index 2b933ec272b0..65e843350d47 100644
--- a/common/calloc.c
+++ b/common/calloc.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <malloc.h>
 
diff --git a/common/console_simple.c b/common/console_simple.c
index 8c404ad264c4..afa9a0f186fb 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <config.h>
 #include <common.h>
 #include <fs.h>
diff --git a/common/globalvar.c b/common/globalvar.c
index 9e5a99f79353..4fd6361c2f34 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <malloc.h>
 #include <globalvar.h>
diff --git a/common/imd-barebox.c b/common/imd-barebox.c
index 06731d0600cf..e11fdca845ad 100644
--- a/common/imd-barebox.c
+++ b/common/imd-barebox.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <image-metadata.h>
 #include <generated/compile.h>
diff --git a/common/kallsyms.c b/common/kallsyms.c
index f641903147db..a9b2b9368992 100644
--- a/common/kallsyms.c
+++ b/common/kallsyms.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <kallsyms.h>
diff --git a/common/meminfo.c b/common/meminfo.c
index d239fde5828b..e6b251e5bfee 100644
--- a/common/meminfo.c
+++ b/common/meminfo.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <memory.h>
diff --git a/common/memory_display.c b/common/memory_display.c
index fbb8bbb6faa7..77868be26ace 100644
--- a/common/memory_display.c
+++ b/common/memory_display.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <errno.h>
 #include <abort.h>
@@ -132,4 +134,4 @@ int memory_display(const void *addr, loff_t offs, unsigned nbytes,
 		   int size, int swab)
 {
 	return pr_memory_display(-1, addr, offs, nbytes, size, swab);
-}
\ No newline at end of file
+}
diff --git a/common/oftree.c b/common/oftree.c
index 962fff244d87..0738ab6e9e0c 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <environment.h>
 #include <fdt.h>
diff --git a/common/parser.c b/common/parser.c
index 584d4b0efece..387cd64c4267 100644
--- a/common/parser.c
+++ b/common/parser.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <common.h>
 #include <command.h>
 #include <password.h>
diff --git a/common/serdev.c b/common/serdev.c
index 4bf11b161892..1d328c6a3337 100644
--- a/common/serdev.c
+++ b/common/serdev.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 
 #include <common.h>
 #include <serdev.h>
diff --git a/common/state/state.h b/common/state/state.h
index 48572c5d4137..0545cf6ac108 100644
--- a/common/state/state.h
+++ b/common/state/state.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/err.h>
diff --git a/common/tlsf.c b/common/tlsf.c
index 4247a9d3c716..520cce496ef6 100644
--- a/common/tlsf.c
+++ b/common/tlsf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/common/tlsfbits.h b/common/tlsfbits.h
index edbac8063645..8633fb595985 100644
--- a/common/tlsfbits.h
+++ b/common/tlsfbits.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef INCLUDED_tlsfbits
 #define INCLUDED_tlsfbits
 
diff --git a/common/version.c b/common/version.c
index 54cec5335d9c..15f03c2a00ff 100644
--- a/common/version.c
+++ b/common/version.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <generated/compile.h>
 #include <generated/utsrelease.h>
diff --git a/crypto/md5.c b/crypto/md5.c
index f8f52bf4a505..f91a6fe08f89 100644
--- a/crypto/md5.c
+++ b/crypto/md5.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * This file was transplanted with slight modifications from Linux sources
  * (fs/cifs/md5.c) into U-Boot by Bartlomiej Sieka <tur at semihalf.com>.
diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c
index b7887bd65439..82c82adf044c 100644
--- a/fs/cramfs/uncompress.c
+++ b/fs/cramfs/uncompress.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * uncompress.c
  *
diff --git a/fs/fat/diskio.h b/fs/fat/diskio.h
index aee1ce2b0b3b..57626d2fbd7b 100644
--- a/fs/fat/diskio.h
+++ b/fs/fat/diskio.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*-----------------------------------------------------------------------
 /  Low level disk interface modlue include file
 /-----------------------------------------------------------------------*/
diff --git a/fs/fat/ffconf.h b/fs/fat/ffconf.h
index 2f6a6c154409..abf7d1e92e0b 100644
--- a/fs/fat/ffconf.h
+++ b/fs/fat/ffconf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*---------------------------------------------------------------------------/
 /  FatFs - FAT file system module configuration file  R0.08b (C)ChaN, 2011
 /----------------------------------------------------------------------------/
diff --git a/fs/fat/integer.h b/fs/fat/integer.h
index 04956aa775fa..fe94e374f356 100644
--- a/fs/fat/integer.h
+++ b/fs/fat/integer.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*-------------------------------------------*/
 /* Integer type definitions for FatFs module */
 /*-------------------------------------------*/
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 6b507e4bd3cb..d233ee7e8c0d 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __PSTORE_INTERNAL_H__
 #define __PSTORE_INTERNAL_H__
 
diff --git a/fs/squashfs/squashfs.c b/fs/squashfs/squashfs.c
index be03618b2f52..030be57887b2 100644
--- a/fs/squashfs/squashfs.c
+++ b/fs/squashfs/squashfs.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <malloc.h>
 #include <driver.h>
diff --git a/lib/bcd.c b/lib/bcd.c
index b072d50a9041..4bed6eddfec8 100644
--- a/lib/bcd.c
+++ b/lib/bcd.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <linux/bcd.h>
 #include <module.h>
 
diff --git a/lib/fdt.c b/lib/fdt.c
index 97f20069fc37..c83f9b94d2a2 100644
--- a/lib/fdt.c
+++ b/lib/fdt.c
@@ -1,2 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 #include <linux/libfdt_env.h>
 #include "../scripts/dtc/libfdt/fdt.c"
diff --git a/lib/fdt_empty_tree.c b/lib/fdt_empty_tree.c
index 5d30c58150ad..794fcb6cac62 100644
--- a/lib/fdt_empty_tree.c
+++ b/lib/fdt_empty_tree.c
@@ -1,2 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/libfdt_env.h>
 #include "../scripts/dtc/libfdt/fdt_empty_tree.c"
diff --git a/lib/fdt_ro.c b/lib/fdt_ro.c
index f73c04ea7be4..b4bab9618e37 100644
--- a/lib/fdt_ro.c
+++ b/lib/fdt_ro.c
@@ -1,2 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/libfdt_env.h>
 #include "../scripts/dtc/libfdt/fdt_ro.c"
diff --git a/lib/fdt_rw.c b/lib/fdt_rw.c
index 0c1f0f4a4b13..72b5df529dfb 100644
--- a/lib/fdt_rw.c
+++ b/lib/fdt_rw.c
@@ -1,2 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/libfdt_env.h>
 #include "../scripts/dtc/libfdt/fdt_rw.c"
diff --git a/lib/fdt_strerror.c b/lib/fdt_strerror.c
index 8713e3ff4707..25883d28d938 100644
--- a/lib/fdt_strerror.c
+++ b/lib/fdt_strerror.c
@@ -1,2 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 #include <linux/libfdt_env.h>
 #include "../scripts/dtc/libfdt/fdt_strerror.c"
diff --git a/lib/fdt_sw.c b/lib/fdt_sw.c
index 9ac7e50c76ce..3f8e3397a9a9 100644
--- a/lib/fdt_sw.c
+++ b/lib/fdt_sw.c
@@ -1,2 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/libfdt_env.h>
 #include "../scripts/dtc/libfdt/fdt_sw.c"
diff --git a/lib/fdt_wip.c b/lib/fdt_wip.c
index 45b3fc3d3ba1..da120b6dc97e 100644
--- a/lib/fdt_wip.c
+++ b/lib/fdt_wip.c
@@ -1,2 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/libfdt_env.h>
 #include "../scripts/dtc/libfdt/fdt_wip.c"
diff --git a/lib/fonts/font_6x8.c b/lib/fonts/font_6x8.c
index a5efeee61686..2b9061cbd049 100644
--- a/lib/fonts/font_6x8.c
+++ b/lib/fonts/font_6x8.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <init.h>
 #include <linux/font.h>
 
diff --git a/lib/fonts/font_7x14.c b/lib/fonts/font_7x14.c
index e5ef8323ca7b..13b3897d8cd0 100644
--- a/lib/fonts/font_7x14.c
+++ b/lib/fonts/font_7x14.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /**************************************/
 /* this file adapted from font_8x16.c */
 /* by Jurriaan Kalkman 05-2005        */
diff --git a/lib/fonts/font_8x16.c b/lib/fonts/font_8x16.c
index e6d40d0de3e0..dbebf07e27ad 100644
--- a/lib/fonts/font_8x16.c
+++ b/lib/fonts/font_8x16.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /**********************************************/
 /*                                            */
 /*       Font file generated by cpi2fnt       */
diff --git a/lib/fonts/font_8x8.c b/lib/fonts/font_8x8.c
index 27d53de57833..40f1112427fc 100644
--- a/lib/fonts/font_8x8.c
+++ b/lib/fonts/font_8x8.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /**********************************************/
 /*                                            */
 /*       Font file generated by cpi2fnt       */
diff --git a/lib/fonts/font_custom_16x.c b/lib/fonts/font_custom_16x.c
index 2666e1f6d659..eb21a813608f 100644
--- a/lib/fonts/font_custom_16x.c
+++ b/lib/fonts/font_custom_16x.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * by Du Huanpeng <u74147 at gmail.com>
  */
diff --git a/lib/fonts/font_mini_4x6.c b/lib/fonts/font_mini_4x6.c
index 4a1de138a9ed..560a3e1c3a06 100644
--- a/lib/fonts/font_mini_4x6.c
+++ b/lib/fonts/font_mini_4x6.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 
 /* Hand composed "Minuscule" 4x6 font, with binary data generated using
  * Perl stub.
diff --git a/lib/gcd.c b/lib/gcd.c
index 86bdba911265..d895c1f12d6a 100644
--- a/lib/gcd.c
+++ b/lib/gcd.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <linux/gcd.h>
 
 /* Greatest common divisor */
diff --git a/lib/gui/2d-primitives.c b/lib/gui/2d-primitives.c
index 940e82b7d499..55dc1b1dda89 100644
--- a/lib/gui/2d-primitives.c
+++ b/lib/gui/2d-primitives.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <fb.h>
 #include <gui/graphic_utils.h>
diff --git a/lib/gui/bmp.c b/lib/gui/bmp.c
index 8bffc70a42ed..bbc623dba329 100644
--- a/lib/gui/bmp.c
+++ b/lib/gui/bmp.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <errno.h>
 #include <malloc.h>
diff --git a/lib/gui/graphic_utils.c b/lib/gui/graphic_utils.c
index 0bed932213ff..92f249e722bc 100644
--- a/lib/gui/graphic_utils.c
+++ b/lib/gui/graphic_utils.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <fb.h>
 #include <gui/graphic_utils.h>
diff --git a/lib/gui/picopng.h b/lib/gui/picopng.h
index 14c5e28bcc21..a17dd14b0c9e 100644
--- a/lib/gui/picopng.h
+++ b/lib/gui/picopng.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _PICOPNG_H
 #define _PICOPNG_H
 
diff --git a/lib/gui/png.c b/lib/gui/png.c
index 6bf997c29a57..01833485ce73 100644
--- a/lib/gui/png.c
+++ b/lib/gui/png.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <errno.h>
 #include <malloc.h>
diff --git a/lib/gui/png_lode.c b/lib/gui/png_lode.c
index e30db0f853b3..68149c848d5b 100644
--- a/lib/gui/png_lode.c
+++ b/lib/gui/png_lode.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <errno.h>
 #include <malloc.h>
diff --git a/lib/gui/png_pico.c b/lib/gui/png_pico.c
index 256db35ce061..029fee2a4060 100644
--- a/lib/gui/png_pico.c
+++ b/lib/gui/png_pico.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <errno.h>
 #include <malloc.h>
diff --git a/lib/list_sort.c b/lib/list_sort.c
index f5122b259229..77ddadb3d6ac 100644
--- a/lib/list_sort.c
+++ b/lib/list_sort.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #ifndef __BAREBOX__
 #include <linux/kernel.h>
 #define EXPORT_SYMBOL(x)
diff --git a/lib/make_directory.c b/lib/make_directory.c
index 29d08cf536c7..7db93ded8817 100644
--- a/lib/make_directory.c
+++ b/lib/make_directory.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 
 #include <string.h>
 #include <errno.h>
diff --git a/lib/nls_base.c b/lib/nls_base.c
index cd6a5ff12442..5def1411f9ab 100644
--- a/lib/nls_base.c
+++ b/lib/nls_base.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * linux/fs/nls/nls_base.c
  *
diff --git a/lib/notifier.c b/lib/notifier.c
index 9eb734e504b5..c55ec22f94c2 100644
--- a/lib/notifier.c
+++ b/lib/notifier.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/list.h>
 #include <notifier.h>
diff --git a/lib/parseopt.c b/lib/parseopt.c
index d0a27d8bf372..4fdd72fa15bb 100644
--- a/lib/parseopt.c
+++ b/lib/parseopt.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 
 #include "parseopt.h"
diff --git a/lib/random.c b/lib/random.c
index 759271f0c82b..fb3580f9c086 100644
--- a/lib/random.c
+++ b/lib/random.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <stdlib.h>
 #include <linux/hw_random.h>
diff --git a/lib/readline.c b/lib/readline.c
index 25aa99b95e46..37d5b0a343a7 100644
--- a/lib/readline.c
+++ b/lib/readline.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <readkey.h>
 #include <init.h>
diff --git a/lib/readline_simple.c b/lib/readline_simple.c
index 2e52bfc2a070..7a8df9549457 100644
--- a/lib/readline_simple.c
+++ b/lib/readline_simple.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 
 static char erase_seq[] = "\b \b";		/* erase sequence	*/
diff --git a/lib/string.c b/lib/string.c
index 9aeb1d883022..6389217d5b41 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  linux/lib/string.c
  *
diff --git a/lib/stringlist.c b/lib/stringlist.c
index fc86640b94a8..bb2ba54a6c80 100644
--- a/lib/stringlist.c
+++ b/lib/stringlist.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <xfuncs.h>
 #include <malloc.h>
diff --git a/lib/strtox.c b/lib/strtox.c
index a5b770c8ca7a..76927743a72c 100644
--- a/lib/strtox.c
+++ b/lib/strtox.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/ctype.h>
 
diff --git a/lib/unlink-recursive.c b/lib/unlink-recursive.c
index f28c6dae5b3c..398e43693bdf 100644
--- a/lib/unlink-recursive.c
+++ b/lib/unlink-recursive.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <libfile.h>
 #include <errno.h>
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 8681eb43b522..1f3a45be327a 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  *  linux/lib/vsprintf.c
  *
diff --git a/net/nfs.c b/net/nfs.c
index 591417e0de20..9bd0b8f05f99 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * NFS support driver - based on etherboot and barebox's tftp.c
  *
diff --git a/net/ping.c b/net/ping.c
index a71f59a805fb..7b319e532e79 100644
--- a/net/ping.c
+++ b/net/ping.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <clock.h>
diff --git a/pbl/console.c b/pbl/console.c
index 1efcaa0047aa..fc8e8cdf1383 100644
--- a/pbl/console.c
+++ b/pbl/console.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <debug_ll.h>
 #include <linux/err.h>
diff --git a/pbl/misc.c b/pbl/misc.c
index 201ae38e9af6..1f0d992ce08b 100644
--- a/pbl/misc.c
+++ b/pbl/misc.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <linux/types.h>
diff --git a/pbl/string.c b/pbl/string.c
index e96eb99fc22d..7c10f064dc7e 100644
--- a/pbl/string.c
+++ b/pbl/string.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * arch/arm/boot/compressed/string.c
  *
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:28 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:28 +0100
Subject: [PATCH 00/11] treewide: SPDXify files without license statement
Message-ID: <20220103120539.1730644-1-a.fatoum@pengutronix.de>

SPDX for tests, scripts and Documentation will follow. This series
covers everything else.

Ahmad Fatoum (11):
  commands: set SPDX-License-Identifier for files without license
    statement
  treewide: add SPDX-License-Identifier for Kbuild/Kconfig
  treewide: add SPDX-License-Identifier for .gitignore
  images: add SPDX-License-Identifiers
  fs: jffs2: add SPDX-License-Identifier: GPL-2.0-only
  include: add SPDX-License-Identifier
  ARM: i.MX: add SPDX-License-Identifier for DCD
  arch: add SPDX-License-Identifier to all headers
  arch: add SPDX-License-Identifier to all .S files
  arch: add SPDX-License-Identifier to all .c files
  treewide: add SPDX-License-Identifier for files without explicit
    license

 .gitignore                                                   | 1 +
 Documentation/.gitignore                                     | 2 ++
 Kconfig                                                      | 2 ++
 MAKEALL                                                      | 2 ++
 arch/arm/Kconfig                                             | 2 ++
 arch/arm/Makefile                                            | 2 ++
 arch/arm/boards/Makefile                                     | 2 ++
 arch/arm/boards/a9m2410/Makefile                             | 1 +
 arch/arm/boards/a9m2410/lowlevel_init.S                      | 4 +---
 arch/arm/boards/a9m2440/Makefile                             | 1 +
 arch/arm/boards/a9m2440/lowlevel_init.S                      | 4 +---
 arch/arm/boards/ac-sxb/Makefile                              | 2 ++
 arch/arm/boards/advantech-mx6/Makefile                       | 2 ++
 .../advantech-mx6/flash-header-advantech-rom-7421.imxcfg     | 2 ++
 arch/arm/boards/afi-gf/Makefile                              | 2 ++
 arch/arm/boards/afi-gf/lowlevel.c                            | 2 ++
 arch/arm/boards/altera-socdk/Makefile                        | 2 ++
 arch/arm/boards/altera-socdk/board.c                         | 2 ++
 arch/arm/boards/altera-socdk/lowlevel.c                      | 2 ++
 arch/arm/boards/animeo_ip/Makefile                           | 2 ++
 arch/arm/boards/archosg9/Makefile                            | 2 ++
 arch/arm/boards/archosg9/archos_features.h                   | 2 ++
 arch/arm/boards/archosg9/mux.h                               | 2 ++
 arch/arm/boards/at91rm9200ek/Makefile                        | 2 ++
 arch/arm/boards/at91rm9200ek/config.h                        | 2 ++
 arch/arm/boards/at91sam9260ek/Makefile                       | 2 ++
 arch/arm/boards/at91sam9261ek/Makefile                       | 2 ++
 arch/arm/boards/at91sam9263ek/Makefile                       | 2 ++
 arch/arm/boards/at91sam9m10g45ek/Makefile                    | 2 ++
 arch/arm/boards/at91sam9m10ihd/Makefile                      | 2 ++
 arch/arm/boards/at91sam9n12ek/Makefile                       | 2 ++
 arch/arm/boards/at91sam9x5ek/Makefile                        | 2 ++
 arch/arm/boards/at91sam9x5ek/lowlevel.c                      | 2 ++
 arch/arm/boards/avnet-zedboard/Makefile                      | 2 ++
 arch/arm/boards/beagle/Makefile                              | 2 ++
 arch/arm/boards/beagle/lowlevel.c                            | 2 ++
 arch/arm/boards/beaglebone/Makefile                          | 2 ++
 arch/arm/boards/beaglebone/beaglebone.h                      | 2 ++
 arch/arm/boards/beaglebone/lowlevel.c                        | 2 ++
 arch/arm/boards/boundarydevices-nitrogen6/Makefile           | 2 ++
 .../flash-header-nitrogen6dl-1g.imxcfg                       | 2 ++
 .../flash-header-nitrogen6dl-2g.imxcfg                       | 2 ++
 .../flash-header-nitrogen6q-1g.imxcfg                        | 2 ++
 .../flash-header-nitrogen6q-2g.imxcfg                        | 2 ++
 .../flash-header-nitrogen6qp-max.imxcfg                      | 2 ++
 arch/arm/boards/boundarydevices-nitrogen6/lowlevel.c         | 2 ++
 arch/arm/boards/boundarydevices-nitrogen6/ram-base.imxcfg    | 2 ++
 arch/arm/boards/canon-a1100/Makefile                         | 2 ++
 arch/arm/boards/canon-a1100/lowlevel.c                       | 2 ++
 arch/arm/boards/ccxmx51/Makefile                             | 2 ++
 arch/arm/boards/ccxmx51/flash-header.imxcfg                  | 2 ++
 arch/arm/boards/ccxmx53/Makefile                             | 2 ++
 .../boards/ccxmx53/flash-header-imx53-ccxmx53_1gib.imxcfg    | 2 ++
 .../boards/ccxmx53/flash-header-imx53-ccxmx53_512mb.imxcfg   | 2 ++
 arch/arm/boards/chumby_falconwing/Makefile                   | 2 ++
 arch/arm/boards/chumby_falconwing/lowlevel.c                 | 2 ++
 arch/arm/boards/clep7212/Makefile                            | 2 ++
 arch/arm/boards/cm-fx6/Makefile                              | 2 ++
 arch/arm/boards/cm-fx6/flash-header-mx6-cm-fx6.imxcfg        | 2 ++
 arch/arm/boards/cm-fx6/lowlevel.c                            | 2 ++
 arch/arm/boards/crystalfontz-cfa10036/Makefile               | 2 ++
 arch/arm/boards/crystalfontz-cfa10036/lowlevel.c             | 2 ++
 arch/arm/boards/datamodul-edm-qmx6/Makefile                  | 2 ++
 arch/arm/boards/datamodul-edm-qmx6/flash-header.imxcfg       | 2 ++
 arch/arm/boards/dfi-fs700-m60/Makefile                       | 2 ++
 .../dfi-fs700-m60/flash-header-fs700-m60-6q-micron.imxcfg    | 2 ++
 .../dfi-fs700-m60/flash-header-fs700-m60-6q-nanya.imxcfg     | 2 ++
 .../boards/dfi-fs700-m60/flash-header-fs700-m60-6s.imxcfg    | 2 ++
 arch/arm/boards/digi-ccimx6ulsom/Makefile                    | 2 ++
 .../flash-header-imx6ul-ccimx6ulsbcpro.imxcfg                | 2 ++
 arch/arm/boards/digi-ccimx6ulsom/lowlevel.c                  | 2 ++
 arch/arm/boards/dss11/Makefile                               | 2 ++
 arch/arm/boards/duckbill/Makefile                            | 2 ++
 arch/arm/boards/duckbill/lowlevel.c                          | 2 ++
 arch/arm/boards/ebv-socrates/Makefile                        | 2 ++
 arch/arm/boards/ebv-socrates/board.c                         | 2 ++
 arch/arm/boards/ebv-socrates/lowlevel.c                      | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_auto.h                | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_auto_ac_init.c        | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_auto_inst_init.c      | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_defines.h             | 2 ++
 arch/arm/boards/edb93xx/Makefile                             | 1 +
 arch/arm/boards/efika-mx-smartbook/Makefile                  | 2 ++
 .../flash-header-imx51-genesi-efikasb.imxcfg                 | 2 ++
 arch/arm/boards/efika-mx-smartbook/lowlevel.c                | 2 ++
 arch/arm/boards/element14-warp7/Makefile                     | 2 ++
 arch/arm/boards/element14-warp7/lowlevel.c                   | 2 ++
 arch/arm/boards/eltec-hipercam/Makefile                      | 2 ++
 .../boards/eltec-hipercam/flash-header-eltec-hipercam.imxcfg | 2 ++
 arch/arm/boards/embedsky-e9/Makefile                         | 2 ++
 arch/arm/boards/embedsky-e9/flash-header-e9.imxcfg           | 2 ++
 arch/arm/boards/embedsky-e9/lowlevel.c                       | 2 ++
 arch/arm/boards/embest-marsboard/Makefile                    | 2 ++
 .../embest-marsboard/flash-header-embest-marsboard.imxcfg    | 2 ++
 arch/arm/boards/embest-riotboard/Makefile                    | 2 ++
 .../embest-riotboard/flash-header-embest-riotboard.imxcfg    | 2 ++
 arch/arm/boards/embest-riotboard/lowlevel.c                  | 2 ++
 arch/arm/boards/eukrea_cpuimx25/flash-header.imxcfg          | 2 ++
 arch/arm/boards/eukrea_cpuimx27/Makefile                     | 1 +
 arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S              | 2 ++
 arch/arm/boards/eukrea_cpuimx35/flash-header.imxcfg          | 2 ++
 arch/arm/boards/eukrea_cpuimx51/Makefile                     | 2 ++
 arch/arm/boards/eukrea_cpuimx51/flash-header.imxcfg          | 2 ++
 arch/arm/boards/eukrea_cpuimx51/lowlevel.c                   | 2 ++
 arch/arm/boards/freescale-mx21-ads/Makefile                  | 2 ++
 arch/arm/boards/freescale-mx23-evk/Makefile                  | 3 ++-
 arch/arm/boards/freescale-mx23-evk/lowlevel.c                | 2 ++
 arch/arm/boards/freescale-mx25-3ds/flash-header.imxcfg       | 2 ++
 arch/arm/boards/freescale-mx27-ads/Makefile                  | 1 +
 arch/arm/boards/freescale-mx27-ads/lowlevel_init.S           | 2 ++
 arch/arm/boards/freescale-mx28-evk/Makefile                  | 2 ++
 arch/arm/boards/freescale-mx28-evk/lowlevel.c                | 2 ++
 arch/arm/boards/freescale-mx35-3ds/Makefile                  | 2 ++
 arch/arm/boards/freescale-mx35-3ds/flash-header.imxcfg       | 2 ++
 arch/arm/boards/freescale-mx51-babbage/Makefile              | 2 ++
 .../freescale-mx51-babbage/flash-header-imx51-babbage.imxcfg | 2 ++
 arch/arm/boards/freescale-mx51-babbage/lowlevel.c            | 2 ++
 arch/arm/boards/freescale-mx51-babbage/power.c               | 2 ++
 arch/arm/boards/freescale-mx53-qsb/Makefile                  | 2 ++
 .../boards/freescale-mx53-qsb/flash-header-imx53-loco.imxcfg | 2 ++
 arch/arm/boards/freescale-mx53-qsb/lowlevel.c                | 2 ++
 arch/arm/boards/freescale-mx53-smd/Makefile                  | 2 ++
 arch/arm/boards/freescale-mx53-smd/flash-header.imxcfg       | 2 ++
 arch/arm/boards/freescale-mx53-smd/lowlevel.c                | 2 ++
 arch/arm/boards/freescale-mx53-vmx53/Makefile                | 2 ++
 .../freescale-mx53-vmx53/flash-header-imx53-vmx53.imxcfg     | 2 ++
 arch/arm/boards/freescale-mx53-vmx53/lowlevel.c              | 2 ++
 arch/arm/boards/freescale-mx6-sabrelite/Makefile             | 2 ++
 .../flash-header-mx6-sabrelite.imxcfg                        | 2 ++
 arch/arm/boards/freescale-mx6-sabrelite/lowlevel.c           | 2 ++
 arch/arm/boards/freescale-mx6-sabresd/Makefile               | 2 ++
 .../freescale-mx6-sabresd/flash-header-mx6q-sabresd.imxcfg   | 2 ++
 .../freescale-mx6-sabresd/flash-header-mx6qp-sabresd.imxcfg  | 2 ++
 arch/arm/boards/freescale-mx6-sabresd/lowlevel.c             | 2 ++
 arch/arm/boards/freescale-mx6sx-sabresdb/Makefile            | 2 ++
 .../flash-header-mx6sx-sabresdb.imxcfg                       | 2 ++
 arch/arm/boards/freescale-mx7-sabresd/Makefile               | 2 ++
 .../freescale-mx7-sabresd/flash-header-mx7-sabresd.imxcfg    | 4 +++-
 arch/arm/boards/freescale-mx7-sabresd/lowlevel.c             | 2 ++
 arch/arm/boards/freescale-vf610-twr/Makefile                 | 2 ++
 .../boards/freescale-vf610-twr/flash-header-vf610-twr.imxcfg | 2 ++
 arch/arm/boards/freescale-vf610-twr/lowlevel.c               | 2 ++
 arch/arm/boards/friendlyarm-mini2440/Kconfig                 | 1 +
 arch/arm/boards/friendlyarm-mini2440/Makefile                | 2 ++
 arch/arm/boards/friendlyarm-mini2440/lowlevel_init.S         | 2 ++
 arch/arm/boards/friendlyarm-mini6410/Makefile                | 2 ++
 arch/arm/boards/friendlyarm-mini6410/config.h                | 2 ++
 arch/arm/boards/friendlyarm-mini6410/lowlevel.c              | 2 ++
 arch/arm/boards/friendlyarm-tiny210/Makefile                 | 2 ++
 arch/arm/boards/friendlyarm-tiny210/config.h                 | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/Kconfig                 | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/Makefile                | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/config.h                | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/lowlevel.c              | 2 ++
 arch/arm/boards/gateworks-ventana/Makefile                   | 2 ++
 .../gateworks-ventana/flash-header-ventana-quad-1gx64.imxcfg | 2 ++
 arch/arm/boards/gateworks-ventana/lowlevel.c                 | 2 ++
 arch/arm/boards/gateworks-ventana/quad_128x64.imxcfg         | 2 ++
 arch/arm/boards/gateworks-ventana/ram-base.imxcfg            | 2 ++
 arch/arm/boards/gk802/Makefile                               | 2 ++
 arch/arm/boards/gk802/flash-header.imxcfg                    | 2 ++
 arch/arm/boards/gk802/lowlevel.c                             | 2 ++
 arch/arm/boards/globalscale-guruplug/Makefile                | 2 ++
 arch/arm/boards/globalscale-mirabox/Makefile                 | 2 ++
 arch/arm/boards/grinn-liteboard/Makefile                     | 2 ++
 .../grinn-liteboard/flash-header-liteboard-256mb.imxcfg      | 1 +
 .../grinn-liteboard/flash-header-liteboard-512mb.imxcfg      | 1 +
 arch/arm/boards/grinn-liteboard/flash-header-liteboard.h     | 1 +
 arch/arm/boards/guf-neso/Makefile                            | 2 ++
 arch/arm/boards/guf-neso/pll_init.S                          | 2 ++
 arch/arm/boards/guf-santaro/Makefile                         | 2 ++
 arch/arm/boards/guf-santaro/flash-header.imxcfg              | 2 ++
 arch/arm/boards/guf-santaro/lowlevel.c                       | 2 ++
 arch/arm/boards/guf-vincell/Makefile                         | 2 ++
 arch/arm/boards/guf-vincell/flash-header.imxcfg              | 2 ++
 arch/arm/boards/guf-vincell/lowlevel.c                       | 2 ++
 arch/arm/boards/haba-knx/Makefile                            | 2 ++
 arch/arm/boards/imx233-olinuxino/Makefile                    | 2 ++
 arch/arm/boards/imx233-olinuxino/lowlevel.c                  | 2 ++
 arch/arm/boards/kamstrup-mx7-concentrator/Makefile           | 4 +++-
 .../kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg     | 2 ++
 arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c         | 2 ++
 arch/arm/boards/karo-tx25/flash-header-tx25.imxcfg           | 1 +
 arch/arm/boards/karo-tx28/Makefile                           | 2 ++
 arch/arm/boards/karo-tx28/lowlevel.c                         | 2 ++
 arch/arm/boards/karo-tx28/tx28.h                             | 1 +
 arch/arm/boards/karo-tx53/Makefile                           | 2 ++
 arch/arm/boards/karo-tx53/flash-header-tx53-rev1011.imxcfg   | 2 ++
 .../karo-tx53/flash-header-tx53-revxx30-samsung.imxcfg       | 2 ++
 arch/arm/boards/karo-tx53/flash-header-tx53-revxx30.imxcfg   | 2 ++
 arch/arm/boards/karo-tx53/lowlevel.c                         | 2 ++
 arch/arm/boards/karo-tx6x/1600mhz_4x128mx16.imxcfg           | 2 ++
 arch/arm/boards/karo-tx6x/Makefile                           | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6dl-1g.imxcfg       | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6dl-512m.imxcfg     | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6q-1g.imxcfg        | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6qp-2g.imxcfg       | 2 ++
 arch/arm/boards/karo-tx6x/pmic.h                             | 1 +
 arch/arm/boards/karo-tx6x/ram-base.imxcfg                    | 2 ++
 arch/arm/boards/kindle-mx50/Makefile                         | 2 ++
 .../arm/boards/kindle-mx50/flash-header-kindle-lpddr1.imxcfg | 2 ++
 .../arm/boards/kindle-mx50/flash-header-kindle-lpddr2.imxcfg | 2 ++
 arch/arm/boards/kindle-mx50/lowlevel.c                       | 2 ++
 arch/arm/boards/kindle3/Makefile                             | 2 ++
 arch/arm/boards/kindle3/flash-header.imxcfg                  | 2 ++
 arch/arm/boards/kontron-samx6i/Makefile                      | 2 ++
 .../kontron-samx6i/flash-header-samx6i-duallite.imxcfg       | 2 ++
 .../boards/kontron-samx6i/flash-header-samx6i-quad.imxcfg    | 2 ++
 arch/arm/boards/kontron-samx6i/mem.h                         | 2 ++
 arch/arm/boards/lenovo-ix4-300d/Makefile                     | 2 ++
 arch/arm/boards/ls1046ardb/Makefile                          | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_pbi.cfg                | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_qspi_pbi.cfg           | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_rcw_emmc.cfg           | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_rcw_qspi.cfg           | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_rcw_sd.cfg             | 2 ++
 arch/arm/boards/lubbock/Makefile                             | 2 ++
 arch/arm/boards/lubbock/lowlevel.c                           | 2 ++
 arch/arm/boards/lxa-mc1/Makefile                             | 2 ++
 arch/arm/boards/mainstone/Makefile                           | 2 ++
 arch/arm/boards/mainstone/lowlevel.c                         | 2 ++
 arch/arm/boards/marvell-armada-xp-db/Makefile                | 2 ++
 arch/arm/boards/marvell-armada-xp-gp/Makefile                | 2 ++
 arch/arm/boards/microchip-ksz9477-evb/Makefile               | 2 ++
 arch/arm/boards/mioa701/Makefile                             | 2 ++
 arch/arm/boards/mioa701/lowlevel.c                           | 2 ++
 arch/arm/boards/mnt-reform/Makefile                          | 4 +++-
 arch/arm/boards/mnt-reform/flash-header-mnt-reform.imxcfg    | 2 ++
 arch/arm/boards/module-mb7707/Makefile                       | 2 ++
 arch/arm/boards/netgear-rn104/Makefile                       | 2 ++
 arch/arm/boards/netgear-rn104/lowlevel.c                     | 2 ++
 arch/arm/boards/netgear-rn2120/Makefile                      | 2 ++
 arch/arm/boards/netgear-rn2120/board.c                       | 2 ++
 arch/arm/boards/nhk8815/Makefile                             | 2 ++
 arch/arm/boards/nhk8815/lowlevel.c                           | 2 ++
 arch/arm/boards/nvidia-beaver/Makefile                       | 2 ++
 arch/arm/boards/nvidia-jetson-tk1/Makefile                   | 2 ++
 arch/arm/boards/nxp-imx6ull-evk/Makefile                     | 2 ++
 arch/arm/boards/nxp-imx8mm-evk/Makefile                      | 2 ++
 .../arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg | 2 ++
 arch/arm/boards/nxp-imx8mn-evk/Makefile                      | 2 ++
 .../arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg | 2 ++
 arch/arm/boards/nxp-imx8mp-evk/Makefile                      | 2 ++
 .../arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg | 2 ++
 arch/arm/boards/nxp-imx8mq-evk/.gitignore                    | 2 ++
 arch/arm/boards/nxp-imx8mq-evk/Makefile                      | 2 ++
 .../arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg | 2 ++
 arch/arm/boards/omap343xdsp/Makefile                         | 2 ++
 arch/arm/boards/omap343xdsp/lowlevel.c                       | 2 ++
 arch/arm/boards/omap3evm/Makefile                            | 2 ++
 arch/arm/boards/omap3evm/lowlevel.c                          | 2 ++
 arch/arm/boards/panda/Makefile                               | 2 ++
 arch/arm/boards/panda/board.c                                | 2 ++
 arch/arm/boards/panda/mux.c                                  | 2 ++
 arch/arm/boards/panda/mux.h                                  | 2 ++
 arch/arm/boards/phytec-phycard-imx27/Makefile                | 1 +
 arch/arm/boards/phytec-phycard-imx27/lowlevel.c              | 2 ++
 arch/arm/boards/phytec-phycard-omap3/lowlevel.c              | 2 ++
 arch/arm/boards/phytec-phycard-omap4/mux.c                   | 2 ++
 arch/arm/boards/phytec-phycard-omap4/mux.h                   | 2 ++
 arch/arm/boards/phytec-phycore-imx27/Makefile                | 2 ++
 arch/arm/boards/phytec-phycore-imx35/flash-header.imxcfg     | 2 ++
 arch/arm/boards/phytec-phycore-imx7/Makefile                 | 2 ++
 arch/arm/boards/phytec-phycore-imx7/lowlevel.c               | 2 ++
 arch/arm/boards/phytec-phycore-omap4460/Makefile             | 2 ++
 arch/arm/boards/phytec-phycore-omap4460/mux.c                | 2 ++
 arch/arm/boards/phytec-phycore-omap4460/mux.h                | 2 ++
 arch/arm/boards/phytec-phycore-pxa270/Makefile               | 2 ++
 arch/arm/boards/phytec-som-am335x/Kconfig                    | 1 +
 arch/arm/boards/phytec-som-am335x/Makefile                   | 2 ++
 arch/arm/boards/phytec-som-imx6/Makefile                     | 2 ++
 .../flash-header-phytec-pcaaxl3-1gib-1bank.imxcfg            | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib.imxcfg  | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcaaxl3-2gib.imxcfg  | 2 ++
 .../arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.h | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcl063-512mb.h       | 1 +
 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063.h | 1 +
 .../flash-header-phytec-pcl063ul-512mb.imxcfg                | 1 +
 .../flash-header-phytec-pcl063ull-256mb.imxcfg               | 1 +
 .../flash-header-phytec-pcl063ull-512mb.imxcfg               | 1 +
 .../phytec-som-imx6/flash-header-phytec-pcm058-1gib.imxcfg   | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058-2gib.imxcfg   | 2 ++
 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058.h | 2 ++
 .../flash-header-phytec-pcm058dl-1gib-32bit.imxcfg           | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058dl-1gib.imxcfg | 2 ++
 .../flash-header-phytec-pcm058dl-256mb.imxcfg                | 2 ++
 .../flash-header-phytec-pcm058dl-512mb.imxcfg                | 2 ++
 .../boards/phytec-som-imx6/flash-header-phytec-pcm058dl.h    | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058qp-1gib.imxcfg | 2 ++
 .../boards/phytec-som-imx6/flash-header-phytec-pcm058qp.h    | 2 ++
 .../flash-header-phytec-pfla02-1gib-1bank.imxcfg             | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02-1gib.imxcfg   | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02-2gib.imxcfg   | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02-4gib.imxcfg   | 2 ++
 .../flash-header-phytec-pfla02-512mb-1bank.imxcfg            | 2 ++
 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02.h | 2 ++
 .../flash-header-phytec-pfla02dl-1gib-1bank.imxcfg           | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg | 2 ++
 .../boards/phytec-som-imx6/flash-header-phytec-pfla02dl.h    | 2 ++
 .../flash-header-phytec-pfla02s-128mb-1bank.imxcfg           | 2 ++
 .../flash-header-phytec-pfla02s-256mb-1bank.imxcfg           | 2 ++
 .../flash-header-phytec-pfla02s-512mb-1bank.imxcfg           | 2 ++
 arch/arm/boards/phytec-som-imx8mq/.gitignore                 | 2 ++
 arch/arm/boards/phytec-som-imx8mq/Makefile                   | 2 ++
 .../phytec-som-imx8mq/flash-header-phycore-imx8mq.imxcfg     | 2 ++
 arch/arm/boards/phytec-som-rk3288/Makefile                   | 2 ++
 arch/arm/boards/plathome-openblocks-a6/Makefile              | 2 ++
 arch/arm/boards/plathome-openblocks-ax3/Makefile             | 2 ++
 arch/arm/boards/pm9261/Makefile                              | 2 ++
 arch/arm/boards/pm9263/Makefile                              | 2 ++
 arch/arm/boards/pm9g45/Makefile                              | 2 ++
 arch/arm/boards/protonic-imx6/Makefile                       | 2 ++
 arch/arm/boards/protonic-imx6/ddr3-defines.imxcfg            | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-alti6p.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-jozacp.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-lanmcu.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-plybas.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-plym2m.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prti6g.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prti6q.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtmvt.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtrvt.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtvt7.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtwd2.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtwd3.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-victgo.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-vicut1.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-vicut1q.imxcfg    | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-vicutp.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/lpddr2-defines.imxcfg          | 2 ++
 arch/arm/boards/protonic-imx6/padsetup-dl.imxcfg             | 1 +
 arch/arm/boards/protonic-imx6/padsetup-q.imxcfg              | 1 +
 arch/arm/boards/protonic-imx6/padsetup-ul.imxcfg             | 1 +
 arch/arm/boards/protonic-imx8m/Makefile                      | 2 ++
 arch/arm/boards/protonic-imx8m/flash-header-prt8mm.imxcfg    | 2 ++
 arch/arm/boards/protonic-stm32mp1/Makefile                   | 2 ++
 arch/arm/boards/qemu-virt/.gitignore                         | 2 ++
 arch/arm/boards/qemu-virt/Makefile                           | 2 ++
 arch/arm/boards/qil-a926x/Makefile                           | 2 ++
 arch/arm/boards/radxa-rock/Makefile                          | 2 ++
 arch/arm/boards/raspberry-pi/Makefile                        | 2 ++
 arch/arm/boards/raspberry-pi/lowlevel.c                      | 2 ++
 arch/arm/boards/raspberry-pi/lowlevel.h                      | 2 ++
 arch/arm/boards/reflex-achilles/Makefile                     | 2 ++
 arch/arm/boards/reflex-achilles/board.c                      | 2 ++
 arch/arm/boards/reflex-achilles/lowlevel.c                   | 2 ++
 arch/arm/boards/reflex-achilles/pinmux-config-arria10.c      | 2 ++
 arch/arm/boards/reflex-achilles/pll-config-arria10.c         | 2 ++
 arch/arm/boards/rockchip-rk3568-evb/Makefile                 | 2 ++
 arch/arm/boards/sama5d27-giantboard/Makefile                 | 2 ++
 arch/arm/boards/sama5d27-som1/Makefile                       | 2 ++
 arch/arm/boards/sama5d3_xplained/Makefile                    | 2 ++
 arch/arm/boards/sama5d3xek/Makefile                          | 2 ++
 arch/arm/boards/sama5d4_xplained/Makefile                    | 2 ++
 arch/arm/boards/sama5d4ek/Makefile                           | 2 ++
 arch/arm/boards/scb9328/Makefile                             | 1 +
 arch/arm/boards/seeed-odyssey/Makefile                       | 2 ++
 arch/arm/boards/skov-arm9cpu/Makefile                        | 2 ++
 arch/arm/boards/skov-imx6/Makefile                           | 2 ++
 arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg  | 2 ++
 arch/arm/boards/skov-imx6/version.h                          | 2 ++
 arch/arm/boards/solidrun-cubox/Makefile                      | 2 ++
 arch/arm/boards/solidrun-microsom/Makefile                   | 2 ++
 .../boards/solidrun-microsom/flash-header-microsom-i1.imxcfg | 2 ++
 .../boards/solidrun-microsom/flash-header-microsom-i2.imxcfg | 2 ++
 .../solidrun-microsom/flash-header-microsom-i2eX.imxcfg      | 2 ++
 .../boards/solidrun-microsom/flash-header-microsom-i4.imxcfg | 2 ++
 arch/arm/boards/solidrun-microsom/lowlevel.c                 | 2 ++
 arch/arm/boards/stm32mp15x-ev1/Makefile                      | 2 ++
 arch/arm/boards/stm32mp15xx-dkx/Makefile                     | 2 ++
 arch/arm/boards/technexion-pico-hobbit/Makefile              | 2 ++
 .../flash-header-imx6ul-pico-hobbit-256.imxcfg               | 2 ++
 .../flash-header-imx6ul-pico-hobbit-512.imxcfg               | 2 ++
 arch/arm/boards/technexion-pico-hobbit/lowlevel.c            | 2 ++
 arch/arm/boards/technexion-wandboard/Makefile                | 2 ++
 .../flash-header-technexion-wandboard.imxcfg                 | 2 ++
 arch/arm/boards/telit-evk-pro3/Makefile                      | 2 ++
 arch/arm/boards/terasic-de0-nano-soc/Makefile                | 2 ++
 arch/arm/boards/terasic-de0-nano-soc/board.c                 | 2 ++
 arch/arm/boards/terasic-de0-nano-soc/lowlevel.c              | 2 ++
 arch/arm/boards/terasic-de10-nano/Makefile                   | 2 ++
 arch/arm/boards/terasic-de10-nano/board.c                    | 2 ++
 arch/arm/boards/terasic-de10-nano/lowlevel.c                 | 2 ++
 arch/arm/boards/terasic-sockit/Makefile                      | 2 ++
 arch/arm/boards/terasic-sockit/board.c                       | 2 ++
 arch/arm/boards/terasic-sockit/lowlevel.c                    | 2 ++
 arch/arm/boards/tny-a926x/Makefile                           | 2 ++
 arch/arm/boards/toradex-colibri-t20/Makefile                 | 2 ++
 arch/arm/boards/toshiba-ac100/Makefile                       | 2 ++
 arch/arm/boards/tqma53/Makefile                              | 2 ++
 arch/arm/boards/tqma53/flash-header-tq-tqma53-1gib.imxcfg    | 2 ++
 arch/arm/boards/tqma53/flash-header-tq-tqma53-512mib.imxcfg  | 2 ++
 arch/arm/boards/tqma53/flash-header-tq-tqma53.h              | 2 ++
 arch/arm/boards/tqma53/flash-header.imxcfg                   | 2 ++
 arch/arm/boards/tqma53/lowlevel.c                            | 2 ++
 arch/arm/boards/tqma6x/Makefile                              | 2 ++
 arch/arm/boards/tqma6x/flash-header-tqma6dl.imxcfg           | 2 ++
 arch/arm/boards/tqma6x/flash-header-tqma6q.imxcfg            | 2 ++
 arch/arm/boards/tqmls1046a/Makefile                          | 2 ++
 arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg                | 2 ++
 arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg | 2 ++
 arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg   | 2 ++
 arch/arm/boards/turris-omnia/Makefile                        | 2 ++
 arch/arm/boards/udoo-neo/Makefile                            | 2 ++
 .../boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg  | 2 ++
 arch/arm/boards/udoo-neo/lowlevel.c                          | 2 ++
 arch/arm/boards/udoo/Makefile                                | 2 ++
 arch/arm/boards/udoo/flash-header-mx6-udoo.imxcfg            | 2 ++
 arch/arm/boards/udoo/lowlevel.c                              | 2 ++
 arch/arm/boards/usb-a926x/Makefile                           | 2 ++
 arch/arm/boards/usi-topkick/Makefile                         | 2 ++
 arch/arm/boards/variscite-mx6/Makefile                       | 2 ++
 arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg  | 2 ++
 arch/arm/boards/versatile/Kconfig                            | 1 +
 arch/arm/boards/versatile/Makefile                           | 2 ++
 arch/arm/boards/versatile/lowlevel.c                         | 2 ++
 arch/arm/boards/vexpress/Makefile                            | 2 ++
 arch/arm/boards/virt2real/Makefile                           | 2 ++
 arch/arm/boards/vscom-baltos/Makefile                        | 2 ++
 arch/arm/boards/vscom-baltos/lowlevel.c                      | 2 ++
 arch/arm/boards/wago-pfc-am35xx/Makefile                     | 2 ++
 arch/arm/boards/webasto-ccbv2/Makefile                       | 2 ++
 arch/arm/boards/zii-common/Makefile                          | 2 ++
 arch/arm/boards/zii-imx51-rdu1/Makefile                      | 2 ++
 .../boards/zii-imx51-rdu1/flash-header-imx51-zii-rdu1.imxcfg | 2 ++
 arch/arm/boards/zii-imx51-rdu1/lowlevel.c                    | 2 ++
 arch/arm/boards/zii-imx6q-rdu2/Makefile                      | 2 ++
 arch/arm/boards/zii-imx6q-rdu2/flash-header-rdu2.imxcfg      | 2 ++
 arch/arm/boards/zii-imx7d-dev/Makefile                       | 2 ++
 .../boards/zii-imx7d-dev/flash-header-zii-imx7d-dev.imxcfg   | 2 ++
 arch/arm/boards/zii-imx8mq-dev/Makefile                      | 2 ++
 .../boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg | 2 ++
 arch/arm/boards/zii-vf610-dev/Makefile                       | 2 ++
 .../boards/zii-vf610-dev/flash-header-zii-vf610-dev.imxcfg   | 2 ++
 arch/arm/boards/zylonite/Makefile                            | 2 ++
 arch/arm/boards/zylonite/lowlevel.c                          | 2 ++
 arch/arm/cpu/Kconfig                                         | 2 ++
 arch/arm/cpu/Makefile                                        | 2 ++
 arch/arm/cpu/atf.c                                           | 2 ++
 arch/arm/cpu/cache-armv4.S                                   | 2 ++
 arch/arm/cpu/cache-armv5.S                                   | 2 ++
 arch/arm/cpu/cache-armv6.S                                   | 2 ++
 arch/arm/cpu/cache-armv7.S                                   | 2 ++
 arch/arm/cpu/cache-l2x0.c                                    | 2 ++
 arch/arm/cpu/cache.c                                         | 2 ++
 arch/arm/cpu/entry.c                                         | 2 ++
 arch/arm/cpu/entry.h                                         | 2 ++
 arch/arm/cpu/entry_ll.S                                      | 2 ++
 arch/arm/cpu/entry_ll_64.S                                   | 2 ++
 arch/arm/cpu/exceptions.S                                    | 2 ++
 arch/arm/cpu/hyp.S                                           | 2 ++
 arch/arm/cpu/lowlevel.S                                      | 2 ++
 arch/arm/cpu/lowlevel_64.S                                   | 2 ++
 arch/arm/cpu/mmu-common.c                                    | 2 ++
 arch/arm/cpu/mmu-common.h                                    | 4 +++-
 arch/arm/cpu/mmu-early.c                                     | 2 ++
 arch/arm/cpu/mmu-early_64.c                                  | 4 +++-
 arch/arm/cpu/mmu.h                                           | 2 ++
 arch/arm/cpu/mmu_64.h                                        | 1 +
 arch/arm/cpu/sections.c                                      | 2 ++
 arch/arm/cpu/setupc.S                                        | 2 ++
 arch/arm/cpu/setupc_64.S                                     | 2 ++
 arch/arm/cpu/sm_as.S                                         | 2 ++
 arch/arm/crypto/.gitignore                                   | 2 ++
 arch/arm/crypto/Makefile                                     | 1 +
 arch/arm/dts/Makefile                                        | 2 ++
 arch/arm/include/asm/armlinux.h                              | 2 ++
 arch/arm/include/asm/asm-offsets.h                           | 4 +++-
 arch/arm/include/asm/assembler64.h                           | 4 +++-
 arch/arm/include/asm/barebox-arm-head.h                      | 2 ++
 arch/arm/include/asm/bitops.h                                | 2 ++
 arch/arm/include/asm/bitsperlong.h                           | 2 ++
 arch/arm/include/asm/byteorder.h                             | 2 ++
 arch/arm/include/asm/cache.h                                 | 2 ++
 arch/arm/include/asm/common.h                                | 2 ++
 arch/arm/include/asm/cputype.h                               | 2 ++
 arch/arm/include/asm/elf.h                                   | 2 ++
 arch/arm/include/asm/gic.h                                   | 2 ++
 arch/arm/include/asm/hardware/arm_timer.h                    | 2 ++
 arch/arm/include/asm/io.h                                    | 2 ++
 arch/arm/include/asm/linkage.h                               | 2 ++
 arch/arm/include/asm/memory.h                                | 2 ++
 arch/arm/include/asm/mmu.h                                   | 2 ++
 arch/arm/include/asm/module.h                                | 2 ++
 arch/arm/include/asm/posix_types.h                           | 2 ++
 arch/arm/include/asm/sections.h                              | 2 ++
 arch/arm/include/asm/secure.h                                | 2 ++
 arch/arm/include/asm/semihosting.h                           | 2 ++
 arch/arm/include/asm/stacktrace.h                            | 2 ++
 arch/arm/include/asm/string.h                                | 2 ++
 arch/arm/include/asm/swab.h                                  | 2 ++
 arch/arm/include/asm/syscounter.h                            | 4 +++-
 arch/arm/include/asm/system.h                                | 2 ++
 arch/arm/include/asm/system_info.h                           | 2 ++
 arch/arm/include/asm/types.h                                 | 2 ++
 arch/arm/include/asm/unaligned.h                             | 2 ++
 arch/arm/lib/Makefile                                        | 2 ++
 arch/arm/lib32/.gitignore                                    | 2 ++
 arch/arm/lib32/Makefile                                      | 2 ++
 arch/arm/lib32/bootm.c                                       | 2 ++
 arch/arm/lib32/bootu.c                                       | 2 ++
 arch/arm/lib32/bootz.c                                       | 2 ++
 arch/arm/lib32/io.c                                          | 2 ++
 arch/arm/lib32/runtime-offset.S                              | 2 ++
 arch/arm/lib32/start-kernel-optee.S                          | 2 ++
 arch/arm/lib32/unwind.c                                      | 2 ++
 arch/arm/lib64/.gitignore                                    | 2 ++
 arch/arm/lib64/Makefile                                      | 2 ++
 arch/arm/lib64/pbl.c                                         | 2 ++
 arch/arm/lib64/runtime-offset.S                              | 2 ++
 arch/arm/lib64/string.c                                      | 2 ++
 arch/arm/mach-at91/Kconfig                                   | 2 ++
 arch/arm/mach-at91/Makefile                                  | 2 ++
 arch/arm/mach-at91/at91rm9200.c                              | 2 ++
 arch/arm/mach-at91/at91sam9260.c                             | 2 ++
 arch/arm/mach-at91/at91sam9261.c                             | 2 ++
 arch/arm/mach-at91/at91sam9263.c                             | 2 ++
 arch/arm/mach-at91/at91sam9g45.c                             | 2 ++
 arch/arm/mach-at91/at91sam9n12.c                             | 2 ++
 arch/arm/mach-at91/at91sam9x5.c                              | 2 ++
 arch/arm/mach-at91/bootm-barebox.c                           | 2 ++
 arch/arm/mach-at91/include/mach/at91sam926x.h                | 2 ++
 arch/arm/mach-at91/include/mach/barebox-arm-head.h           | 2 ++
 arch/arm/mach-at91/include/mach/early_udelay.h               | 2 ++
 arch/arm/mach-at91/include/mach/sama5d2_ll.h                 | 2 ++
 arch/arm/mach-at91/include/mach/xload.h                      | 2 ++
 arch/arm/mach-at91/sama5d3.c                                 | 2 ++
 arch/arm/mach-at91/xload-mmc.c                               | 2 ++
 arch/arm/mach-bcm283x/Kconfig                                | 2 ++
 arch/arm/mach-bcm283x/Makefile                               | 2 ++
 arch/arm/mach-clps711x/Kconfig                               | 2 ++
 arch/arm/mach-clps711x/Makefile                              | 2 ++
 arch/arm/mach-clps711x/include/mach/devices.h                | 2 ++
 arch/arm/mach-davinci/Kconfig                                | 2 ++
 arch/arm/mach-davinci/Makefile                               | 2 ++
 arch/arm/mach-digic/Kconfig                                  | 2 ++
 arch/arm/mach-digic/Makefile                                 | 2 ++
 arch/arm/mach-ep93xx/Kconfig                                 | 2 ++
 arch/arm/mach-ep93xx/Makefile                                | 2 ++
 arch/arm/mach-ep93xx/header.c                                | 2 ++
 arch/arm/mach-ep93xx/include/mach/barebox.lds.h              | 1 +
 arch/arm/mach-imx/Kconfig                                    | 2 ++
 arch/arm/mach-imx/Makefile                                   | 2 ++
 arch/arm/mach-imx/atf.c                                      | 2 ++
 arch/arm/mach-imx/devices.c                                  | 2 ++
 arch/arm/mach-imx/imx5.c                                     | 2 ++
 arch/arm/mach-imx/include/mach/atf.h                         | 2 ++
 arch/arm/mach-imx/include/mach/bbu.h                         | 2 ++
 arch/arm/mach-imx/include/mach/ccm.h                         | 4 +++-
 arch/arm/mach-imx/include/mach/clock.h                       | 2 ++
 arch/arm/mach-imx/include/mach/debug_ll.h                    | 2 ++
 arch/arm/mach-imx/include/mach/devices-imx1.h                | 2 ++
 arch/arm/mach-imx/include/mach/devices-imx21.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx25.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx27.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx31.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx35.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx50.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx51.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx53.h               | 1 +
 arch/arm/mach-imx/include/mach/devices-imx6.h                | 2 ++
 arch/arm/mach-imx/include/mach/devices.h                     | 1 +
 arch/arm/mach-imx/include/mach/esdctl-v4.h                   | 2 ++
 arch/arm/mach-imx/include/mach/esdctl.h                      | 2 ++
 .../include/mach/flash-header/vf610-ddr-cr-default.imxcfg    | 4 +++-
 .../include/mach/flash-header/vf610-ddr-pll2-400mhz.imxcfg   | 2 ++
 arch/arm/mach-imx/include/mach/generic.h                     | 2 ++
 arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h          | 2 ++
 arch/arm/mach-imx/include/mach/habv4-imx6-gencsf-template.h  | 2 ++
 arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h           | 1 +
 arch/arm/mach-imx/include/mach/habv4-imx6ull-gencsf.h        | 1 +
 arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h           | 2 ++
 arch/arm/mach-imx/include/mach/imx-gpio.h                    | 2 ++
 arch/arm/mach-imx/include/mach/imx-header.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx-nand.h                    | 2 ++
 arch/arm/mach-imx/include/mach/imx-pll.h                     | 2 ++
 arch/arm/mach-imx/include/mach/imx1-regs.h                   | 2 ++
 arch/arm/mach-imx/include/mach/imx21-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx25-fusemap.h               | 2 ++
 arch/arm/mach-imx/include/mach/imx27-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx5.h                        | 2 ++
 arch/arm/mach-imx/include/mach/imx50-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx51-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx53-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx6-fusemap.h                | 2 ++
 arch/arm/mach-imx/include/mach/imx6-mmdc.h                   | 2 ++
 arch/arm/mach-imx/include/mach/imx6-regs.h                   | 2 ++
 arch/arm/mach-imx/include/mach/imx6.h                        | 2 ++
 arch/arm/mach-imx/include/mach/imx7-ccm-regs.h               | 2 ++
 arch/arm/mach-imx/include/mach/imx7-regs.h                   | 2 ++
 arch/arm/mach-imx/include/mach/imx7.h                        | 4 +++-
 arch/arm/mach-imx/include/mach/imx8m-ccm-regs.h              | 2 ++
 arch/arm/mach-imx/include/mach/imx8m-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx8mm-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx8mp-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx8mq-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx8mq.h                      | 2 ++
 arch/arm/mach-imx/include/mach/imx_cpu_types.h               | 2 ++
 arch/arm/mach-imx/include/mach/imxfb.h                       | 2 ++
 arch/arm/mach-imx/include/mach/iomux-mx1.h                   | 2 ++
 arch/arm/mach-imx/include/mach/iomux-mx8m.h                  | 2 ++
 arch/arm/mach-imx/include/mach/iomux-v1.h                    | 2 ++
 arch/arm/mach-imx/include/mach/ocotp-fusemap.h               | 2 ++
 arch/arm/mach-imx/include/mach/ocotp.h                       | 2 ++
 arch/arm/mach-imx/include/mach/reset-reason.h                | 2 ++
 arch/arm/mach-imx/include/mach/revision.h                    | 2 ++
 arch/arm/mach-imx/include/mach/spi.h                         | 1 +
 arch/arm/mach-imx/include/mach/usb.h                         | 2 ++
 arch/arm/mach-imx/include/mach/vf610-ddrmc.h                 | 2 ++
 arch/arm/mach-imx/include/mach/vf610-fusemap.h               | 2 ++
 arch/arm/mach-imx/include/mach/vf610.h                       | 2 ++
 arch/arm/mach-imx/include/mach/weim.h                        | 2 ++
 arch/arm/mach-imx/include/mach/xload.h                       | 2 ++
 arch/arm/mach-imx/xload-common.c                             | 2 ++
 arch/arm/mach-imx/xload-spi.c                                | 2 ++
 arch/arm/mach-layerscape/Kconfig                             | 2 ++
 arch/arm/mach-layerscape/Makefile                            | 2 ++
 arch/arm/mach-layerscape/icid.c                              | 2 ++
 arch/arm/mach-layerscape/include/mach/bbu.h                  | 4 +++-
 arch/arm/mach-layerscape/include/mach/debug_ll.h             | 2 ++
 arch/arm/mach-layerscape/include/mach/errata.h               | 2 ++
 arch/arm/mach-layerscape/include/mach/layerscape.h           | 2 ++
 arch/arm/mach-layerscape/include/mach/lowlevel.h             | 2 ++
 arch/arm/mach-layerscape/include/mach/xload.h                | 2 ++
 arch/arm/mach-layerscape/lowlevel.S                          | 2 ++
 arch/arm/mach-layerscape/pblimage.c                          | 2 ++
 arch/arm/mach-layerscape/ppa-entry.S                         | 2 ++
 arch/arm/mach-mvebu/Kconfig                                  | 2 ++
 arch/arm/mach-mvebu/Makefile                                 | 2 ++
 arch/arm/mach-mvebu/include/mach/barebox-arm-head.h          | 2 ++
 arch/arm/mach-mvebu/include/mach/bbu.h                       | 2 ++
 arch/arm/mach-mvebu/kwb_bbu.c                                | 2 ++
 arch/arm/mach-mvebu/kwbootimage.c                            | 2 ++
 arch/arm/mach-mxs/Kconfig                                    | 2 ++
 arch/arm/mach-mxs/Makefile                                   | 2 ++
 arch/arm/mach-mxs/include/mach/debug_ll.h                    | 2 ++
 arch/arm/mach-mxs/include/mach/devices.h                     | 2 ++
 arch/arm/mach-mxs/include/mach/imx23.h                       | 4 +++-
 arch/arm/mach-mxs/include/mach/imx28.h                       | 4 +++-
 arch/arm/mach-mxs/include/mach/power.h                       | 2 ++
 arch/arm/mach-mxs/include/mach/revision.h                    | 2 ++
 arch/arm/mach-mxs/include/mach/usb.h                         | 2 ++
 arch/arm/mach-nomadik/Kconfig                                | 2 ++
 arch/arm/mach-nomadik/Makefile                               | 1 +
 arch/arm/mach-nomadik/clock.c                                | 2 ++
 arch/arm/mach-nomadik/include/mach/fsmc.h                    | 2 ++
 arch/arm/mach-nomadik/include/mach/nand.h                    | 2 ++
 arch/arm/mach-omap/am3xxx.c                                  | 4 +++-
 arch/arm/mach-omap/include/mach/am33xx-generic.h             | 2 ++
 arch/arm/mach-omap/include/mach/am3xxx-silicon.h             | 4 +++-
 arch/arm/mach-omap/include/mach/bbu.h                        | 2 ++
 arch/arm/mach-omap/include/mach/devices.h                    | 2 ++
 arch/arm/mach-omap/include/mach/generic.h                    | 2 ++
 arch/arm/mach-omap/include/mach/mcspi.h                      | 2 ++
 arch/arm/mach-omap/include/mach/omap-fb.h                    | 2 ++
 arch/arm/mach-omap/include/mach/omap3-devices.h              | 2 ++
 arch/arm/mach-omap/include/mach/omap3-generic.h              | 2 ++
 arch/arm/mach-omap/include/mach/omap4-clock.h                | 2 ++
 arch/arm/mach-omap/include/mach/omap4-devices.h              | 2 ++
 arch/arm/mach-omap/include/mach/omap4-generic.h              | 2 ++
 arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h          | 2 ++
 arch/arm/mach-omap/omap4_clock.c                             | 2 ++
 arch/arm/mach-omap/omap4_generic.c                           | 2 ++
 arch/arm/mach-omap/omap_devices.c                            | 2 ++
 arch/arm/mach-omap/omap_fb.c                                 | 2 ++
 arch/arm/mach-omap/xload.c                                   | 2 ++
 arch/arm/mach-pxa/Kconfig                                    | 2 ++
 arch/arm/mach-pxa/Makefile                                   | 2 ++
 arch/arm/mach-pxa/include/mach/mci_pxa2xx.h                  | 2 ++
 arch/arm/mach-pxa/include/mach/mfp-pxa27x.h                  | 2 ++
 arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h                  | 2 ++
 arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h                  | 2 ++
 arch/arm/mach-pxa/include/mach/pxa25x-regs.h                 | 2 ++
 arch/arm/mach-pxa/include/mach/pxa27x-regs.h                 | 2 ++
 arch/arm/mach-pxa/include/mach/pxafb.h                       | 2 ++
 arch/arm/mach-pxa/include/mach/regs-intc.h                   | 2 ++
 arch/arm/mach-pxa/include/mach/regs-lcd.h                    | 2 ++
 arch/arm/mach-pxa/include/mach/regs-ost.h                    | 2 ++
 arch/arm/mach-pxa/include/mach/udc_pxa2xx.h                  | 2 ++
 arch/arm/mach-rockchip/Kconfig                               | 2 ++
 arch/arm/mach-rockchip/Makefile                              | 2 ++
 arch/arm/mach-rockchip/bootm.c                               | 2 ++
 arch/arm/mach-rockchip/include/mach/atf.h                    | 2 ++
 arch/arm/mach-rockchip/include/mach/bbu.h                    | 2 ++
 arch/arm/mach-rockchip/include/mach/debug_ll.h               | 2 ++
 arch/arm/mach-rockchip/include/mach/rk3568-regs.h            | 2 ++
 arch/arm/mach-rockchip/include/mach/rockchip.h               | 2 ++
 arch/arm/mach-samsung/Kconfig                                | 2 ++
 arch/arm/mach-samsung/Makefile                               | 2 ++
 arch/arm/mach-samsung/include/mach/bbu.h                     | 2 ++
 arch/arm/mach-socfpga/Kconfig                                | 2 ++
 arch/arm/mach-socfpga/Makefile                               | 2 ++
 arch/arm/mach-socfpga/arria10-generic.c                      | 2 ++
 arch/arm/mach-socfpga/arria10-xload-emmc.c                   | 2 ++
 arch/arm/mach-socfpga/arria10-xload.c                        | 2 ++
 arch/arm/mach-socfpga/cyclone5-generic.c                     | 2 ++
 arch/arm/mach-socfpga/cyclone5-init.c                        | 2 ++
 arch/arm/mach-socfpga/include/mach/arria10-xload.h           | 2 ++
 arch/arm/mach-socfpga/include/mach/barebox-arm-head.h        | 2 ++
 arch/arm/mach-socfpga/include/mach/cyclone5-regs.h           | 2 ++
 arch/arm/mach-socfpga/include/mach/cyclone5-sdram-config.h   | 2 ++
 arch/arm/mach-socfpga/include/mach/debug_ll.h                | 2 ++
 arch/arm/mach-socfpga/include/mach/generic.h                 | 2 ++
 arch/arm/mach-socfpga/include/mach/lowlevel.h                | 2 ++
 arch/arm/mach-socfpga/include/mach/pll_config.h              | 2 ++
 arch/arm/mach-socfpga/xload.c                                | 2 ++
 arch/arm/mach-stm32mp/Kconfig                                | 2 ++
 arch/arm/mach-stm32mp/Makefile                               | 2 ++
 arch/arm/mach-stm32mp/include/mach/bbu.h                     | 2 ++
 arch/arm/mach-stm32mp/include/mach/bsec.h                    | 2 ++
 arch/arm/mach-stm32mp/include/mach/debug_ll.h                | 2 ++
 arch/arm/mach-stm32mp/include/mach/entry.h                   | 2 ++
 arch/arm/mach-stm32mp/include/mach/smc.h                     | 2 ++
 arch/arm/mach-stm32mp/stm32image.c                           | 2 ++
 arch/arm/mach-tegra/Kconfig                                  | 2 ++
 arch/arm/mach-tegra/Makefile                                 | 2 ++
 arch/arm/mach-uemd/Kconfig                                   | 2 ++
 arch/arm/mach-uemd/Makefile                                  | 2 ++
 arch/arm/mach-uemd/include/mach/hardware.h                   | 2 ++
 arch/arm/mach-versatile/Kconfig                              | 1 +
 arch/arm/mach-versatile/Makefile                             | 1 +
 arch/arm/mach-versatile/include/mach/init.h                  | 1 +
 arch/arm/mach-vexpress/Kconfig                               | 2 ++
 arch/arm/mach-vexpress/Makefile                              | 2 ++
 arch/arm/mach-zynq/Kconfig                                   | 2 ++
 arch/arm/mach-zynq/Makefile                                  | 2 ++
 arch/arm/mach-zynq/include/mach/debug_ll.h                   | 2 ++
 arch/arm/mach-zynq/include/mach/zynq-flash-header.h          | 2 ++
 arch/arm/tools/Makefile                                      | 2 ++
 arch/arm/tools/gen-mach-types                                | 2 ++
 arch/kvx/Kconfig                                             | 2 ++
 arch/kvx/Makefile                                            | 2 ++
 arch/kvx/dts/Makefile                                        | 2 ++
 arch/mips/Kconfig                                            | 5 ++---
 arch/mips/Makefile                                           | 2 ++
 arch/mips/boards/8devices-lima/Makefile                      | 2 ++
 arch/mips/boards/Makefile                                    | 2 ++
 arch/mips/boards/black-swift/Makefile                        | 2 ++
 arch/mips/boards/dlink-dir-320/Makefile                      | 2 ++
 arch/mips/boards/dptechnics-dpt-module/Makefile              | 2 ++
 arch/mips/boards/img-ci20/Makefile                           | 2 ++
 arch/mips/boards/loongson-ls1b/Makefile                      | 2 ++
 arch/mips/boards/netgear-wg102/Makefile                      | 2 ++
 arch/mips/boards/netgear-wg102/ram.c                         | 2 ++
 arch/mips/boards/okud-max9331/Makefile                       | 2 ++
 arch/mips/boards/openembed-som9331/Makefile                  | 2 ++
 arch/mips/boards/qemu-malta/Makefile                         | 2 ++
 arch/mips/boards/ritmix-rzx50/Makefile                       | 2 ++
 arch/mips/boards/tplink-mr3020/Makefile                      | 2 ++
 arch/mips/boards/tplink-wdr4300/Makefile                     | 2 ++
 arch/mips/boot/Makefile                                      | 2 ++
 arch/mips/dts/Makefile                                       | 2 ++
 arch/mips/include/asm/asm-offsets.h                          | 2 ++
 arch/mips/include/asm/bitsperlong.h                          | 2 ++
 arch/mips/include/asm/cache.h                                | 2 ++
 arch/mips/include/asm/cpu.h                                  | 2 ++
 arch/mips/include/asm/dma-mapping.h                          | 2 ++
 arch/mips/include/asm/io.h                                   | 2 ++
 arch/mips/include/asm/memory.h                               | 2 ++
 arch/mips/include/asm/mmu.h                                  | 2 ++
 arch/mips/lib/.gitignore                                     | 2 ++
 arch/mips/lib/Makefile                                       | 2 ++
 arch/mips/lib/asm-offsets.c                                  | 2 ++
 arch/mips/lib/bootm.c                                        | 2 ++
 arch/mips/lib/genex.S                                        | 2 ++
 arch/mips/lib/sections.c                                     | 2 ++
 arch/mips/lib/shutdown.c                                     | 2 ++
 arch/mips/lib/traps.c                                        | 2 ++
 arch/mips/mach-ar231x/Kconfig                                | 2 ++
 arch/mips/mach-ar231x/Makefile                               | 2 ++
 arch/mips/mach-ar231x/include/mach/pbl_macros.h              | 2 ++
 arch/mips/mach-ath79/Kconfig                                 | 2 ++
 arch/mips/mach-ath79/Makefile                                | 2 ++
 arch/mips/mach-ath79/include/mach/pbl_ll_init_ar9344_1.1.h   | 2 ++
 arch/mips/mach-ath79/include/mach/pbl_ll_init_qca4531.h      | 2 ++
 arch/mips/mach-ath79/include/mach/pbl_macros.h               | 2 ++
 arch/mips/mach-bcm47xx/Kconfig                               | 2 ++
 arch/mips/mach-bcm47xx/Makefile                              | 2 ++
 arch/mips/mach-loongson/Kconfig                              | 2 ++
 arch/mips/mach-loongson/Makefile                             | 2 ++
 arch/mips/mach-loongson/include/mach/pbl_macros.h            | 2 ++
 arch/mips/mach-malta/Kconfig                                 | 2 ++
 arch/mips/mach-malta/Makefile                                | 2 ++
 arch/mips/mach-malta/include/mach/mach-gt64120.h             | 2 ++
 arch/mips/mach-malta/pci.c                                   | 2 ++
 arch/mips/mach-xburst/Kconfig                                | 2 ++
 arch/mips/mach-xburst/Makefile                               | 2 ++
 arch/mips/mach-xburst/include/mach/devices.h                 | 2 ++
 arch/mips/pbl/.gitignore                                     | 2 ++
 arch/mips/pbl/Makefile                                       | 1 +
 arch/mips/pbl/piggy.gzip.S                                   | 2 ++
 arch/mips/pbl/piggy.lz4.S                                    | 2 ++
 arch/mips/pbl/piggy.lzo.S                                    | 2 ++
 arch/mips/pbl/piggy.shipped.S                                | 2 ++
 arch/mips/pbl/piggy.xzkern.S                                 | 2 ++
 arch/openrisc/Kconfig                                        | 2 ++
 arch/openrisc/Makefile                                       | 2 ++
 arch/openrisc/boards/generic/Makefile                        | 2 ++
 arch/openrisc/boards/generic/config.h                        | 1 +
 arch/openrisc/boards/generic/generic.c                       | 1 +
 arch/openrisc/cpu/.gitignore                                 | 2 ++
 arch/openrisc/cpu/Makefile                                   | 2 ++
 arch/openrisc/dts/Makefile                                   | 1 +
 arch/openrisc/include/asm/bitsperlong.h                      | 2 ++
 arch/openrisc/include/asm/byteorder.h                        | 2 ++
 arch/openrisc/include/asm/common.h                           | 2 ++
 arch/openrisc/include/asm/linkage.h                          | 2 ++
 arch/openrisc/include/asm/mmu.h                              | 2 ++
 arch/openrisc/include/asm/posix_types.h                      | 2 ++
 arch/openrisc/include/asm/sections.h                         | 2 ++
 arch/openrisc/include/asm/string.h                           | 2 ++
 arch/openrisc/include/asm/swab.h                             | 2 ++
 arch/openrisc/lib/Makefile                                   | 2 ++
 arch/openrisc/lib/ashldi3.S                                  | 2 ++
 arch/openrisc/lib/asm-offsets.c                              | 2 ++
 arch/openrisc/lib/lshrdi3.S                                  | 2 ++
 arch/openrisc/lib/muldi3.S                                   | 2 ++
 arch/powerpc/Kbuild                                          | 2 ++
 arch/powerpc/Kconfig                                         | 2 ++
 arch/powerpc/Makefile                                        | 2 ++
 arch/powerpc/boards/.gitignore                               | 2 ++
 arch/powerpc/boards/freescale-p1010rdb/Makefile              | 2 ++
 arch/powerpc/boards/freescale-p1022ds/Makefile               | 2 ++
 arch/powerpc/boards/freescale-p2020rdb/Makefile              | 2 ++
 arch/powerpc/boards/owc-da923rc/Makefile                     | 2 ++
 arch/powerpc/boards/pcm030/Makefile                          | 2 ++
 arch/powerpc/cpu-85xx/Makefile                               | 2 ++
 arch/powerpc/cpu-85xx/resetvec.S                             | 2 ++
 arch/powerpc/ddr-8xxx/Makefile                               | 2 ++
 arch/powerpc/include/asm/atomic.h                            | 2 ++
 arch/powerpc/include/asm/bitops.h                            | 2 ++
 arch/powerpc/include/asm/bitsperlong.h                       | 2 ++
 arch/powerpc/include/asm/cache.h                             | 2 ++
 arch/powerpc/include/asm/common.h                            | 2 ++
 arch/powerpc/include/asm/io.h                                | 2 ++
 arch/powerpc/include/asm/mmu.h                               | 2 ++
 arch/powerpc/include/asm/module.h                            | 2 ++
 arch/powerpc/include/asm/pci_io.h                            | 2 ++
 arch/powerpc/include/asm/posix_types.h                       | 2 ++
 arch/powerpc/include/asm/processor.h                         | 2 ++
 arch/powerpc/include/asm/ptrace.h                            | 2 ++
 arch/powerpc/include/asm/sections.h                          | 2 ++
 arch/powerpc/include/asm/sigcontext.h                        | 2 ++
 arch/powerpc/include/asm/signal.h                            | 2 ++
 arch/powerpc/include/asm/status_led.h                        | 2 ++
 arch/powerpc/include/asm/string.h                            | 2 ++
 arch/powerpc/include/asm/types.h                             | 2 ++
 arch/powerpc/include/asm/unaligned.h                         | 2 ++
 arch/powerpc/lib/Makefile                                    | 2 ++
 arch/powerpc/lib/kgdb.c                                      | 2 ++
 arch/powerpc/lib/misc.S                                      | 1 +
 arch/powerpc/lib/ppclinux.c                                  | 2 ++
 arch/powerpc/mach-mpc5xxx/Kconfig                            | 2 ++
 arch/powerpc/mach-mpc5xxx/Makefile                           | 2 ++
 arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S   | 2 ++
 arch/powerpc/mach-mpc5xxx/include/mach/clock.h               | 2 ++
 arch/powerpc/mach-mpc5xxx/include/mach/sdma.h                | 2 ++
 arch/powerpc/mach-mpc5xxx/loadtask.c                         | 2 ++
 arch/powerpc/mach-mpc5xxx/reginfo.c                          | 2 ++
 arch/powerpc/mach-mpc85xx/.gitignore                         | 2 ++
 arch/powerpc/mach-mpc85xx/Kconfig                            | 2 ++
 arch/powerpc/mach-mpc85xx/Makefile                           | 2 ++
 arch/powerpc/mach-mpc85xx/include/mach/clock.h               | 2 ++
 arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h             | 2 ++
 arch/riscv/Kconfig                                           | 2 ++
 arch/riscv/Kconfig.socs                                      | 2 ++
 arch/riscv/Makefile                                          | 2 ++
 arch/riscv/boards/riscvemu/Makefile                          | 2 ++
 arch/riscv/include/asm/asm-offsets.h                         | 2 ++
 arch/riscv/include/asm/bitsperlong.h                         | 2 ++
 arch/riscv/include/asm/byteorder.h                           | 2 ++
 arch/riscv/include/asm/io.h                                  | 2 ++
 arch/riscv/include/asm/mmu.h                                 | 2 ++
 arch/riscv/include/asm/posix_types.h                         | 2 ++
 arch/riscv/include/asm/swab.h                                | 2 ++
 arch/riscv/include/asm/types.h                               | 2 ++
 arch/riscv/include/asm/unaligned.h                           | 2 ++
 arch/riscv/lib/.gitignore                                    | 2 ++
 arch/riscv/lib/asm-offsets.c                                 | 2 ++
 arch/sandbox/Kconfig                                         | 2 ++
 arch/sandbox/Makefile                                        | 2 ++
 arch/sandbox/board/.gitignore                                | 2 ++
 arch/sandbox/board/Makefile                                  | 2 ++
 arch/sandbox/board/barebox.lds.S                             | 2 ++
 arch/sandbox/board/dev-random.c                              | 2 ++
 arch/sandbox/board/power.c                                   | 2 ++
 arch/sandbox/dts/Makefile                                    | 2 ++
 arch/sandbox/include/asm/bitsperlong.h                       | 2 ++
 arch/sandbox/include/asm/byteorder.h                         | 2 ++
 arch/sandbox/include/asm/common.h                            | 2 ++
 arch/sandbox/include/asm/elf.h                               | 2 ++
 arch/sandbox/include/asm/io.h                                | 2 ++
 arch/sandbox/include/asm/mmu.h                               | 2 ++
 arch/sandbox/include/asm/posix_types.h                       | 2 ++
 arch/sandbox/include/asm/sections.h                          | 2 ++
 arch/sandbox/include/asm/string.h                            | 2 ++
 arch/sandbox/include/asm/swab.h                              | 2 ++
 arch/sandbox/include/asm/types.h                             | 2 ++
 arch/sandbox/include/asm/unaligned.h                         | 2 ++
 arch/sandbox/lib/Makefile                                    | 2 ++
 arch/sandbox/lib/asm-offsets.c                               | 2 ++
 arch/sandbox/mach-sandbox/include/mach/hostfile.h            | 2 ++
 arch/sandbox/mach-sandbox/include/mach/linux.h               | 2 ++
 arch/sandbox/os/Makefile                                     | 2 ++
 arch/x86/Kconfig                                             | 5 ++---
 arch/x86/Makefile                                            | 2 ++
 arch/x86/include/asm/bitsperlong.h                           | 2 ++
 arch/x86/include/asm/elf.h                                   | 2 ++
 arch/x86/include/asm/io.h                                    | 2 ++
 arch/x86/include/asm/linkage.h                               | 2 ++
 arch/x86/include/asm/mmu.h                                   | 2 ++
 arch/x86/include/asm/posix_types.h                           | 2 ++
 arch/x86/include/asm/sections.h                              | 2 ++
 arch/x86/include/asm/swab.h                                  | 2 ++
 arch/x86/include/asm/types.h                                 | 2 ++
 arch/x86/include/asm/unaligned.h                             | 2 ++
 arch/x86/lib/Makefile                                        | 2 ++
 arch/x86/lib/asm-offsets.c                                   | 1 +
 arch/x86/mach-efi/.gitignore                                 | 2 ++
 arch/x86/mach-efi/Makefile                                   | 2 ++
 arch/x86/mach-efi/clocksource.c                              | 2 ++
 arch/x86/mach-efi/elf_ia32_efi.lds.S                         | 2 ++
 arch/x86/mach-efi/elf_x86_64_efi.lds.S                       | 2 ++
 arch/x86/mach-efi/include/mach/debug_ll.h                    | 2 ++
 commands/Kconfig                                             | 2 ++
 commands/Makefile                                            | 2 ++
 commands/clk.c                                               | 2 ++
 commands/fbtest.c                                            | 2 ++
 commands/hwclock.c                                           | 2 ++
 commands/hwmon.c                                             | 2 ++
 commands/insmod.c                                            | 2 ++
 commands/internal.h                                          | 2 ++
 commands/keystore.c                                          | 2 ++
 commands/lsmod.c                                             | 2 ++
 commands/magicvar.c                                          | 2 ++
 commands/memtester/Makefile                                  | 2 ++
 commands/mmc.c                                               | 2 ++
 commands/readf.c                                             | 2 ++
 commands/rmdir.c                                             | 2 ++
 commands/splash.c                                            | 2 ++
 commands/time.c                                              | 2 ++
 commands/ubi.c                                               | 2 ++
 commands/uimage.c                                            | 2 ++
 common/.gitignore                                            | 2 ++
 common/Kconfig                                               | 2 ++
 common/Makefile                                              | 2 ++
 common/boards/qemu-virt/overlay-of-flash.dts                 | 2 ++
 common/calloc.c                                              | 2 ++
 common/console_simple.c                                      | 2 ++
 common/globalvar.c                                           | 2 ++
 common/imd-barebox.c                                         | 2 ++
 common/kallsyms.c                                            | 2 ++
 common/meminfo.c                                             | 2 ++
 common/memory_display.c                                      | 4 +++-
 common/oftree.c                                              | 2 ++
 common/parser.c                                              | 2 ++
 common/partitions/Kconfig                                    | 2 ++
 common/partitions/Makefile                                   | 2 ++
 common/ratp/Kconfig                                          | 3 ++-
 common/ratp/Makefile                                         | 2 ++
 common/serdev.c                                              | 1 +
 common/state/Makefile                                        | 2 ++
 common/state/state.h                                         | 2 ++
 common/tlsf.c                                                | 2 ++
 common/tlsfbits.h                                            | 2 ++
 common/version.c                                             | 2 ++
 crypto/.gitignore                                            | 2 ++
 crypto/Kconfig                                               | 2 ++
 crypto/Makefile                                              | 2 ++
 crypto/md5.c                                                 | 1 +
 defaultenv/.gitignore                                        | 2 ++
 defaultenv/Makefile                                          | 2 ++
 firmware/.gitignore                                          | 2 ++
 firmware/Kconfig                                             | 2 ++
 fs/Kconfig                                                   | 1 +
 fs/Makefile                                                  | 2 ++
 fs/cramfs/Makefile                                           | 2 ++
 fs/cramfs/uncompress.c                                       | 2 ++
 fs/ext4/Kconfig                                              | 2 ++
 fs/ext4/Makefile                                             | 2 ++
 fs/fat/Kconfig                                               | 2 ++
 fs/fat/Makefile                                              | 2 ++
 fs/fat/diskio.h                                              | 2 ++
 fs/fat/ffconf.h                                              | 2 ++
 fs/fat/integer.h                                             | 2 ++
 fs/jffs2/Kconfig                                             | 2 ++
 fs/jffs2/Makefile                                            | 2 ++
 fs/jffs2/acl.h                                               | 4 +---
 fs/jffs2/build.c                                             | 4 +---
 fs/jffs2/compr.c                                             | 4 +---
 fs/jffs2/compr.h                                             | 4 +---
 fs/jffs2/compr_lzo.c                                         | 4 +---
 fs/jffs2/compr_rtime.c                                       | 5 +----
 fs/jffs2/compr_rubin.c                                       | 4 +---
 fs/jffs2/compr_zlib.c                                        | 4 +---
 fs/jffs2/debug.c                                             | 4 +---
 fs/jffs2/debug.h                                             | 5 ++---
 fs/jffs2/dir.c                                               | 4 +---
 fs/jffs2/fs.c                                                | 4 +---
 fs/jffs2/jffs2_fs_i.h                                        | 5 ++---
 fs/jffs2/jffs2_fs_sb.h                                       | 5 ++---
 fs/jffs2/malloc.c                                            | 4 +---
 fs/jffs2/nodelist.c                                          | 4 +---
 fs/jffs2/nodelist.h                                          | 4 +---
 fs/jffs2/os-linux.h                                          | 5 ++---
 fs/jffs2/read.c                                              | 4 +---
 fs/jffs2/readinode.c                                         | 4 +---
 fs/jffs2/scan.c                                              | 4 +---
 fs/jffs2/summary.h                                           | 4 +---
 fs/jffs2/super.c                                             | 5 ++---
 fs/jffs2/xattr.h                                             | 4 +---
 fs/pstore/Kconfig                                            | 2 ++
 fs/pstore/Makefile                                           | 2 ++
 fs/pstore/internal.h                                         | 2 ++
 fs/squashfs/Kconfig                                          | 2 ++
 fs/squashfs/Makefile                                         | 2 ++
 fs/squashfs/squashfs.c                                       | 2 ++
 fs/ubifs/Kconfig                                             | 2 ++
 fs/ubifs/Makefile                                            | 2 ++
 images/.gitignore                                            | 2 ++
 images/Makefile                                              | 1 +
 images/Makefile.am33xx                                       | 1 +
 images/Makefile.am35xx                                       | 1 +
 images/Makefile.ar231x                                       | 2 ++
 images/Makefile.at91                                         | 1 +
 images/Makefile.ath79                                        | 2 ++
 images/Makefile.bcm283x                                      | 3 ++-
 images/Makefile.bcm47xx                                      | 2 ++
 images/Makefile.imx                                          | 1 +
 images/Makefile.layerscape                                   | 1 +
 images/Makefile.loongson                                     | 2 ++
 images/Makefile.malta                                        | 2 ++
 images/Makefile.mvebu                                        | 1 +
 images/Makefile.mxs                                          | 1 +
 images/Makefile.omap3                                        | 2 ++
 images/Makefile.rockchip                                     | 1 +
 images/Makefile.socfpga                                      | 1 +
 images/Makefile.tegra                                        | 1 +
 images/Makefile.vexpress                                     | 1 +
 images/Makefile.xburst                                       | 2 ++
 images/Makefile.zynq                                         | 1 +
 images/piggy.S                                               | 2 ++
 include/.gitignore                                           | 2 ++
 include/aiodev.h                                             | 2 ++
 include/asm-generic/atomic-long.h                            | 2 ++
 include/asm-generic/barebox.lds.h                            | 2 ++
 include/asm-generic/bitops/__ffs.h                           | 2 ++
 include/asm-generic/bitops/__fls.h                           | 2 ++
 include/asm-generic/bitops/ffs.h                             | 2 ++
 include/asm-generic/bitops/ffz.h                             | 2 ++
 include/asm-generic/bitops/find.h                            | 2 ++
 include/asm-generic/bitops/fls.h                             | 2 ++
 include/asm-generic/bitops/fls64.h                           | 2 ++
 include/asm-generic/bitops/hweight.h                         | 2 ++
 include/asm-generic/bitops/ops.h                             | 2 ++
 include/asm-generic/bitsperlong.h                            | 2 ++
 include/asm-generic/bug.h                                    | 2 ++
 include/asm-generic/errno.h                                  | 2 ++
 include/asm-generic/int-ll64.h                               | 2 ++
 include/asm-generic/ioctl.h                                  | 2 ++
 include/asm-generic/memory_layout.h                          | 2 ++
 include/asm-generic/posix_types.h                            | 2 ++
 include/asm-generic/sections.h                               | 2 ++
 include/asm-generic/swab.h                                   | 2 ++
 include/base64.h                                             | 2 ++
 include/cramfs/cramfs_fs.h                                   | 2 ++
 include/crypto/crc.h                                         | 2 ++
 include/crypto/des.h                                         | 2 ++
 include/crypto/sha.h                                         | 2 ++
 include/debug_ll/ns16550.h                                   | 2 ++
 include/debug_ll/pl011.h                                     | 2 ++
 include/fastboot.h                                           | 2 ++
 include/fpga-bridge.h                                        | 1 +
 include/gui/2d-primitives.h                                  | 2 ++
 include/i2c/i2c-early.h                                      | 2 ++
 include/input/input.h                                        | 2 ++
 include/input/keyboard.h                                     | 2 ++
 include/input/matrix_keypad.h                                | 2 ++
 include/linux/amba/mmci.h                                    | 2 ++
 include/linux/amba/pl061.h                                   | 2 ++
 include/linux/bcd.h                                          | 2 ++
 include/linux/bitmap.h                                       | 2 ++
 include/linux/bitops.h                                       | 2 ++
 include/linux/bitrev.h                                       | 2 ++
 include/linux/bug.h                                          | 2 ++
 include/linux/byteorder/big_endian.h                         | 2 ++
 include/linux/byteorder/generic.h                            | 2 ++
 include/linux/byteorder/little_endian.h                      | 2 ++
 include/linux/circ_buf.h                                     | 2 ++
 include/linux/compiler_types.h                               | 2 ++
 include/linux/const.h                                        | 2 ++
 include/linux/crc8.h                                         | 2 ++
 include/linux/ctype.h                                        | 2 ++
 include/linux/dcache.h                                       | 2 ++
 include/linux/decompress/mm.h                                | 2 ++
 include/linux/decompress/unlz4.h                             | 2 ++
 include/linux/err.h                                          | 2 ++
 include/linux/ethtool.h                                      | 2 ++
 include/linux/fs.h                                           | 2 ++
 include/linux/gcd.h                                          | 2 ++
 include/linux/hash.h                                         | 2 ++
 include/linux/ioport.h                                       | 2 ++
 include/linux/jffs2.h                                        | 2 ++
 include/linux/kbuild.h                                       | 2 ++
 include/linux/linkage.h                                      | 2 ++
 include/linux/list_sort.h                                    | 2 ++
 include/linux/magic.h                                        | 2 ++
 include/linux/mdio-bitbang.h                                 | 2 ++
 include/linux/mii.h                                          | 2 ++
 include/linux/mod_devicetable.h                              | 2 ++
 include/linux/mount.h                                        | 2 ++
 include/linux/mtd/mtd-abi.h                                  | 2 ++
 include/linux/mtd/nftl.h                                     | 2 ++
 include/linux/mutex.h                                        | 2 ++
 include/linux/pagemap.h                                      | 2 ++
 include/linux/path.h                                         | 2 ++
 include/linux/pci.h                                          | 2 ++
 include/linux/pci_regs.h                                     | 2 ++
 include/linux/posix_types.h                                  | 2 ++
 include/linux/reset-controller.h                             | 2 ++
 include/linux/reset.h                                        | 2 ++
 include/linux/rtc.h                                          | 2 ++
 include/linux/rwsem.h                                        | 2 ++
 include/linux/sched.h                                        | 2 ++
 include/linux/slab.h                                         | 2 ++
 include/linux/smscphy.h                                      | 2 ++
 include/linux/spinlock.h                                     | 2 ++
 include/linux/stat.h                                         | 2 ++
 include/linux/stddef.h                                       | 2 ++
 include/linux/string.h                                       | 2 ++
 include/linux/stringify.h                                    | 2 ++
 include/linux/swab.h                                         | 2 ++
 include/linux/time.h                                         | 2 ++
 include/linux/types.h                                        | 2 ++
 include/linux/unaligned/access_ok.h                          | 2 ++
 include/linux/unaligned/be_byteshift.h                       | 2 ++
 include/linux/unaligned/be_memmove.h                         | 2 ++
 include/linux/unaligned/be_struct.h                          | 2 ++
 include/linux/unaligned/generic.h                            | 2 ++
 include/linux/unaligned/le_byteshift.h                       | 2 ++
 include/linux/unaligned/le_memmove.h                         | 2 ++
 include/linux/unaligned/le_struct.h                          | 2 ++
 include/linux/unaligned/memmove.h                            | 2 ++
 include/linux/unaligned/packed_struct.h                      | 2 ++
 include/linux/wait.h                                         | 2 ++
 include/linux/xz.h                                           | 2 ++
 include/linux/zutil.h                                        | 2 ++
 include/machine_id.h                                         | 2 ++
 include/mfd/lp3972.h                                         | 2 ++
 include/mfd/pfuze.h                                          | 2 ++
 include/mtd/mtd-peb.h                                        | 2 ++
 include/platform_data/atmel-mci.h                            | 2 ++
 include/platform_data/cadence_qspi.h                         | 2 ++
 include/platform_data/dw_mmc.h                               | 2 ++
 include/platform_data/eth-designware.h                       | 2 ++
 include/platform_data/eth-dm9000.h                           | 1 +
 include/platform_data/pca953x.h                              | 2 ++
 include/pm_domain.h                                          | 4 +++-
 include/serial/cadence.h                                     | 2 ++
 include/serial/imx-uart.h                                    | 2 ++
 include/slice.h                                              | 2 ++
 include/soc/fsl/fsl_udc.h                                    | 2 ++
 include/soc/imx/imx-nand-bcb.h                               | 2 ++
 include/soc/imx8m/clk-early.h                                | 2 ++
 include/sys/ioctl.h                                          | 2 ++
 include/sys/mount.h                                          | 2 ++
 include/sys/stat.h                                           | 2 ++
 include/usb/cdc.h                                            | 2 ++
 include/usb/ch11.h                                           | 2 ++
 include/usb/ch9.h                                            | 2 ++
 include/usb/chipidea-imx.h                                   | 2 ++
 include/usb/ehci.h                                           | 2 ++
 include/usb/fastboot.h                                       | 2 ++
 include/usb/fsl_usb2.h                                       | 2 ++
 include/usb/gadget-multi.h                                   | 2 ++
 include/usb/musb.h                                           | 2 ++
 include/usb/phy.h                                            | 2 ++
 include/usb/ulpi.h                                           | 2 ++
 include/usb/usbserial.h                                      | 2 ++
 include/video/backlight.h                                    | 2 ++
 include/video/fourcc.h                                       | 2 ++
 include/video/vpl.h                                          | 2 ++
 include/work.h                                               | 2 ++
 lib/Kconfig                                                  | 2 ++
 lib/Makefile                                                 | 2 ++
 lib/bcd.c                                                    | 2 ++
 lib/bootstrap/Kconfig                                        | 2 ++
 lib/bootstrap/Makefile                                       | 2 ++
 lib/fdt.c                                                    | 1 +
 lib/fdt_empty_tree.c                                         | 2 ++
 lib/fdt_ro.c                                                 | 2 ++
 lib/fdt_rw.c                                                 | 2 ++
 lib/fdt_strerror.c                                           | 1 +
 lib/fdt_sw.c                                                 | 2 ++
 lib/fdt_wip.c                                                | 2 ++
 lib/fonts/Kconfig                                            | 2 ++
 lib/fonts/Makefile                                           | 2 ++
 lib/fonts/font_6x8.c                                         | 2 ++
 lib/fonts/font_7x14.c                                        | 2 ++
 lib/fonts/font_8x16.c                                        | 2 ++
 lib/fonts/font_8x8.c                                         | 2 ++
 lib/fonts/font_custom_16x.c                                  | 2 ++
 lib/fonts/font_mini_4x6.c                                    | 2 ++
 lib/gcd.c                                                    | 2 ++
 lib/gui/2d-primitives.c                                      | 2 ++
 lib/gui/Kconfig                                              | 2 ++
 lib/gui/Makefile                                             | 2 ++
 lib/gui/bmp.c                                                | 2 ++
 lib/gui/graphic_utils.c                                      | 2 ++
 lib/gui/picopng.h                                            | 2 ++
 lib/gui/png.c                                                | 2 ++
 lib/gui/png_lode.c                                           | 2 ++
 lib/gui/png_pico.c                                           | 2 ++
 lib/kasan/Kconfig                                            | 2 ++
 lib/kasan/Makefile                                           | 1 +
 lib/list_sort.c                                              | 2 ++
 lib/logo/.gitignore                                          | 2 ++
 lib/logo/Kconfig                                             | 2 ++
 lib/logo/Makefile                                            | 1 +
 lib/lz4/Makefile                                             | 2 ++
 lib/lzo/Kconfig                                              | 2 ++
 lib/lzo/Makefile                                             | 2 ++
 lib/make_directory.c                                         | 1 +
 lib/math/Makefile                                            | 2 ++
 lib/nls_base.c                                               | 2 ++
 lib/notifier.c                                               | 2 ++
 lib/parseopt.c                                               | 2 ++
 lib/random.c                                                 | 2 ++
 lib/readline.c                                               | 2 ++
 lib/readline_simple.c                                        | 2 ++
 lib/reed_solomon/Makefile                                    | 2 ++
 lib/string.c                                                 | 1 +
 lib/stringlist.c                                             | 2 ++
 lib/strtox.c                                                 | 2 ++
 lib/unlink-recursive.c                                       | 2 ++
 lib/vsprintf.c                                               | 2 ++
 lib/xz/Makefile                                              | 2 ++
 lib/zlib_inflate/Makefile                                    | 2 ++
 lib/zstd/Makefile                                            | 2 ++
 net/Kconfig                                                  | 2 ++
 net/Makefile                                                 | 2 ++
 net/nfs.c                                                    | 2 ++
 net/ping.c                                                   | 2 ++
 pbl/Kconfig                                                  | 2 ++
 pbl/Makefile                                                 | 2 ++
 pbl/console.c                                                | 2 ++
 pbl/misc.c                                                   | 2 ++
 pbl/string.c                                                 | 2 ++
 scripts/.gitignore                                           | 2 ++
 scripts/Kconfig                                              | 2 ++
 scripts/Makefile                                             | 2 ++
 scripts/dtc/.gitignore                                       | 2 ++
 scripts/imx/.gitignore                                       | 2 ++
 scripts/imx/Kconfig                                          | 2 ++
 scripts/imx/Makefile                                         | 2 ++
 scripts/mod/.gitignore                                       | 2 ++
 scripts/mod/Makefile                                         | 2 ++
 scripts/tegra/.gitignore                                     | 2 ++
 scripts/tegra/Makefile                                       | 2 ++
 test/.gitignore                                              | 2 ++
 test/Kconfig                                                 | 2 ++
 test/Makefile                                                | 2 ++
 1262 files changed, 2447 insertions(+), 106 deletions(-)

-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:30 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:30 +0100
Subject: [PATCH 02/11] treewide: add SPDX-License-Identifier for Kbuild/Kconfig
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-3-a.fatoum@pengutronix.de>

To verify only Kconfig/Makefile is touched:

  git show --numstat --format=oneline HEAD | grep -v 'Kconfig\|Makefile'

will print only arch/powerpc/Kbuild.
To verify nothing unexpected is added:

  git show -U0 | grep '^-[^-]\|^+[^+]' | sort -u

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Kconfig                                            | 2 ++
 arch/arm/Kconfig                                   | 2 ++
 arch/arm/Makefile                                  | 2 ++
 arch/arm/boards/Makefile                           | 2 ++
 arch/arm/boards/a9m2410/Makefile                   | 1 +
 arch/arm/boards/a9m2440/Makefile                   | 1 +
 arch/arm/boards/ac-sxb/Makefile                    | 2 ++
 arch/arm/boards/advantech-mx6/Makefile             | 2 ++
 arch/arm/boards/afi-gf/Makefile                    | 2 ++
 arch/arm/boards/altera-socdk/Makefile              | 2 ++
 arch/arm/boards/animeo_ip/Makefile                 | 2 ++
 arch/arm/boards/archosg9/Makefile                  | 2 ++
 arch/arm/boards/at91rm9200ek/Makefile              | 2 ++
 arch/arm/boards/at91sam9260ek/Makefile             | 2 ++
 arch/arm/boards/at91sam9261ek/Makefile             | 2 ++
 arch/arm/boards/at91sam9263ek/Makefile             | 2 ++
 arch/arm/boards/at91sam9m10g45ek/Makefile          | 2 ++
 arch/arm/boards/at91sam9m10ihd/Makefile            | 2 ++
 arch/arm/boards/at91sam9n12ek/Makefile             | 2 ++
 arch/arm/boards/at91sam9x5ek/Makefile              | 2 ++
 arch/arm/boards/avnet-zedboard/Makefile            | 2 ++
 arch/arm/boards/beagle/Makefile                    | 2 ++
 arch/arm/boards/beaglebone/Makefile                | 2 ++
 arch/arm/boards/boundarydevices-nitrogen6/Makefile | 2 ++
 arch/arm/boards/canon-a1100/Makefile               | 2 ++
 arch/arm/boards/ccxmx51/Makefile                   | 2 ++
 arch/arm/boards/ccxmx53/Makefile                   | 2 ++
 arch/arm/boards/chumby_falconwing/Makefile         | 2 ++
 arch/arm/boards/clep7212/Makefile                  | 2 ++
 arch/arm/boards/cm-fx6/Makefile                    | 2 ++
 arch/arm/boards/crystalfontz-cfa10036/Makefile     | 2 ++
 arch/arm/boards/datamodul-edm-qmx6/Makefile        | 2 ++
 arch/arm/boards/dfi-fs700-m60/Makefile             | 2 ++
 arch/arm/boards/digi-ccimx6ulsom/Makefile          | 2 ++
 arch/arm/boards/dss11/Makefile                     | 2 ++
 arch/arm/boards/duckbill/Makefile                  | 2 ++
 arch/arm/boards/ebv-socrates/Makefile              | 2 ++
 arch/arm/boards/edb93xx/Makefile                   | 1 +
 arch/arm/boards/efika-mx-smartbook/Makefile        | 2 ++
 arch/arm/boards/element14-warp7/Makefile           | 2 ++
 arch/arm/boards/eltec-hipercam/Makefile            | 2 ++
 arch/arm/boards/embedsky-e9/Makefile               | 2 ++
 arch/arm/boards/embest-marsboard/Makefile          | 2 ++
 arch/arm/boards/embest-riotboard/Makefile          | 2 ++
 arch/arm/boards/eukrea_cpuimx27/Makefile           | 1 +
 arch/arm/boards/eukrea_cpuimx51/Makefile           | 2 ++
 arch/arm/boards/freescale-mx21-ads/Makefile        | 2 ++
 arch/arm/boards/freescale-mx23-evk/Makefile        | 3 ++-
 arch/arm/boards/freescale-mx27-ads/Makefile        | 1 +
 arch/arm/boards/freescale-mx28-evk/Makefile        | 2 ++
 arch/arm/boards/freescale-mx35-3ds/Makefile        | 2 ++
 arch/arm/boards/freescale-mx51-babbage/Makefile    | 2 ++
 arch/arm/boards/freescale-mx53-qsb/Makefile        | 2 ++
 arch/arm/boards/freescale-mx53-smd/Makefile        | 2 ++
 arch/arm/boards/freescale-mx53-vmx53/Makefile      | 2 ++
 arch/arm/boards/freescale-mx6-sabrelite/Makefile   | 2 ++
 arch/arm/boards/freescale-mx6-sabresd/Makefile     | 2 ++
 arch/arm/boards/freescale-mx6sx-sabresdb/Makefile  | 2 ++
 arch/arm/boards/freescale-mx7-sabresd/Makefile     | 2 ++
 arch/arm/boards/freescale-vf610-twr/Makefile       | 2 ++
 arch/arm/boards/friendlyarm-mini2440/Kconfig       | 1 +
 arch/arm/boards/friendlyarm-mini2440/Makefile      | 2 ++
 arch/arm/boards/friendlyarm-mini6410/Makefile      | 2 ++
 arch/arm/boards/friendlyarm-tiny210/Makefile       | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/Kconfig       | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/Makefile      | 2 ++
 arch/arm/boards/gateworks-ventana/Makefile         | 2 ++
 arch/arm/boards/gk802/Makefile                     | 2 ++
 arch/arm/boards/globalscale-guruplug/Makefile      | 2 ++
 arch/arm/boards/globalscale-mirabox/Makefile       | 2 ++
 arch/arm/boards/grinn-liteboard/Makefile           | 2 ++
 arch/arm/boards/guf-neso/Makefile                  | 2 ++
 arch/arm/boards/guf-santaro/Makefile               | 2 ++
 arch/arm/boards/guf-vincell/Makefile               | 2 ++
 arch/arm/boards/haba-knx/Makefile                  | 2 ++
 arch/arm/boards/imx233-olinuxino/Makefile          | 2 ++
 arch/arm/boards/kamstrup-mx7-concentrator/Makefile | 4 +++-
 arch/arm/boards/karo-tx28/Makefile                 | 2 ++
 arch/arm/boards/karo-tx53/Makefile                 | 2 ++
 arch/arm/boards/karo-tx6x/Makefile                 | 2 ++
 arch/arm/boards/kindle-mx50/Makefile               | 2 ++
 arch/arm/boards/kindle3/Makefile                   | 2 ++
 arch/arm/boards/kontron-samx6i/Makefile            | 2 ++
 arch/arm/boards/lenovo-ix4-300d/Makefile           | 2 ++
 arch/arm/boards/ls1046ardb/Makefile                | 2 ++
 arch/arm/boards/lubbock/Makefile                   | 2 ++
 arch/arm/boards/lxa-mc1/Makefile                   | 2 ++
 arch/arm/boards/mainstone/Makefile                 | 2 ++
 arch/arm/boards/marvell-armada-xp-db/Makefile      | 2 ++
 arch/arm/boards/marvell-armada-xp-gp/Makefile      | 2 ++
 arch/arm/boards/microchip-ksz9477-evb/Makefile     | 2 ++
 arch/arm/boards/mioa701/Makefile                   | 2 ++
 arch/arm/boards/mnt-reform/Makefile                | 4 +++-
 arch/arm/boards/module-mb7707/Makefile             | 2 ++
 arch/arm/boards/netgear-rn104/Makefile             | 2 ++
 arch/arm/boards/netgear-rn2120/Makefile            | 2 ++
 arch/arm/boards/nhk8815/Makefile                   | 2 ++
 arch/arm/boards/nvidia-beaver/Makefile             | 2 ++
 arch/arm/boards/nvidia-jetson-tk1/Makefile         | 2 ++
 arch/arm/boards/nxp-imx6ull-evk/Makefile           | 2 ++
 arch/arm/boards/nxp-imx8mm-evk/Makefile            | 2 ++
 arch/arm/boards/nxp-imx8mn-evk/Makefile            | 2 ++
 arch/arm/boards/nxp-imx8mp-evk/Makefile            | 2 ++
 arch/arm/boards/nxp-imx8mq-evk/Makefile            | 2 ++
 arch/arm/boards/omap343xdsp/Makefile               | 2 ++
 arch/arm/boards/omap3evm/Makefile                  | 2 ++
 arch/arm/boards/panda/Makefile                     | 2 ++
 arch/arm/boards/phytec-phycard-imx27/Makefile      | 1 +
 arch/arm/boards/phytec-phycore-imx27/Makefile      | 2 ++
 arch/arm/boards/phytec-phycore-imx7/Makefile       | 2 ++
 arch/arm/boards/phytec-phycore-omap4460/Makefile   | 2 ++
 arch/arm/boards/phytec-phycore-pxa270/Makefile     | 2 ++
 arch/arm/boards/phytec-som-am335x/Kconfig          | 1 +
 arch/arm/boards/phytec-som-am335x/Makefile         | 2 ++
 arch/arm/boards/phytec-som-imx6/Makefile           | 2 ++
 arch/arm/boards/phytec-som-imx8mq/Makefile         | 2 ++
 arch/arm/boards/phytec-som-rk3288/Makefile         | 2 ++
 arch/arm/boards/plathome-openblocks-a6/Makefile    | 2 ++
 arch/arm/boards/plathome-openblocks-ax3/Makefile   | 2 ++
 arch/arm/boards/pm9261/Makefile                    | 2 ++
 arch/arm/boards/pm9263/Makefile                    | 2 ++
 arch/arm/boards/pm9g45/Makefile                    | 2 ++
 arch/arm/boards/protonic-imx6/Makefile             | 2 ++
 arch/arm/boards/protonic-imx8m/Makefile            | 2 ++
 arch/arm/boards/protonic-stm32mp1/Makefile         | 2 ++
 arch/arm/boards/qemu-virt/Makefile                 | 2 ++
 arch/arm/boards/qil-a926x/Makefile                 | 2 ++
 arch/arm/boards/radxa-rock/Makefile                | 2 ++
 arch/arm/boards/raspberry-pi/Makefile              | 2 ++
 arch/arm/boards/reflex-achilles/Makefile           | 2 ++
 arch/arm/boards/rockchip-rk3568-evb/Makefile       | 2 ++
 arch/arm/boards/sama5d27-giantboard/Makefile       | 2 ++
 arch/arm/boards/sama5d27-som1/Makefile             | 2 ++
 arch/arm/boards/sama5d3_xplained/Makefile          | 2 ++
 arch/arm/boards/sama5d3xek/Makefile                | 2 ++
 arch/arm/boards/sama5d4_xplained/Makefile          | 2 ++
 arch/arm/boards/sama5d4ek/Makefile                 | 2 ++
 arch/arm/boards/scb9328/Makefile                   | 1 +
 arch/arm/boards/seeed-odyssey/Makefile             | 2 ++
 arch/arm/boards/skov-arm9cpu/Makefile              | 2 ++
 arch/arm/boards/skov-imx6/Makefile                 | 2 ++
 arch/arm/boards/solidrun-cubox/Makefile            | 2 ++
 arch/arm/boards/solidrun-microsom/Makefile         | 2 ++
 arch/arm/boards/stm32mp15x-ev1/Makefile            | 2 ++
 arch/arm/boards/stm32mp15xx-dkx/Makefile           | 2 ++
 arch/arm/boards/technexion-pico-hobbit/Makefile    | 2 ++
 arch/arm/boards/technexion-wandboard/Makefile      | 2 ++
 arch/arm/boards/telit-evk-pro3/Makefile            | 2 ++
 arch/arm/boards/terasic-de0-nano-soc/Makefile      | 2 ++
 arch/arm/boards/terasic-de10-nano/Makefile         | 2 ++
 arch/arm/boards/terasic-sockit/Makefile            | 2 ++
 arch/arm/boards/tny-a926x/Makefile                 | 2 ++
 arch/arm/boards/toradex-colibri-t20/Makefile       | 2 ++
 arch/arm/boards/toshiba-ac100/Makefile             | 2 ++
 arch/arm/boards/tqma53/Makefile                    | 2 ++
 arch/arm/boards/tqma6x/Makefile                    | 2 ++
 arch/arm/boards/tqmls1046a/Makefile                | 2 ++
 arch/arm/boards/turris-omnia/Makefile              | 2 ++
 arch/arm/boards/udoo-neo/Makefile                  | 2 ++
 arch/arm/boards/udoo/Makefile                      | 2 ++
 arch/arm/boards/usb-a926x/Makefile                 | 2 ++
 arch/arm/boards/usi-topkick/Makefile               | 2 ++
 arch/arm/boards/variscite-mx6/Makefile             | 2 ++
 arch/arm/boards/versatile/Kconfig                  | 1 +
 arch/arm/boards/versatile/Makefile                 | 2 ++
 arch/arm/boards/vexpress/Makefile                  | 2 ++
 arch/arm/boards/virt2real/Makefile                 | 2 ++
 arch/arm/boards/vscom-baltos/Makefile              | 2 ++
 arch/arm/boards/wago-pfc-am35xx/Makefile           | 2 ++
 arch/arm/boards/webasto-ccbv2/Makefile             | 2 ++
 arch/arm/boards/zii-common/Makefile                | 2 ++
 arch/arm/boards/zii-imx51-rdu1/Makefile            | 2 ++
 arch/arm/boards/zii-imx6q-rdu2/Makefile            | 2 ++
 arch/arm/boards/zii-imx7d-dev/Makefile             | 2 ++
 arch/arm/boards/zii-imx8mq-dev/Makefile            | 2 ++
 arch/arm/boards/zii-vf610-dev/Makefile             | 2 ++
 arch/arm/boards/zylonite/Makefile                  | 2 ++
 arch/arm/cpu/Kconfig                               | 2 ++
 arch/arm/cpu/Makefile                              | 2 ++
 arch/arm/crypto/Makefile                           | 1 +
 arch/arm/dts/Makefile                              | 2 ++
 arch/arm/lib/Makefile                              | 2 ++
 arch/arm/lib32/Makefile                            | 2 ++
 arch/arm/lib64/Makefile                            | 2 ++
 arch/arm/mach-at91/Kconfig                         | 2 ++
 arch/arm/mach-at91/Makefile                        | 2 ++
 arch/arm/mach-bcm283x/Kconfig                      | 2 ++
 arch/arm/mach-bcm283x/Makefile                     | 2 ++
 arch/arm/mach-clps711x/Kconfig                     | 2 ++
 arch/arm/mach-clps711x/Makefile                    | 2 ++
 arch/arm/mach-davinci/Kconfig                      | 2 ++
 arch/arm/mach-davinci/Makefile                     | 2 ++
 arch/arm/mach-digic/Kconfig                        | 2 ++
 arch/arm/mach-digic/Makefile                       | 2 ++
 arch/arm/mach-ep93xx/Kconfig                       | 2 ++
 arch/arm/mach-ep93xx/Makefile                      | 2 ++
 arch/arm/mach-imx/Kconfig                          | 2 ++
 arch/arm/mach-imx/Makefile                         | 2 ++
 arch/arm/mach-layerscape/Kconfig                   | 2 ++
 arch/arm/mach-layerscape/Makefile                  | 2 ++
 arch/arm/mach-mvebu/Kconfig                        | 2 ++
 arch/arm/mach-mvebu/Makefile                       | 2 ++
 arch/arm/mach-mxs/Kconfig                          | 2 ++
 arch/arm/mach-mxs/Makefile                         | 2 ++
 arch/arm/mach-nomadik/Kconfig                      | 2 ++
 arch/arm/mach-nomadik/Makefile                     | 1 +
 arch/arm/mach-pxa/Kconfig                          | 2 ++
 arch/arm/mach-pxa/Makefile                         | 2 ++
 arch/arm/mach-rockchip/Kconfig                     | 2 ++
 arch/arm/mach-rockchip/Makefile                    | 2 ++
 arch/arm/mach-samsung/Kconfig                      | 2 ++
 arch/arm/mach-samsung/Makefile                     | 2 ++
 arch/arm/mach-socfpga/Kconfig                      | 2 ++
 arch/arm/mach-socfpga/Makefile                     | 2 ++
 arch/arm/mach-stm32mp/Kconfig                      | 2 ++
 arch/arm/mach-stm32mp/Makefile                     | 2 ++
 arch/arm/mach-tegra/Kconfig                        | 2 ++
 arch/arm/mach-tegra/Makefile                       | 2 ++
 arch/arm/mach-uemd/Kconfig                         | 2 ++
 arch/arm/mach-uemd/Makefile                        | 2 ++
 arch/arm/mach-versatile/Kconfig                    | 1 +
 arch/arm/mach-versatile/Makefile                   | 1 +
 arch/arm/mach-vexpress/Kconfig                     | 2 ++
 arch/arm/mach-vexpress/Makefile                    | 2 ++
 arch/arm/mach-zynq/Kconfig                         | 2 ++
 arch/arm/mach-zynq/Makefile                        | 2 ++
 arch/arm/tools/Makefile                            | 2 ++
 arch/kvx/Kconfig                                   | 2 ++
 arch/kvx/Makefile                                  | 2 ++
 arch/kvx/dts/Makefile                              | 2 ++
 arch/mips/Kconfig                                  | 5 ++---
 arch/mips/Makefile                                 | 2 ++
 arch/mips/boards/8devices-lima/Makefile            | 2 ++
 arch/mips/boards/Makefile                          | 2 ++
 arch/mips/boards/black-swift/Makefile              | 2 ++
 arch/mips/boards/dlink-dir-320/Makefile            | 2 ++
 arch/mips/boards/dptechnics-dpt-module/Makefile    | 2 ++
 arch/mips/boards/img-ci20/Makefile                 | 2 ++
 arch/mips/boards/loongson-ls1b/Makefile            | 2 ++
 arch/mips/boards/netgear-wg102/Makefile            | 2 ++
 arch/mips/boards/okud-max9331/Makefile             | 2 ++
 arch/mips/boards/openembed-som9331/Makefile        | 2 ++
 arch/mips/boards/qemu-malta/Makefile               | 2 ++
 arch/mips/boards/ritmix-rzx50/Makefile             | 2 ++
 arch/mips/boards/tplink-mr3020/Makefile            | 2 ++
 arch/mips/boards/tplink-wdr4300/Makefile           | 2 ++
 arch/mips/boot/Makefile                            | 2 ++
 arch/mips/dts/Makefile                             | 2 ++
 arch/mips/lib/Makefile                             | 2 ++
 arch/mips/mach-ar231x/Kconfig                      | 2 ++
 arch/mips/mach-ar231x/Makefile                     | 2 ++
 arch/mips/mach-ath79/Kconfig                       | 2 ++
 arch/mips/mach-ath79/Makefile                      | 2 ++
 arch/mips/mach-bcm47xx/Kconfig                     | 2 ++
 arch/mips/mach-bcm47xx/Makefile                    | 2 ++
 arch/mips/mach-loongson/Kconfig                    | 2 ++
 arch/mips/mach-loongson/Makefile                   | 2 ++
 arch/mips/mach-malta/Kconfig                       | 2 ++
 arch/mips/mach-malta/Makefile                      | 2 ++
 arch/mips/mach-xburst/Kconfig                      | 2 ++
 arch/mips/mach-xburst/Makefile                     | 2 ++
 arch/mips/pbl/Makefile                             | 1 +
 arch/openrisc/Kconfig                              | 2 ++
 arch/openrisc/Makefile                             | 2 ++
 arch/openrisc/boards/generic/Makefile              | 2 ++
 arch/openrisc/cpu/Makefile                         | 2 ++
 arch/openrisc/dts/Makefile                         | 1 +
 arch/openrisc/lib/Makefile                         | 2 ++
 arch/powerpc/Kbuild                                | 2 ++
 arch/powerpc/Kconfig                               | 2 ++
 arch/powerpc/Makefile                              | 2 ++
 arch/powerpc/boards/freescale-p1010rdb/Makefile    | 2 ++
 arch/powerpc/boards/freescale-p1022ds/Makefile     | 2 ++
 arch/powerpc/boards/freescale-p2020rdb/Makefile    | 2 ++
 arch/powerpc/boards/owc-da923rc/Makefile           | 2 ++
 arch/powerpc/boards/pcm030/Makefile                | 2 ++
 arch/powerpc/cpu-85xx/Makefile                     | 2 ++
 arch/powerpc/ddr-8xxx/Makefile                     | 2 ++
 arch/powerpc/lib/Makefile                          | 2 ++
 arch/powerpc/mach-mpc5xxx/Kconfig                  | 2 ++
 arch/powerpc/mach-mpc5xxx/Makefile                 | 2 ++
 arch/powerpc/mach-mpc85xx/Kconfig                  | 2 ++
 arch/powerpc/mach-mpc85xx/Makefile                 | 2 ++
 arch/riscv/Kconfig                                 | 2 ++
 arch/riscv/Kconfig.socs                            | 2 ++
 arch/riscv/Makefile                                | 2 ++
 arch/riscv/boards/riscvemu/Makefile                | 2 ++
 arch/sandbox/Kconfig                               | 2 ++
 arch/sandbox/Makefile                              | 2 ++
 arch/sandbox/board/Makefile                        | 2 ++
 arch/sandbox/dts/Makefile                          | 2 ++
 arch/sandbox/lib/Makefile                          | 2 ++
 arch/sandbox/os/Makefile                           | 2 ++
 arch/x86/Kconfig                                   | 5 ++---
 arch/x86/Makefile                                  | 2 ++
 arch/x86/lib/Makefile                              | 2 ++
 arch/x86/mach-efi/Makefile                         | 2 ++
 common/Kconfig                                     | 2 ++
 common/Makefile                                    | 2 ++
 common/partitions/Kconfig                          | 2 ++
 common/partitions/Makefile                         | 2 ++
 common/ratp/Kconfig                                | 3 ++-
 common/ratp/Makefile                               | 2 ++
 common/state/Makefile                              | 2 ++
 crypto/Kconfig                                     | 2 ++
 crypto/Makefile                                    | 2 ++
 defaultenv/Makefile                                | 2 ++
 firmware/Kconfig                                   | 2 ++
 fs/Kconfig                                         | 1 +
 fs/Makefile                                        | 2 ++
 fs/cramfs/Makefile                                 | 2 ++
 fs/ext4/Kconfig                                    | 2 ++
 fs/ext4/Makefile                                   | 2 ++
 fs/fat/Kconfig                                     | 2 ++
 fs/fat/Makefile                                    | 2 ++
 fs/jffs2/Kconfig                                   | 2 ++
 fs/jffs2/Makefile                                  | 2 ++
 fs/pstore/Kconfig                                  | 2 ++
 fs/pstore/Makefile                                 | 2 ++
 fs/squashfs/Kconfig                                | 2 ++
 fs/squashfs/Makefile                               | 2 ++
 fs/ubifs/Kconfig                                   | 2 ++
 fs/ubifs/Makefile                                  | 2 ++
 images/Makefile                                    | 1 +
 lib/Kconfig                                        | 2 ++
 lib/Makefile                                       | 2 ++
 lib/bootstrap/Kconfig                              | 2 ++
 lib/bootstrap/Makefile                             | 2 ++
 lib/fonts/Kconfig                                  | 2 ++
 lib/fonts/Makefile                                 | 2 ++
 lib/gui/Kconfig                                    | 2 ++
 lib/gui/Makefile                                   | 2 ++
 lib/kasan/Kconfig                                  | 2 ++
 lib/kasan/Makefile                                 | 1 +
 lib/logo/Kconfig                                   | 2 ++
 lib/logo/Makefile                                  | 1 +
 lib/lz4/Makefile                                   | 2 ++
 lib/lzo/Kconfig                                    | 2 ++
 lib/lzo/Makefile                                   | 2 ++
 lib/math/Makefile                                  | 2 ++
 lib/reed_solomon/Makefile                          | 2 ++
 lib/xz/Makefile                                    | 2 ++
 lib/zlib_inflate/Makefile                          | 2 ++
 lib/zstd/Makefile                                  | 2 ++
 net/Kconfig                                        | 2 ++
 net/Makefile                                       | 2 ++
 pbl/Kconfig                                        | 2 ++
 pbl/Makefile                                       | 2 ++
 scripts/Kconfig                                    | 2 ++
 scripts/Makefile                                   | 2 ++
 scripts/imx/Kconfig                                | 2 ++
 scripts/imx/Makefile                               | 2 ++
 scripts/mod/Makefile                               | 2 ++
 scripts/tegra/Makefile                             | 2 ++
 test/Kconfig                                       | 2 ++
 test/Makefile                                      | 2 ++
 356 files changed, 694 insertions(+), 10 deletions(-)

diff --git a/Kconfig b/Kconfig
index 7c4cf36881b4..7e9b892129da 100644
--- a/Kconfig
+++ b/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/kconfig-language.txt.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b532d3fe2fc2..fecbe392333b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config ARM
 	bool
 	select HAS_KALLSYMS
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index f4b0e8d6b68f..610ded8a125e 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := qemu_virt64_defconfig
 
 KBUILD_CPPFLAGS	+= -D__ARM__ -fno-strict-aliasing
diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index 50b07462bb78..6fe1b5991455 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 # keep sorted by CONFIG_* macro name.
 obj-$(CONFIG_MACH_ADVANTECH_ROM_742X)		+= advantech-mx6/
 obj-$(CONFIG_MACH_AFI_GF)			+= afi-gf/
diff --git a/arch/arm/boards/a9m2410/Makefile b/arch/arm/boards/a9m2410/Makefile
index 4bf737c1fc9b..6c53eafae249 100644
--- a/arch/arm/boards/a9m2410/Makefile
+++ b/arch/arm/boards/a9m2410/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 lwl-y += lowlevel_init.o
 obj-y += a9m2410.o
diff --git a/arch/arm/boards/a9m2440/Makefile b/arch/arm/boards/a9m2440/Makefile
index f21d389c140d..e32c0aca640e 100644
--- a/arch/arm/boards/a9m2440/Makefile
+++ b/arch/arm/boards/a9m2440/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 lwl-y += lowlevel_init.o
 obj-y += a9m2440.o
diff --git a/arch/arm/boards/ac-sxb/Makefile b/arch/arm/boards/ac-sxb/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/ac-sxb/Makefile
+++ b/arch/arm/boards/ac-sxb/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/advantech-mx6/Makefile b/arch/arm/boards/advantech-mx6/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/advantech-mx6/Makefile
+++ b/arch/arm/boards/advantech-mx6/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/afi-gf/Makefile b/arch/arm/boards/afi-gf/Makefile
index 399a4b8cc00d..8d1041650e9b 100644
--- a/arch/arm/boards/afi-gf/Makefile
+++ b/arch/arm/boards/afi-gf/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
 bbenv-y += defaultenv-gf
diff --git a/arch/arm/boards/altera-socdk/Makefile b/arch/arm/boards/altera-socdk/Makefile
index 8c927fe291a6..ea898309d720 100644
--- a/arch/arm/boards/altera-socdk/Makefile
+++ b/arch/arm/boards/altera-socdk/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += lowlevel.o board.o
 pbl-y += lowlevel.o
diff --git a/arch/arm/boards/animeo_ip/Makefile b/arch/arm/boards/animeo_ip/Makefile
index 61c714b45d2e..149c41024a12 100644
--- a/arch/arm/boards/animeo_ip/Makefile
+++ b/arch/arm/boards/animeo_ip/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/archosg9/Makefile b/arch/arm/boards/archosg9/Makefile
index a78956f4e4d0..790ff623f591 100644
--- a/arch/arm/boards/archosg9/Makefile
+++ b/arch/arm/boards/archosg9/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 obj-$(CONFIG_ARM_BOARD_APPEND_ATAG) += archos_features.o
 lwl-y += lowlevel.o mux.o
diff --git a/arch/arm/boards/at91rm9200ek/Makefile b/arch/arm/boards/at91rm9200ek/Makefile
index a07c06a6d909..da5c1038b25c 100644
--- a/arch/arm/boards/at91rm9200ek/Makefile
+++ b/arch/arm/boards/at91rm9200ek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/at91sam9260ek/Makefile b/arch/arm/boards/at91sam9260ek/Makefile
index 9cc933a28793..7aa83a77366a 100644
--- a/arch/arm/boards/at91sam9260ek/Makefile
+++ b/arch/arm/boards/at91sam9260ek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/at91sam9261ek/Makefile b/arch/arm/boards/at91sam9261ek/Makefile
index e7a9cde419fa..91e0037d6d4b 100644
--- a/arch/arm/boards/at91sam9261ek/Makefile
+++ b/arch/arm/boards/at91sam9261ek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel_init.o
diff --git a/arch/arm/boards/at91sam9263ek/Makefile b/arch/arm/boards/at91sam9263ek/Makefile
index d4d5e76395be..7f4c1bfac3e3 100644
--- a/arch/arm/boards/at91sam9263ek/Makefile
+++ b/arch/arm/boards/at91sam9263ek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 ifeq ($(CONFIG_OFDEVICE),)
 obj-y += init.o
 endif
diff --git a/arch/arm/boards/at91sam9m10g45ek/Makefile b/arch/arm/boards/at91sam9m10g45ek/Makefile
index da011f825b6d..291716cbf062 100644
--- a/arch/arm/boards/at91sam9m10g45ek/Makefile
+++ b/arch/arm/boards/at91sam9m10g45ek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/at91sam9m10ihd/Makefile b/arch/arm/boards/at91sam9m10ihd/Makefile
index 06193007ad38..8bf9a102fe36 100644
--- a/arch/arm/boards/at91sam9m10ihd/Makefile
+++ b/arch/arm/boards/at91sam9m10ihd/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 obj-y += hw_version.o
 
diff --git a/arch/arm/boards/at91sam9n12ek/Makefile b/arch/arm/boards/at91sam9n12ek/Makefile
index 458b05591814..6ba8b4e38f99 100644
--- a/arch/arm/boards/at91sam9n12ek/Makefile
+++ b/arch/arm/boards/at91sam9n12ek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/at91sam9x5ek/Makefile b/arch/arm/boards/at91sam9x5ek/Makefile
index 4939b7e17e16..c6c1ad967058 100644
--- a/arch/arm/boards/at91sam9x5ek/Makefile
+++ b/arch/arm/boards/at91sam9x5ek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 obj-y += hw_version.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-at91sam9x5ek
diff --git a/arch/arm/boards/avnet-zedboard/Makefile b/arch/arm/boards/avnet-zedboard/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/avnet-zedboard/Makefile
+++ b/arch/arm/boards/avnet-zedboard/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/beagle/Makefile b/arch/arm/boards/beagle/Makefile
index 3bee9a22ab4a..e273f4a3dace 100644
--- a/arch/arm/boards/beagle/Makefile
+++ b/arch/arm/boards/beagle/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-beagle
diff --git a/arch/arm/boards/beaglebone/Makefile b/arch/arm/boards/beaglebone/Makefile
index 21a1a29d0b48..108e481be3b0 100644
--- a/arch/arm/boards/beaglebone/Makefile
+++ b/arch/arm/boards/beaglebone/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
 bbenv-y += defaultenv-beaglebone
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/Makefile b/arch/arm/boards/boundarydevices-nitrogen6/Makefile
index 0ec04ce8986e..b365c8eab067 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/Makefile
+++ b/arch/arm/boards/boundarydevices-nitrogen6/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/canon-a1100/Makefile b/arch/arm/boards/canon-a1100/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/canon-a1100/Makefile
+++ b/arch/arm/boards/canon-a1100/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/ccxmx51/Makefile b/arch/arm/boards/ccxmx51/Makefile
index 50cf929c5d49..9fbde144a5f7 100644
--- a/arch/arm/boards/ccxmx51/Makefile
+++ b/arch/arm/boards/ccxmx51/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y					+= ccxmx51.o
 lwl-y					+= lowlevel.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT)	+= defaultenv-ccxmx51
diff --git a/arch/arm/boards/ccxmx53/Makefile b/arch/arm/boards/ccxmx53/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/ccxmx53/Makefile
+++ b/arch/arm/boards/ccxmx53/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/chumby_falconwing/Makefile b/arch/arm/boards/chumby_falconwing/Makefile
index cf92c6a9eafe..6aaff6cdf72d 100644
--- a/arch/arm/boards/chumby_falconwing/Makefile
+++ b/arch/arm/boards/chumby_falconwing/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y = falconwing.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/clep7212/Makefile b/arch/arm/boards/clep7212/Makefile
index a5001df9b5d5..096120e56772 100644
--- a/arch/arm/boards/clep7212/Makefile
+++ b/arch/arm/boards/clep7212/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += clep7212.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-clep7212
diff --git a/arch/arm/boards/cm-fx6/Makefile b/arch/arm/boards/cm-fx6/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/cm-fx6/Makefile
+++ b/arch/arm/boards/cm-fx6/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/crystalfontz-cfa10036/Makefile b/arch/arm/boards/crystalfontz-cfa10036/Makefile
index 5b764a698106..3cd1cecaa722 100644
--- a/arch/arm/boards/crystalfontz-cfa10036/Makefile
+++ b/arch/arm/boards/crystalfontz-cfa10036/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += cfa10036.o hwdetect.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/datamodul-edm-qmx6/Makefile b/arch/arm/boards/datamodul-edm-qmx6/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/datamodul-edm-qmx6/Makefile
+++ b/arch/arm/boards/datamodul-edm-qmx6/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/dfi-fs700-m60/Makefile b/arch/arm/boards/dfi-fs700-m60/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/dfi-fs700-m60/Makefile
+++ b/arch/arm/boards/dfi-fs700-m60/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/digi-ccimx6ulsom/Makefile b/arch/arm/boards/digi-ccimx6ulsom/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/digi-ccimx6ulsom/Makefile
+++ b/arch/arm/boards/digi-ccimx6ulsom/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/dss11/Makefile b/arch/arm/boards/dss11/Makefile
index e11fd5b6924e..d59545033d21 100644
--- a/arch/arm/boards/dss11/Makefile
+++ b/arch/arm/boards/dss11/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/duckbill/Makefile b/arch/arm/boards/duckbill/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/duckbill/Makefile
+++ b/arch/arm/boards/duckbill/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/ebv-socrates/Makefile b/arch/arm/boards/ebv-socrates/Makefile
index 8c927fe291a6..ea898309d720 100644
--- a/arch/arm/boards/ebv-socrates/Makefile
+++ b/arch/arm/boards/ebv-socrates/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += lowlevel.o board.o
 pbl-y += lowlevel.o
diff --git a/arch/arm/boards/edb93xx/Makefile b/arch/arm/boards/edb93xx/Makefile
index eec5ed265801..be969bde201b 100644
--- a/arch/arm/boards/edb93xx/Makefile
+++ b/arch/arm/boards/edb93xx/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 obj-y += edb93xx.o
 lwl-y += flash_cfg.o pll_cfg.o sdram_cfg.o
diff --git a/arch/arm/boards/efika-mx-smartbook/Makefile b/arch/arm/boards/efika-mx-smartbook/Makefile
index 73d7b9696cf4..497da461efba 100644
--- a/arch/arm/boards/efika-mx-smartbook/Makefile
+++ b/arch/arm/boards/efika-mx-smartbook/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-efikasb
diff --git a/arch/arm/boards/element14-warp7/Makefile b/arch/arm/boards/element14-warp7/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/element14-warp7/Makefile
+++ b/arch/arm/boards/element14-warp7/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/eltec-hipercam/Makefile b/arch/arm/boards/eltec-hipercam/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/eltec-hipercam/Makefile
+++ b/arch/arm/boards/eltec-hipercam/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/embedsky-e9/Makefile b/arch/arm/boards/embedsky-e9/Makefile
index 86afde47fbf4..116bbfb4c2bf 100644
--- a/arch/arm/boards/embedsky-e9/Makefile
+++ b/arch/arm/boards/embedsky-e9/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-e9
diff --git a/arch/arm/boards/embest-marsboard/Makefile b/arch/arm/boards/embest-marsboard/Makefile
index ef5219444c0e..eaa6ace2f43f 100644
--- a/arch/arm/boards/embest-marsboard/Makefile
+++ b/arch/arm/boards/embest-marsboard/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-mars
diff --git a/arch/arm/boards/embest-riotboard/Makefile b/arch/arm/boards/embest-riotboard/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/embest-riotboard/Makefile
+++ b/arch/arm/boards/embest-riotboard/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/eukrea_cpuimx27/Makefile b/arch/arm/boards/eukrea_cpuimx27/Makefile
index 2c3148abd085..6b6de4e87dc1 100644
--- a/arch/arm/boards/eukrea_cpuimx27/Makefile
+++ b/arch/arm/boards/eukrea_cpuimx27/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 lwl-y += lowlevel_init.o
 obj-y += eukrea_cpuimx27.o
diff --git a/arch/arm/boards/eukrea_cpuimx51/Makefile b/arch/arm/boards/eukrea_cpuimx51/Makefile
index e8c84fe17da0..77bd4cc87ac9 100644
--- a/arch/arm/boards/eukrea_cpuimx51/Makefile
+++ b/arch/arm/boards/eukrea_cpuimx51/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += eukrea_cpuimx51.o
 lwl-y += lowlevel.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-eukrea_cpuimx51
diff --git a/arch/arm/boards/freescale-mx21-ads/Makefile b/arch/arm/boards/freescale-mx21-ads/Makefile
index a43425b9ea8b..3e809a8c5927 100644
--- a/arch/arm/boards/freescale-mx21-ads/Makefile
+++ b/arch/arm/boards/freescale-mx21-ads/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel_init.o
 obj-y += imx21ads.o
diff --git a/arch/arm/boards/freescale-mx23-evk/Makefile b/arch/arm/boards/freescale-mx23-evk/Makefile
index 3e0026252cbd..7723ad93b091 100644
--- a/arch/arm/boards/freescale-mx23-evk/Makefile
+++ b/arch/arm/boards/freescale-mx23-evk/Makefile
@@ -1,3 +1,4 @@
-#
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y := mx23-evk.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx27-ads/Makefile b/arch/arm/boards/freescale-mx27-ads/Makefile
index 398db9b6b971..9fd43dd984cc 100644
--- a/arch/arm/boards/freescale-mx27-ads/Makefile
+++ b/arch/arm/boards/freescale-mx27-ads/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 lwl-y += lowlevel_init.o
 obj-y += imx27ads.o
diff --git a/arch/arm/boards/freescale-mx28-evk/Makefile b/arch/arm/boards/freescale-mx28-evk/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/freescale-mx28-evk/Makefile
+++ b/arch/arm/boards/freescale-mx28-evk/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx35-3ds/Makefile b/arch/arm/boards/freescale-mx35-3ds/Makefile
index c192854f0bec..e33babb4b3c7 100644
--- a/arch/arm/boards/freescale-mx35-3ds/Makefile
+++ b/arch/arm/boards/freescale-mx35-3ds/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y					+= 3stack.o
 lwl-y					+= lowlevel_init.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-freescale-mx35-3ds
diff --git a/arch/arm/boards/freescale-mx51-babbage/Makefile b/arch/arm/boards/freescale-mx51-babbage/Makefile
index b6e085818fdf..aed38f2eaa8f 100644
--- a/arch/arm/boards/freescale-mx51-babbage/Makefile
+++ b/arch/arm/boards/freescale-mx51-babbage/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_MACH_FREESCALE_MX51_PDK_POWER) += power.o
 obj-$(CONFIG_MACH_FREESCALE_MX51_PDK) += board.o
 lwl-$(CONFIG_MACH_FREESCALE_MX51_PDK) += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx53-qsb/Makefile b/arch/arm/boards/freescale-mx53-qsb/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/freescale-mx53-qsb/Makefile
+++ b/arch/arm/boards/freescale-mx53-qsb/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx53-smd/Makefile b/arch/arm/boards/freescale-mx53-smd/Makefile
index 98ed2753962e..9e7882a5db6c 100644
--- a/arch/arm/boards/freescale-mx53-smd/Makefile
+++ b/arch/arm/boards/freescale-mx53-smd/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-freescale-mx53-smd
diff --git a/arch/arm/boards/freescale-mx53-vmx53/Makefile b/arch/arm/boards/freescale-mx53-vmx53/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/freescale-mx53-vmx53/Makefile
+++ b/arch/arm/boards/freescale-mx53-vmx53/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx6-sabrelite/Makefile b/arch/arm/boards/freescale-mx6-sabrelite/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/freescale-mx6-sabrelite/Makefile
+++ b/arch/arm/boards/freescale-mx6-sabrelite/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx6-sabresd/Makefile b/arch/arm/boards/freescale-mx6-sabresd/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/freescale-mx6-sabresd/Makefile
+++ b/arch/arm/boards/freescale-mx6-sabresd/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx6sx-sabresdb/Makefile b/arch/arm/boards/freescale-mx6sx-sabresdb/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/freescale-mx6sx-sabresdb/Makefile
+++ b/arch/arm/boards/freescale-mx6sx-sabresdb/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-mx7-sabresd/Makefile b/arch/arm/boards/freescale-mx7-sabresd/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/freescale-mx7-sabresd/Makefile
+++ b/arch/arm/boards/freescale-mx7-sabresd/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/freescale-vf610-twr/Makefile b/arch/arm/boards/freescale-vf610-twr/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/freescale-vf610-twr/Makefile
+++ b/arch/arm/boards/freescale-vf610-twr/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/friendlyarm-mini2440/Kconfig b/arch/arm/boards/friendlyarm-mini2440/Kconfig
index feb905e96e33..1037f7c77ddd 100644
--- a/arch/arm/boards/friendlyarm-mini2440/Kconfig
+++ b/arch/arm/boards/friendlyarm-mini2440/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 if MACH_MINI2440
 
diff --git a/arch/arm/boards/friendlyarm-mini2440/Makefile b/arch/arm/boards/friendlyarm-mini2440/Makefile
index da3520cc816c..618828126cf7 100644
--- a/arch/arm/boards/friendlyarm-mini2440/Makefile
+++ b/arch/arm/boards/friendlyarm-mini2440/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 
 obj-y += mini2440.o
 lwl-y += lowlevel_init.o
diff --git a/arch/arm/boards/friendlyarm-mini6410/Makefile b/arch/arm/boards/friendlyarm-mini6410/Makefile
index c04150e97ff3..2e6ea7aa7e5c 100644
--- a/arch/arm/boards/friendlyarm-mini6410/Makefile
+++ b/arch/arm/boards/friendlyarm-mini6410/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += mini6410.o
 lwl-y += lowlevel.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-friendlyarm-mini6410
diff --git a/arch/arm/boards/friendlyarm-tiny210/Makefile b/arch/arm/boards/friendlyarm-tiny210/Makefile
index 7deb178739c5..d026a7ed4775 100644
--- a/arch/arm/boards/friendlyarm-tiny210/Makefile
+++ b/arch/arm/boards/friendlyarm-tiny210/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += tiny210.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/friendlyarm-tiny6410/Kconfig b/arch/arm/boards/friendlyarm-tiny6410/Kconfig
index 374820f8b351..1283b8e7d922 100644
--- a/arch/arm/boards/friendlyarm-tiny6410/Kconfig
+++ b/arch/arm/boards/friendlyarm-tiny6410/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if MACH_TINY6410
 
 choice
diff --git a/arch/arm/boards/friendlyarm-tiny6410/Makefile b/arch/arm/boards/friendlyarm-tiny6410/Makefile
index ba3f3360f8f6..f0b868d67fed 100644
--- a/arch/arm/boards/friendlyarm-tiny6410/Makefile
+++ b/arch/arm/boards/friendlyarm-tiny6410/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += tiny6410.o
 lwl-y += lowlevel.o
 lwl-$(CONFIG_MACH_TINY6410_FA) += development-board.o
diff --git a/arch/arm/boards/gateworks-ventana/Makefile b/arch/arm/boards/gateworks-ventana/Makefile
index 7d195eebd642..4e1cefbc4c94 100644
--- a/arch/arm/boards/gateworks-ventana/Makefile
+++ b/arch/arm/boards/gateworks-ventana/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o gsc.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/gk802/Makefile b/arch/arm/boards/gk802/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/gk802/Makefile
+++ b/arch/arm/boards/gk802/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/globalscale-guruplug/Makefile b/arch/arm/boards/globalscale-guruplug/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/globalscale-guruplug/Makefile
+++ b/arch/arm/boards/globalscale-guruplug/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/globalscale-mirabox/Makefile b/arch/arm/boards/globalscale-mirabox/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/globalscale-mirabox/Makefile
+++ b/arch/arm/boards/globalscale-mirabox/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/grinn-liteboard/Makefile b/arch/arm/boards/grinn-liteboard/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/grinn-liteboard/Makefile
+++ b/arch/arm/boards/grinn-liteboard/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/guf-neso/Makefile b/arch/arm/boards/guf-neso/Makefile
index af90c36c7e62..8d304e4afb41 100644
--- a/arch/arm/boards/guf-neso/Makefile
+++ b/arch/arm/boards/guf-neso/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
 obj-y += pll_init.o
diff --git a/arch/arm/boards/guf-santaro/Makefile b/arch/arm/boards/guf-santaro/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/guf-santaro/Makefile
+++ b/arch/arm/boards/guf-santaro/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/guf-vincell/Makefile b/arch/arm/boards/guf-vincell/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/guf-vincell/Makefile
+++ b/arch/arm/boards/guf-vincell/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/haba-knx/Makefile b/arch/arm/boards/haba-knx/Makefile
index b1c469dcf9a6..f2cf1123ed7a 100644
--- a/arch/arm/boards/haba-knx/Makefile
+++ b/arch/arm/boards/haba-knx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/imx233-olinuxino/Makefile b/arch/arm/boards/imx233-olinuxino/Makefile
index 987b34394aa4..1288c8c1ded3 100644
--- a/arch/arm/boards/imx233-olinuxino/Makefile
+++ b/arch/arm/boards/imx233-olinuxino/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y = imx23-olinuxino.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-imx233-olinuxino
diff --git a/arch/arm/boards/kamstrup-mx7-concentrator/Makefile b/arch/arm/boards/kamstrup-mx7-concentrator/Makefile
index 7ab9f5274768..458f5209008d 100644
--- a/arch/arm/boards/kamstrup-mx7-concentrator/Makefile
+++ b/arch/arm/boards/kamstrup-mx7-concentrator/Makefile
@@ -1 +1,3 @@
-lwl-y += lowlevel.o
\ No newline at end of file
+# SPDX-License-Identifier: GPL-2.0-only
+
+lwl-y += lowlevel.o
diff --git a/arch/arm/boards/karo-tx28/Makefile b/arch/arm/boards/karo-tx28/Makefile
index c7d7398cf3d4..b13ffc8f3c6e 100644
--- a/arch/arm/boards/karo-tx28/Makefile
+++ b/arch/arm/boards/karo-tx28/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += tx28.o
 obj-$(CONFIG_MACH_TX28STK5) += tx28-stk5.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/karo-tx53/Makefile b/arch/arm/boards/karo-tx53/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/karo-tx53/Makefile
+++ b/arch/arm/boards/karo-tx53/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/karo-tx6x/Makefile b/arch/arm/boards/karo-tx6x/Makefile
index 51b7c2d449d8..bfd7eed20a0a 100644
--- a/arch/arm/boards/karo-tx6x/Makefile
+++ b/arch/arm/boards/karo-tx6x/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 obj-y += pmic-ltc3676.o pmic-rn5t567.o pmic-rn5t618.o
diff --git a/arch/arm/boards/kindle-mx50/Makefile b/arch/arm/boards/kindle-mx50/Makefile
index 2cc614a8785b..14cf83793d89 100644
--- a/arch/arm/boards/kindle-mx50/Makefile
+++ b/arch/arm/boards/kindle-mx50/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-kindle-mx50
diff --git a/arch/arm/boards/kindle3/Makefile b/arch/arm/boards/kindle3/Makefile
index 86c746240e28..75a0ff560f26 100644
--- a/arch/arm/boards/kindle3/Makefile
+++ b/arch/arm/boards/kindle3/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += kindle3.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/kontron-samx6i/Makefile b/arch/arm/boards/kontron-samx6i/Makefile
index 816962241a5f..d753ff5f1813 100644
--- a/arch/arm/boards/kontron-samx6i/Makefile
+++ b/arch/arm/boards/kontron-samx6i/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o mem.o
 lwl-y += lowlevel.o mem.o
diff --git a/arch/arm/boards/lenovo-ix4-300d/Makefile b/arch/arm/boards/lenovo-ix4-300d/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/lenovo-ix4-300d/Makefile
+++ b/arch/arm/boards/lenovo-ix4-300d/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/ls1046ardb/Makefile b/arch/arm/boards/ls1046ardb/Makefile
index 03ac4ecca3dd..829be5327aed 100644
--- a/arch/arm/boards/ls1046ardb/Makefile
+++ b/arch/arm/boards/ls1046ardb/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
 lwl-y += start.o
diff --git a/arch/arm/boards/lubbock/Makefile b/arch/arm/boards/lubbock/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/lubbock/Makefile
+++ b/arch/arm/boards/lubbock/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/lxa-mc1/Makefile b/arch/arm/boards/lxa-mc1/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/lxa-mc1/Makefile
+++ b/arch/arm/boards/lxa-mc1/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/mainstone/Makefile b/arch/arm/boards/mainstone/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/mainstone/Makefile
+++ b/arch/arm/boards/mainstone/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/marvell-armada-xp-db/Makefile b/arch/arm/boards/marvell-armada-xp-db/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/marvell-armada-xp-db/Makefile
+++ b/arch/arm/boards/marvell-armada-xp-db/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/marvell-armada-xp-gp/Makefile b/arch/arm/boards/marvell-armada-xp-gp/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/marvell-armada-xp-gp/Makefile
+++ b/arch/arm/boards/marvell-armada-xp-gp/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/microchip-ksz9477-evb/Makefile b/arch/arm/boards/microchip-ksz9477-evb/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/microchip-ksz9477-evb/Makefile
+++ b/arch/arm/boards/microchip-ksz9477-evb/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/mioa701/Makefile b/arch/arm/boards/mioa701/Makefile
index 3072706237d6..bf17869fb2ac 100644
--- a/arch/arm/boards/mioa701/Makefile
+++ b/arch/arm/boards/mioa701/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o gpio0_poweroff.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/mnt-reform/Makefile b/arch/arm/boards/mnt-reform/Makefile
index a3da88fbe68f..35d8640087b1 100644
--- a/arch/arm/boards/mnt-reform/Makefile
+++ b/arch/arm/boards/mnt-reform/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
-lwl-y += lowlevel.o lpddr4-timing.o
\ No newline at end of file
+lwl-y += lowlevel.o lpddr4-timing.o
diff --git a/arch/arm/boards/module-mb7707/Makefile b/arch/arm/boards/module-mb7707/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/module-mb7707/Makefile
+++ b/arch/arm/boards/module-mb7707/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/netgear-rn104/Makefile b/arch/arm/boards/netgear-rn104/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/netgear-rn104/Makefile
+++ b/arch/arm/boards/netgear-rn104/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/netgear-rn2120/Makefile b/arch/arm/boards/netgear-rn2120/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/netgear-rn2120/Makefile
+++ b/arch/arm/boards/netgear-rn2120/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/nhk8815/Makefile b/arch/arm/boards/nhk8815/Makefile
index 56f2013e2254..0367fa7dd5da 100644
--- a/arch/arm/boards/nhk8815/Makefile
+++ b/arch/arm/boards/nhk8815/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += setup.o
 lwl-y += lowlevel.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-nhk8815
diff --git a/arch/arm/boards/nvidia-beaver/Makefile b/arch/arm/boards/nvidia-beaver/Makefile
index 1b90eb13fdd0..6485e5d2da77 100644
--- a/arch/arm/boards/nvidia-beaver/Makefile
+++ b/arch/arm/boards/nvidia-beaver/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 CFLAGS_entry.pbl.o := -mcpu=arm7tdmi -march=armv4t
 soc := tegra30
 lwl-y += entry.o
diff --git a/arch/arm/boards/nvidia-jetson-tk1/Makefile b/arch/arm/boards/nvidia-jetson-tk1/Makefile
index d38001c15890..7d9402f9b345 100644
--- a/arch/arm/boards/nvidia-jetson-tk1/Makefile
+++ b/arch/arm/boards/nvidia-jetson-tk1/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 CFLAGS_entry.pbl.o := -mcpu=arm7tdmi -march=armv4t
 soc := tegra124
 lwl-y += entry.o
diff --git a/arch/arm/boards/nxp-imx6ull-evk/Makefile b/arch/arm/boards/nxp-imx6ull-evk/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/nxp-imx6ull-evk/Makefile
+++ b/arch/arm/boards/nxp-imx6ull-evk/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/nxp-imx8mm-evk/Makefile b/arch/arm/boards/nxp-imx8mm-evk/Makefile
index 4d0d9890153b..35d8640087b1 100644
--- a/arch/arm/boards/nxp-imx8mm-evk/Makefile
+++ b/arch/arm/boards/nxp-imx8mm-evk/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o lpddr4-timing.o
diff --git a/arch/arm/boards/nxp-imx8mn-evk/Makefile b/arch/arm/boards/nxp-imx8mn-evk/Makefile
index 4b13ff3b94e4..d74c5845ef7d 100644
--- a/arch/arm/boards/nxp-imx8mn-evk/Makefile
+++ b/arch/arm/boards/nxp-imx8mn-evk/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o ddr4-timing.o lpddr4-timing.o
diff --git a/arch/arm/boards/nxp-imx8mp-evk/Makefile b/arch/arm/boards/nxp-imx8mp-evk/Makefile
index 4d0d9890153b..35d8640087b1 100644
--- a/arch/arm/boards/nxp-imx8mp-evk/Makefile
+++ b/arch/arm/boards/nxp-imx8mp-evk/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o lpddr4-timing.o
diff --git a/arch/arm/boards/nxp-imx8mq-evk/Makefile b/arch/arm/boards/nxp-imx8mq-evk/Makefile
index 2995f06f0fd9..17d769f3309b 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/Makefile
+++ b/arch/arm/boards/nxp-imx8mq-evk/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o ddr_init.o ddrphy_train.o
diff --git a/arch/arm/boards/omap343xdsp/Makefile b/arch/arm/boards/omap343xdsp/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/omap343xdsp/Makefile
+++ b/arch/arm/boards/omap343xdsp/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/omap3evm/Makefile b/arch/arm/boards/omap3evm/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/omap3evm/Makefile
+++ b/arch/arm/boards/omap3evm/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/panda/Makefile b/arch/arm/boards/panda/Makefile
index 5d4eb10b9b1b..3bd91350ce8b 100644
--- a/arch/arm/boards/panda/Makefile
+++ b/arch/arm/boards/panda/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o mux.o
diff --git a/arch/arm/boards/phytec-phycard-imx27/Makefile b/arch/arm/boards/phytec-phycard-imx27/Makefile
index 34492bb127b4..0e6411d58809 100644
--- a/arch/arm/boards/phytec-phycard-imx27/Makefile
+++ b/arch/arm/boards/phytec-phycard-imx27/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 lwl-y += lowlevel.o
 obj-y += pca100.o
diff --git a/arch/arm/boards/phytec-phycore-imx27/Makefile b/arch/arm/boards/phytec-phycore-imx27/Makefile
index 4723c77818f2..ce7b990407ce 100644
--- a/arch/arm/boards/phytec-phycore-imx27/Makefile
+++ b/arch/arm/boards/phytec-phycore-imx27/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y	+= pcm038.o pcm970.o
 lwl-y	+= lowlevel.o
 bbenv-y += defaultenv-pcm038
diff --git a/arch/arm/boards/phytec-phycore-imx7/Makefile b/arch/arm/boards/phytec-phycore-imx7/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/phytec-phycore-imx7/Makefile
+++ b/arch/arm/boards/phytec-phycore-imx7/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/phytec-phycore-omap4460/Makefile b/arch/arm/boards/phytec-phycore-omap4460/Makefile
index 5e78e11ec133..c5d3950bc3c7 100644
--- a/arch/arm/boards/phytec-phycore-omap4460/Makefile
+++ b/arch/arm/boards/phytec-phycore-omap4460/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o mux.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-phytec-phycore-omap4460
diff --git a/arch/arm/boards/phytec-phycore-pxa270/Makefile b/arch/arm/boards/phytec-phycore-pxa270/Makefile
index 040cf93944ee..e00d1cfd7f70 100644
--- a/arch/arm/boards/phytec-phycore-pxa270/Makefile
+++ b/arch/arm/boards/phytec-phycore-pxa270/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel_init.o
diff --git a/arch/arm/boards/phytec-som-am335x/Kconfig b/arch/arm/boards/phytec-som-am335x/Kconfig
index 52fa723a21a1..054a1d219f83 100644
--- a/arch/arm/boards/phytec-som-am335x/Kconfig
+++ b/arch/arm/boards/phytec-som-am335x/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 if MACH_PHYTEC_SOM_AM335X
 
diff --git a/arch/arm/boards/phytec-som-am335x/Makefile b/arch/arm/boards/phytec-som-am335x/Makefile
index 78397bd59fdf..82dd631c9f08 100644
--- a/arch/arm/boards/phytec-som-am335x/Makefile
+++ b/arch/arm/boards/phytec-som-am335x/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
 bbenv-y += defaultenv-physom-am335x
diff --git a/arch/arm/boards/phytec-som-imx6/Makefile b/arch/arm/boards/phytec-som-imx6/Makefile
index 73456aed8bf7..0780da79b9b3 100644
--- a/arch/arm/boards/phytec-som-imx6/Makefile
+++ b/arch/arm/boards/phytec-som-imx6/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-physom-imx6
diff --git a/arch/arm/boards/phytec-som-imx8mq/Makefile b/arch/arm/boards/phytec-som-imx8mq/Makefile
index 2995f06f0fd9..17d769f3309b 100644
--- a/arch/arm/boards/phytec-som-imx8mq/Makefile
+++ b/arch/arm/boards/phytec-som-imx8mq/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o ddr_init.o ddrphy_train.o
diff --git a/arch/arm/boards/phytec-som-rk3288/Makefile b/arch/arm/boards/phytec-som-rk3288/Makefile
index 6f34c9a2f21e..e4ba704dea09 100644
--- a/arch/arm/boards/phytec-som-rk3288/Makefile
+++ b/arch/arm/boards/phytec-som-rk3288/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-physom-rk3288
diff --git a/arch/arm/boards/plathome-openblocks-a6/Makefile b/arch/arm/boards/plathome-openblocks-a6/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/plathome-openblocks-a6/Makefile
+++ b/arch/arm/boards/plathome-openblocks-a6/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/plathome-openblocks-ax3/Makefile b/arch/arm/boards/plathome-openblocks-ax3/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/plathome-openblocks-ax3/Makefile
+++ b/arch/arm/boards/plathome-openblocks-ax3/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/pm9261/Makefile b/arch/arm/boards/pm9261/Makefile
index e9bf1212fe04..5b501a548fd5 100644
--- a/arch/arm/boards/pm9261/Makefile
+++ b/arch/arm/boards/pm9261/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel_init.o
diff --git a/arch/arm/boards/pm9263/Makefile b/arch/arm/boards/pm9263/Makefile
index 68bfbfa92695..7220ee11f357 100644
--- a/arch/arm/boards/pm9263/Makefile
+++ b/arch/arm/boards/pm9263/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel_init.o
diff --git a/arch/arm/boards/pm9g45/Makefile b/arch/arm/boards/pm9g45/Makefile
index abf50243e540..148ae4a2521c 100644
--- a/arch/arm/boards/pm9g45/Makefile
+++ b/arch/arm/boards/pm9g45/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/protonic-imx6/Makefile b/arch/arm/boards/protonic-imx6/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/protonic-imx6/Makefile
+++ b/arch/arm/boards/protonic-imx6/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/protonic-imx8m/Makefile b/arch/arm/boards/protonic-imx8m/Makefile
index 51a27f0c2dfd..18da0f5a4415 100644
--- a/arch/arm/boards/protonic-imx8m/Makefile
+++ b/arch/arm/boards/protonic-imx8m/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel-prt8mm.o lpddr4-timing-prt8mm.o
 bbenv-y += defaultenv-prt8m
diff --git a/arch/arm/boards/protonic-stm32mp1/Makefile b/arch/arm/boards/protonic-stm32mp1/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/protonic-stm32mp1/Makefile
+++ b/arch/arm/boards/protonic-stm32mp1/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/qemu-virt/Makefile b/arch/arm/boards/qemu-virt/Makefile
index dcfc2937d325..ad283446eaf1 100644
--- a/arch/arm/boards/qemu-virt/Makefile
+++ b/arch/arm/boards/qemu-virt/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
diff --git a/arch/arm/boards/qil-a926x/Makefile b/arch/arm/boards/qil-a926x/Makefile
index 82e46b369f41..bf5ed8b4f4c5 100644
--- a/arch/arm/boards/qil-a926x/Makefile
+++ b/arch/arm/boards/qil-a926x/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/radxa-rock/Makefile b/arch/arm/boards/radxa-rock/Makefile
index ec930bc264e7..79d3969dcde1 100644
--- a/arch/arm/boards/radxa-rock/Makefile
+++ b/arch/arm/boards/radxa-rock/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_MACH_RADXA_ROCK) += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-radxa-rock
diff --git a/arch/arm/boards/raspberry-pi/Makefile b/arch/arm/boards/raspberry-pi/Makefile
index ddcf015f0848..6f995b564017 100644
--- a/arch/arm/boards/raspberry-pi/Makefile
+++ b/arch/arm/boards/raspberry-pi/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_MACH_RPI_COMMON) += rpi-common.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-rpi
diff --git a/arch/arm/boards/reflex-achilles/Makefile b/arch/arm/boards/reflex-achilles/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/reflex-achilles/Makefile
+++ b/arch/arm/boards/reflex-achilles/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/rockchip-rk3568-evb/Makefile b/arch/arm/boards/rockchip-rk3568-evb/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/rockchip-rk3568-evb/Makefile
+++ b/arch/arm/boards/rockchip-rk3568-evb/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/sama5d27-giantboard/Makefile b/arch/arm/boards/sama5d27-giantboard/Makefile
index f5869c483978..e2c6a3adf671 100644
--- a/arch/arm/boards/sama5d27-giantboard/Makefile
+++ b/arch/arm/boards/sama5d27-giantboard/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
 bbenv-y += defaultenv-giantboard
diff --git a/arch/arm/boards/sama5d27-som1/Makefile b/arch/arm/boards/sama5d27-som1/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/sama5d27-som1/Makefile
+++ b/arch/arm/boards/sama5d27-som1/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/sama5d3_xplained/Makefile b/arch/arm/boards/sama5d3_xplained/Makefile
index e5c86e58957e..b7d6b2e7fa89 100644
--- a/arch/arm/boards/sama5d3_xplained/Makefile
+++ b/arch/arm/boards/sama5d3_xplained/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-sama5d3_xplained
diff --git a/arch/arm/boards/sama5d3xek/Makefile b/arch/arm/boards/sama5d3xek/Makefile
index 6ed914fc0a47..9691f0791702 100644
--- a/arch/arm/boards/sama5d3xek/Makefile
+++ b/arch/arm/boards/sama5d3xek/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 obj-$(CONFIG_W1) += hw_version.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/sama5d4_xplained/Makefile b/arch/arm/boards/sama5d4_xplained/Makefile
index 8873dfc22c44..eece4cc38118 100644
--- a/arch/arm/boards/sama5d4_xplained/Makefile
+++ b/arch/arm/boards/sama5d4_xplained/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += sama5d4_xplained.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/sama5d4ek/Makefile b/arch/arm/boards/sama5d4ek/Makefile
index 152750bbe0a7..82ffe9771caf 100644
--- a/arch/arm/boards/sama5d4ek/Makefile
+++ b/arch/arm/boards/sama5d4ek/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += sama5d4ek.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/scb9328/Makefile b/arch/arm/boards/scb9328/Makefile
index 8e1c7ef7a505..5c13dddc0657 100644
--- a/arch/arm/boards/scb9328/Makefile
+++ b/arch/arm/boards/scb9328/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 lwl-y += lowlevel_init.o lowlevel.o
 obj-y += scb9328.o
diff --git a/arch/arm/boards/seeed-odyssey/Makefile b/arch/arm/boards/seeed-odyssey/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/seeed-odyssey/Makefile
+++ b/arch/arm/boards/seeed-odyssey/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/skov-arm9cpu/Makefile b/arch/arm/boards/skov-arm9cpu/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/skov-arm9cpu/Makefile
+++ b/arch/arm/boards/skov-arm9cpu/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/skov-imx6/Makefile b/arch/arm/boards/skov-imx6/Makefile
index 07b87ff11df0..b6b8b44b847b 100644
--- a/arch/arm/boards/skov-imx6/Makefile
+++ b/arch/arm/boards/skov-imx6/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 obj-pbl-y += version.o
diff --git a/arch/arm/boards/solidrun-cubox/Makefile b/arch/arm/boards/solidrun-cubox/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/solidrun-cubox/Makefile
+++ b/arch/arm/boards/solidrun-cubox/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/solidrun-microsom/Makefile b/arch/arm/boards/solidrun-microsom/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/solidrun-microsom/Makefile
+++ b/arch/arm/boards/solidrun-microsom/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/stm32mp15x-ev1/Makefile b/arch/arm/boards/stm32mp15x-ev1/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/stm32mp15x-ev1/Makefile
+++ b/arch/arm/boards/stm32mp15x-ev1/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/stm32mp15xx-dkx/Makefile b/arch/arm/boards/stm32mp15xx-dkx/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/stm32mp15xx-dkx/Makefile
+++ b/arch/arm/boards/stm32mp15xx-dkx/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/technexion-pico-hobbit/Makefile b/arch/arm/boards/technexion-pico-hobbit/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/technexion-pico-hobbit/Makefile
+++ b/arch/arm/boards/technexion-pico-hobbit/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/technexion-wandboard/Makefile b/arch/arm/boards/technexion-wandboard/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/technexion-wandboard/Makefile
+++ b/arch/arm/boards/technexion-wandboard/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/telit-evk-pro3/Makefile b/arch/arm/boards/telit-evk-pro3/Makefile
index e11fd5b6924e..d59545033d21 100644
--- a/arch/arm/boards/telit-evk-pro3/Makefile
+++ b/arch/arm/boards/telit-evk-pro3/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/terasic-de0-nano-soc/Makefile b/arch/arm/boards/terasic-de0-nano-soc/Makefile
index 8c927fe291a6..ea898309d720 100644
--- a/arch/arm/boards/terasic-de0-nano-soc/Makefile
+++ b/arch/arm/boards/terasic-de0-nano-soc/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += lowlevel.o board.o
 pbl-y += lowlevel.o
diff --git a/arch/arm/boards/terasic-de10-nano/Makefile b/arch/arm/boards/terasic-de10-nano/Makefile
index 8c927fe291a6..ea898309d720 100644
--- a/arch/arm/boards/terasic-de10-nano/Makefile
+++ b/arch/arm/boards/terasic-de10-nano/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += lowlevel.o board.o
 pbl-y += lowlevel.o
diff --git a/arch/arm/boards/terasic-sockit/Makefile b/arch/arm/boards/terasic-sockit/Makefile
index 8c927fe291a6..ea898309d720 100644
--- a/arch/arm/boards/terasic-sockit/Makefile
+++ b/arch/arm/boards/terasic-sockit/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += lowlevel.o board.o
 pbl-y += lowlevel.o
diff --git a/arch/arm/boards/tny-a926x/Makefile b/arch/arm/boards/tny-a926x/Makefile
index d400788757b6..1ebe527d608e 100644
--- a/arch/arm/boards/tny-a926x/Makefile
+++ b/arch/arm/boards/tny-a926x/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 obj-$(CONFIG_AT91_BOOTSTRAP) += tny_a9263_bootstrap.o
diff --git a/arch/arm/boards/toradex-colibri-t20/Makefile b/arch/arm/boards/toradex-colibri-t20/Makefile
index cdce48d1f847..aeb4765cf674 100644
--- a/arch/arm/boards/toradex-colibri-t20/Makefile
+++ b/arch/arm/boards/toradex-colibri-t20/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 CFLAGS_entry.pbl.o := -mcpu=arm7tdmi -march=armv4t
 soc := tegra20
 lwl-y += entry.o
diff --git a/arch/arm/boards/toshiba-ac100/Makefile b/arch/arm/boards/toshiba-ac100/Makefile
index e8158cb253cf..702c86a9247a 100644
--- a/arch/arm/boards/toshiba-ac100/Makefile
+++ b/arch/arm/boards/toshiba-ac100/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 CFLAGS_entry.pbl.o := -mcpu=arm7tdmi -march=armv4t
 lwl-y += entry.o
 obj-y += board.o
diff --git a/arch/arm/boards/tqma53/Makefile b/arch/arm/boards/tqma53/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/tqma53/Makefile
+++ b/arch/arm/boards/tqma53/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/tqma6x/Makefile b/arch/arm/boards/tqma6x/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/tqma6x/Makefile
+++ b/arch/arm/boards/tqma6x/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/tqmls1046a/Makefile b/arch/arm/boards/tqmls1046a/Makefile
index 851a5dcb3d7c..4af7fc3602a6 100644
--- a/arch/arm/boards/tqmls1046a/Makefile
+++ b/arch/arm/boards/tqmls1046a/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o start.o
 obj-y += board.o
 bbenv-y += defaultenv-tqmls1046a
diff --git a/arch/arm/boards/turris-omnia/Makefile b/arch/arm/boards/turris-omnia/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/turris-omnia/Makefile
+++ b/arch/arm/boards/turris-omnia/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/udoo-neo/Makefile b/arch/arm/boards/udoo-neo/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/udoo-neo/Makefile
+++ b/arch/arm/boards/udoo-neo/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/udoo/Makefile b/arch/arm/boards/udoo/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/udoo/Makefile
+++ b/arch/arm/boards/udoo/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/usb-a926x/Makefile b/arch/arm/boards/usb-a926x/Makefile
index 65cc4082fc0f..022b1a4ab6fb 100644
--- a/arch/arm/boards/usb-a926x/Makefile
+++ b/arch/arm/boards/usb-a926x/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 
 obj-$(CONFIG_AT91_BOOTSTRAP) += usb_a9263_bootstrap.o
diff --git a/arch/arm/boards/usi-topkick/Makefile b/arch/arm/boards/usi-topkick/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/arm/boards/usi-topkick/Makefile
+++ b/arch/arm/boards/usi-topkick/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/variscite-mx6/Makefile b/arch/arm/boards/variscite-mx6/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/variscite-mx6/Makefile
+++ b/arch/arm/boards/variscite-mx6/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/versatile/Kconfig b/arch/arm/boards/versatile/Kconfig
index 94cba3ba8173..66492404e0b2 100644
--- a/arch/arm/boards/versatile/Kconfig
+++ b/arch/arm/boards/versatile/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 if MACH_VERSATILEPB
 
diff --git a/arch/arm/boards/versatile/Makefile b/arch/arm/boards/versatile/Makefile
index 89232a7884c8..5a55d0017d14 100644
--- a/arch/arm/boards/versatile/Makefile
+++ b/arch/arm/boards/versatile/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_MACH_VERSATILEPB) += versatilepb.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/vexpress/Makefile b/arch/arm/boards/vexpress/Makefile
index 2da0494d49b3..720210d8905f 100644
--- a/arch/arm/boards/vexpress/Makefile
+++ b/arch/arm/boards/vexpress/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += init.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/virt2real/Makefile b/arch/arm/boards/virt2real/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/virt2real/Makefile
+++ b/arch/arm/boards/virt2real/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/vscom-baltos/Makefile b/arch/arm/boards/vscom-baltos/Makefile
index 092c31d6b28d..5678718188b9 100644
--- a/arch/arm/boards/vscom-baltos/Makefile
+++ b/arch/arm/boards/vscom-baltos/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += board.o
diff --git a/arch/arm/boards/wago-pfc-am35xx/Makefile b/arch/arm/boards/wago-pfc-am35xx/Makefile
index 7bd3009f31e3..35ac0462cba1 100644
--- a/arch/arm/boards/wago-pfc-am35xx/Makefile
+++ b/arch/arm/boards/wago-pfc-am35xx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 ifdef CONFIG_OMAP_BUILD_IFT
 obj-y += board-mlo.o
diff --git a/arch/arm/boards/webasto-ccbv2/Makefile b/arch/arm/boards/webasto-ccbv2/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/webasto-ccbv2/Makefile
+++ b/arch/arm/boards/webasto-ccbv2/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/zii-common/Makefile b/arch/arm/boards/zii-common/Makefile
index 90bdf21e77bd..7488148cff9c 100644
--- a/arch/arm/boards/zii-common/Makefile
+++ b/arch/arm/boards/zii-common/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o switch-cmd.o pn-fixup.o
 bbenv-y += defaultenv-zii-common
diff --git a/arch/arm/boards/zii-imx51-rdu1/Makefile b/arch/arm/boards/zii-imx51-rdu1/Makefile
index 7f2569bda37d..96663f9ae867 100644
--- a/arch/arm/boards/zii-imx51-rdu1/Makefile
+++ b/arch/arm/boards/zii-imx51-rdu1/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-rdu1
diff --git a/arch/arm/boards/zii-imx6q-rdu2/Makefile b/arch/arm/boards/zii-imx6q-rdu2/Makefile
index c6285362f2ee..31b592bd36a5 100644
--- a/arch/arm/boards/zii-imx6q-rdu2/Makefile
+++ b/arch/arm/boards/zii-imx6q-rdu2/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-rdu2
diff --git a/arch/arm/boards/zii-imx7d-dev/Makefile b/arch/arm/boards/zii-imx7d-dev/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/zii-imx7d-dev/Makefile
+++ b/arch/arm/boards/zii-imx7d-dev/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/boards/zii-imx8mq-dev/Makefile b/arch/arm/boards/zii-imx8mq-dev/Makefile
index d0148b506752..8894e40b5a3f 100644
--- a/arch/arm/boards/zii-imx8mq-dev/Makefile
+++ b/arch/arm/boards/zii-imx8mq-dev/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o ddr_init.o ddrphy_train.o
 bbenv-y += defaultenv-imx8mq-zii-dev
diff --git a/arch/arm/boards/zii-vf610-dev/Makefile b/arch/arm/boards/zii-vf610-dev/Makefile
index 1297d815e319..a1a8318e1588 100644
--- a/arch/arm/boards/zii-vf610-dev/Makefile
+++ b/arch/arm/boards/zii-vf610-dev/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
 bbenv-y += defaultenv-zii-vf610-dev
diff --git a/arch/arm/boards/zylonite/Makefile b/arch/arm/boards/zylonite/Makefile
index 01c7a259e9a5..da63d2625f7a 100644
--- a/arch/arm/boards/zylonite/Makefile
+++ b/arch/arm/boards/zylonite/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig
index ca3bd98962e2..0a493754a418 100644
--- a/arch/arm/cpu/Kconfig
+++ b/arch/arm/cpu/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 comment "Processor Type"
 
 config PHYS_ADDR_T_64BIT
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index 6344ab506645..c0993c1abe5d 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += cpu.o
 
 obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions$(S64).o interrupts$(S64).o
diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile
index fda4eeafeca0..990c0bd609cd 100644
--- a/arch/arm/crypto/Makefile
+++ b/arch/arm/crypto/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # Arch-specific CryptoAPI modules.
 #
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 76c96752cd78..8ae8244bfeee 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 # just to build a built-in.o. Otherwise compilation fails when no devicetree is
 # created.
 obj- += dummy.o
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 33db7350f85f..1a8144f6c64a 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_BOOTM)	+= bootm.o
 obj-$(CONFIG_CMD_BOOTU)	+= bootu.o
diff --git a/arch/arm/lib32/Makefile b/arch/arm/lib32/Makefile
index ec6a3aea6721..82507fffc02b 100644
--- a/arch/arm/lib32/Makefile
+++ b/arch/arm/lib32/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_ARM_LINUX)	+= armlinux.o
 obj-$(CONFIG_CMD_BOOTZ)	+= bootz.o
 obj-$(CONFIG_BOOTM)     += bootm.o
diff --git a/arch/arm/lib64/Makefile b/arch/arm/lib64/Makefile
index a004af4867f2..e86a2e5a2f3d 100644
--- a/arch/arm/lib64/Makefile
+++ b/arch/arm/lib64/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += stacktrace.o
 obj-$(CONFIG_ARM_LINUX)	+= armlinux.o
 obj-y	+= div0.o
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 734256e3614e..bc55b1c4e76e 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_AT91
 
 config HAVE_AT91_UTMI
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c895af7a2f8b..bfdc89f680ed 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += setup.o aic.o
 lwl-y += at91_pmc_ll.o ddramc_ll.o matrix.o
 lwl-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += early_udelay.o
diff --git a/arch/arm/mach-bcm283x/Kconfig b/arch/arm/mach-bcm283x/Kconfig
index 9d6a7b2ec2d4..75acee8dad56 100644
--- a/arch/arm/mach-bcm283x/Kconfig
+++ b/arch/arm/mach-bcm283x/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_BCM283X
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-bcm283x/Makefile b/arch/arm/mach-bcm283x/Makefile
index 940f98cbce76..e5ef78af978f 100644
--- a/arch/arm/mach-bcm283x/Makefile
+++ b/arch/arm/mach-bcm283x/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += core.o mbox.o
diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig
index c00514e86d6c..52cf8468c03f 100644
--- a/arch/arm/mach-clps711x/Kconfig
+++ b/arch/arm/mach-clps711x/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_CLPS711X
 
 choice
diff --git a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile
index 45525343d737..4d5950d9b5f0 100644
--- a/arch/arm/mach-clps711x/Makefile
+++ b/arch/arm/mach-clps711x/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += clock.o devices.o reset.o
 lwl-y += lowlevel.o
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index c6d4fce603ae..a87b6256ce49 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_DAVINCI
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index b96d4146f6d5..f7865a941b82 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += time.o
diff --git a/arch/arm/mach-digic/Kconfig b/arch/arm/mach-digic/Kconfig
index d25c3b3f5108..25b9a0da2fe6 100644
--- a/arch/arm/mach-digic/Kconfig
+++ b/arch/arm/mach-digic/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_DIGIC
 
 choice
diff --git a/arch/arm/mach-digic/Makefile b/arch/arm/mach-digic/Makefile
index 16a218658ade..1c2b374603ce 100644
--- a/arch/arm/mach-digic/Makefile
+++ b/arch/arm/mach-digic/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj- := __dummy__.o
diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig
index f805a8fd527a..e39f1d8a9b28 100644
--- a/arch/arm/mach-ep93xx/Kconfig
+++ b/arch/arm/mach-ep93xx/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_EP93XX
 
 config EP93XX_SDCE0_PHYS_OFFSET
diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile
index fc0cb1afcd6e..80dbe7c42bfa 100644
--- a/arch/arm/mach-ep93xx/Makefile
+++ b/arch/arm/mach-ep93xx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += clocksource.o gpio.o header.o
 
 lwl-y += lowlevel_init.o led.o
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 92db011baed7..454f7328d834 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_IMX
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index d94c846a13bf..2cafcd77e00d 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_ARCH_IMX1)  += imx1.o
 obj-$(CONFIG_ARCH_IMX25) += imx25.o
 obj-$(CONFIG_ARCH_IMX21) += imx21.o
diff --git a/arch/arm/mach-layerscape/Kconfig b/arch/arm/mach-layerscape/Kconfig
index c15d5873a55e..bdd7d0dbfe52 100644
--- a/arch/arm/mach-layerscape/Kconfig
+++ b/arch/arm/mach-layerscape/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_LAYERSCAPE
 
 config ARCH_LAYERSCAPE_PPA
diff --git a/arch/arm/mach-layerscape/Makefile b/arch/arm/mach-layerscape/Makefile
index 854a327c9125..58d3ea820aa3 100644
--- a/arch/arm/mach-layerscape/Makefile
+++ b/arch/arm/mach-layerscape/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj- := __dummy__.o
 lwl-y += lowlevel.o errata.o
 lwl-$(CONFIG_ARCH_LS1046) += lowlevel-ls1046a.o
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index bab22f07ff34..1b26148434ad 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_MVEBU
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 6079403b83dd..88580cb58f4c 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-pbl-y			+= common.o
 obj-$(CONFIG_ARCH_ARMADA_370)	+= armada-370-xp.o
 obj-$(CONFIG_ARCH_ARMADA_XP)	+= armada-370-xp.o
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index f4a9d3d4221e..691c159e365f 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_MXS
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index e3843368c2d1..0f3fba896751 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += imx.o iomux-imx.o power.o
 pbl-y += iomux-imx.o
 obj-$(CONFIG_ARCH_IMX23) += clocksource-imx23.o usb-imx23.o soc-imx23.o
diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig
index 51d490df1b1b..823777917391 100644
--- a/arch/arm/mach-nomadik/Kconfig
+++ b/arch/arm/mach-nomadik/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_NOMADIK
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-nomadik/Makefile b/arch/arm/mach-nomadik/Makefile
index 1d77c4cf52f9..0ab83f61c816 100644
--- a/arch/arm/mach-nomadik/Makefile
+++ b/arch/arm/mach-nomadik/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 obj-y	+= clock.o reset.o timer.o
 obj-y	+= 8815.o
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index fd9084f83ea1..711f8ed8d83c 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_PXA
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 0c3219807bc6..9249c8fe14e3 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += clocksource.o
 obj-y += common.o
 obj-y += gpio.o
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 5603fc12c307..2e855714f7da 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menu "Rockchip Features"
 	depends on ARCH_ROCKCHIP
 
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 66bcdba2eb22..72bf77c1e124 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += rockchip.o
 pbl-$(CONFIG_ARCH_RK3568) += atf.o
 obj-$(CONFIG_ARCH_RK3188) += rk3188.o
diff --git a/arch/arm/mach-samsung/Kconfig b/arch/arm/mach-samsung/Kconfig
index fa1a3ddcc49f..aa2ae67e2d86 100644
--- a/arch/arm/mach-samsung/Kconfig
+++ b/arch/arm/mach-samsung/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config ARCH_SAMSUNG
 	bool
 
diff --git a/arch/arm/mach-samsung/Makefile b/arch/arm/mach-samsung/Makefile
index 284c80a2ad43..8a893a076ff1 100644
--- a/arch/arm/mach-samsung/Makefile
+++ b/arch/arm/mach-samsung/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += s3c-timer.o generic.o
 obj-$(CONFIG_RESET_SOURCE) += reset_source.o
 obj-lowlevel-$(CONFIG_ARCH_S3C24xx) += lowlevel-s3c24x0.o
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index ea2abebaa20c..80344315e3d9 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_SOCFPGA
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 3a3a2fc57dd3..935270bfad8e 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 pbl-$(CONFIG_ARCH_SOCFPGA_CYCLONE5) += cyclone5-init.o cyclone5-freeze-controller.o cyclone5-scan-manager.o cyclone5-system-manager.o
 pbl-$(CONFIG_ARCH_SOCFPGA_CYCLONE5) += cyclone5-clock-manager.o
 obj-$(CONFIG_ARCH_SOCFPGA_CYCLONE5) += cyclone5-generic.o nic301.o cyclone5-bootsource.o cyclone5-reset-manager.o
diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
index 8328eb899aba..d059dbda56a9 100644
--- a/arch/arm/mach-stm32mp/Kconfig
+++ b/arch/arm/mach-stm32mp/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_STM32MP
 
 config ARCH_NR_GPIO
diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
index 8e14b225359d..4163bd176b1f 100644
--- a/arch/arm/mach-stm32mp/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y := init.o
 obj-pbl-y := ddrctrl.o
 obj-$(CONFIG_BOOTM) += stm32image.o
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index f144d346b4c5..cc256f584ac6 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_TEGRA
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 60aae41ea06c..ddc029bda26a 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 CFLAGS_tegra_avp_init.o := -mcpu=arm7tdmi -march=armv4t
 CFLAGS_tegra_avp_init.pbl.o := -mcpu=arm7tdmi -march=armv4t
 lwl-y += tegra_avp_init.o
diff --git a/arch/arm/mach-uemd/Kconfig b/arch/arm/mach-uemd/Kconfig
index 2bcdd320c99a..7844b9c78fbc 100644
--- a/arch/arm/mach-uemd/Kconfig
+++ b/arch/arm/mach-uemd/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_UEMD
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-uemd/Makefile b/arch/arm/mach-uemd/Makefile
index 16a218658ade..1c2b374603ce 100644
--- a/arch/arm/mach-uemd/Makefile
+++ b/arch/arm/mach-uemd/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj- := __dummy__.o
diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig
index 95172cff8c2d..e0e1996d333e 100644
--- a/arch/arm/mach-versatile/Kconfig
+++ b/arch/arm/mach-versatile/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 if ARCH_VERSATILE
 
diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile
index a8da54c27b2f..6a9630115f9f 100644
--- a/arch/arm/mach-versatile/Makefile
+++ b/arch/arm/mach-versatile/Makefile
@@ -1,2 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 obj-y += core.o
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index b72684caa722..1b89d0edf9ef 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_VEXPRESS
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
index 9a06e648a6f1..b52ba00f3c11 100644
--- a/arch/arm/mach-vexpress/Makefile
+++ b/arch/arm/mach-vexpress/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += v2m.o
 obj-y += reset.o
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
index 3e07633e5f08..3f2cd8e99c14 100644
--- a/arch/arm/mach-zynq/Kconfig
+++ b/arch/arm/mach-zynq/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_ZYNQ
 
 config ARCH_TEXT_BASE
diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
index 06c2ce996cfa..d5e94859a6b1 100644
--- a/arch/arm/mach-zynq/Makefile
+++ b/arch/arm/mach-zynq/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += zynq.o bootm-zynqimg.o
 lwl-y += cpu_init.o
diff --git a/arch/arm/tools/Makefile b/arch/arm/tools/Makefile
index bff825e58a01..298a7f90e627 100644
--- a/arch/arm/tools/Makefile
+++ b/arch/arm/tools/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #
 # linux/arch/arm/tools/Makefile
 #
diff --git a/arch/kvx/Kconfig b/arch/kvx/Kconfig
index 09344408806b..960b712ac9b4 100644
--- a/arch/kvx/Kconfig
+++ b/arch/kvx/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config KVX
 	bool
 	select 64BIT
diff --git a/arch/kvx/Makefile b/arch/kvx/Makefile
index f29eeef9210b..9431c9fe18fd 100644
--- a/arch/kvx/Makefile
+++ b/arch/kvx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := generic_defconfig
 
 KBUILD_CPPFLAGS += -fno-strict-aliasing
diff --git a/arch/kvx/dts/Makefile b/arch/kvx/dts/Makefile
index d4221d2c1bb6..3f03192750bc 100644
--- a/arch/kvx/dts/Makefile
+++ b/arch/kvx/dts/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
 # just to build a built-in.o. Otherwise compilation fails when no devicetree is
 # created.
 obj- += dummy.o
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 7774abe94827..be5a4ff30de9 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1,6 +1,5 @@
-#
-#
-#
+# SPDX-License-Identifier: GPL-2.0-only
+
 config MIPS
 	bool
 	select GENERIC_LIB_ASHLDI3
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 786695194490..345e703d332b 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := qemu-malta_defconfig
 
 #
diff --git a/arch/mips/boards/8devices-lima/Makefile b/arch/mips/boards/8devices-lima/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/8devices-lima/Makefile
+++ b/arch/mips/boards/8devices-lima/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/Makefile b/arch/mips/boards/Makefile
index 5f9b61e7545c..9402035856c2 100644
--- a/arch/mips/boards/Makefile
+++ b/arch/mips/boards/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_BOARD_8DEVICES_LIMA) += 8devices-lima/
 obj-$(CONFIG_BOARD_BLACK_SWIFT) += black-swift/
 obj-$(CONFIG_BOARD_CI20) += img-ci20/
diff --git a/arch/mips/boards/black-swift/Makefile b/arch/mips/boards/black-swift/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/black-swift/Makefile
+++ b/arch/mips/boards/black-swift/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/dlink-dir-320/Makefile b/arch/mips/boards/dlink-dir-320/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/dlink-dir-320/Makefile
+++ b/arch/mips/boards/dlink-dir-320/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/dptechnics-dpt-module/Makefile b/arch/mips/boards/dptechnics-dpt-module/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/dptechnics-dpt-module/Makefile
+++ b/arch/mips/boards/dptechnics-dpt-module/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/img-ci20/Makefile b/arch/mips/boards/img-ci20/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/img-ci20/Makefile
+++ b/arch/mips/boards/img-ci20/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/loongson-ls1b/Makefile b/arch/mips/boards/loongson-ls1b/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/loongson-ls1b/Makefile
+++ b/arch/mips/boards/loongson-ls1b/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/netgear-wg102/Makefile b/arch/mips/boards/netgear-wg102/Makefile
index 344a6711b2bd..fe0616fdb8f6 100644
--- a/arch/mips/boards/netgear-wg102/Makefile
+++ b/arch/mips/boards/netgear-wg102/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 obj-y += ram.o
diff --git a/arch/mips/boards/okud-max9331/Makefile b/arch/mips/boards/okud-max9331/Makefile
index c58bf72354db..c28b1a9059a2 100644
--- a/arch/mips/boards/okud-max9331/Makefile
+++ b/arch/mips/boards/okud-max9331/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
 lwl-y += lowlevel_boot0.o
diff --git a/arch/mips/boards/openembed-som9331/Makefile b/arch/mips/boards/openembed-som9331/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/openembed-som9331/Makefile
+++ b/arch/mips/boards/openembed-som9331/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/qemu-malta/Makefile b/arch/mips/boards/qemu-malta/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/qemu-malta/Makefile
+++ b/arch/mips/boards/qemu-malta/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/ritmix-rzx50/Makefile b/arch/mips/boards/ritmix-rzx50/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/ritmix-rzx50/Makefile
+++ b/arch/mips/boards/ritmix-rzx50/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/tplink-mr3020/Makefile b/arch/mips/boards/tplink-mr3020/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/tplink-mr3020/Makefile
+++ b/arch/mips/boards/tplink-mr3020/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boards/tplink-wdr4300/Makefile b/arch/mips/boards/tplink-wdr4300/Makefile
index b08c4a93ca27..458f5209008d 100644
--- a/arch/mips/boards/tplink-wdr4300/Makefile
+++ b/arch/mips/boards/tplink-wdr4300/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel.o
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index 3d46e836f7a7..d1e27b5e6b8a 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += start.o
 obj-y += main_entry.o
 
diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
index e5900c971b9a..e4cc3b44a53e 100644
--- a/arch/mips/dts/Makefile
+++ b/arch/mips/dts/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_NAME))
 ifneq ($(BUILTIN_DTB),)
 obj-$(CONFIG_BUILTIN_DTB) += $(BUILTIN_DTB).dtb.o
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 88a2bdbd282b..1ef340202acf 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 extra-$(CONFIG_GENERIC_LINKER_SCRIPT) += barebox.lds
 obj-$(CONFIG_CSRC_R4K_LIB) += csrc-r4k.o
 obj-y += cpu-probe.o
diff --git a/arch/mips/mach-ar231x/Kconfig b/arch/mips/mach-ar231x/Kconfig
index f920f300bd20..f3e17000a754 100644
--- a/arch/mips/mach-ar231x/Kconfig
+++ b/arch/mips/mach-ar231x/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if MACH_MIPS_AR231X
 
 choice
diff --git a/arch/mips/mach-ar231x/Makefile b/arch/mips/mach-ar231x/Makefile
index eba8e818b5b7..65e32c7bc3a7 100644
--- a/arch/mips/mach-ar231x/Makefile
+++ b/arch/mips/mach-ar231x/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += ar231x.o
 obj-y += board.o
 obj-y += ar231x_reset.o
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig
index 2dfe0e587a65..75640504895c 100644
--- a/arch/mips/mach-ath79/Kconfig
+++ b/arch/mips/mach-ath79/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if MACH_MIPS_ATH79
 
 config SOC_QCA_AR9331
diff --git a/arch/mips/mach-ath79/Makefile b/arch/mips/mach-ath79/Makefile
index 396df66bf162..9f3a34b3eb77 100644
--- a/arch/mips/mach-ath79/Makefile
+++ b/arch/mips/mach-ath79/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 lwl-y += lowlevel_ar9331_spi_trap.o
 lwl-y += lowlevel_ar9331_sram.o
 
diff --git a/arch/mips/mach-bcm47xx/Kconfig b/arch/mips/mach-bcm47xx/Kconfig
index c4791901afb0..606d9e600099 100644
--- a/arch/mips/mach-bcm47xx/Kconfig
+++ b/arch/mips/mach-bcm47xx/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if MACH_MIPS_BCM47XX
 
 choice
diff --git a/arch/mips/mach-bcm47xx/Makefile b/arch/mips/mach-bcm47xx/Makefile
index f3cc6684b896..d19b1f29501a 100644
--- a/arch/mips/mach-bcm47xx/Makefile
+++ b/arch/mips/mach-bcm47xx/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += reset.o
diff --git a/arch/mips/mach-loongson/Kconfig b/arch/mips/mach-loongson/Kconfig
index ab7ccd0cb569..38d05e415be4 100644
--- a/arch/mips/mach-loongson/Kconfig
+++ b/arch/mips/mach-loongson/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if MACH_MIPS_LOONGSON
 
 choice
diff --git a/arch/mips/mach-loongson/Makefile b/arch/mips/mach-loongson/Makefile
index 52b36f3cf946..451c572e76cb 100644
--- a/arch/mips/mach-loongson/Makefile
+++ b/arch/mips/mach-loongson/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += loongson1_reset.o
diff --git a/arch/mips/mach-malta/Kconfig b/arch/mips/mach-malta/Kconfig
index 467107514006..cf061f667057 100644
--- a/arch/mips/mach-malta/Kconfig
+++ b/arch/mips/mach-malta/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if MACH_MIPS_MALTA
 
 config BOARD_QEMU_MALTA
diff --git a/arch/mips/mach-malta/Makefile b/arch/mips/mach-malta/Makefile
index 7d56f215b034..d937083bbb0a 100644
--- a/arch/mips/mach-malta/Makefile
+++ b/arch/mips/mach-malta/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/mach-xburst/Kconfig b/arch/mips/mach-xburst/Kconfig
index ae8093d1a311..954e295fd149 100644
--- a/arch/mips/mach-xburst/Kconfig
+++ b/arch/mips/mach-xburst/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if MACH_MIPS_XBURST
 
 config CPU_JZ4755
diff --git a/arch/mips/mach-xburst/Makefile b/arch/mips/mach-xburst/Makefile
index e5634ba9cc4c..0d2bb542c790 100644
--- a/arch/mips/mach-xburst/Makefile
+++ b/arch/mips/mach-xburst/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_CPU_JZ4755) += csrc-jz4750.o reset-jz4750.o
diff --git a/arch/mips/pbl/Makefile b/arch/mips/pbl/Makefile
index f85c7a6d6d58..38dfbd47243c 100644
--- a/arch/mips/pbl/Makefile
+++ b/arch/mips/pbl/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 suffix_$(CONFIG_IMAGE_COMPRESSION_GZIP) = gzip
 suffix_$(CONFIG_IMAGE_COMPRESSION_LZO)	= lzo
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index bd8851e4b306..34b24bec0858 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config OPENRISC
 	bool
 	select OFTREE
diff --git a/arch/openrisc/Makefile b/arch/openrisc/Makefile
index 1776f56df97b..609b998de98e 100644
--- a/arch/openrisc/Makefile
+++ b/arch/openrisc/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := generic_defconfig
 
 KBUILD_CPPFLAGS += -D__OR1K__ -ffixed-r10 -mhard-mul -mhard-div
diff --git a/arch/openrisc/boards/generic/Makefile b/arch/openrisc/boards/generic/Makefile
index d8a3d7f2cc2d..3cdac31b391d 100644
--- a/arch/openrisc/boards/generic/Makefile
+++ b/arch/openrisc/boards/generic/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += generic.o
diff --git a/arch/openrisc/cpu/Makefile b/arch/openrisc/cpu/Makefile
index 1cd7506003be..9828dff95d02 100644
--- a/arch/openrisc/cpu/Makefile
+++ b/arch/openrisc/cpu/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y                 += start.o
 obj-y                 += cpu.o
 obj-y                 += exceptions.o
diff --git a/arch/openrisc/dts/Makefile b/arch/openrisc/dts/Makefile
index 6d6c9a3ce094..f43a28d6b905 100644
--- a/arch/openrisc/dts/Makefile
+++ b/arch/openrisc/dts/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_NAME))
 obj-$(CONFIG_BUILTIN_DTB) += $(BUILTIN_DTB).dtb.o
diff --git a/arch/openrisc/lib/Makefile b/arch/openrisc/lib/Makefile
index 808b09f3aa50..a55a9049e6e9 100644
--- a/arch/openrisc/lib/Makefile
+++ b/arch/openrisc/lib/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y                 += clock.o
 obj-y                 += board.o
 obj-y                 += cpuinfo.o
diff --git a/arch/powerpc/Kbuild b/arch/powerpc/Kbuild
index 65e249338688..e9f7b32848e0 100644
--- a/arch/powerpc/Kbuild
+++ b/arch/powerpc/Kbuild
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_ARCH_MPC85XX) += cpu-85xx/
 obj-y += lib/
 obj-$(CONFIG_FSL_DDR2) += ddr-8xxx/
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 376c1bf42b5e..7525ecef4948 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config PPC
 	bool
 	select HAVE_CONFIGURABLE_TEXT_BASE
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index aa7626049613..ebd8fe60d3f1 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := p2020rdb_defconfig
 
 KBUILD_CPPFLAGS += -ffixed-r14 -m32 	\
diff --git a/arch/powerpc/boards/freescale-p1010rdb/Makefile b/arch/powerpc/boards/freescale-p1010rdb/Makefile
index a7b64eef4d34..e54ee8ee43fa 100644
--- a/arch/powerpc/boards/freescale-p1010rdb/Makefile
+++ b/arch/powerpc/boards/freescale-p1010rdb/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y	+= p1010rdb.o
 obj-y	+= law.o
 obj-y	+= tlb.o
diff --git a/arch/powerpc/boards/freescale-p1022ds/Makefile b/arch/powerpc/boards/freescale-p1022ds/Makefile
index 48867fa851ee..1d969d48ebb2 100644
--- a/arch/powerpc/boards/freescale-p1022ds/Makefile
+++ b/arch/powerpc/boards/freescale-p1022ds/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y	+= p1022ds.o
 obj-y	+= law.o
 obj-y	+= tlb.o
diff --git a/arch/powerpc/boards/freescale-p2020rdb/Makefile b/arch/powerpc/boards/freescale-p2020rdb/Makefile
index b2497f695cc7..ff0cdd657c94 100644
--- a/arch/powerpc/boards/freescale-p2020rdb/Makefile
+++ b/arch/powerpc/boards/freescale-p2020rdb/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y	+= p2020rdb.o
 obj-y	+= law.o
 obj-y	+= tlb.o
diff --git a/arch/powerpc/boards/owc-da923rc/Makefile b/arch/powerpc/boards/owc-da923rc/Makefile
index 4cf6c5cf3c90..78b6885c0873 100644
--- a/arch/powerpc/boards/owc-da923rc/Makefile
+++ b/arch/powerpc/boards/owc-da923rc/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += da923rc.o
 obj-y += tlb.o
 obj-y += law.o
diff --git a/arch/powerpc/boards/pcm030/Makefile b/arch/powerpc/boards/pcm030/Makefile
index 4e5dc4f57bcd..95dd0610437c 100644
--- a/arch/powerpc/boards/pcm030/Makefile
+++ b/arch/powerpc/boards/pcm030/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += pcm030.o eeprom.o
 extra-y += barebox.lds
diff --git a/arch/powerpc/cpu-85xx/Makefile b/arch/powerpc/cpu-85xx/Makefile
index c649c4ec2530..c7c5c8a00663 100644
--- a/arch/powerpc/cpu-85xx/Makefile
+++ b/arch/powerpc/cpu-85xx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y			+= traps.o
 obj-y			+= tlb.o
 obj-$(CONFIG_MMU)	+= mmu.o
diff --git a/arch/powerpc/ddr-8xxx/Makefile b/arch/powerpc/ddr-8xxx/Makefile
index 43ae3a41df4b..651fe050f65b 100644
--- a/arch/powerpc/ddr-8xxx/Makefile
+++ b/arch/powerpc/ddr-8xxx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y	+=  	main.o util.o ctrl_regs.o options.o lc_common_dimm_params.o
 obj-y	+=	ddr_setctrl.o
 obj-$(CONFIG_FSL_DDR2)	+= ddr2_dimm_params.o
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 405351c19929..65729953e693 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += bat_rw.o
 obj-y += board.o
 obj-y += extable.o
diff --git a/arch/powerpc/mach-mpc5xxx/Kconfig b/arch/powerpc/mach-mpc5xxx/Kconfig
index 4da947dc6cfc..e78c2fa350b1 100644
--- a/arch/powerpc/mach-mpc5xxx/Kconfig
+++ b/arch/powerpc/mach-mpc5xxx/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_MPC5XXX
 
 config ARCH_TEXT_BASE
diff --git a/arch/powerpc/mach-mpc5xxx/Makefile b/arch/powerpc/mach-mpc5xxx/Makefile
index 101d0618152a..9fc45c08bb31 100644
--- a/arch/powerpc/mach-mpc5xxx/Makefile
+++ b/arch/powerpc/mach-mpc5xxx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y 				+= cpu.o
 obj-y				+= cpu_init.o
 obj-y				+= loadtask.o
diff --git a/arch/powerpc/mach-mpc85xx/Kconfig b/arch/powerpc/mach-mpc85xx/Kconfig
index aa518b98fca8..550c554286d7 100644
--- a/arch/powerpc/mach-mpc85xx/Kconfig
+++ b/arch/powerpc/mach-mpc85xx/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 if ARCH_MPC85XX
 
 config MMU
diff --git a/arch/powerpc/mach-mpc85xx/Makefile b/arch/powerpc/mach-mpc85xx/Makefile
index 9886c7da45d6..3e23c1b8125d 100644
--- a/arch/powerpc/mach-mpc85xx/Makefile
+++ b/arch/powerpc/mach-mpc85xx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y 			+= cpuid.o
 obj-y 			+= cpu.o
 obj-y 			+= cpu_init.o
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 8c6669718554..e093ed4226de 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config RISCV
 	def_bool y
 	select GENERIC_FIND_NEXT_BIT
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 9f2a4f825ebb..828b65a0c177 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menu "SoC selection"
 
 config SOC_ERIZO
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 23ea6178a25a..6fbf1d4dddbf 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := virt64_defconfig
 
 KBUILD_CPPFLAGS += -fno-strict-aliasing
diff --git a/arch/riscv/boards/riscvemu/Makefile b/arch/riscv/boards/riscvemu/Makefile
index dcfc2937d325..ad283446eaf1 100644
--- a/arch/riscv/boards/riscvemu/Makefile
+++ b/arch/riscv/boards/riscvemu/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 01078bca971f..a8bca8757f28 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 source "scripts/Kconfig.include"
 
 config SANDBOX
diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile
index 5fc7e227be67..2cf51fa34917 100644
--- a/arch/sandbox/Makefile
+++ b/arch/sandbox/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := sandbox_defconfig
 
 KBUILD_CPPFLAGS += -D__SANDBOX__ -fno-strict-aliasing -fvisibility=hidden
diff --git a/arch/sandbox/board/Makefile b/arch/sandbox/board/Makefile
index ed01cb9c3e25..11688c5aba45 100644
--- a/arch/sandbox/board/Makefile
+++ b/arch/sandbox/board/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += board.o
 obj-y += clock.o
 obj-y += hostfile.o
diff --git a/arch/sandbox/dts/Makefile b/arch/sandbox/dts/Makefile
index c8d83141ceab..9af91cb72c03 100644
--- a/arch/sandbox/dts/Makefile
+++ b/arch/sandbox/dts/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_OFTREE) += \
 	sandbox.dtb.o
 
diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile
index b32ca6aaf804..9535305d5bfa 100644
--- a/arch/sandbox/lib/Makefile
+++ b/arch/sandbox/lib/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_ARCH_HAS_STACK_DUMP) += unwind.o
diff --git a/arch/sandbox/os/Makefile b/arch/sandbox/os/Makefile
index 5d0c938ce68c..ebcbe5833b26 100644
--- a/arch/sandbox/os/Makefile
+++ b/arch/sandbox/os/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 machine-y := sandbox
 
 machdirs := $(patsubst %,arch/sandbox/mach-%/,$(machine-y))
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f40b14dddc00..5e2e26cd6e5b 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1,6 +1,5 @@
-#
-#
-#
+# SPDX-License-Identifier: GPL-2.0-only
+
 config X86
 	bool
 	select HAS_KALLSYMS
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index a0ce8c17f181..dba5b196b310 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 KBUILD_DEFCONFIG := efi_defconfig
 
 KBUILD_CPPFLAGS += -D__X86__
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 360aebf56936..d713065fd395 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_X86_32) += setjmp_32.o
 obj-$(CONFIG_X86_64) += setjmp_64.o
diff --git a/arch/x86/mach-efi/Makefile b/arch/x86/mach-efi/Makefile
index f633e7c7ed95..bddbac8f66b8 100644
--- a/arch/x86/mach-efi/Makefile
+++ b/arch/x86/mach-efi/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_X86_64) += reloc_x86_64.o crt0-efi-x86_64.o
 obj-$(CONFIG_X86_32) += reloc_ia32.o crt0-efi-ia32.o
 obj-y += clocksource.o
diff --git a/common/Kconfig b/common/Kconfig
index e540cba7ebaa..276b2c0d8f7d 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 source "common/boards/Kconfig"
 
 config GREGORIAN_CALENDER
diff --git a/common/Makefile b/common/Makefile
index f4496c4d9b69..35f2120496ea 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y				+= boards/
 obj-y				+= memory.o
 obj-y				+= memory_display.o
diff --git a/common/partitions/Kconfig b/common/partitions/Kconfig
index be9405a6495f..7f12383082c4 100644
--- a/common/partitions/Kconfig
+++ b/common/partitions/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config PARTITION_DISK
 	depends on PARTITION
 	depends on BLOCK
diff --git a/common/partitions/Makefile b/common/partitions/Makefile
index 2b0c5b4b9c77..d304b6f8d587 100644
--- a/common/partitions/Makefile
+++ b/common/partitions/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_PARTITION_DISK_DOS)	+= dos.o
 obj-$(CONFIG_PARTITION_DISK_EFI)	+= efi.o
diff --git a/common/ratp/Kconfig b/common/ratp/Kconfig
index 25150addfd75..43720e30a0e4 100644
--- a/common/ratp/Kconfig
+++ b/common/ratp/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 config CONSOLE_RATP
 	bool
@@ -28,4 +29,4 @@ config RATP_CMD_GPIO
 	depends on GENERIC_GPIO
 	prompt "RATP GPIO support"
 	help
-	  This option adds support for GPIO get/set/direction commands via RATP.
\ No newline at end of file
+	  This option adds support for GPIO get/set/direction commands via RATP.
diff --git a/common/ratp/Makefile b/common/ratp/Makefile
index 71288bcb8ceb..e37ccca1fa5b 100644
--- a/common/ratp/Makefile
+++ b/common/ratp/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += ratp.o
 obj-y += ping.o
 obj-y += getenv.o
diff --git a/common/state/Makefile b/common/state/Makefile
index fcf9add52cbe..93215dd06921 100644
--- a/common/state/Makefile
+++ b/common/state/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += state.o
 obj-y += state_variables.o
 obj-y += backend_format_dtb.o
diff --git a/crypto/Kconfig b/crypto/Kconfig
index ff83a40f5b43..3b68836b3482 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menu "Crypto support"
 
 config CRC32
diff --git a/crypto/Makefile b/crypto/Makefile
index 5da58d799882..be0f79d4e39c 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_CRC32)	+= crc32.o
 obj-pbl-$(CONFIG_CRC_ITU_T)	+= crc-itu-t.o
 obj-$(CONFIG_CRC7)	+= crc7.o
diff --git a/defaultenv/Makefile b/defaultenv/Makefile
index 68790321187d..1eaca9f41087 100644
--- a/defaultenv/Makefile
+++ b/defaultenv/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW) += defaultenv-2-base
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_MENU) += defaultenv-2-menu
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_DFU) += defaultenv-2-dfu
diff --git a/firmware/Kconfig b/firmware/Kconfig
index b44753892776..b4a6fd913709 100644
--- a/firmware/Kconfig
+++ b/firmware/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menu "Firmware files"
 
 config EXTRA_FIRMWARE_DIR
diff --git a/fs/Kconfig b/fs/Kconfig
index e0405de334ee..aeba00073eed 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 menu "Filesystem support"
 
diff --git a/fs/Makefile b/fs/Makefile
index fa950941de92..6160ef4e1a0b 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_FS_CRAMFS)	+= cramfs/
 obj-$(CONFIG_FS_EXT4)	+= ext4/
 obj-$(CONFIG_FS_RAMFS)	+= ramfs.o
diff --git a/fs/cramfs/Makefile b/fs/cramfs/Makefile
index 4e84a98fe119..1b54096664b2 100644
--- a/fs/cramfs/Makefile
+++ b/fs/cramfs/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y	+= cramfs.o
 obj-y	+= uncompress.o
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index f36043d9a743..cb01675507ca 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config FS_EXT4
 	bool
 	prompt "ext4 filesystem support"
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 5084e3fb25ab..223f50e470f6 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_FS_EXT4) += ext4fs.o ext4_common.o ext_barebox.o
diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig
index bc3b4b69e870..8cd3b604baeb 100644
--- a/fs/fat/Kconfig
+++ b/fs/fat/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig FS_FAT
 	bool
 	select FS_LEGACY
diff --git a/fs/fat/Makefile b/fs/fat/Makefile
index fe47569bda09..7a7a5ccdc688 100644
--- a/fs/fat/Makefile
+++ b/fs/fat/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += fat.o
 pbl-y += fat-pbl.o
 obj-pbl-y += ff.o fat-diskio.o
diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig
index 3121d369b470..329e7b806a6e 100644
--- a/fs/jffs2/Kconfig
+++ b/fs/jffs2/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig FS_JFFS2
 	bool
 	select CRC32
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index a4da48d3c3c6..3c5bfd261c48 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += compr.o dir.o nodelist.o malloc.o
 obj-y += read.o readinode.o scan.o
 obj-y += build.o fs.o
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 30c2de19c82a..ff9091d3f39f 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig FS_PSTORE
 	select FS_LEGACY
 	bool
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index c4043e1a8fb2..18475497a3f3 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #
 # Makefile for the linux pstorefs routines.
 #
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
index 19b8297af622..af187a2a8ac7 100644
--- a/fs/squashfs/Kconfig
+++ b/fs/squashfs/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig FS_SQUASHFS
 	bool
 	prompt "squashfs support"
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
index 81fc7e570d81..59a78a24b0d7 100644
--- a/fs/squashfs/Makefile
+++ b/fs/squashfs/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y	+= squashfs.o
 obj-y	+= block.o
 obj-y	+= cache.o
diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index 889a2be97a5f..ae58c2b7f230 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig FS_UBIFS
 	bool
 	depends on MTD_UBI
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index d8c4b2299eb8..7a1ce4e8fcc0 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += ubifs.o io.o super.o sb.o master.o
 obj-y += scan.o dir.o misc.o
 obj-y += tnc.o tnc_misc.o debug.o
diff --git a/images/Makefile b/images/Makefile
index cc330d957597..5e2b9ecaaa9f 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile
 #
diff --git a/lib/Kconfig b/lib/Kconfig
index 718033e56e64..53c0e70e3a7c 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menu "Library routines"
 config PARAMETER
 	bool
diff --git a/lib/Makefile b/lib/Makefile
index 9b37d847e0cc..3f6653d74e9a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y			+= bcd.o
 obj-$(CONFIG_BOOTSTRAP)	+= bootstrap/
 obj-pbl-y		+= ctype.o
diff --git a/lib/bootstrap/Kconfig b/lib/bootstrap/Kconfig
index 645f0b4b78dd..5cd6035beef4 100644
--- a/lib/bootstrap/Kconfig
+++ b/lib/bootstrap/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig BOOTSTRAP
 	bool "Library bootstrap routines"
 	depends on SHELL_NONE
diff --git a/lib/bootstrap/Makefile b/lib/bootstrap/Makefile
index cbaa49f9d9da..295d63e07458 100644
--- a/lib/bootstrap/Makefile
+++ b/lib/bootstrap/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y				+= common.o
 obj-$(CONFIG_BOOTSTRAP_DEVFS)	+= devfs.o
 obj-$(CONFIG_BOOTSTRAP_DISK)	+= disk.o
diff --git a/lib/fonts/Kconfig b/lib/fonts/Kconfig
index e1a736d137c2..3201364cae27 100644
--- a/lib/fonts/Kconfig
+++ b/lib/fonts/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #
 # Font configuration
 #
diff --git a/lib/fonts/Makefile b/lib/fonts/Makefile
index 394e2c5e4c18..1eae8ee67b35 100644
--- a/lib/fonts/Makefile
+++ b/lib/fonts/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 # Font handling
 
 font-objs := fonts.o
diff --git a/lib/gui/Kconfig b/lib/gui/Kconfig
index 2625d9fb2fbe..d102604335b5 100644
--- a/lib/gui/Kconfig
+++ b/lib/gui/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menu "Library gui routines"
 
 config IMAGE_RENDERER
diff --git a/lib/gui/Makefile b/lib/gui/Makefile
index 31e66225d7c0..59caa8fbeb8a 100644
--- a/lib/gui/Makefile
+++ b/lib/gui/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_BMP)	+= bmp.o
 obj-$(CONFIG_IMAGE_RENDERER)	+= image_renderer.o graphic_utils.o
 obj-$(CONFIG_PNG)	+= png.o
diff --git a/lib/kasan/Kconfig b/lib/kasan/Kconfig
index 7a18cf95be87..46fc4f263b3e 100644
--- a/lib/kasan/Kconfig
+++ b/lib/kasan/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 source "scripts/Kconfig.include"
 
 config HAVE_ARCH_KASAN
diff --git a/lib/kasan/Makefile b/lib/kasan/Makefile
index 31e9d890d538..e3f4bb61f900 100644
--- a/lib/kasan/Makefile
+++ b/lib/kasan/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 obj-y += generic_report.o generic.o report.o common.o test_kasan.o
 KASAN_SANITIZE_generic_report.o := n
diff --git a/lib/logo/Kconfig b/lib/logo/Kconfig
index 7d55f7fa2727..56ec76afb6cf 100644
--- a/lib/logo/Kconfig
+++ b/lib/logo/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig BAREBOX_LOGO
 	bool "include barebox logos in build"
 	help
diff --git a/lib/logo/Makefile b/lib/logo/Makefile
index f08beef76b95..3e36cf911f94 100644
--- a/lib/logo/Makefile
+++ b/lib/logo/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 OPTS_barebox-logo-w64.bblogo = -resize 64
 bblogo-$(CONFIG_BAREBOX_LOGO_64) += barebox-logo-w64
diff --git a/lib/lz4/Makefile b/lib/lz4/Makefile
index 7f548c6d1c5c..7156ec914589 100644
--- a/lib/lz4/Makefile
+++ b/lib/lz4/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o
diff --git a/lib/lzo/Kconfig b/lib/lzo/Kconfig
index 17b0083236af..2ead1321e862 100644
--- a/lib/lzo/Kconfig
+++ b/lib/lzo/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config LZO_DECOMPRESS
 	bool "include lzo uncompression support"
 	select UNCOMPRESS
diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile
index 0e576a1c10d2..4ab28ff6f5cd 100644
--- a/lib/lzo/Makefile
+++ b/lib/lzo/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_LZO_DECOMPRESS) += lzo1x_decompress_safe.o
diff --git a/lib/math/Makefile b/lib/math/Makefile
index 756d7dd90d76..2830dedb2ff9 100644
--- a/lib/math/Makefile
+++ b/lib/math/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += div64.o
 pbl-y += div64.o
 obj-y += rational.o
diff --git a/lib/reed_solomon/Makefile b/lib/reed_solomon/Makefile
index c3d7136827ed..f7475981b92e 100644
--- a/lib/reed_solomon/Makefile
+++ b/lib/reed_solomon/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #
 # This is a modified version of reed solomon lib,
 #
diff --git a/lib/xz/Makefile b/lib/xz/Makefile
index 86ba5507335a..23581d2d8c6b 100644
--- a/lib/xz/Makefile
+++ b/lib/xz/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_XZ_DECOMPRESS) += xz_crc32.o xz_dec_bcj.o
 obj-$(CONFIG_XZ_DECOMPRESS) += xz_dec_lzma2.o xz_dec_stream.o
diff --git a/lib/zlib_inflate/Makefile b/lib/zlib_inflate/Makefile
index 8e95fcd3c939..bfe12b0d6ed0 100644
--- a/lib/zlib_inflate/Makefile
+++ b/lib/zlib_inflate/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #
 # This is a modified version of zlib, which does all memory
 # allocation ahead of time.
diff --git a/lib/zstd/Makefile b/lib/zstd/Makefile
index 0c4f56c50c5b..4e8689a4855d 100644
--- a/lib/zstd/Makefile
+++ b/lib/zstd/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd_decompress.o
 
 ccflags-y += -O3
diff --git a/net/Kconfig b/net/Kconfig
index 3512055c456a..59f14c23cba2 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig NET
 	bool "Networking Support"
 	select POLLER
diff --git a/net/Makefile b/net/Makefile
index 962b2dec58e8..c93d0772c3e4 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y			+= lib.o
 obj-$(CONFIG_NET)	+= eth.o
 obj-$(CONFIG_NET)	+= net.o
diff --git a/pbl/Kconfig b/pbl/Kconfig
index 5fc9971084a5..ce0acbb646c7 100644
--- a/pbl/Kconfig
+++ b/pbl/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config HAVE_PBL_IMAGE
 	bool
 
diff --git a/pbl/Makefile b/pbl/Makefile
index 9faa56ac91d1..f6e98e78be3f 100644
--- a/pbl/Makefile
+++ b/pbl/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #
 # only unsed by the pbl
 #
diff --git a/scripts/Kconfig b/scripts/Kconfig
index 96b0d26f8874..1ec907b5f1cc 100644
--- a/scripts/Kconfig
+++ b/scripts/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menu "Host Tools"
 
 config COMPILE_HOST_TOOLS
diff --git a/scripts/Makefile b/scripts/Makefile
index dc5fa75f908b..2a17058333e7 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 ###
 # scripts contains sources for various helper programs used throughout
 # barebox for the build process.
diff --git a/scripts/imx/Kconfig b/scripts/imx/Kconfig
index ef83fa14dd14..759f5521a5e5 100644
--- a/scripts/imx/Kconfig
+++ b/scripts/imx/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 config ARCH_IMX_USBLOADER
 	depends on ARCH_MXS || ARCH_IMX || COMPILE_HOST_TOOLS
 	bool "imx-usb-loader"
diff --git a/scripts/imx/Makefile b/scripts/imx/Makefile
index a7f487a0452c..d62277bb5430 100644
--- a/scripts/imx/Makefile
+++ b/scripts/imx/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 hostprogs-always-$(CONFIG_ARCH_IMX_IMXIMAGE)	+= imx-image
 hostprogs-always-$(CONFIG_ARCH_IMX_USBLOADER)	+= imx-usb-loader
 
diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile
index 9926ed08dc57..b381877a8330 100644
--- a/scripts/mod/Makefile
+++ b/scripts/mod/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 hostprogs-always-y	+= modpost mk_elfconfig
 always-y		+= empty.o
 
diff --git a/scripts/tegra/Makefile b/scripts/tegra/Makefile
index dec0b529d6a4..2c682786b168 100644
--- a/scripts/tegra/Makefile
+++ b/scripts/tegra/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 hostprogs-always-$(CONFIG_ARCH_TEGRA) += cbootimage
 
 HOSTLDLIBS_cbootimage  = '-lm'
diff --git a/test/Kconfig b/test/Kconfig
index eece702e68aa..958b483ea946 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 menuconfig TEST
 	bool "Testing"
 
diff --git a/test/Makefile b/test/Makefile
index 1b9eb2171a82..ac2aa2843518 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += self/
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:34 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:34 +0100
Subject: [PATCH 06/11] include: add SPDX-License-Identifier
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-7-a.fatoum@pengutronix.de>

All these files lack a license statement, so add the default
GPL-2.0-only.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/aiodev.h                        | 2 ++
 include/asm-generic/atomic-long.h       | 2 ++
 include/asm-generic/barebox.lds.h       | 2 ++
 include/asm-generic/bitops/__ffs.h      | 2 ++
 include/asm-generic/bitops/__fls.h      | 2 ++
 include/asm-generic/bitops/ffs.h        | 2 ++
 include/asm-generic/bitops/ffz.h        | 2 ++
 include/asm-generic/bitops/find.h       | 2 ++
 include/asm-generic/bitops/fls.h        | 2 ++
 include/asm-generic/bitops/fls64.h      | 2 ++
 include/asm-generic/bitops/hweight.h    | 2 ++
 include/asm-generic/bitops/ops.h        | 2 ++
 include/asm-generic/bitsperlong.h       | 2 ++
 include/asm-generic/bug.h               | 2 ++
 include/asm-generic/errno.h             | 2 ++
 include/asm-generic/int-ll64.h          | 2 ++
 include/asm-generic/ioctl.h             | 2 ++
 include/asm-generic/memory_layout.h     | 2 ++
 include/asm-generic/posix_types.h       | 2 ++
 include/asm-generic/sections.h          | 2 ++
 include/asm-generic/swab.h              | 2 ++
 include/base64.h                        | 2 ++
 include/cramfs/cramfs_fs.h              | 2 ++
 include/crypto/crc.h                    | 2 ++
 include/crypto/des.h                    | 2 ++
 include/crypto/sha.h                    | 2 ++
 include/debug_ll/ns16550.h              | 2 ++
 include/debug_ll/pl011.h                | 2 ++
 include/fastboot.h                      | 2 ++
 include/fpga-bridge.h                   | 1 +
 include/gui/2d-primitives.h             | 2 ++
 include/i2c/i2c-early.h                 | 2 ++
 include/input/input.h                   | 2 ++
 include/input/keyboard.h                | 2 ++
 include/input/matrix_keypad.h           | 2 ++
 include/linux/amba/mmci.h               | 2 ++
 include/linux/amba/pl061.h              | 2 ++
 include/linux/bcd.h                     | 2 ++
 include/linux/bitmap.h                  | 2 ++
 include/linux/bitops.h                  | 2 ++
 include/linux/bitrev.h                  | 2 ++
 include/linux/bug.h                     | 2 ++
 include/linux/byteorder/big_endian.h    | 2 ++
 include/linux/byteorder/generic.h       | 2 ++
 include/linux/byteorder/little_endian.h | 2 ++
 include/linux/circ_buf.h                | 2 ++
 include/linux/compiler_types.h          | 2 ++
 include/linux/const.h                   | 2 ++
 include/linux/crc8.h                    | 2 ++
 include/linux/ctype.h                   | 2 ++
 include/linux/dcache.h                  | 2 ++
 include/linux/decompress/mm.h           | 2 ++
 include/linux/decompress/unlz4.h        | 2 ++
 include/linux/err.h                     | 2 ++
 include/linux/ethtool.h                 | 2 ++
 include/linux/fs.h                      | 2 ++
 include/linux/gcd.h                     | 2 ++
 include/linux/hash.h                    | 2 ++
 include/linux/ioport.h                  | 2 ++
 include/linux/jffs2.h                   | 2 ++
 include/linux/kbuild.h                  | 2 ++
 include/linux/linkage.h                 | 2 ++
 include/linux/list_sort.h               | 2 ++
 include/linux/magic.h                   | 2 ++
 include/linux/mdio-bitbang.h            | 2 ++
 include/linux/mii.h                     | 2 ++
 include/linux/mod_devicetable.h         | 2 ++
 include/linux/mount.h                   | 2 ++
 include/linux/mtd/mtd-abi.h             | 2 ++
 include/linux/mtd/nftl.h                | 2 ++
 include/linux/mutex.h                   | 2 ++
 include/linux/pagemap.h                 | 2 ++
 include/linux/path.h                    | 2 ++
 include/linux/pci.h                     | 2 ++
 include/linux/pci_regs.h                | 2 ++
 include/linux/posix_types.h             | 2 ++
 include/linux/reset-controller.h        | 2 ++
 include/linux/reset.h                   | 2 ++
 include/linux/rtc.h                     | 2 ++
 include/linux/rwsem.h                   | 2 ++
 include/linux/sched.h                   | 2 ++
 include/linux/slab.h                    | 2 ++
 include/linux/smscphy.h                 | 2 ++
 include/linux/spinlock.h                | 2 ++
 include/linux/stat.h                    | 2 ++
 include/linux/stddef.h                  | 2 ++
 include/linux/string.h                  | 2 ++
 include/linux/stringify.h               | 2 ++
 include/linux/swab.h                    | 2 ++
 include/linux/time.h                    | 2 ++
 include/linux/types.h                   | 2 ++
 include/linux/unaligned/access_ok.h     | 2 ++
 include/linux/unaligned/be_byteshift.h  | 2 ++
 include/linux/unaligned/be_memmove.h    | 2 ++
 include/linux/unaligned/be_struct.h     | 2 ++
 include/linux/unaligned/generic.h       | 2 ++
 include/linux/unaligned/le_byteshift.h  | 2 ++
 include/linux/unaligned/le_memmove.h    | 2 ++
 include/linux/unaligned/le_struct.h     | 2 ++
 include/linux/unaligned/memmove.h       | 2 ++
 include/linux/unaligned/packed_struct.h | 2 ++
 include/linux/wait.h                    | 2 ++
 include/linux/xz.h                      | 2 ++
 include/linux/zutil.h                   | 2 ++
 include/machine_id.h                    | 2 ++
 include/mfd/lp3972.h                    | 2 ++
 include/mfd/pfuze.h                     | 2 ++
 include/mtd/mtd-peb.h                   | 2 ++
 include/platform_data/atmel-mci.h       | 2 ++
 include/platform_data/cadence_qspi.h    | 2 ++
 include/platform_data/dw_mmc.h          | 2 ++
 include/platform_data/eth-designware.h  | 2 ++
 include/platform_data/eth-dm9000.h      | 1 +
 include/platform_data/pca953x.h         | 2 ++
 include/pm_domain.h                     | 4 +++-
 include/serial/cadence.h                | 2 ++
 include/serial/imx-uart.h               | 2 ++
 include/slice.h                         | 2 ++
 include/soc/fsl/fsl_udc.h               | 2 ++
 include/soc/imx/imx-nand-bcb.h          | 2 ++
 include/soc/imx8m/clk-early.h           | 2 ++
 include/sys/ioctl.h                     | 2 ++
 include/sys/mount.h                     | 2 ++
 include/sys/stat.h                      | 2 ++
 include/usb/cdc.h                       | 2 ++
 include/usb/ch11.h                      | 2 ++
 include/usb/ch9.h                       | 2 ++
 include/usb/chipidea-imx.h              | 2 ++
 include/usb/ehci.h                      | 2 ++
 include/usb/fastboot.h                  | 2 ++
 include/usb/fsl_usb2.h                  | 2 ++
 include/usb/gadget-multi.h              | 2 ++
 include/usb/musb.h                      | 2 ++
 include/usb/phy.h                       | 2 ++
 include/usb/ulpi.h                      | 2 ++
 include/usb/usbserial.h                 | 2 ++
 include/video/backlight.h               | 2 ++
 include/video/fourcc.h                  | 2 ++
 include/video/vpl.h                     | 2 ++
 include/work.h                          | 2 ++
 140 files changed, 279 insertions(+), 1 deletion(-)

diff --git a/include/aiodev.h b/include/aiodev.h
index d5577156718d..f0c26d7c580c 100644
--- a/include/aiodev.h
+++ b/include/aiodev.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * core.c - Code implementing core functionality of AIODEV susbsystem
  *
diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
index fd1fdad20f66..cafb25172cf6 100644
--- a/include/asm-generic/atomic-long.h
+++ b/include/asm-generic/atomic-long.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_ATOMIC_LONG_H
 #define _ASM_GENERIC_ATOMIC_LONG_H
 /*
diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h
index a03655d41cc4..a22e251c9d64 100644
--- a/include/asm-generic/barebox.lds.h
+++ b/include/asm-generic/barebox.lds.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 
 /*
  * Align to a 32 byte boundary equal to the
diff --git a/include/asm-generic/bitops/__ffs.h b/include/asm-generic/bitops/__ffs.h
index 9a3274aecf83..6421acb3a5b6 100644
--- a/include/asm-generic/bitops/__ffs.h
+++ b/include/asm-generic/bitops/__ffs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS___FFS_H_
 #define _ASM_GENERIC_BITOPS___FFS_H_
 
diff --git a/include/asm-generic/bitops/__fls.h b/include/asm-generic/bitops/__fls.h
index be24465403d6..a5615539c359 100644
--- a/include/asm-generic/bitops/__fls.h
+++ b/include/asm-generic/bitops/__fls.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS___FLS_H_
 #define _ASM_GENERIC_BITOPS___FLS_H_
 
diff --git a/include/asm-generic/bitops/ffs.h b/include/asm-generic/bitops/ffs.h
index 0ff1b8b7c79a..4a375eae14df 100644
--- a/include/asm-generic/bitops/ffs.h
+++ b/include/asm-generic/bitops/ffs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS_FFS_H_
 #define _ASM_GENERIC_BITOPS_FFS_H_
 
diff --git a/include/asm-generic/bitops/ffz.h b/include/asm-generic/bitops/ffz.h
index 6744bd4cdf46..f9f624837ed0 100644
--- a/include/asm-generic/bitops/ffz.h
+++ b/include/asm-generic/bitops/ffz.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS_FFZ_H_
 #define _ASM_GENERIC_BITOPS_FFZ_H_
 
diff --git a/include/asm-generic/bitops/find.h b/include/asm-generic/bitops/find.h
index 72a51e5a12ef..2ef6e94fa1ea 100644
--- a/include/asm-generic/bitops/find.h
+++ b/include/asm-generic/bitops/find.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS_FIND_H_
 #define _ASM_GENERIC_BITOPS_FIND_H_
 
diff --git a/include/asm-generic/bitops/fls.h b/include/asm-generic/bitops/fls.h
index cc0d3ca95aaa..faa02fc48dfb 100644
--- a/include/asm-generic/bitops/fls.h
+++ b/include/asm-generic/bitops/fls.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS_FLS_H_
 #define _ASM_GENERIC_BITOPS_FLS_H_
 
diff --git a/include/asm-generic/bitops/fls64.h b/include/asm-generic/bitops/fls64.h
index 86d403f8b256..45533402f06b 100644
--- a/include/asm-generic/bitops/fls64.h
+++ b/include/asm-generic/bitops/fls64.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS_FLS64_H_
 #define _ASM_GENERIC_BITOPS_FLS64_H_
 
diff --git a/include/asm-generic/bitops/hweight.h b/include/asm-generic/bitops/hweight.h
index 7268c8b9ab2e..f0c188b675a8 100644
--- a/include/asm-generic/bitops/hweight.h
+++ b/include/asm-generic/bitops/hweight.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
 #define _ASM_GENERIC_BITOPS_HWEIGHT_H_
 
diff --git a/include/asm-generic/bitops/ops.h b/include/asm-generic/bitops/ops.h
index f19bcaa29bfd..1684621922e5 100644
--- a/include/asm-generic/bitops/ops.h
+++ b/include/asm-generic/bitops/ops.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BITOPS_OPS_H_
 #define _ASM_GENERIC_BITOPS_OPS_H_
 
diff --git a/include/asm-generic/bitsperlong.h b/include/asm-generic/bitsperlong.h
index bb986502988d..836a1d4c83dd 100644
--- a/include/asm-generic/bitsperlong.h
+++ b/include/asm-generic/bitsperlong.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_GENERIC_BITS_PER_LONG
 #define __ASM_GENERIC_BITS_PER_LONG
 
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 6aa3eada0ec5..f20e1b4d65ac 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_BUG_H
 #define _ASM_GENERIC_BUG_H
 
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index 7d99a9537050..a96f8864dfd4 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ARM_ERRNO_H
 #define _ARM_ERRNO_H
 
diff --git a/include/asm-generic/int-ll64.h b/include/asm-generic/int-ll64.h
index f394147c0739..8f220128d7f8 100644
--- a/include/asm-generic/int-ll64.h
+++ b/include/asm-generic/int-ll64.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * asm-generic/int-ll64.h
  *
diff --git a/include/asm-generic/ioctl.h b/include/asm-generic/ioctl.h
index 864181385579..eba15da2cc3e 100644
--- a/include/asm-generic/ioctl.h
+++ b/include/asm-generic/ioctl.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_IOCTL_H
 #define _ASM_GENERIC_IOCTL_H
 
diff --git a/include/asm-generic/memory_layout.h b/include/asm-generic/memory_layout.h
index 0d7ce3fe02a1..5cfd2a43a056 100644
--- a/include/asm-generic/memory_layout.h
+++ b/include/asm-generic/memory_layout.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_GENERIC_MEMORY_LAYOUT_H
 #define __ASM_GENERIC_MEMORY_LAYOUT_H
 
diff --git a/include/asm-generic/posix_types.h b/include/asm-generic/posix_types.h
index 136f161e1520..35123c776a2b 100644
--- a/include/asm-generic/posix_types.h
+++ b/include/asm-generic/posix_types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_GENERIC_POSIX_TYPES_H
 #define __ASM_GENERIC_POSIX_TYPES_H
 
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 870bff21f668..0b2ed5615bd6 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_SECTIONS_H_
 #define _ASM_GENERIC_SECTIONS_H_
 
diff --git a/include/asm-generic/swab.h b/include/asm-generic/swab.h
index 3ab5add54f75..f652dfe93fa1 100644
--- a/include/asm-generic/swab.h
+++ b/include/asm-generic/swab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_GENERIC_SWAB_H
 #define _ASM_GENERIC_SWAB_H
 
diff --git a/include/base64.h b/include/base64.h
index 0df510281df4..993a366b48b0 100644
--- a/include/base64.h
+++ b/include/base64.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __BASE64_H
 #define __BASE64_H
 
diff --git a/include/cramfs/cramfs_fs.h b/include/cramfs/cramfs_fs.h
index d2b67c5fe0aa..6b1d7a62d895 100644
--- a/include/cramfs/cramfs_fs.h
+++ b/include/cramfs/cramfs_fs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __CRAMFS_H
 #define __CRAMFS_H
 
diff --git a/include/crypto/crc.h b/include/crypto/crc.h
index 6428634d0a27..f36c2d644503 100644
--- a/include/crypto/crc.h
+++ b/include/crypto/crc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Common values for CRC algorithms
  */
diff --git a/include/crypto/des.h b/include/crypto/des.h
index 58fdaaa99d7b..abc3d9c59d01 100644
--- a/include/crypto/des.h
+++ b/include/crypto/des.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* 
  * DES & Triple DES EDE Cipher Algorithms.
  */
diff --git a/include/crypto/sha.h b/include/crypto/sha.h
index 190f8a0e0242..17a489bd4a8d 100644
--- a/include/crypto/sha.h
+++ b/include/crypto/sha.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Common values for SHA algorithms
  */
diff --git a/include/debug_ll/ns16550.h b/include/debug_ll/ns16550.h
index 373c917d86a3..a4ca7332d300 100644
--- a/include/debug_ll/ns16550.h
+++ b/include/debug_ll/ns16550.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __DEBUG_LL_NS16550_H
 #define __DEBUG_LL_NS16550_H
 
diff --git a/include/debug_ll/pl011.h b/include/debug_ll/pl011.h
index db015a373bc0..12f9ce1564c5 100644
--- a/include/debug_ll/pl011.h
+++ b/include/debug_ll/pl011.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__
 #define __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__
 
diff --git a/include/fastboot.h b/include/fastboot.h
index cf8a177bf12c..8a98b482fe14 100644
--- a/include/fastboot.h
+++ b/include/fastboot.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __FASTBOOT__
 #define __FASTBOOT__
 
diff --git a/include/fpga-bridge.h b/include/fpga-bridge.h
index fef2a9ccbbd3..300ab17b25ae 100644
--- a/include/fpga-bridge.h
+++ b/include/fpga-bridge.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 #include <common.h>
 
 #ifndef _LINUX_FPGA_BRIDGE_H
diff --git a/include/gui/2d-primitives.h b/include/gui/2d-primitives.h
index 06216bb03c56..4fbddfae2567 100644
--- a/include/gui/2d-primitives.h
+++ b/include/gui/2d-primitives.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __2D_PRIMITIVES__
 #define __2D_PRIMITIVES__
 
diff --git a/include/i2c/i2c-early.h b/include/i2c/i2c-early.h
index d64c1a438448..fa93656e28e8 100644
--- a/include/i2c/i2c-early.h
+++ b/include/i2c/i2c-early.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __I2C_EARLY_H
 #define __I2C_EARLY_H
 
diff --git a/include/input/input.h b/include/input/input.h
index dbf3e7f57406..d169c647bdaf 100644
--- a/include/input/input.h
+++ b/include/input/input.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INPUT_H
 #define __INPUT_H
 
diff --git a/include/input/keyboard.h b/include/input/keyboard.h
index d1f5bf553ad4..5761273a4ff7 100644
--- a/include/input/keyboard.h
+++ b/include/input/keyboard.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INPUT_KEYBOARD_H
 #define __INPUT_KEYBOARD_H
 
diff --git a/include/input/matrix_keypad.h b/include/input/matrix_keypad.h
index 03d963af0e73..7b78944f9bf6 100644
--- a/include/input/matrix_keypad.h
+++ b/include/input/matrix_keypad.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _MATRIX_KEYPAD_H
 #define _MATRIX_KEYPAD_H
 
diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h
index 0bf558124cef..719daadbb7b7 100644
--- a/include/linux/amba/mmci.h
+++ b/include/linux/amba/mmci.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  *  include/linux/amba/mmci.h
  */
diff --git a/include/linux/amba/pl061.h b/include/linux/amba/pl061.h
index d498cd7a8c5f..e1b2fac1523f 100644
--- a/include/linux/amba/pl061.h
+++ b/include/linux/amba/pl061.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __AMBA_PL061_H__
 #define __AMBA_PL061_H__
 
diff --git a/include/linux/bcd.h b/include/linux/bcd.h
index 18fff11fb3ea..718f305bf7c9 100644
--- a/include/linux/bcd.h
+++ b/include/linux/bcd.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _BCD_H
 #define _BCD_H
 
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 4b98521a833e..adaf5428fe86 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_BITMAP_H
 #define __LINUX_BITMAP_H
 
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index dd13bf93118c..645fd2e6f68c 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_BITOPS_H
 #define _LINUX_BITOPS_H
 #include <asm/types.h>
diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h
index 7ffe03f4693d..ba2965977dd5 100644
--- a/include/linux/bitrev.h
+++ b/include/linux/bitrev.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_BITREV_H
 #define _LINUX_BITREV_H
 
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 8367a11ec227..d8fc328a0706 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_BUG_H
 #define _LINUX_BUG_H
 
diff --git a/include/linux/byteorder/big_endian.h b/include/linux/byteorder/big_endian.h
index 539f710a3938..ba07edf0aeed 100644
--- a/include/linux/byteorder/big_endian.h
+++ b/include/linux/byteorder/big_endian.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_BYTEORDER_BIG_ENDIAN_H
 #define _LINUX_BYTEORDER_BIG_ENDIAN_H
 
diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h
index e59ba455e3ee..d5252959d8a1 100644
--- a/include/linux/byteorder/generic.h
+++ b/include/linux/byteorder/generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_BYTEORDER_GENERIC_H
 #define _LINUX_BYTEORDER_GENERIC_H
 
diff --git a/include/linux/byteorder/little_endian.h b/include/linux/byteorder/little_endian.h
index dfe9531fbaf4..e23111d4cd7d 100644
--- a/include/linux/byteorder/little_endian.h
+++ b/include/linux/byteorder/little_endian.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H
 #define _LINUX_BYTEORDER_LITTLE_ENDIAN_H
 
diff --git a/include/linux/circ_buf.h b/include/linux/circ_buf.h
index 90f2471dc6f2..36b3be9c1476 100644
--- a/include/linux/circ_buf.h
+++ b/include/linux/circ_buf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * See Documentation/circular-buffers.txt for more information.
  */
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index db192becfec4..9a5a6f0e8b17 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_COMPILER_TYPES_H
 #define __LINUX_COMPILER_TYPES_H
 
diff --git a/include/linux/const.h b/include/linux/const.h
index c872bfd25e13..07f886d27155 100644
--- a/include/linux/const.h
+++ b/include/linux/const.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* const.h: Macros for dealing with constants.  */
 
 #ifndef _LINUX_CONST_H
diff --git a/include/linux/crc8.h b/include/linux/crc8.h
index 13c8dabb0441..8fcd6d1324a2 100644
--- a/include/linux/crc8.h
+++ b/include/linux/crc8.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Copyright (c) 2011 Broadcom Corporation
  *
diff --git a/include/linux/ctype.h b/include/linux/ctype.h
index 633c3862d843..ab9bf910d84d 100644
--- a/include/linux/ctype.h
+++ b/include/linux/ctype.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_CTYPE_H
 #define _LINUX_CTYPE_H
 
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index a9619422013e..ed7e5c2cbcff 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_DCACHE_H
 #define __LINUX_DCACHE_H
 
diff --git a/include/linux/decompress/mm.h b/include/linux/decompress/mm.h
index 81676ae9067d..ac0702dfb111 100644
--- a/include/linux/decompress/mm.h
+++ b/include/linux/decompress/mm.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * linux/compr_mm.h
  *
diff --git a/include/linux/decompress/unlz4.h b/include/linux/decompress/unlz4.h
index 7aaafc2b1c62..0ad189d2d9ef 100644
--- a/include/linux/decompress/unlz4.h
+++ b/include/linux/decompress/unlz4.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef DECOMPRESS_UNLZ4_H
 #define DECOMPRESS_UNLZ4_H
 
diff --git a/include/linux/err.h b/include/linux/err.h
index ed563f2c4a71..69efc7c4ac27 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_ERR_H
 #define _LINUX_ERR_H
 
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 324e40cdeb5f..f47e17ea31bb 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * ethtool.h: Defines for Linux ethtool.
  *
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a72bc066c30d..fc1357137ade 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_FS_H
 #define _LINUX_FS_H
 
diff --git a/include/linux/gcd.h b/include/linux/gcd.h
index 0ac262162d1f..affb402f22cd 100644
--- a/include/linux/gcd.h
+++ b/include/linux/gcd.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _GCD_H
 #define _GCD_H
 
diff --git a/include/linux/hash.h b/include/linux/hash.h
index ad6fa21d977b..5e62f1bd8c85 100644
--- a/include/linux/hash.h
+++ b/include/linux/hash.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_HASH_H
 #define _LINUX_HASH_H
 /* Fast hashing routine for ints,  longs and pointers.
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 295ab4a49dff..ee9587ba0feb 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * ioport.h	Definitions of routines for detecting, reserving and
  *		allocating system resources.
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index ed2ebcfc42a1..e34465263cf8 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
diff --git a/include/linux/kbuild.h b/include/linux/kbuild.h
index 359d4a8682a1..de0f9bdb952f 100644
--- a/include/linux/kbuild.h
+++ b/include/linux/kbuild.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_KBUILD_H
 #define __LINUX_KBUILD_H
 
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 9fd1f859021b..efb2d6fa407b 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_LINKAGE_H
 #define _LINUX_LINKAGE_H
 
diff --git a/include/linux/list_sort.h b/include/linux/list_sort.h
index 1a2df2efb771..9260df2fb1ac 100644
--- a/include/linux/list_sort.h
+++ b/include/linux/list_sort.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_LIST_SORT_H
 #define _LINUX_LIST_SORT_H
 
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 0de181ad73d5..2af96650750a 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_MAGIC_H__
 #define __LINUX_MAGIC_H__
 
diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h
index 76f52bbbb2f4..a6e60578865f 100644
--- a/include/linux/mdio-bitbang.h
+++ b/include/linux/mdio-bitbang.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_MDIO_BITBANG_H
 #define __LINUX_MDIO_BITBANG_H
 
diff --git a/include/linux/mii.h b/include/linux/mii.h
index 5bac6c229a24..257dfd179060 100644
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * linux/mii.h: definitions for MII-compatible transceivers
  * Originally drivers/net/sunhme.h.
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 2c04454260a9..dac3c6e8a57c 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Device tables which are exported to userspace via
  * scripts/mod/file2alias.c.  You must keep that file in sync with this
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 9557365fb51f..4abeda6b7942 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  *
  * Definitions for mount interface. This describes the in the kernel build
diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h
index b7a8955880fe..b74f4b834897 100644
--- a/include/linux/mtd/mtd-abi.h
+++ b/include/linux/mtd/mtd-abi.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $
  *
diff --git a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h
index 438130625df9..36b80dea7792 100644
--- a/include/linux/mtd/nftl.h
+++ b/include/linux/mtd/nftl.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 
 /* Defines for NAND Flash Translation Layer  */
 /* (c) 1999 Machine Vision Holdings, Inc.    */
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index de698dbc4fe2..41eda79b763a 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Mutexes: blocking mutual exclusion locks
  *
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 345bd402b775..20c38a0b8912 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_PAGEMAP_H
 #define _LINUX_PAGEMAP_H
 
diff --git a/include/linux/path.h b/include/linux/path.h
index cbebdc5c9a60..3891c784d2f0 100644
--- a/include/linux/path.h
+++ b/include/linux/path.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_PATH_H
 #define _LINUX_PATH_H
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 486d4251d42a..269e7b354c2e 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  *	pci.h
  *
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index efe3443572ba..2c335f583588 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  *	pci_regs.h
  *
diff --git a/include/linux/posix_types.h b/include/linux/posix_types.h
index bd37e1faf459..4a0b852b27a6 100644
--- a/include/linux/posix_types.h
+++ b/include/linux/posix_types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_POSIX_TYPES_H
 #define _LINUX_POSIX_TYPES_H
 
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index aff03a9c62dd..8ace8cd41794 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_RESET_CONTROLLER_H_
 #define _LINUX_RESET_CONTROLLER_H_
 
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 818b06412f8c..d25464d4bd60 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_RESET_H_
 #define _LINUX_RESET_H_
 
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 2dacb14239f1..632bc9b7bc70 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Generic RTC interface.
  * This version contains the part of the user interface to the Real Time Clock
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 5259957ed266..4ed693dc2c37 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* rwsem.h: R/W semaphores, public interface
  *
  * Written by David Howells (dhowells at redhat.com).
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3375a09f2da0..18b90ad8844b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_SCHED_H
 #define _LINUX_SCHED_H
 
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 806d5bfb21d2..348770a3a28c 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_SLAB_H
 #define _LINUX_SLAB_H
 
diff --git a/include/linux/smscphy.h b/include/linux/smscphy.h
index ce718cbce435..45e1192384c3 100644
--- a/include/linux/smscphy.h
+++ b/include/linux/smscphy.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_SMSCPHY_H__
 #define __LINUX_SMSCPHY_H__
 
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index 7d011785eda7..12af3dab231b 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_SPINLOCK_H
 #define __LINUX_SPINLOCK_H
 
diff --git a/include/linux/stat.h b/include/linux/stat.h
index f5043d8bcea7..2bdf3ec9c96c 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_STAT_H
 #define _LINUX_STAT_H
 
diff --git a/include/linux/stddef.h b/include/linux/stddef.h
index 680d0c76627d..5429a7b58295 100644
--- a/include/linux/stddef.h
+++ b/include/linux/stddef.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_STDDEF_H
 #define _LINUX_STDDEF_H
 
diff --git a/include/linux/string.h b/include/linux/string.h
index 47a27a391f0b..3da174116a92 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_STRING_H_
 #define _LINUX_STRING_H_
 
diff --git a/include/linux/stringify.h b/include/linux/stringify.h
index 841cec8ed525..55f6d04d48b1 100644
--- a/include/linux/stringify.h
+++ b/include/linux/stringify.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_STRINGIFY_H
 #define __LINUX_STRINGIFY_H
 
diff --git a/include/linux/swab.h b/include/linux/swab.h
index ea0c02fd5163..243315184e9c 100644
--- a/include/linux/swab.h
+++ b/include/linux/swab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_SWAB_H
 #define _LINUX_SWAB_H
 
diff --git a/include/linux/time.h b/include/linux/time.h
index 7903139a65b2..ebb7cb82ee5d 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_TIME_H
 #define _LINUX_TIME_H
 
diff --git a/include/linux/types.h b/include/linux/types.h
index dfef336c198b..5872bd8e381a 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_TYPES_H
 #define _LINUX_TYPES_H
 #ifndef __ASSEMBLY__
diff --git a/include/linux/unaligned/access_ok.h b/include/linux/unaligned/access_ok.h
index 99c1b4d20b0f..7039ec8ed0a4 100644
--- a/include/linux/unaligned/access_ok.h
+++ b/include/linux/unaligned/access_ok.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_ACCESS_OK_H
 #define _LINUX_UNALIGNED_ACCESS_OK_H
 
diff --git a/include/linux/unaligned/be_byteshift.h b/include/linux/unaligned/be_byteshift.h
index 9356b24223ac..632a7308b570 100644
--- a/include/linux/unaligned/be_byteshift.h
+++ b/include/linux/unaligned/be_byteshift.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H
 #define _LINUX_UNALIGNED_BE_BYTESHIFT_H
 
diff --git a/include/linux/unaligned/be_memmove.h b/include/linux/unaligned/be_memmove.h
index c2a76c5c9ed0..0723c286fc23 100644
--- a/include/linux/unaligned/be_memmove.h
+++ b/include/linux/unaligned/be_memmove.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_BE_MEMMOVE_H
 #define _LINUX_UNALIGNED_BE_MEMMOVE_H
 
diff --git a/include/linux/unaligned/be_struct.h b/include/linux/unaligned/be_struct.h
index 132415836c50..3cc8fcd68dd0 100644
--- a/include/linux/unaligned/be_struct.h
+++ b/include/linux/unaligned/be_struct.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_BE_STRUCT_H
 #define _LINUX_UNALIGNED_BE_STRUCT_H
 
diff --git a/include/linux/unaligned/generic.h b/include/linux/unaligned/generic.h
index 43d5f2af2480..298e977fb7a7 100644
--- a/include/linux/unaligned/generic.h
+++ b/include/linux/unaligned/generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_GENERIC_H
 #define _LINUX_UNALIGNED_GENERIC_H
 
diff --git a/include/linux/unaligned/le_byteshift.h b/include/linux/unaligned/le_byteshift.h
index be376fb79b64..aa425707f865 100644
--- a/include/linux/unaligned/le_byteshift.h
+++ b/include/linux/unaligned/le_byteshift.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_LE_BYTESHIFT_H
 #define _LINUX_UNALIGNED_LE_BYTESHIFT_H
 
diff --git a/include/linux/unaligned/le_memmove.h b/include/linux/unaligned/le_memmove.h
index 269849bee4ec..e21fccc9b96d 100644
--- a/include/linux/unaligned/le_memmove.h
+++ b/include/linux/unaligned/le_memmove.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_LE_MEMMOVE_H
 #define _LINUX_UNALIGNED_LE_MEMMOVE_H
 
diff --git a/include/linux/unaligned/le_struct.h b/include/linux/unaligned/le_struct.h
index 088c4572faa8..4bbeba57784c 100644
--- a/include/linux/unaligned/le_struct.h
+++ b/include/linux/unaligned/le_struct.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_LE_STRUCT_H
 #define _LINUX_UNALIGNED_LE_STRUCT_H
 
diff --git a/include/linux/unaligned/memmove.h b/include/linux/unaligned/memmove.h
index eeb5a779a4fd..c44dff67ab26 100644
--- a/include/linux/unaligned/memmove.h
+++ b/include/linux/unaligned/memmove.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_MEMMOVE_H
 #define _LINUX_UNALIGNED_MEMMOVE_H
 
diff --git a/include/linux/unaligned/packed_struct.h b/include/linux/unaligned/packed_struct.h
index 2498bb9fe002..7caf433fae99 100644
--- a/include/linux/unaligned/packed_struct.h
+++ b/include/linux/unaligned/packed_struct.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_UNALIGNED_PACKED_STRUCT_H
 #define _LINUX_UNALIGNED_PACKED_STRUCT_H
 
diff --git a/include/linux/wait.h b/include/linux/wait.h
index e2df8878ed78..e4b0e2a49207 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_WAIT_H
 #define _LINUX_WAIT_H
 /*
diff --git a/include/linux/xz.h b/include/linux/xz.h
index d1afab056242..77e80ce4b1bb 100644
--- a/include/linux/xz.h
+++ b/include/linux/xz.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * XZ decompressor
  *
diff --git a/include/linux/zutil.h b/include/linux/zutil.h
index 6adfa9a6ffe9..b10b50d0970d 100644
--- a/include/linux/zutil.h
+++ b/include/linux/zutil.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* zutil.h -- internal interface and configuration of the compression library
  * Copyright (C) 1995-1998 Jean-loup Gailly.
  * For conditions of distribution and use, see copyright notice in zlib.h
diff --git a/include/machine_id.h b/include/machine_id.h
index 31d5e0bb2851..e30bbada1acd 100644
--- a/include/machine_id.h
+++ b/include/machine_id.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACHINE_ID_H__
 #define __MACHINE_ID_H__
 
diff --git a/include/mfd/lp3972.h b/include/mfd/lp3972.h
index edb580111893..40ab98665796 100644
--- a/include/mfd/lp3972.h
+++ b/include/mfd/lp3972.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_LP3972_H
 #define __ASM_ARCH_LP3972_H
 
diff --git a/include/mfd/pfuze.h b/include/mfd/pfuze.h
index 8e021680ef64..4fb3863a723e 100644
--- a/include/mfd/pfuze.h
+++ b/include/mfd/pfuze.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INCLUDE_PFUZE_H
 #define __INCLUDE_PFUZE_H
 
diff --git a/include/mtd/mtd-peb.h b/include/mtd/mtd-peb.h
index 311f25c3df44..cfcc0be611b5 100644
--- a/include/mtd/mtd-peb.h
+++ b/include/mtd/mtd-peb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __LINUX_MTD_MTDPEB_H
 #define __LINUX_MTD_MTDPEB_H
 
diff --git a/include/platform_data/atmel-mci.h b/include/platform_data/atmel-mci.h
index d99ee3d1382b..53c2e4dfa5f9 100644
--- a/include/platform_data/atmel-mci.h
+++ b/include/platform_data/atmel-mci.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef PLATFORM_DATA_ATMEL_MCI_H
 #define PLATFORM_DATA_ATMEL_MCI_H
 
diff --git a/include/platform_data/cadence_qspi.h b/include/platform_data/cadence_qspi.h
index ad1a680c9f95..e1095cf6b808 100644
--- a/include/platform_data/cadence_qspi.h
+++ b/include/platform_data/cadence_qspi.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INCLUDE_PLATFORM_DATA_CADENCE_QSPI_H
 #define __INCLUDE_PLATFORM_DATA_CADENCE_QSPI_H
 
diff --git a/include/platform_data/dw_mmc.h b/include/platform_data/dw_mmc.h
index 4325a4f483d7..6c648d7073b3 100644
--- a/include/platform_data/dw_mmc.h
+++ b/include/platform_data/dw_mmc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INCLUDE_PLATFORM_DATA_DW_MMC_H
 #define __INCLUDE_PLATFORM_DATA_DW_MMC_H
 
diff --git a/include/platform_data/eth-designware.h b/include/platform_data/eth-designware.h
index 7a7a26abfde1..df00c5e64f6d 100644
--- a/include/platform_data/eth-designware.h
+++ b/include/platform_data/eth-designware.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __DWC_UNIMAC_H
 #define __DWC_UNIMAC_H
 
diff --git a/include/platform_data/eth-dm9000.h b/include/platform_data/eth-dm9000.h
index a9a4635d2aa8..241552cee266 100644
--- a/include/platform_data/eth-dm9000.h
+++ b/include/platform_data/eth-dm9000.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #ifndef __DM9000_H__
 #define __DM9000_H__
diff --git a/include/platform_data/pca953x.h b/include/platform_data/pca953x.h
index cfd253ebceda..de71c864816c 100644
--- a/include/platform_data/pca953x.h
+++ b/include/platform_data/pca953x.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _LINUX_PCA953X_H
 #define _LINUX_PCA953X_H
 
diff --git a/include/pm_domain.h b/include/pm_domain.h
index 6d59587ece44..48fd170007fd 100644
--- a/include/pm_domain.h
+++ b/include/pm_domain.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _PM_DOMAIN_H
 #define _PM_DOMAIN_H
 
@@ -79,4 +81,4 @@ of_genpd_add_provider_simple(struct device_node *np,
 
 #endif
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/serial/cadence.h b/include/serial/cadence.h
index f08b5b0cba4a..9105883dd641 100644
--- a/include/serial/cadence.h
+++ b/include/serial/cadence.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __CADENCE_UART_H__
 #define __CADENCE_UART_H__
 
diff --git a/include/serial/imx-uart.h b/include/serial/imx-uart.h
index c0a03ac05401..516f318b68c9 100644
--- a/include/serial/imx-uart.h
+++ b/include/serial/imx-uart.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __IMX_UART_H__
 #define __IMX_UART_H__
 
diff --git a/include/slice.h b/include/slice.h
index 6c4688e308fa..800c5b2de08c 100644
--- a/include/slice.h
+++ b/include/slice.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __SLICE_H
 #define __SLICE_H
 
diff --git a/include/soc/fsl/fsl_udc.h b/include/soc/fsl/fsl_udc.h
index 0b409a9f6be8..9fb6da58a146 100644
--- a/include/soc/fsl/fsl_udc.h
+++ b/include/soc/fsl/fsl_udc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __FSL_UDC_H
 #define __FSL_UDC_H
 
diff --git a/include/soc/imx/imx-nand-bcb.h b/include/soc/imx/imx-nand-bcb.h
index b60205bd59ee..6c42d804289c 100644
--- a/include/soc/imx/imx-nand-bcb.h
+++ b/include/soc/imx/imx-nand-bcb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX_NAND_BCB_H
 #define __MACH_IMX_NAND_BCB_H
 
diff --git a/include/soc/imx8m/clk-early.h b/include/soc/imx8m/clk-early.h
index 1e1ca5954336..c2034e54f070 100644
--- a/include/soc/imx8m/clk-early.h
+++ b/include/soc/imx8m/clk-early.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __SOC_IMX8M_CLK_EARLY_H
 #define __SOC_IMX8M_CLK_EARLY_H
 
diff --git a/include/sys/ioctl.h b/include/sys/ioctl.h
index 6d6d3f5c004b..5a949f1f3c0c 100644
--- a/include/sys/ioctl.h
+++ b/include/sys/ioctl.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __SYS_IOCTL_H
 #define __SYS_IOCTL_H
 
diff --git a/include/sys/mount.h b/include/sys/mount.h
index 978f3406e80a..368e54a343c7 100644
--- a/include/sys/mount.h
+++ b/include/sys/mount.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __SYS_MOUNT_H
 #define __SYS_MOUNT_H
 
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 037e5f136d12..0dd43d1f02c8 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __STAT_H
 #define __STAT_H
 
diff --git a/include/usb/cdc.h b/include/usb/cdc.h
index c24124a42ce5..e29429d783ba 100644
--- a/include/usb/cdc.h
+++ b/include/usb/cdc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * USB Communications Device Class (CDC) definitions
  *
diff --git a/include/usb/ch11.h b/include/usb/ch11.h
index 93f891aea753..c712d80275e1 100644
--- a/include/usb/ch11.h
+++ b/include/usb/ch11.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * This file holds Hub protocol constants and data structures that are
  * defined in chapter 11 (Hub Specification) of the USB 2.0 specification.
diff --git a/include/usb/ch9.h b/include/usb/ch9.h
index 2e06dd89fd02..4c1e7653261c 100644
--- a/include/usb/ch9.h
+++ b/include/usb/ch9.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * This file holds USB constants and structures that are needed for
  * USB device APIs.  These are used by the USB device model, which is
diff --git a/include/usb/chipidea-imx.h b/include/usb/chipidea-imx.h
index dfd84a965033..772f48c631d9 100644
--- a/include/usb/chipidea-imx.h
+++ b/include/usb/chipidea-imx.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __USB_CHIPIDEA_IMX_H
 #define __USB_CHIPIDEA_IMX_H
 
diff --git a/include/usb/ehci.h b/include/usb/ehci.h
index 327500d49aed..d937146b4d23 100644
--- a/include/usb/ehci.h
+++ b/include/usb/ehci.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __USB_EHCI_H
 #define __USB_EHCI_H
 
diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
index a3609ba5dbe9..7dc445455a84 100644
--- a/include/usb/fastboot.h
+++ b/include/usb/fastboot.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _USB_FASTBOOT_H
 #define _USB_FASTBOOT_H
 
diff --git a/include/usb/fsl_usb2.h b/include/usb/fsl_usb2.h
index 39757f71ad60..01232da4f92f 100644
--- a/include/usb/fsl_usb2.h
+++ b/include/usb/fsl_usb2.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __USB_FSL_USB2_H
 #define __USB_FSL_USB2_H
 
diff --git a/include/usb/gadget-multi.h b/include/usb/gadget-multi.h
index 79b24ca4df72..2d8d7533a816 100644
--- a/include/usb/gadget-multi.h
+++ b/include/usb/gadget-multi.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __USB_GADGET_MULTI_H
 #define __USB_GADGET_MULTI_H
 
diff --git a/include/usb/musb.h b/include/usb/musb.h
index fef7dc5f2c8d..c21428dbf159 100644
--- a/include/usb/musb.h
+++ b/include/usb/musb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * This is used to for host and peripheral modes of the driver for
  * Inventra (Multidrop) Highspeed Dual-Role Controllers:  (M)HDRC.
diff --git a/include/usb/phy.h b/include/usb/phy.h
index 057ad1cd9588..8f11e70dfd77 100644
--- a/include/usb/phy.h
+++ b/include/usb/phy.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* USB OTG (On The Go) defines */
 /*
  *
diff --git a/include/usb/ulpi.h b/include/usb/ulpi.h
index e45ea6e0f920..efbfc632083e 100644
--- a/include/usb/ulpi.h
+++ b/include/usb/ulpi.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ULPI_H
 #define __MACH_ULPI_H
 
diff --git a/include/usb/usbserial.h b/include/usb/usbserial.h
index c537eba900fe..e1375c489a02 100644
--- a/include/usb/usbserial.h
+++ b/include/usb/usbserial.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _USB_SERIAL_H
 #define _USB_SERIAL_H
 
diff --git a/include/video/backlight.h b/include/video/backlight.h
index afa384cc9adf..7810ec998ee6 100644
--- a/include/video/backlight.h
+++ b/include/video/backlight.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __VIDEO_BACKLIGHT_H
 #define __VIDEO_BACKLIGHT_H
 
diff --git a/include/video/fourcc.h b/include/video/fourcc.h
index 211aabb1f3d2..4db1d0d0018e 100644
--- a/include/video/fourcc.h
+++ b/include/video/fourcc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __VIDEO_FOURCC_H
 #define __VIDEO_FOURCC_H
 
diff --git a/include/video/vpl.h b/include/video/vpl.h
index 6ae7b0f3e0e2..15711b47018b 100644
--- a/include/video/vpl.h
+++ b/include/video/vpl.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __VIDEO_VPL_H
 #define __VIDEO_VPL_H
 
diff --git a/include/work.h b/include/work.h
index 0785bb3a8818..e6de867f5321 100644
--- a/include/work.h
+++ b/include/work.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __WORK_H
 #define __WORK_H
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:32 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:32 +0100
Subject: [PATCH 04/11] images: add SPDX-License-Identifiers
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-5-a.fatoum@pengutronix.de>

They have no explicit license and thus have the project's license:
GPL-2.0-only. Record this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 images/Makefile.am33xx     | 1 +
 images/Makefile.am35xx     | 1 +
 images/Makefile.ar231x     | 2 ++
 images/Makefile.at91       | 1 +
 images/Makefile.ath79      | 2 ++
 images/Makefile.bcm283x    | 3 ++-
 images/Makefile.bcm47xx    | 2 ++
 images/Makefile.imx        | 1 +
 images/Makefile.layerscape | 1 +
 images/Makefile.loongson   | 2 ++
 images/Makefile.malta      | 2 ++
 images/Makefile.mvebu      | 1 +
 images/Makefile.mxs        | 1 +
 images/Makefile.omap3      | 2 ++
 images/Makefile.rockchip   | 1 +
 images/Makefile.socfpga    | 1 +
 images/Makefile.tegra      | 1 +
 images/Makefile.vexpress   | 1 +
 images/Makefile.xburst     | 2 ++
 images/Makefile.zynq       | 1 +
 images/piggy.S             | 2 ++
 21 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/images/Makefile.am33xx b/images/Makefile.am33xx
index 1de2474df5c9..add676117c6e 100644
--- a/images/Makefile.am33xx
+++ b/images/Makefile.am33xx
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 # %.mlo - convert into mlo image
 # ----------------------------------------------------------------
diff --git a/images/Makefile.am35xx b/images/Makefile.am35xx
index 6d30baee64bb..d5371d9e112d 100644
--- a/images/Makefile.am35xx
+++ b/images/Makefile.am35xx
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 # %.mlo - convert into mlo image
 # ----------------------------------------------------------------
diff --git a/images/Makefile.ar231x b/images/Makefile.ar231x
index 31b97048660f..8992bc0fd099 100644
--- a/images/Makefile.ar231x
+++ b/images/Makefile.ar231x
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 pblb-$(CONFIG_BOARD_NETGEAR_WG102) += start_netgear_wg102
 FILE_barebox-netgear-wg102.img = start_netgear_wg102.pblb
 image-$(CONFIG_BOARD_NETGEAR_WG102) += barebox-netgear-wg102.img
diff --git a/images/Makefile.at91 b/images/Makefile.at91
index c7a2209e0085..71cc959f5d05 100644
--- a/images/Makefile.at91
+++ b/images/Makefile.at91
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for AT91 images
 #
diff --git a/images/Makefile.ath79 b/images/Makefile.ath79
index 072062b0aa9a..018c2223ce9e 100644
--- a/images/Makefile.ath79
+++ b/images/Makefile.ath79
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 pblb-$(CONFIG_SOC_QCA_AR9331) += start_ar9331_spi_trap
 FILE_barebox-ar9331-spi-trap.img = start_ar9331_spi_trap.pblb
 image-$(CONFIG_SOC_QCA_AR9331) += barebox-ar9331-spi-trap.img
diff --git a/images/Makefile.bcm283x b/images/Makefile.bcm283x
index 3fd2c3d06ac9..82787f972c2d 100644
--- a/images/Makefile.bcm283x
+++ b/images/Makefile.bcm283x
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for BCM283x images
 #
@@ -16,4 +17,4 @@ image-$(CONFIG_MACH_RPI3) += barebox-raspberry-pi-3.img
 
 pblb-$(CONFIG_MACH_RPI_CM3) += start_raspberry_pi_cm3
 FILE_barebox-raspberry-pi-cm3.img = start_raspberry_pi_cm3.pblb
-image-$(CONFIG_MACH_RPI_CM3) += barebox-raspberry-pi-cm3.img
\ No newline at end of file
+image-$(CONFIG_MACH_RPI_CM3) += barebox-raspberry-pi-cm3.img
diff --git a/images/Makefile.bcm47xx b/images/Makefile.bcm47xx
index 839243e3a81b..569a2b0ed1a3 100644
--- a/images/Makefile.bcm47xx
+++ b/images/Makefile.bcm47xx
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 pblb-$(CONFIG_BOARD_DLINK_DIR320) += start_dlink_dir_320
 FILE_barebox-dlink-dir-320.img = start_dlink_dir_320.pblb
 image-$(CONFIG_BOARD_DLINK_DIR320) += barebox-dlink-dir-320.img
diff --git a/images/Makefile.imx b/images/Makefile.imx
index d5476a326bdc..1dffab989ec3 100644
--- a/images/Makefile.imx
+++ b/images/Makefile.imx
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for i.MX images
 #
diff --git a/images/Makefile.layerscape b/images/Makefile.layerscape
index 806c09d8fbce..a180c230c7a9 100644
--- a/images/Makefile.layerscape
+++ b/images/Makefile.layerscape
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for NXP Layerscape images
 #
diff --git a/images/Makefile.loongson b/images/Makefile.loongson
index f5918b540778..75c20bf4bccd 100644
--- a/images/Makefile.loongson
+++ b/images/Makefile.loongson
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 pblb-$(CONFIG_BOARD_LOONGSON_TECH_LS1B) += start_loongson_ls1b
 FILE_barebox-loongson-ls1b.img = start_loongson_ls1b.pblb
 image-$(CONFIG_BOARD_LOONGSON_TECH_LS1B) += barebox-loongson-ls1b.img
diff --git a/images/Makefile.malta b/images/Makefile.malta
index 96d7b86b1187..87866f08acf0 100644
--- a/images/Makefile.malta
+++ b/images/Makefile.malta
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 quiet_cmd_bswap32_image = BSWAP4  $@
       cmd_bswap32_image = cp $< $@ && \
 			  truncate -s %4 $@ && \
diff --git a/images/Makefile.mvebu b/images/Makefile.mvebu
index 112227424b75..7c918cb9f184 100644
--- a/images/Makefile.mvebu
+++ b/images/Makefile.mvebu
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for Marvell mvebu
 #
diff --git a/images/Makefile.mxs b/images/Makefile.mxs
index ceb7b376a533..87549afe4837 100644
--- a/images/Makefile.mxs
+++ b/images/Makefile.mxs
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for MXS images
 #
diff --git a/images/Makefile.omap3 b/images/Makefile.omap3
index 4d87b1da26e0..f8ecb68684d9 100644
--- a/images/Makefile.omap3
+++ b/images/Makefile.omap3
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
 # %.mlo - convert into mlo image
 # ----------------------------------------------------------------
 quiet_cmd_omap3_mlo_image = MLO     $@
diff --git a/images/Makefile.rockchip b/images/Makefile.rockchip
index 19980914b29d..0a485cad24d1 100644
--- a/images/Makefile.rockchip
+++ b/images/Makefile.rockchip
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for Rockchip images
 #
diff --git a/images/Makefile.socfpga b/images/Makefile.socfpga
index 26220178af12..90e3c066dc08 100644
--- a/images/Makefile.socfpga
+++ b/images/Makefile.socfpga
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for Altera socfpga
 #
diff --git a/images/Makefile.tegra b/images/Makefile.tegra
index f5b5841e0664..97a92f321cce 100644
--- a/images/Makefile.tegra
+++ b/images/Makefile.tegra
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for Tegra images
 #
diff --git a/images/Makefile.vexpress b/images/Makefile.vexpress
index d2af19184558..11c49cca0cbd 100644
--- a/images/Makefile.vexpress
+++ b/images/Makefile.vexpress
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for VExpress images
 #
diff --git a/images/Makefile.xburst b/images/Makefile.xburst
index 6c63a5657bdf..13ed130672c9 100644
--- a/images/Makefile.xburst
+++ b/images/Makefile.xburst
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 pblb-$(CONFIG_BOARD_CI20) += start_img_ci20
 FILE_barebox-img-ci20.img = start_img_ci20.pblb
 image-$(CONFIG_BOARD_CI20) += barebox-img-ci20.img
diff --git a/images/Makefile.zynq b/images/Makefile.zynq
index b00e74869714..3e61ad6eb611 100644
--- a/images/Makefile.zynq
+++ b/images/Makefile.zynq
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # barebox image generation Makefile for Xilinx Zynq images
 #
diff --git a/images/piggy.S b/images/piggy.S
index c2274ebac735..654933ea2ffe 100644
--- a/images/piggy.S
+++ b/images/piggy.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
         .section .piggydata,"a"
         .globl  input_data
 input_data:
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:35 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:35 +0100
Subject: [PATCH 07/11] ARM: i.MX: add SPDX-License-Identifier for DCD
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-8-a.fatoum@pengutronix.de>

In absence of a license statement, the default is GPL-2.0-only. Add that
to the DCD files. All of //  /* */  # are acceptable comment characters
in the DSL. If there are nearby comments in the file, the same character
is used, otherwise #.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 .../advantech-mx6/flash-header-advantech-rom-7421.imxcfg      | 2 ++
 .../flash-header-nitrogen6dl-1g.imxcfg                        | 2 ++
 .../flash-header-nitrogen6dl-2g.imxcfg                        | 2 ++
 .../flash-header-nitrogen6q-1g.imxcfg                         | 2 ++
 .../flash-header-nitrogen6q-2g.imxcfg                         | 2 ++
 .../flash-header-nitrogen6qp-max.imxcfg                       | 2 ++
 arch/arm/boards/boundarydevices-nitrogen6/ram-base.imxcfg     | 2 ++
 arch/arm/boards/ccxmx51/flash-header.imxcfg                   | 2 ++
 .../arm/boards/ccxmx53/flash-header-imx53-ccxmx53_1gib.imxcfg | 2 ++
 .../boards/ccxmx53/flash-header-imx53-ccxmx53_512mb.imxcfg    | 2 ++
 arch/arm/boards/cm-fx6/flash-header-mx6-cm-fx6.imxcfg         | 2 ++
 arch/arm/boards/datamodul-edm-qmx6/flash-header.imxcfg        | 2 ++
 .../dfi-fs700-m60/flash-header-fs700-m60-6q-micron.imxcfg     | 2 ++
 .../dfi-fs700-m60/flash-header-fs700-m60-6q-nanya.imxcfg      | 2 ++
 .../arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6s.imxcfg | 2 ++
 .../flash-header-imx6ul-ccimx6ulsbcpro.imxcfg                 | 2 ++
 .../flash-header-imx51-genesi-efikasb.imxcfg                  | 2 ++
 .../boards/eltec-hipercam/flash-header-eltec-hipercam.imxcfg  | 2 ++
 arch/arm/boards/embedsky-e9/flash-header-e9.imxcfg            | 2 ++
 .../embest-marsboard/flash-header-embest-marsboard.imxcfg     | 2 ++
 .../embest-riotboard/flash-header-embest-riotboard.imxcfg     | 2 ++
 arch/arm/boards/eukrea_cpuimx25/flash-header.imxcfg           | 2 ++
 arch/arm/boards/eukrea_cpuimx35/flash-header.imxcfg           | 2 ++
 arch/arm/boards/eukrea_cpuimx51/flash-header.imxcfg           | 2 ++
 arch/arm/boards/freescale-mx25-3ds/flash-header.imxcfg        | 2 ++
 arch/arm/boards/freescale-mx35-3ds/flash-header.imxcfg        | 2 ++
 .../freescale-mx51-babbage/flash-header-imx51-babbage.imxcfg  | 2 ++
 .../boards/freescale-mx53-qsb/flash-header-imx53-loco.imxcfg  | 2 ++
 arch/arm/boards/freescale-mx53-smd/flash-header.imxcfg        | 2 ++
 .../freescale-mx53-vmx53/flash-header-imx53-vmx53.imxcfg      | 2 ++
 .../freescale-mx6-sabrelite/flash-header-mx6-sabrelite.imxcfg | 2 ++
 .../freescale-mx6-sabresd/flash-header-mx6q-sabresd.imxcfg    | 2 ++
 .../freescale-mx6-sabresd/flash-header-mx6qp-sabresd.imxcfg   | 2 ++
 .../flash-header-mx6sx-sabresdb.imxcfg                        | 2 ++
 .../freescale-mx7-sabresd/flash-header-mx7-sabresd.imxcfg     | 4 +++-
 .../boards/freescale-vf610-twr/flash-header-vf610-twr.imxcfg  | 2 ++
 .../gateworks-ventana/flash-header-ventana-quad-1gx64.imxcfg  | 2 ++
 arch/arm/boards/gateworks-ventana/quad_128x64.imxcfg          | 2 ++
 arch/arm/boards/gateworks-ventana/ram-base.imxcfg             | 2 ++
 arch/arm/boards/gk802/flash-header.imxcfg                     | 2 ++
 .../grinn-liteboard/flash-header-liteboard-256mb.imxcfg       | 1 +
 .../grinn-liteboard/flash-header-liteboard-512mb.imxcfg       | 1 +
 arch/arm/boards/grinn-liteboard/flash-header-liteboard.h      | 1 +
 arch/arm/boards/guf-santaro/flash-header.imxcfg               | 2 ++
 arch/arm/boards/guf-vincell/flash-header.imxcfg               | 2 ++
 .../kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg      | 2 ++
 arch/arm/boards/karo-tx25/flash-header-tx25.imxcfg            | 1 +
 arch/arm/boards/karo-tx28/tx28.h                              | 1 +
 arch/arm/boards/karo-tx53/flash-header-tx53-rev1011.imxcfg    | 2 ++
 .../boards/karo-tx53/flash-header-tx53-revxx30-samsung.imxcfg | 2 ++
 arch/arm/boards/karo-tx53/flash-header-tx53-revxx30.imxcfg    | 2 ++
 arch/arm/boards/karo-tx6x/1600mhz_4x128mx16.imxcfg            | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6dl-1g.imxcfg        | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6dl-512m.imxcfg      | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6q-1g.imxcfg         | 2 ++
 arch/arm/boards/karo-tx6x/flash-header-tx6qp-2g.imxcfg        | 2 ++
 arch/arm/boards/karo-tx6x/pmic.h                              | 1 +
 arch/arm/boards/karo-tx6x/ram-base.imxcfg                     | 2 ++
 arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr1.imxcfg | 2 ++
 arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr2.imxcfg | 2 ++
 arch/arm/boards/kindle3/flash-header.imxcfg                   | 2 ++
 .../boards/kontron-samx6i/flash-header-samx6i-duallite.imxcfg | 2 ++
 .../arm/boards/kontron-samx6i/flash-header-samx6i-quad.imxcfg | 2 ++
 arch/arm/boards/kontron-samx6i/mem.h                          | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_pbi.cfg                 | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_qspi_pbi.cfg            | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_rcw_emmc.cfg            | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_rcw_qspi.cfg            | 2 ++
 arch/arm/boards/ls1046ardb/ls1046ardb_rcw_sd.cfg              | 2 ++
 arch/arm/boards/mnt-reform/flash-header-mnt-reform.imxcfg     | 2 ++
 arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg | 2 ++
 arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg | 2 ++
 arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg | 2 ++
 arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg | 2 ++
 arch/arm/boards/panda/mux.h                                   | 2 ++
 arch/arm/boards/phytec-phycard-omap4/mux.h                    | 2 ++
 arch/arm/boards/phytec-phycore-imx35/flash-header.imxcfg      | 2 ++
 arch/arm/boards/phytec-phycore-omap4460/mux.h                 | 2 ++
 .../flash-header-phytec-pcaaxl3-1gib-1bank.imxcfg             | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib.imxcfg   | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcaaxl3-2gib.imxcfg   | 2 ++
 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.h | 2 ++
 .../boards/phytec-som-imx6/flash-header-phytec-pcl063-512mb.h | 1 +
 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063.h  | 1 +
 .../phytec-som-imx6/flash-header-phytec-pcl063ul-512mb.imxcfg | 1 +
 .../flash-header-phytec-pcl063ull-256mb.imxcfg                | 1 +
 .../flash-header-phytec-pcl063ull-512mb.imxcfg                | 1 +
 .../phytec-som-imx6/flash-header-phytec-pcm058-1gib.imxcfg    | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058-2gib.imxcfg    | 2 ++
 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058.h  | 2 ++
 .../flash-header-phytec-pcm058dl-1gib-32bit.imxcfg            | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058dl-1gib.imxcfg  | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058dl-256mb.imxcfg | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058dl-512mb.imxcfg | 2 ++
 .../arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl.h | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pcm058qp-1gib.imxcfg  | 2 ++
 .../arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp.h | 2 ++
 .../flash-header-phytec-pfla02-1gib-1bank.imxcfg              | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02-1gib.imxcfg    | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02-2gib.imxcfg    | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02-4gib.imxcfg    | 2 ++
 .../flash-header-phytec-pfla02-512mb-1bank.imxcfg             | 2 ++
 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02.h  | 2 ++
 .../flash-header-phytec-pfla02dl-1gib-1bank.imxcfg            | 2 ++
 .../phytec-som-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg  | 2 ++
 .../arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl.h | 2 ++
 .../flash-header-phytec-pfla02s-128mb-1bank.imxcfg            | 2 ++
 .../flash-header-phytec-pfla02s-256mb-1bank.imxcfg            | 2 ++
 .../flash-header-phytec-pfla02s-512mb-1bank.imxcfg            | 2 ++
 .../phytec-som-imx8mq/flash-header-phycore-imx8mq.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/ddr3-defines.imxcfg             | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-alti6p.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-jozacp.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-lanmcu.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-plybas.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-plym2m.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prti6g.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prti6q.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtmvt.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtrvt.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtvt7.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtwd2.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-prtwd3.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-victgo.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-vicut1.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-vicut1q.imxcfg     | 2 ++
 arch/arm/boards/protonic-imx6/flash-header-vicutp.imxcfg      | 2 ++
 arch/arm/boards/protonic-imx6/lpddr2-defines.imxcfg           | 2 ++
 arch/arm/boards/protonic-imx6/padsetup-dl.imxcfg              | 1 +
 arch/arm/boards/protonic-imx6/padsetup-q.imxcfg               | 1 +
 arch/arm/boards/protonic-imx6/padsetup-ul.imxcfg              | 1 +
 arch/arm/boards/protonic-imx8m/flash-header-prt8mm.imxcfg     | 2 ++
 arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg   | 2 ++
 .../boards/solidrun-microsom/flash-header-microsom-i1.imxcfg  | 2 ++
 .../boards/solidrun-microsom/flash-header-microsom-i2.imxcfg  | 2 ++
 .../solidrun-microsom/flash-header-microsom-i2eX.imxcfg       | 2 ++
 .../boards/solidrun-microsom/flash-header-microsom-i4.imxcfg  | 2 ++
 .../flash-header-imx6ul-pico-hobbit-256.imxcfg                | 2 ++
 .../flash-header-imx6ul-pico-hobbit-512.imxcfg                | 2 ++
 .../flash-header-technexion-wandboard.imxcfg                  | 2 ++
 arch/arm/boards/tqma53/flash-header-tq-tqma53-1gib.imxcfg     | 2 ++
 arch/arm/boards/tqma53/flash-header-tq-tqma53-512mib.imxcfg   | 2 ++
 arch/arm/boards/tqma53/flash-header-tq-tqma53.h               | 2 ++
 arch/arm/boards/tqma53/flash-header.imxcfg                    | 2 ++
 arch/arm/boards/tqma6x/flash-header-tqma6dl.imxcfg            | 2 ++
 arch/arm/boards/tqma6x/flash-header-tqma6q.imxcfg             | 2 ++
 arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg                 | 2 ++
 arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg  | 2 ++
 arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg    | 2 ++
 .../boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg   | 2 ++
 arch/arm/boards/udoo/flash-header-mx6-udoo.imxcfg             | 2 ++
 arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg   | 2 ++
 .../boards/zii-imx51-rdu1/flash-header-imx51-zii-rdu1.imxcfg  | 2 ++
 arch/arm/boards/zii-imx6q-rdu2/flash-header-rdu2.imxcfg       | 2 ++
 .../boards/zii-imx7d-dev/flash-header-zii-imx7d-dev.imxcfg    | 2 ++
 .../boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg  | 2 ++
 .../boards/zii-vf610-dev/flash-header-zii-vf610-dev.imxcfg    | 2 ++
 .../include/mach/flash-header/vf610-ddr-cr-default.imxcfg     | 4 +++-
 .../include/mach/flash-header/vf610-ddr-pll2-400mhz.imxcfg    | 2 ++
 159 files changed, 306 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boards/advantech-mx6/flash-header-advantech-rom-7421.imxcfg b/arch/arm/boards/advantech-mx6/flash-header-advantech-rom-7421.imxcfg
index aefdf68e8950..91a8babafd57 100644
--- a/arch/arm/boards/advantech-mx6/flash-header-advantech-rom-7421.imxcfg
+++ b/arch/arm/boards/advantech-mx6/flash-header-advantech-rom-7421.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-1g.imxcfg b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-1g.imxcfg
index 5da5fd941942..8282d4140ce3 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-1g.imxcfg
+++ b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-1g.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-2g.imxcfg b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-2g.imxcfg
index 3ccf7591c50a..9ef9b5789fcc 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-2g.imxcfg
+++ b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6dl-2g.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-1g.imxcfg b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-1g.imxcfg
index 7bdc0e736cff..5c5af546a74a 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-1g.imxcfg
+++ b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-1g.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-2g.imxcfg b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-2g.imxcfg
index c6f5aa8484e1..58b9dc74681c 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-2g.imxcfg
+++ b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6q-2g.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6qp-max.imxcfg b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6qp-max.imxcfg
index 797b9717e7a5..4ab0a653bd5c 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6qp-max.imxcfg
+++ b/arch/arm/boards/boundarydevices-nitrogen6/flash-header-nitrogen6qp-max.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/ram-base.imxcfg b/arch/arm/boards/boundarydevices-nitrogen6/ram-base.imxcfg
index 5d675883fd49..bf2aec5d965a 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/ram-base.imxcfg
+++ b/arch/arm/boards/boundarydevices-nitrogen6/ram-base.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 wm 32 MX6_IOM_DRAM_SDQS0		0x00000030
 wm 32 MX6_IOM_DRAM_SDQS1		0x00000030
 wm 32 MX6_IOM_DRAM_SDQS2		0x00000030
diff --git a/arch/arm/boards/ccxmx51/flash-header.imxcfg b/arch/arm/boards/ccxmx51/flash-header.imxcfg
index 3b1df11133ea..185a48fe18e5 100644
--- a/arch/arm/boards/ccxmx51/flash-header.imxcfg
+++ b/arch/arm/boards/ccxmx51/flash-header.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx51
 loadaddr 0x90000000
 ivtofs 0x400
diff --git a/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_1gib.imxcfg b/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_1gib.imxcfg
index 390b75b4f230..c049b2a10f52 100644
--- a/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_1gib.imxcfg
+++ b/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_1gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x70000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_512mb.imxcfg b/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_512mb.imxcfg
index c32ab9c1628d..a6460e0333c9 100644
--- a/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_512mb.imxcfg
+++ b/arch/arm/boards/ccxmx53/flash-header-imx53-ccxmx53_512mb.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x70000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/cm-fx6/flash-header-mx6-cm-fx6.imxcfg b/arch/arm/boards/cm-fx6/flash-header-mx6-cm-fx6.imxcfg
index 4bb615ebb0f6..da4cd4bebf77 100644
--- a/arch/arm/boards/cm-fx6/flash-header-mx6-cm-fx6.imxcfg
+++ b/arch/arm/boards/cm-fx6/flash-header-mx6-cm-fx6.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x00907000
 max_load_size 0x11000
diff --git a/arch/arm/boards/datamodul-edm-qmx6/flash-header.imxcfg b/arch/arm/boards/datamodul-edm-qmx6/flash-header.imxcfg
index 14146bed2284..139e6df79206 100644
--- a/arch/arm/boards/datamodul-edm-qmx6/flash-header.imxcfg
+++ b/arch/arm/boards/datamodul-edm-qmx6/flash-header.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x00907000
 ivtofs 0x400
diff --git a/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-micron.imxcfg b/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-micron.imxcfg
index fe8bd8cbd6ee..9f821650668e 100644
--- a/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-micron.imxcfg
+++ b/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-micron.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x27800000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-nanya.imxcfg b/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-nanya.imxcfg
index 6919bd8c3f8e..ccb3e6848766 100644
--- a/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-nanya.imxcfg
+++ b/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6q-nanya.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x27800000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6s.imxcfg b/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6s.imxcfg
index 709c11974b08..5b8bc2625741 100644
--- a/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6s.imxcfg
+++ b/arch/arm/boards/dfi-fs700-m60/flash-header-fs700-m60-6s.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x17800000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/digi-ccimx6ulsom/flash-header-imx6ul-ccimx6ulsbcpro.imxcfg b/arch/arm/boards/digi-ccimx6ulsom/flash-header-imx6ul-ccimx6ulsbcpro.imxcfg
index 7b2a198672dd..6f1c5bc8a78e 100644
--- a/arch/arm/boards/digi-ccimx6ulsom/flash-header-imx6ul-ccimx6ulsbcpro.imxcfg
+++ b/arch/arm/boards/digi-ccimx6ulsom/flash-header-imx6ul-ccimx6ulsbcpro.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x80000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/efika-mx-smartbook/flash-header-imx51-genesi-efikasb.imxcfg b/arch/arm/boards/efika-mx-smartbook/flash-header-imx51-genesi-efikasb.imxcfg
index 60436e7e37d0..de28650519cc 100644
--- a/arch/arm/boards/efika-mx-smartbook/flash-header-imx51-genesi-efikasb.imxcfg
+++ b/arch/arm/boards/efika-mx-smartbook/flash-header-imx51-genesi-efikasb.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx51
 loadaddr 0x90000000
 ivtofs 0x400
diff --git a/arch/arm/boards/eltec-hipercam/flash-header-eltec-hipercam.imxcfg b/arch/arm/boards/eltec-hipercam/flash-header-eltec-hipercam.imxcfg
index 5b422a786714..e53f1c107fe1 100644
--- a/arch/arm/boards/eltec-hipercam/flash-header-eltec-hipercam.imxcfg
+++ b/arch/arm/boards/eltec-hipercam/flash-header-eltec-hipercam.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/embedsky-e9/flash-header-e9.imxcfg b/arch/arm/boards/embedsky-e9/flash-header-e9.imxcfg
index d51dc17a1262..474ad3a15943 100644
--- a/arch/arm/boards/embedsky-e9/flash-header-e9.imxcfg
+++ b/arch/arm/boards/embedsky-e9/flash-header-e9.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x27800000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/embest-marsboard/flash-header-embest-marsboard.imxcfg b/arch/arm/boards/embest-marsboard/flash-header-embest-marsboard.imxcfg
index afc95d9bd936..5cf7201e88fd 100644
--- a/arch/arm/boards/embest-marsboard/flash-header-embest-marsboard.imxcfg
+++ b/arch/arm/boards/embest-marsboard/flash-header-embest-marsboard.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/embest-riotboard/flash-header-embest-riotboard.imxcfg b/arch/arm/boards/embest-riotboard/flash-header-embest-riotboard.imxcfg
index bc30e4c38759..a005b500dee3 100644
--- a/arch/arm/boards/embest-riotboard/flash-header-embest-riotboard.imxcfg
+++ b/arch/arm/boards/embest-riotboard/flash-header-embest-riotboard.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x20000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/eukrea_cpuimx25/flash-header.imxcfg b/arch/arm/boards/eukrea_cpuimx25/flash-header.imxcfg
index 129498ca8521..00417dddedb7 100644
--- a/arch/arm/boards/eukrea_cpuimx25/flash-header.imxcfg
+++ b/arch/arm/boards/eukrea_cpuimx25/flash-header.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx25
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/boards/eukrea_cpuimx35/flash-header.imxcfg b/arch/arm/boards/eukrea_cpuimx35/flash-header.imxcfg
index c1353e2904ec..ad187db742dc 100644
--- a/arch/arm/boards/eukrea_cpuimx35/flash-header.imxcfg
+++ b/arch/arm/boards/eukrea_cpuimx35/flash-header.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx35
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/boards/eukrea_cpuimx51/flash-header.imxcfg b/arch/arm/boards/eukrea_cpuimx51/flash-header.imxcfg
index 85c128c8fdd8..7f9a8773dab8 100644
--- a/arch/arm/boards/eukrea_cpuimx51/flash-header.imxcfg
+++ b/arch/arm/boards/eukrea_cpuimx51/flash-header.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx51
 ivtofs 0x400
 loadaddr 0x90000000
diff --git a/arch/arm/boards/freescale-mx25-3ds/flash-header.imxcfg b/arch/arm/boards/freescale-mx25-3ds/flash-header.imxcfg
index 8c1a25782967..9f83d102cbce 100644
--- a/arch/arm/boards/freescale-mx25-3ds/flash-header.imxcfg
+++ b/arch/arm/boards/freescale-mx25-3ds/flash-header.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx25
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx35-3ds/flash-header.imxcfg b/arch/arm/boards/freescale-mx35-3ds/flash-header.imxcfg
index ea1803b7de59..a6d16e8ab421 100644
--- a/arch/arm/boards/freescale-mx35-3ds/flash-header.imxcfg
+++ b/arch/arm/boards/freescale-mx35-3ds/flash-header.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx35
 loadaddr 0x80000000
 ivtofs 0x400
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 b4e11fc22743..56e2a9607cd4 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,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x90000000
 soc imx51
 ivtofs 0x400
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 2025f5da082c..da08c607392d 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
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x70000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx53-smd/flash-header.imxcfg b/arch/arm/boards/freescale-mx53-smd/flash-header.imxcfg
index fac4c29019a3..e885186c5418 100644
--- a/arch/arm/boards/freescale-mx53-smd/flash-header.imxcfg
+++ b/arch/arm/boards/freescale-mx53-smd/flash-header.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x70000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx53-vmx53/flash-header-imx53-vmx53.imxcfg b/arch/arm/boards/freescale-mx53-vmx53/flash-header-imx53-vmx53.imxcfg
index e6f73df30e6d..20e028691a29 100644
--- a/arch/arm/boards/freescale-mx53-vmx53/flash-header-imx53-vmx53.imxcfg
+++ b/arch/arm/boards/freescale-mx53-vmx53/flash-header-imx53-vmx53.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x70000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx6-sabrelite/flash-header-mx6-sabrelite.imxcfg b/arch/arm/boards/freescale-mx6-sabrelite/flash-header-mx6-sabrelite.imxcfg
index d635c8b9487a..af2807134edc 100644
--- a/arch/arm/boards/freescale-mx6-sabrelite/flash-header-mx6-sabrelite.imxcfg
+++ b/arch/arm/boards/freescale-mx6-sabrelite/flash-header-mx6-sabrelite.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6q-sabresd.imxcfg b/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6q-sabresd.imxcfg
index d0a0b40189a0..39f8950e8e16 100644
--- a/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6q-sabresd.imxcfg
+++ b/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6q-sabresd.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6qp-sabresd.imxcfg b/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6qp-sabresd.imxcfg
index aa52776afb74..224ac3207f01 100644
--- a/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6qp-sabresd.imxcfg
+++ b/arch/arm/boards/freescale-mx6-sabresd/flash-header-mx6qp-sabresd.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx6sx-sabresdb/flash-header-mx6sx-sabresdb.imxcfg b/arch/arm/boards/freescale-mx6sx-sabresdb/flash-header-mx6sx-sabresdb.imxcfg
index 5536f342b4fe..ebae00b8ea10 100644
--- a/arch/arm/boards/freescale-mx6sx-sabresdb/flash-header-mx6sx-sabresdb.imxcfg
+++ b/arch/arm/boards/freescale-mx6sx-sabresdb/flash-header-mx6sx-sabresdb.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x80000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/freescale-mx7-sabresd/flash-header-mx7-sabresd.imxcfg b/arch/arm/boards/freescale-mx7-sabresd/flash-header-mx7-sabresd.imxcfg
index 41e0e9ca61c2..9194b19fe4e8 100644
--- a/arch/arm/boards/freescale-mx7-sabresd/flash-header-mx7-sabresd.imxcfg
+++ b/arch/arm/boards/freescale-mx7-sabresd/flash-header-mx7-sabresd.imxcfg
@@ -1,5 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx7
 loadaddr 0x80000000
 ivtofs 0x400
 
-#include <mach/flash-header/imx7d-ddr-sabresd.imxcfg>
\ No newline at end of file
+#include <mach/flash-header/imx7d-ddr-sabresd.imxcfg>
diff --git a/arch/arm/boards/freescale-vf610-twr/flash-header-vf610-twr.imxcfg b/arch/arm/boards/freescale-vf610-twr/flash-header-vf610-twr.imxcfg
index bcef9921fab0..06d5a40a69cd 100644
--- a/arch/arm/boards/freescale-vf610-twr/flash-header-vf610-twr.imxcfg
+++ b/arch/arm/boards/freescale-vf610-twr/flash-header-vf610-twr.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc vf610
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/boards/gateworks-ventana/flash-header-ventana-quad-1gx64.imxcfg b/arch/arm/boards/gateworks-ventana/flash-header-ventana-quad-1gx64.imxcfg
index 98c7ae60953a..8f155a88dd2a 100644
--- a/arch/arm/boards/gateworks-ventana/flash-header-ventana-quad-1gx64.imxcfg
+++ b/arch/arm/boards/gateworks-ventana/flash-header-ventana-quad-1gx64.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/gateworks-ventana/quad_128x64.imxcfg b/arch/arm/boards/gateworks-ventana/quad_128x64.imxcfg
index daf01a8ad1da..66a78766495d 100644
--- a/arch/arm/boards/gateworks-ventana/quad_128x64.imxcfg
+++ b/arch/arm/boards/gateworks-ventana/quad_128x64.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 wm 32 MX6_MMDC_P0_MPWLDECTRL0	0x00190017
 wm 32 MX6_MMDC_P0_MPWLDECTRL1	0x00140026
 wm 32 MX6_MMDC_P1_MPWLDECTRL0	0x0021001C
diff --git a/arch/arm/boards/gateworks-ventana/ram-base.imxcfg b/arch/arm/boards/gateworks-ventana/ram-base.imxcfg
index 07dc34c0bbd1..c482f60b0930 100644
--- a/arch/arm/boards/gateworks-ventana/ram-base.imxcfg
+++ b/arch/arm/boards/gateworks-ventana/ram-base.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 wm 32 MX6_IOM_DRAM_SDQS0	0x00000030
 wm 32 MX6_IOM_DRAM_SDQS1	0x00000030
 wm 32 MX6_IOM_DRAM_SDQS2	0x00000030
diff --git a/arch/arm/boards/gk802/flash-header.imxcfg b/arch/arm/boards/gk802/flash-header.imxcfg
index acc7a367856a..aa5aef554f1f 100644
--- a/arch/arm/boards/gk802/flash-header.imxcfg
+++ b/arch/arm/boards/gk802/flash-header.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/grinn-liteboard/flash-header-liteboard-256mb.imxcfg b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-256mb.imxcfg
index 1b980c7846dd..c2d4b2875bfe 100644
--- a/arch/arm/boards/grinn-liteboard/flash-header-liteboard-256mb.imxcfg
+++ b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-256mb.imxcfg
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 #define SETUP_MDASP_MDCTL		\
 	wm 32 0x021B0040 0x00000047;	\
diff --git a/arch/arm/boards/grinn-liteboard/flash-header-liteboard-512mb.imxcfg b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-512mb.imxcfg
index c93a2cc0faa7..45bc841ab598 100644
--- a/arch/arm/boards/grinn-liteboard/flash-header-liteboard-512mb.imxcfg
+++ b/arch/arm/boards/grinn-liteboard/flash-header-liteboard-512mb.imxcfg
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 #define SETUP_MDASP_MDCTL		\
 	wm 32 0x021B0040 0x0000004F;	\
diff --git a/arch/arm/boards/grinn-liteboard/flash-header-liteboard.h b/arch/arm/boards/grinn-liteboard/flash-header-liteboard.h
index 82f5c627a3ab..776a69f8b60f 100644
--- a/arch/arm/boards/grinn-liteboard/flash-header-liteboard.h
+++ b/arch/arm/boards/grinn-liteboard/flash-header-liteboard.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 loadaddr 0x80000000
 soc imx6
diff --git a/arch/arm/boards/guf-santaro/flash-header.imxcfg b/arch/arm/boards/guf-santaro/flash-header.imxcfg
index 4505d81ea1f1..eff9f66f9404 100644
--- a/arch/arm/boards/guf-santaro/flash-header.imxcfg
+++ b/arch/arm/boards/guf-santaro/flash-header.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/guf-vincell/flash-header.imxcfg b/arch/arm/boards/guf-vincell/flash-header.imxcfg
index c17dcbab6e64..f5f2eceb5da5 100644
--- a/arch/arm/boards/guf-vincell/flash-header.imxcfg
+++ b/arch/arm/boards/guf-vincell/flash-header.imxcfg
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x71000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg b/arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg
index 4b363241100d..564fa62b91a6 100644
--- a/arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg
+++ b/arch/arm/boards/kamstrup-mx7-concentrator/flash-header-tqma7d.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx7
 loadaddr 0xbfbff000
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx25/flash-header-tx25.imxcfg b/arch/arm/boards/karo-tx25/flash-header-tx25.imxcfg
index 6f8eaf0fc566..0786017a852e 100644
--- a/arch/arm/boards/karo-tx25/flash-header-tx25.imxcfg
+++ b/arch/arm/boards/karo-tx25/flash-header-tx25.imxcfg
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # currently unused in barebox, but useful to generate
 # a imx-image to use with imx-usb-loader
diff --git a/arch/arm/boards/karo-tx28/tx28.h b/arch/arm/boards/karo-tx28/tx28.h
index 5fb1e13412b6..2e14211b7a95 100644
--- a/arch/arm/boards/karo-tx28/tx28.h
+++ b/arch/arm/boards/karo-tx28/tx28.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 void base_board_init(void);
 
diff --git a/arch/arm/boards/karo-tx53/flash-header-tx53-rev1011.imxcfg b/arch/arm/boards/karo-tx53/flash-header-tx53-rev1011.imxcfg
index 4bcb3b8b5eba..158233cc86ae 100644
--- a/arch/arm/boards/karo-tx53/flash-header-tx53-rev1011.imxcfg
+++ b/arch/arm/boards/karo-tx53/flash-header-tx53-rev1011.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x71000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30-samsung.imxcfg b/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30-samsung.imxcfg
index a4e3fab9a377..d7da89beef68 100644
--- a/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30-samsung.imxcfg
+++ b/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30-samsung.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x71000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30.imxcfg b/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30.imxcfg
index 5b6b79f7058d..d516da37702f 100644
--- a/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30.imxcfg
+++ b/arch/arm/boards/karo-tx53/flash-header-tx53-revxx30.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x71000000
 soc imx53
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx6x/1600mhz_4x128mx16.imxcfg b/arch/arm/boards/karo-tx6x/1600mhz_4x128mx16.imxcfg
index 7e244edfd33d..f11387b0232b 100644
--- a/arch/arm/boards/karo-tx6x/1600mhz_4x128mx16.imxcfg
+++ b/arch/arm/boards/karo-tx6x/1600mhz_4x128mx16.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* MDMISC	mirroring	interleaved (row/bank/col) */
 wm 32 MX6_MMDC_P0_MDMISC		0x00000742
 check 32 until_all_bits_set MX6_MMDC_P0_MDMISC 0x00000002
diff --git a/arch/arm/boards/karo-tx6x/flash-header-tx6dl-1g.imxcfg b/arch/arm/boards/karo-tx6x/flash-header-tx6dl-1g.imxcfg
index 7d77f54f00e6..d860a5e2af3d 100644
--- a/arch/arm/boards/karo-tx6x/flash-header-tx6dl-1g.imxcfg
+++ b/arch/arm/boards/karo-tx6x/flash-header-tx6dl-1g.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx6x/flash-header-tx6dl-512m.imxcfg b/arch/arm/boards/karo-tx6x/flash-header-tx6dl-512m.imxcfg
index eb63fa34d315..c327b5f0c149 100644
--- a/arch/arm/boards/karo-tx6x/flash-header-tx6dl-512m.imxcfg
+++ b/arch/arm/boards/karo-tx6x/flash-header-tx6dl-512m.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx6x/flash-header-tx6q-1g.imxcfg b/arch/arm/boards/karo-tx6x/flash-header-tx6q-1g.imxcfg
index e5a1ed233154..9c8196d4da27 100644
--- a/arch/arm/boards/karo-tx6x/flash-header-tx6q-1g.imxcfg
+++ b/arch/arm/boards/karo-tx6x/flash-header-tx6q-1g.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx6x/flash-header-tx6qp-2g.imxcfg b/arch/arm/boards/karo-tx6x/flash-header-tx6qp-2g.imxcfg
index 889416b849b3..c242193a620c 100644
--- a/arch/arm/boards/karo-tx6x/flash-header-tx6qp-2g.imxcfg
+++ b/arch/arm/boards/karo-tx6x/flash-header-tx6qp-2g.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/karo-tx6x/pmic.h b/arch/arm/boards/karo-tx6x/pmic.h
index 2427a52e50c9..5e5616e8c769 100644
--- a/arch/arm/boards/karo-tx6x/pmic.h
+++ b/arch/arm/boards/karo-tx6x/pmic.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <i2c/i2c.h>
 
diff --git a/arch/arm/boards/karo-tx6x/ram-base.imxcfg b/arch/arm/boards/karo-tx6x/ram-base.imxcfg
index e912fb0f2b52..9f15806b5531 100644
--- a/arch/arm/boards/karo-tx6x/ram-base.imxcfg
+++ b/arch/arm/boards/karo-tx6x/ram-base.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 wm 32 MX6_IOM_DRAM_DQM0			0x00020030
 wm 32 MX6_IOM_DRAM_DQM1			0x00020030
 wm 32 MX6_IOM_DRAM_DQM2			0x00020030
diff --git a/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr1.imxcfg b/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr1.imxcfg
index b8a4e824ef5a..5f1f8ef6b00e 100644
--- a/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr1.imxcfg
+++ b/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr1.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 # DCD i.MX50 SoC setup using 256MiB LPDDR1
 # Copyright (C) 2017 Alexander Kurz <akurz at blala.de>
 #
diff --git a/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr2.imxcfg b/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr2.imxcfg
index 527d91dc78c0..520e61be5823 100644
--- a/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr2.imxcfg
+++ b/arch/arm/boards/kindle-mx50/flash-header-kindle-lpddr2.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
 # DCD i.MX50 SoC setup using 256MiB LPDDR2
 # Copyright (C) 2017 Alexander Kurz <akurz at blala.de>
 #
diff --git a/arch/arm/boards/kindle3/flash-header.imxcfg b/arch/arm/boards/kindle3/flash-header.imxcfg
index 74b65d6a5c1f..5ef09200ed69 100644
--- a/arch/arm/boards/kindle3/flash-header.imxcfg
+++ b/arch/arm/boards/kindle3/flash-header.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx35
 loadaddr 0x87eff400
 ivtofs 0x400
diff --git a/arch/arm/boards/kontron-samx6i/flash-header-samx6i-duallite.imxcfg b/arch/arm/boards/kontron-samx6i/flash-header-samx6i-duallite.imxcfg
index db1698d272f7..1ff4caccfaae 100644
--- a/arch/arm/boards/kontron-samx6i/flash-header-samx6i-duallite.imxcfg
+++ b/arch/arm/boards/kontron-samx6i/flash-header-samx6i-duallite.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/kontron-samx6i/flash-header-samx6i-quad.imxcfg b/arch/arm/boards/kontron-samx6i/flash-header-samx6i-quad.imxcfg
index 99608d0fe8fb..a8cc0d512b6b 100644
--- a/arch/arm/boards/kontron-samx6i/flash-header-samx6i-quad.imxcfg
+++ b/arch/arm/boards/kontron-samx6i/flash-header-samx6i-quad.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/kontron-samx6i/mem.h b/arch/arm/boards/kontron-samx6i/mem.h
index 57e3c0ceccab..25faf3849071 100644
--- a/arch/arm/boards/kontron-samx6i/mem.h
+++ b/arch/arm/boards/kontron-samx6i/mem.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __BOARD_KONTRON_SAMX6I_MEM_H
 #define __BOARD_KONTRON_SAMX6I_MEM_H
 
diff --git a/arch/arm/boards/ls1046ardb/ls1046ardb_pbi.cfg b/arch/arm/boards/ls1046ardb/ls1046ardb_pbi.cfg
index 5478217524d0..0ed997031e88 100644
--- a/arch/arm/boards/ls1046ardb/ls1046ardb_pbi.cfg
+++ b/arch/arm/boards/ls1046ardb/ls1046ardb_pbi.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #Configure Scratch register
 09570600 00000000
 09570604 10000000
diff --git a/arch/arm/boards/ls1046ardb/ls1046ardb_qspi_pbi.cfg b/arch/arm/boards/ls1046ardb/ls1046ardb_qspi_pbi.cfg
index 735d46c9f9b7..b9e455da9e1e 100644
--- a/arch/arm/boards/ls1046ardb/ls1046ardb_qspi_pbi.cfg
+++ b/arch/arm/boards/ls1046ardb/ls1046ardb_qspi_pbi.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #QSPI clk
 0957015c 40100000
 #Configure Scratch register
diff --git a/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_emmc.cfg b/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_emmc.cfg
index ccedf87e8495..debb6479a86c 100644
--- a/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_emmc.cfg
+++ b/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_emmc.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #PBL preamble and RCW header
 aa55aa55 01ee0100
 # RCW
diff --git a/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_qspi.cfg b/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_qspi.cfg
index 7b9be0ad3f8e..2167a71b7f1c 100644
--- a/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_qspi.cfg
+++ b/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_qspi.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #PBL preamble and RCW header
 aa55aa55 01ee0100
 # RCW
diff --git a/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_sd.cfg b/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_sd.cfg
index d3b152282f2e..ec18028c4b80 100644
--- a/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_sd.cfg
+++ b/arch/arm/boards/ls1046ardb/ls1046ardb_rcw_sd.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #PBL preamble and RCW header
 aa55aa55 01ee0100
 # RCW
diff --git a/arch/arm/boards/mnt-reform/flash-header-mnt-reform.imxcfg b/arch/arm/boards/mnt-reform/flash-header-mnt-reform.imxcfg
index 80ce03e22c3a..180a44fda361 100644
--- a/arch/arm/boards/mnt-reform/flash-header-mnt-reform.imxcfg
+++ b/arch/arm/boards/mnt-reform/flash-header-mnt-reform.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx8mq
 
 loadaddr 0x007E1000
diff --git a/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg b/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg
index b013173113e4..10606ce29c96 100644
--- a/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg
+++ b/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx8mm
 
 loadaddr 0x007e1000
diff --git a/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg b/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg
index a768874d4076..27a2138e4322 100644
--- a/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg
+++ b/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx8mn
 
 loadaddr 0x912000
diff --git a/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg b/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg
index 7739fe5be6e8..663bd102e9a2 100644
--- a/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg
+++ b/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx8mp
 
 loadaddr 0x920000
diff --git a/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg b/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
index 80ce03e22c3a..180a44fda361 100644
--- a/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
+++ b/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx8mq
 
 loadaddr 0x007E1000
diff --git a/arch/arm/boards/panda/mux.h b/arch/arm/boards/panda/mux.h
index 11f2848a2734..540d4e5d3422 100644
--- a/arch/arm/boards/panda/mux.h
+++ b/arch/arm/boards/panda/mux.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __BOARD_MUX_H
 #define __BOARD_MUX_H
 
diff --git a/arch/arm/boards/phytec-phycard-omap4/mux.h b/arch/arm/boards/phytec-phycard-omap4/mux.h
index 8b1a3d37e9c2..46a2434ad0ee 100644
--- a/arch/arm/boards/phytec-phycard-omap4/mux.h
+++ b/arch/arm/boards/phytec-phycard-omap4/mux.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __BOARD_MUX_H
 #define __BOARD_MUX_H
 
diff --git a/arch/arm/boards/phytec-phycore-imx35/flash-header.imxcfg b/arch/arm/boards/phytec-phycore-imx35/flash-header.imxcfg
index d3049369d9ed..3d690e9732ae 100644
--- a/arch/arm/boards/phytec-phycore-imx35/flash-header.imxcfg
+++ b/arch/arm/boards/phytec-phycore-imx35/flash-header.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx35
 ivtofs 0x400
 loadaddr 0x80000000
diff --git a/arch/arm/boards/phytec-phycore-omap4460/mux.h b/arch/arm/boards/phytec-phycore-omap4460/mux.h
index 64d4478b2c9f..c84ecd32c8a3 100644
--- a/arch/arm/boards/phytec-phycore-omap4460/mux.h
+++ b/arch/arm/boards/phytec-phycore-omap4460/mux.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __BOARD_MUX_H
 #define __BOARD_MUX_H
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib-1bank.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib-1bank.imxcfg
index bb4fbeb20538..d124518930c5 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib-1bank.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib-1bank.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x54597955;	\
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib.imxcfg
index 990c34b3af71..4c3e5b06c9d9 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-1gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x3a3f7975;	\
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-2gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-2gib.imxcfg
index 7c56c24ed757..bb858e874d38 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-2gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3-2gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x54597955;	\
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.h
index 1876a5aa9df0..3d1952fb99fc 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063-512mb.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063-512mb.h
index c4122d245d7d..c7ee1aaeeba3 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063-512mb.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063-512mb.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #define SETUP_MDCFG0			\
 	wm 32 0x021B000C 0x676B52F3
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063.h
index 8e0ab6f58510..984795469302 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 loadaddr 0x80000000
 soc imx6
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ul-512mb.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ul-512mb.imxcfg
index f629a8e7b2f7..225f8a32aa70 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ul-512mb.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ul-512mb.imxcfg
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include "flash-header-phytec-pcl063-512mb.h"
 #include <mach/habv4-imx6-gencsf.h>
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-256mb.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-256mb.imxcfg
index e6871d8534fe..44f103603288 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-256mb.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-256mb.imxcfg
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 #define SETUP_MDCFG0			\
 	wm 32 0x021B000C 0x676B52F3
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-512mb.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-512mb.imxcfg
index d2d71838430e..e976979118a8 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-512mb.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcl063ull-512mb.imxcfg
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 
 #include "flash-header-phytec-pcl063-512mb.h"
 #include <mach/habv4-imx6ull-gencsf.h>
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-1gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-1gib.imxcfg
index 0042909c9592..b2ea8ee0e8d8 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-1gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-1gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x555A7955
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-2gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-2gib.imxcfg
index 8a090369929b..f6895a0587c9 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-2gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058-2gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x8c929b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058.h
index d32ee836a8e3..d213403467bc 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib-32bit.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib-32bit.imxcfg
index c949f985030d..ec5beb937c17 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib-32bit.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib-32bit.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x8c929b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib.imxcfg
index 3ac7e4e7ffa9..a5b3cdc63322 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-1gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x555A7955
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-256mb.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-256mb.imxcfg
index bb8cdc9e4d5e..26755f946a4a 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-256mb.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-256mb.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x3c409b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-512mb.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-512mb.imxcfg
index 5b92e5809c56..cd1d2d185e0d 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-512mb.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl-512mb.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x3c409b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl.h
index e820cbf86b3a..94ca4bcc0eaa 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058dl.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp-1gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp-1gib.imxcfg
index 3ed5b346aeea..0d2d245fc270 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp-1gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp-1gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x555A7955
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp.h
index f3174f9bb70c..aae646e75c56 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcm058qp.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib-1bank.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib-1bank.imxcfg
index 02f3fa7b33b8..77ef6358ec54 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib-1bank.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib-1bank.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0                    \
 	wm 32 0x021b000c 0x565c9b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib.imxcfg
index dd142a20a9f3..dd222ed7a179 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-1gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x3c409b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-2gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-2gib.imxcfg
index 3f9d11dc49b9..de5aab6242cb 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-2gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-2gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0                    \
 	wm 32 0x021b000c 0x565c9b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-4gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-4gib.imxcfg
index fdb1d155380e..c3819e958f22 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-4gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-4gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0                    \
 	wm 32 0x021b000c 0x8c929b85
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-512mb-1bank.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-512mb-1bank.imxcfg
index f4f150ee68ff..08d579241ee9 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-512mb-1bank.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02-512mb-1bank.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x555a7975
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02.h
index 4a9b179f59f3..998411784401 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib-1bank.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib-1bank.imxcfg
index b2a0521bbc87..c851cc2844a6 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib-1bank.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib-1bank.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0                    \
 	wm 32 0x021b000c 0x41447525
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg
index e03e25eae284..7276adad604b 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl-1gib.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x2d307525
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl.h b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl.h
index be4084c1615e..48d2001fb243 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl.h
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02dl.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-128mb-1bank.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-128mb-1bank.imxcfg
index 58c1576219b2..d450ec1efda6 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-128mb-1bank.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-128mb-1bank.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0                    \
         wm 32 0x021b000c 0x2D307525
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-256mb-1bank.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-256mb-1bank.imxcfg
index 9975e2197bea..7f1535d0e0fd 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-256mb-1bank.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-256mb-1bank.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0                    \
         wm 32 0x021b000c 0x2D307525
 
diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-512mb-1bank.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-512mb-1bank.imxcfg
index edc396bc5d33..b6fd2db254f4 100644
--- a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-512mb-1bank.imxcfg
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pfla02s-512mb-1bank.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 #define SETUP_MDCFG0			\
 	wm 32 0x021b000c 0x41447525
 
diff --git a/arch/arm/boards/phytec-som-imx8mq/flash-header-phycore-imx8mq.imxcfg b/arch/arm/boards/phytec-som-imx8mq/flash-header-phycore-imx8mq.imxcfg
index 8921f32110b9..93cf14f26ba5 100644
--- a/arch/arm/boards/phytec-som-imx8mq/flash-header-phycore-imx8mq.imxcfg
+++ b/arch/arm/boards/phytec-som-imx8mq/flash-header-phycore-imx8mq.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx8mq
 
 loadaddr 0x007E1000
diff --git a/arch/arm/boards/protonic-imx6/ddr3-defines.imxcfg b/arch/arm/boards/protonic-imx6/ddr3-defines.imxcfg
index 65bd1bc3c6f0..5bcd6c5f3c01 100644
--- a/arch/arm/boards/protonic-imx6/ddr3-defines.imxcfg
+++ b/arch/arm/boards/protonic-imx6/ddr3-defines.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Timing configuration:
  *
diff --git a/arch/arm/boards/protonic-imx6/flash-header-alti6p.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-alti6p.imxcfg
index c778391d7576..4e71e493aeef 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-alti6p.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-alti6p.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-jozacp.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-jozacp.imxcfg
index ec9fb8410834..472767611dc8 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-jozacp.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-jozacp.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-lanmcu.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-lanmcu.imxcfg
index b08e14983454..e6e37672aa3e 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-lanmcu.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-lanmcu.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-plybas.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-plybas.imxcfg
index dbbb9818b645..16f2f596c773 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-plybas.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-plybas.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-plym2m.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-plym2m.imxcfg
index dbbb9818b645..1692c1e08771 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-plym2m.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-plym2m.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-prti6g.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-prti6g.imxcfg
index ec9fb8410834..472767611dc8 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-prti6g.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-prti6g.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-prti6q.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-prti6q.imxcfg
index 029edc248af6..2d0064e8c1cb 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-prti6q.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-prti6q.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-prtmvt.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-prtmvt.imxcfg
index 1131174f70a6..887811fa4240 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-prtmvt.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-prtmvt.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-prtrvt.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-prtrvt.imxcfg
index dbbb9818b645..16f2f596c773 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-prtrvt.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-prtrvt.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-prtvt7.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-prtvt7.imxcfg
index 019696295de5..7f2662567e6b 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-prtvt7.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-prtvt7.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-prtwd2.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-prtwd2.imxcfg
index 5f847c004dce..035b5f13152c 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-prtwd2.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-prtwd2.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-prtwd3.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-prtwd3.imxcfg
index 054043cc800e..be2b9883a8cc 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-prtwd3.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-prtwd3.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-victgo.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-victgo.imxcfg
index d3de7b6aab4f..e3f0f0a19a7c 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-victgo.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-victgo.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-vicut1.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-vicut1.imxcfg
index 54f655c4c2e5..b86a32be0c2c 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-vicut1.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-vicut1.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-vicut1q.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-vicut1q.imxcfg
index f7e75b47bf8d..3abb21b70e32 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-vicut1q.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-vicut1q.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/flash-header-vicutp.imxcfg b/arch/arm/boards/protonic-imx6/flash-header-vicutp.imxcfg
index e21827923960..a8178fe2580b 100644
--- a/arch/arm/boards/protonic-imx6/flash-header-vicutp.imxcfg
+++ b/arch/arm/boards/protonic-imx6/flash-header-vicutp.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x10000000
 ivtofs 0x400
diff --git a/arch/arm/boards/protonic-imx6/lpddr2-defines.imxcfg b/arch/arm/boards/protonic-imx6/lpddr2-defines.imxcfg
index 29c42cc697c9..b54b9542bd68 100644
--- a/arch/arm/boards/protonic-imx6/lpddr2-defines.imxcfg
+++ b/arch/arm/boards/protonic-imx6/lpddr2-defines.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Timing configuration:
  *
diff --git a/arch/arm/boards/protonic-imx6/padsetup-dl.imxcfg b/arch/arm/boards/protonic-imx6/padsetup-dl.imxcfg
index f60d37f63e2e..380ce8863cf4 100644
--- a/arch/arm/boards/protonic-imx6/padsetup-dl.imxcfg
+++ b/arch/arm/boards/protonic-imx6/padsetup-dl.imxcfg
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 /*
  * Some defines for PAD setup:
diff --git a/arch/arm/boards/protonic-imx6/padsetup-q.imxcfg b/arch/arm/boards/protonic-imx6/padsetup-q.imxcfg
index f5fa3e8d2857..c58a481e13a2 100644
--- a/arch/arm/boards/protonic-imx6/padsetup-q.imxcfg
+++ b/arch/arm/boards/protonic-imx6/padsetup-q.imxcfg
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 /*
  * Some defines for PAD setup:
diff --git a/arch/arm/boards/protonic-imx6/padsetup-ul.imxcfg b/arch/arm/boards/protonic-imx6/padsetup-ul.imxcfg
index e36601942d10..9cdc9ac9a3c8 100644
--- a/arch/arm/boards/protonic-imx6/padsetup-ul.imxcfg
+++ b/arch/arm/boards/protonic-imx6/padsetup-ul.imxcfg
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 /*
  * Some defines for PAD setup:
diff --git a/arch/arm/boards/protonic-imx8m/flash-header-prt8mm.imxcfg b/arch/arm/boards/protonic-imx8m/flash-header-prt8mm.imxcfg
index b013173113e4..10606ce29c96 100644
--- a/arch/arm/boards/protonic-imx8m/flash-header-prt8mm.imxcfg
+++ b/arch/arm/boards/protonic-imx8m/flash-header-prt8mm.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx8mm
 
 loadaddr 0x007e1000
diff --git a/arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg b/arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg
index 4bb615ebb0f6..da4cd4bebf77 100644
--- a/arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg
+++ b/arch/arm/boards/skov-imx6/flash-header-mx6-skov-imx6.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x00907000
 max_load_size 0x11000
diff --git a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i1.imxcfg b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i1.imxcfg
index 2c6a32eed425..374ea2e8a20b 100644
--- a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i1.imxcfg
+++ b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i1.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2.imxcfg b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2.imxcfg
index 7f9b2a3988ff..7c1b17f6f266 100644
--- a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2.imxcfg
+++ b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2eX.imxcfg b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2eX.imxcfg
index 7f75a17a35d3..f777784e44af 100644
--- a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2eX.imxcfg
+++ b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i2eX.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i4.imxcfg b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i4.imxcfg
index 9d5bc03c965d..2a12b053408a 100644
--- a/arch/arm/boards/solidrun-microsom/flash-header-microsom-i4.imxcfg
+++ b/arch/arm/boards/solidrun-microsom/flash-header-microsom-i4.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-256.imxcfg b/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-256.imxcfg
index 6d2d37de59d2..00ac4ef8ec74 100644
--- a/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-256.imxcfg
+++ b/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-256.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x80000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-512.imxcfg b/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-512.imxcfg
index 201493e6a38c..915203950778 100644
--- a/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-512.imxcfg
+++ b/arch/arm/boards/technexion-pico-hobbit/flash-header-imx6ul-pico-hobbit-512.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x80000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg b/arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg
index 5f91bed6f377..61425976ec59 100644
--- a/arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg
+++ b/arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 loadaddr 0x00907000
 soc imx6
 max_load_size 0x11000
diff --git a/arch/arm/boards/tqma53/flash-header-tq-tqma53-1gib.imxcfg b/arch/arm/boards/tqma53/flash-header-tq-tqma53-1gib.imxcfg
index 50a8f27dc5af..6aeff80de5b6 100644
--- a/arch/arm/boards/tqma53/flash-header-tq-tqma53-1gib.imxcfg
+++ b/arch/arm/boards/tqma53/flash-header-tq-tqma53-1gib.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #define SETUP_512MIB_1GIB \
 	wm 32 0x63fd9018 0x00011740; \
 	wm 32 0x63fd9000 0xc3190000
diff --git a/arch/arm/boards/tqma53/flash-header-tq-tqma53-512mib.imxcfg b/arch/arm/boards/tqma53/flash-header-tq-tqma53-512mib.imxcfg
index 4c8eed40d2af..2431d6f03998 100644
--- a/arch/arm/boards/tqma53/flash-header-tq-tqma53-512mib.imxcfg
+++ b/arch/arm/boards/tqma53/flash-header-tq-tqma53-512mib.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #define SETUP_512MIB_1GIB \
 	wm 32 0x63fd9018 0x00101740; \
 	wm 32 0x63fd9000 0x83190000
diff --git a/arch/arm/boards/tqma53/flash-header-tq-tqma53.h b/arch/arm/boards/tqma53/flash-header-tq-tqma53.h
index b9492bbcb302..a11855f926b8 100644
--- a/arch/arm/boards/tqma53/flash-header-tq-tqma53.h
+++ b/arch/arm/boards/tqma53/flash-header-tq-tqma53.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx53
 loadaddr 0x70000000
 ivtofs 0x400
diff --git a/arch/arm/boards/tqma53/flash-header.imxcfg b/arch/arm/boards/tqma53/flash-header.imxcfg
index bbe2300ece53..6981a230a56c 100644
--- a/arch/arm/boards/tqma53/flash-header.imxcfg
+++ b/arch/arm/boards/tqma53/flash-header.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx53
 loadaddr 0x70000000
 ivtofs 0x400
diff --git a/arch/arm/boards/tqma6x/flash-header-tqma6dl.imxcfg b/arch/arm/boards/tqma6x/flash-header-tqma6dl.imxcfg
index 4f557d5db56c..9f8d9c0d2624 100644
--- a/arch/arm/boards/tqma6x/flash-header-tqma6dl.imxcfg
+++ b/arch/arm/boards/tqma6x/flash-header-tqma6dl.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/tqma6x/flash-header-tqma6q.imxcfg b/arch/arm/boards/tqma6x/flash-header-tqma6q.imxcfg
index deda53b46433..b0923e77f9ea 100644
--- a/arch/arm/boards/tqma6x/flash-header-tqma6q.imxcfg
+++ b/arch/arm/boards/tqma6x/flash-header-tqma6q.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg
index 0a04afa770b6..e4c293ab778d 100644
--- a/arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg
+++ b/arch/arm/boards/tqmls1046a/tqmls1046a_pbi.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
 #Configure QSPI clock
 0957015c 40100000
 #Configure Scratch register
diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg
index 2df229c56c2c..490d45af9e31 100644
--- a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg
+++ b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_qspi_3333_5559.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
 # RCW values
 #   0:  1 - SYS_PLL_CFG              :       0 [0x0 / 0b00]
 #   2:  6 - SYS_PLL_RAT              :       6 [0x6 / 0b00110]
diff --git a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg
index 72ab1cd7d7ac..645dc4fd22ed 100644
--- a/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg
+++ b/arch/arm/boards/tqmls1046a/tqmls1046a_rcw_sd_3333_5559.cfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
 # RCW values
 #   0:  1 - SYS_PLL_CFG              :       0 [0x0 / 0b00]
 #   2:  6 - SYS_PLL_RAT              :       6 [0x6 / 0b00110]
diff --git a/arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg b/arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg
index a349b1022b86..6246e17a7387 100644
--- a/arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg
+++ b/arch/arm/boards/udoo-neo/flash-header-mx6sx-udoo-neo_full.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * These values are taken from:
  * repository: https://github.com/UDOOboard/uboot-imx
diff --git a/arch/arm/boards/udoo/flash-header-mx6-udoo.imxcfg b/arch/arm/boards/udoo/flash-header-mx6-udoo.imxcfg
index fc88a0b8b4d0..0d364bf8ce52 100644
--- a/arch/arm/boards/udoo/flash-header-mx6-udoo.imxcfg
+++ b/arch/arm/boards/udoo/flash-header-mx6-udoo.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx6
 loadaddr 0x20000000
 ivtofs 0x400
diff --git a/arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg b/arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg
index 50968d79409f..b0a31a0b96f6 100644
--- a/arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg
+++ b/arch/arm/boards/variscite-mx6/flash-header-variscite.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 loadaddr 0x10000000
 soc imx6
 ivtofs 0x400
diff --git a/arch/arm/boards/zii-imx51-rdu1/flash-header-imx51-zii-rdu1.imxcfg b/arch/arm/boards/zii-imx51-rdu1/flash-header-imx51-zii-rdu1.imxcfg
index 5674e7a6e139..6d40976b83c0 100644
--- a/arch/arm/boards/zii-imx51-rdu1/flash-header-imx51-zii-rdu1.imxcfg
+++ b/arch/arm/boards/zii-imx51-rdu1/flash-header-imx51-zii-rdu1.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx51
 loadaddr 0x90000000
 ivtofs 0x400
diff --git a/arch/arm/boards/zii-imx6q-rdu2/flash-header-rdu2.imxcfg b/arch/arm/boards/zii-imx6q-rdu2/flash-header-rdu2.imxcfg
index fcfef9c23477..0b37ab248f90 100644
--- a/arch/arm/boards/zii-imx6q-rdu2/flash-header-rdu2.imxcfg
+++ b/arch/arm/boards/zii-imx6q-rdu2/flash-header-rdu2.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx6
 loadaddr 0x00907000
 max_load_size 0x31000
diff --git a/arch/arm/boards/zii-imx7d-dev/flash-header-zii-imx7d-dev.imxcfg b/arch/arm/boards/zii-imx7d-dev/flash-header-zii-imx7d-dev.imxcfg
index 022f9711b252..05f95bbed11e 100644
--- a/arch/arm/boards/zii-imx7d-dev/flash-header-zii-imx7d-dev.imxcfg
+++ b/arch/arm/boards/zii-imx7d-dev/flash-header-zii-imx7d-dev.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc imx7
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg b/arch/arm/boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg
index 8921f32110b9..93cf14f26ba5 100644
--- a/arch/arm/boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg
+++ b/arch/arm/boards/zii-imx8mq-dev/flash-header-zii-imx8mq-dev.imxcfg
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
 soc imx8mq
 
 loadaddr 0x007E1000
diff --git a/arch/arm/boards/zii-vf610-dev/flash-header-zii-vf610-dev.imxcfg b/arch/arm/boards/zii-vf610-dev/flash-header-zii-vf610-dev.imxcfg
index 4b73da4c191d..617245b2d372 100644
--- a/arch/arm/boards/zii-vf610-dev/flash-header-zii-vf610-dev.imxcfg
+++ b/arch/arm/boards/zii-vf610-dev/flash-header-zii-vf610-dev.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 soc vf610
 loadaddr 0x80000000
 ivtofs 0x400
diff --git a/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-cr-default.imxcfg b/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-cr-default.imxcfg
index 8c411ddc7ecf..ab70fa7bd938 100644
--- a/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-cr-default.imxcfg
+++ b/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-cr-default.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
 
  The following table contains DDR3 memory timing parameters derived
@@ -128,4 +130,4 @@ wm 32 DDRMC_CR138 0x01000100
 wm 32 DDRMC_CR154 0x682c4000
 wm 32 DDRMC_CR155 0x00000009
 wm 32 DDRMC_CR158 0x00000006
-wm 32 DDRMC_CR161 0x00010606
\ No newline at end of file
+wm 32 DDRMC_CR161 0x00010606
diff --git a/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-pll2-400mhz.imxcfg b/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-pll2-400mhz.imxcfg
index 74d119b59ed3..e235b0990b74 100644
--- a/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-pll2-400mhz.imxcfg
+++ b/arch/arm/mach-imx/include/mach/flash-header/vf610-ddr-pll2-400mhz.imxcfg
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Ungate all IP block clocks
  */
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:36 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:36 +0100
Subject: [PATCH 08/11] arch: add SPDX-License-Identifier to all headers
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-9-a.fatoum@pengutronix.de>

Record GPL-2.0-only as license for all files lacking an explicit license
statement.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/boards/archosg9/archos_features.h                  | 2 ++
 arch/arm/boards/archosg9/mux.h                              | 2 ++
 arch/arm/boards/at91rm9200ek/config.h                       | 2 ++
 arch/arm/boards/beaglebone/beaglebone.h                     | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_auto.h               | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_defines.h            | 2 ++
 arch/arm/boards/friendlyarm-mini6410/config.h               | 2 ++
 arch/arm/boards/friendlyarm-tiny210/config.h                | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/config.h               | 2 ++
 arch/arm/boards/raspberry-pi/lowlevel.h                     | 2 ++
 arch/arm/boards/skov-imx6/version.h                         | 2 ++
 arch/arm/cpu/entry.h                                        | 2 ++
 arch/arm/cpu/mmu-common.h                                   | 4 +++-
 arch/arm/cpu/mmu.h                                          | 2 ++
 arch/arm/cpu/mmu_64.h                                       | 1 +
 arch/arm/include/asm/armlinux.h                             | 2 ++
 arch/arm/include/asm/asm-offsets.h                          | 4 +++-
 arch/arm/include/asm/assembler64.h                          | 4 +++-
 arch/arm/include/asm/barebox-arm-head.h                     | 2 ++
 arch/arm/include/asm/bitops.h                               | 2 ++
 arch/arm/include/asm/bitsperlong.h                          | 2 ++
 arch/arm/include/asm/byteorder.h                            | 2 ++
 arch/arm/include/asm/cache.h                                | 2 ++
 arch/arm/include/asm/common.h                               | 2 ++
 arch/arm/include/asm/cputype.h                              | 2 ++
 arch/arm/include/asm/elf.h                                  | 2 ++
 arch/arm/include/asm/gic.h                                  | 2 ++
 arch/arm/include/asm/hardware/arm_timer.h                   | 2 ++
 arch/arm/include/asm/io.h                                   | 2 ++
 arch/arm/include/asm/linkage.h                              | 2 ++
 arch/arm/include/asm/memory.h                               | 2 ++
 arch/arm/include/asm/mmu.h                                  | 2 ++
 arch/arm/include/asm/module.h                               | 2 ++
 arch/arm/include/asm/posix_types.h                          | 2 ++
 arch/arm/include/asm/sections.h                             | 2 ++
 arch/arm/include/asm/secure.h                               | 2 ++
 arch/arm/include/asm/semihosting.h                          | 2 ++
 arch/arm/include/asm/stacktrace.h                           | 2 ++
 arch/arm/include/asm/string.h                               | 2 ++
 arch/arm/include/asm/swab.h                                 | 2 ++
 arch/arm/include/asm/syscounter.h                           | 4 +++-
 arch/arm/include/asm/system.h                               | 2 ++
 arch/arm/include/asm/system_info.h                          | 2 ++
 arch/arm/include/asm/types.h                                | 2 ++
 arch/arm/include/asm/unaligned.h                            | 2 ++
 arch/arm/mach-at91/include/mach/at91sam926x.h               | 2 ++
 arch/arm/mach-at91/include/mach/barebox-arm-head.h          | 2 ++
 arch/arm/mach-at91/include/mach/early_udelay.h              | 2 ++
 arch/arm/mach-at91/include/mach/sama5d2_ll.h                | 2 ++
 arch/arm/mach-at91/include/mach/xload.h                     | 2 ++
 arch/arm/mach-clps711x/include/mach/devices.h               | 2 ++
 arch/arm/mach-ep93xx/include/mach/barebox.lds.h             | 1 +
 arch/arm/mach-imx/include/mach/atf.h                        | 2 ++
 arch/arm/mach-imx/include/mach/bbu.h                        | 2 ++
 arch/arm/mach-imx/include/mach/ccm.h                        | 4 +++-
 arch/arm/mach-imx/include/mach/clock.h                      | 2 ++
 arch/arm/mach-imx/include/mach/debug_ll.h                   | 2 ++
 arch/arm/mach-imx/include/mach/devices-imx1.h               | 2 ++
 arch/arm/mach-imx/include/mach/devices-imx21.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx25.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx27.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx31.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx35.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx50.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx51.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx53.h              | 1 +
 arch/arm/mach-imx/include/mach/devices-imx6.h               | 2 ++
 arch/arm/mach-imx/include/mach/devices.h                    | 1 +
 arch/arm/mach-imx/include/mach/esdctl-v4.h                  | 2 ++
 arch/arm/mach-imx/include/mach/esdctl.h                     | 2 ++
 arch/arm/mach-imx/include/mach/generic.h                    | 2 ++
 arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h         | 2 ++
 arch/arm/mach-imx/include/mach/habv4-imx6-gencsf-template.h | 2 ++
 arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h          | 1 +
 arch/arm/mach-imx/include/mach/habv4-imx6ull-gencsf.h       | 1 +
 arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h          | 2 ++
 arch/arm/mach-imx/include/mach/imx-gpio.h                   | 2 ++
 arch/arm/mach-imx/include/mach/imx-header.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx-nand.h                   | 2 ++
 arch/arm/mach-imx/include/mach/imx-pll.h                    | 2 ++
 arch/arm/mach-imx/include/mach/imx1-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx21-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx25-fusemap.h              | 2 ++
 arch/arm/mach-imx/include/mach/imx27-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx5.h                       | 2 ++
 arch/arm/mach-imx/include/mach/imx50-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx51-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx53-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx6-fusemap.h               | 2 ++
 arch/arm/mach-imx/include/mach/imx6-mmdc.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx6-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx6.h                       | 2 ++
 arch/arm/mach-imx/include/mach/imx7-ccm-regs.h              | 2 ++
 arch/arm/mach-imx/include/mach/imx7-regs.h                  | 2 ++
 arch/arm/mach-imx/include/mach/imx7.h                       | 4 +++-
 arch/arm/mach-imx/include/mach/imx8m-ccm-regs.h             | 2 ++
 arch/arm/mach-imx/include/mach/imx8m-regs.h                 | 2 ++
 arch/arm/mach-imx/include/mach/imx8mm-regs.h                | 2 ++
 arch/arm/mach-imx/include/mach/imx8mp-regs.h                | 2 ++
 arch/arm/mach-imx/include/mach/imx8mq-regs.h                | 2 ++
 arch/arm/mach-imx/include/mach/imx8mq.h                     | 2 ++
 arch/arm/mach-imx/include/mach/imx_cpu_types.h              | 2 ++
 arch/arm/mach-imx/include/mach/imxfb.h                      | 2 ++
 arch/arm/mach-imx/include/mach/iomux-mx1.h                  | 2 ++
 arch/arm/mach-imx/include/mach/iomux-mx8m.h                 | 2 ++
 arch/arm/mach-imx/include/mach/iomux-v1.h                   | 2 ++
 arch/arm/mach-imx/include/mach/ocotp-fusemap.h              | 2 ++
 arch/arm/mach-imx/include/mach/ocotp.h                      | 2 ++
 arch/arm/mach-imx/include/mach/reset-reason.h               | 2 ++
 arch/arm/mach-imx/include/mach/revision.h                   | 2 ++
 arch/arm/mach-imx/include/mach/spi.h                        | 1 +
 arch/arm/mach-imx/include/mach/usb.h                        | 2 ++
 arch/arm/mach-imx/include/mach/vf610-ddrmc.h                | 2 ++
 arch/arm/mach-imx/include/mach/vf610-fusemap.h              | 2 ++
 arch/arm/mach-imx/include/mach/vf610.h                      | 2 ++
 arch/arm/mach-imx/include/mach/weim.h                       | 2 ++
 arch/arm/mach-imx/include/mach/xload.h                      | 2 ++
 arch/arm/mach-layerscape/include/mach/bbu.h                 | 4 +++-
 arch/arm/mach-layerscape/include/mach/debug_ll.h            | 2 ++
 arch/arm/mach-layerscape/include/mach/errata.h              | 2 ++
 arch/arm/mach-layerscape/include/mach/layerscape.h          | 2 ++
 arch/arm/mach-layerscape/include/mach/lowlevel.h            | 2 ++
 arch/arm/mach-layerscape/include/mach/xload.h               | 2 ++
 arch/arm/mach-mvebu/include/mach/barebox-arm-head.h         | 2 ++
 arch/arm/mach-mvebu/include/mach/bbu.h                      | 2 ++
 arch/arm/mach-mxs/include/mach/debug_ll.h                   | 2 ++
 arch/arm/mach-mxs/include/mach/devices.h                    | 2 ++
 arch/arm/mach-mxs/include/mach/imx23.h                      | 4 +++-
 arch/arm/mach-mxs/include/mach/imx28.h                      | 4 +++-
 arch/arm/mach-mxs/include/mach/power.h                      | 2 ++
 arch/arm/mach-mxs/include/mach/revision.h                   | 2 ++
 arch/arm/mach-mxs/include/mach/usb.h                        | 2 ++
 arch/arm/mach-nomadik/include/mach/fsmc.h                   | 2 ++
 arch/arm/mach-nomadik/include/mach/nand.h                   | 2 ++
 arch/arm/mach-omap/include/mach/am33xx-generic.h            | 2 ++
 arch/arm/mach-omap/include/mach/am3xxx-silicon.h            | 4 +++-
 arch/arm/mach-omap/include/mach/bbu.h                       | 2 ++
 arch/arm/mach-omap/include/mach/devices.h                   | 2 ++
 arch/arm/mach-omap/include/mach/generic.h                   | 2 ++
 arch/arm/mach-omap/include/mach/mcspi.h                     | 2 ++
 arch/arm/mach-omap/include/mach/omap-fb.h                   | 2 ++
 arch/arm/mach-omap/include/mach/omap3-devices.h             | 2 ++
 arch/arm/mach-omap/include/mach/omap3-generic.h             | 2 ++
 arch/arm/mach-omap/include/mach/omap4-clock.h               | 2 ++
 arch/arm/mach-omap/include/mach/omap4-devices.h             | 2 ++
 arch/arm/mach-omap/include/mach/omap4-generic.h             | 2 ++
 arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h         | 2 ++
 arch/arm/mach-pxa/include/mach/mci_pxa2xx.h                 | 2 ++
 arch/arm/mach-pxa/include/mach/mfp-pxa27x.h                 | 2 ++
 arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h                 | 2 ++
 arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h                 | 2 ++
 arch/arm/mach-pxa/include/mach/pxa25x-regs.h                | 2 ++
 arch/arm/mach-pxa/include/mach/pxa27x-regs.h                | 2 ++
 arch/arm/mach-pxa/include/mach/pxafb.h                      | 2 ++
 arch/arm/mach-pxa/include/mach/regs-intc.h                  | 2 ++
 arch/arm/mach-pxa/include/mach/regs-lcd.h                   | 2 ++
 arch/arm/mach-pxa/include/mach/regs-ost.h                   | 2 ++
 arch/arm/mach-pxa/include/mach/udc_pxa2xx.h                 | 2 ++
 arch/arm/mach-rockchip/include/mach/atf.h                   | 2 ++
 arch/arm/mach-rockchip/include/mach/bbu.h                   | 2 ++
 arch/arm/mach-rockchip/include/mach/debug_ll.h              | 2 ++
 arch/arm/mach-rockchip/include/mach/rk3568-regs.h           | 2 ++
 arch/arm/mach-rockchip/include/mach/rockchip.h              | 2 ++
 arch/arm/mach-samsung/include/mach/bbu.h                    | 2 ++
 arch/arm/mach-socfpga/include/mach/arria10-xload.h          | 2 ++
 arch/arm/mach-socfpga/include/mach/barebox-arm-head.h       | 2 ++
 arch/arm/mach-socfpga/include/mach/cyclone5-regs.h          | 2 ++
 arch/arm/mach-socfpga/include/mach/cyclone5-sdram-config.h  | 2 ++
 arch/arm/mach-socfpga/include/mach/debug_ll.h               | 2 ++
 arch/arm/mach-socfpga/include/mach/generic.h                | 2 ++
 arch/arm/mach-socfpga/include/mach/lowlevel.h               | 2 ++
 arch/arm/mach-socfpga/include/mach/pll_config.h             | 2 ++
 arch/arm/mach-stm32mp/include/mach/bbu.h                    | 2 ++
 arch/arm/mach-stm32mp/include/mach/bsec.h                   | 2 ++
 arch/arm/mach-stm32mp/include/mach/debug_ll.h               | 2 ++
 arch/arm/mach-stm32mp/include/mach/entry.h                  | 2 ++
 arch/arm/mach-stm32mp/include/mach/smc.h                    | 2 ++
 arch/arm/mach-uemd/include/mach/hardware.h                  | 2 ++
 arch/arm/mach-versatile/include/mach/init.h                 | 1 +
 arch/arm/mach-zynq/include/mach/debug_ll.h                  | 2 ++
 arch/arm/mach-zynq/include/mach/zynq-flash-header.h         | 2 ++
 arch/mips/include/asm/asm-offsets.h                         | 2 ++
 arch/mips/include/asm/bitsperlong.h                         | 2 ++
 arch/mips/include/asm/cache.h                               | 2 ++
 arch/mips/include/asm/cpu.h                                 | 2 ++
 arch/mips/include/asm/dma-mapping.h                         | 2 ++
 arch/mips/include/asm/io.h                                  | 2 ++
 arch/mips/include/asm/memory.h                              | 2 ++
 arch/mips/include/asm/mmu.h                                 | 2 ++
 arch/mips/mach-ar231x/include/mach/pbl_macros.h             | 2 ++
 arch/mips/mach-ath79/include/mach/pbl_ll_init_ar9344_1.1.h  | 2 ++
 arch/mips/mach-ath79/include/mach/pbl_ll_init_qca4531.h     | 2 ++
 arch/mips/mach-ath79/include/mach/pbl_macros.h              | 2 ++
 arch/mips/mach-loongson/include/mach/pbl_macros.h           | 2 ++
 arch/mips/mach-malta/include/mach/mach-gt64120.h            | 2 ++
 arch/mips/mach-xburst/include/mach/devices.h                | 2 ++
 arch/openrisc/boards/generic/config.h                       | 1 +
 arch/openrisc/include/asm/bitsperlong.h                     | 2 ++
 arch/openrisc/include/asm/byteorder.h                       | 2 ++
 arch/openrisc/include/asm/common.h                          | 2 ++
 arch/openrisc/include/asm/linkage.h                         | 2 ++
 arch/openrisc/include/asm/mmu.h                             | 2 ++
 arch/openrisc/include/asm/posix_types.h                     | 2 ++
 arch/openrisc/include/asm/sections.h                        | 2 ++
 arch/openrisc/include/asm/string.h                          | 2 ++
 arch/openrisc/include/asm/swab.h                            | 2 ++
 arch/powerpc/include/asm/atomic.h                           | 2 ++
 arch/powerpc/include/asm/bitops.h                           | 2 ++
 arch/powerpc/include/asm/bitsperlong.h                      | 2 ++
 arch/powerpc/include/asm/cache.h                            | 2 ++
 arch/powerpc/include/asm/common.h                           | 2 ++
 arch/powerpc/include/asm/io.h                               | 2 ++
 arch/powerpc/include/asm/mmu.h                              | 2 ++
 arch/powerpc/include/asm/module.h                           | 2 ++
 arch/powerpc/include/asm/pci_io.h                           | 2 ++
 arch/powerpc/include/asm/posix_types.h                      | 2 ++
 arch/powerpc/include/asm/processor.h                        | 2 ++
 arch/powerpc/include/asm/ptrace.h                           | 2 ++
 arch/powerpc/include/asm/sections.h                         | 2 ++
 arch/powerpc/include/asm/sigcontext.h                       | 2 ++
 arch/powerpc/include/asm/signal.h                           | 2 ++
 arch/powerpc/include/asm/status_led.h                       | 2 ++
 arch/powerpc/include/asm/string.h                           | 2 ++
 arch/powerpc/include/asm/types.h                            | 2 ++
 arch/powerpc/include/asm/unaligned.h                        | 2 ++
 arch/powerpc/mach-mpc5xxx/include/mach/clock.h              | 2 ++
 arch/powerpc/mach-mpc5xxx/include/mach/sdma.h               | 2 ++
 arch/powerpc/mach-mpc85xx/include/mach/clock.h              | 2 ++
 arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h            | 2 ++
 arch/riscv/include/asm/asm-offsets.h                        | 2 ++
 arch/riscv/include/asm/bitsperlong.h                        | 2 ++
 arch/riscv/include/asm/byteorder.h                          | 2 ++
 arch/riscv/include/asm/io.h                                 | 2 ++
 arch/riscv/include/asm/mmu.h                                | 2 ++
 arch/riscv/include/asm/posix_types.h                        | 2 ++
 arch/riscv/include/asm/swab.h                               | 2 ++
 arch/riscv/include/asm/types.h                              | 2 ++
 arch/riscv/include/asm/unaligned.h                          | 2 ++
 arch/sandbox/include/asm/bitsperlong.h                      | 2 ++
 arch/sandbox/include/asm/byteorder.h                        | 2 ++
 arch/sandbox/include/asm/common.h                           | 2 ++
 arch/sandbox/include/asm/elf.h                              | 2 ++
 arch/sandbox/include/asm/io.h                               | 2 ++
 arch/sandbox/include/asm/mmu.h                              | 2 ++
 arch/sandbox/include/asm/posix_types.h                      | 2 ++
 arch/sandbox/include/asm/sections.h                         | 2 ++
 arch/sandbox/include/asm/string.h                           | 2 ++
 arch/sandbox/include/asm/swab.h                             | 2 ++
 arch/sandbox/include/asm/types.h                            | 2 ++
 arch/sandbox/include/asm/unaligned.h                        | 2 ++
 arch/sandbox/mach-sandbox/include/mach/hostfile.h           | 2 ++
 arch/sandbox/mach-sandbox/include/mach/linux.h              | 2 ++
 arch/x86/include/asm/bitsperlong.h                          | 2 ++
 arch/x86/include/asm/elf.h                                  | 2 ++
 arch/x86/include/asm/io.h                                   | 2 ++
 arch/x86/include/asm/linkage.h                              | 2 ++
 arch/x86/include/asm/mmu.h                                  | 2 ++
 arch/x86/include/asm/posix_types.h                          | 2 ++
 arch/x86/include/asm/sections.h                             | 2 ++
 arch/x86/include/asm/swab.h                                 | 2 ++
 arch/x86/include/asm/types.h                                | 2 ++
 arch/x86/include/asm/unaligned.h                            | 2 ++
 arch/x86/mach-efi/include/mach/debug_ll.h                   | 2 ++
 263 files changed, 520 insertions(+), 10 deletions(-)

diff --git a/arch/arm/boards/archosg9/archos_features.h b/arch/arm/boards/archosg9/archos_features.h
index 5769c6c668be..f46b9e9eb884 100644
--- a/arch/arm/boards/archosg9/archos_features.h
+++ b/arch/arm/boards/archosg9/archos_features.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ARCHOS_FEATURES_H
 #define __ARCHOS_FEATURES_H
 
diff --git a/arch/arm/boards/archosg9/mux.h b/arch/arm/boards/archosg9/mux.h
index 4ee541587172..d4b0c9da861d 100644
--- a/arch/arm/boards/archosg9/mux.h
+++ b/arch/arm/boards/archosg9/mux.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _MUX_H
 #define _MUX_H
 
diff --git a/arch/arm/boards/at91rm9200ek/config.h b/arch/arm/boards/at91rm9200ek/config.h
index 5f4f6fe1ae2f..a3a0be18ec91 100644
--- a/arch/arm/boards/at91rm9200ek/config.h
+++ b/arch/arm/boards/at91rm9200ek/config.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
diff --git a/arch/arm/boards/beaglebone/beaglebone.h b/arch/arm/boards/beaglebone/beaglebone.h
index a4f48e5b0bb0..9f1f9066993c 100644
--- a/arch/arm/boards/beaglebone/beaglebone.h
+++ b/arch/arm/boards/beaglebone/beaglebone.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __BOARD_BEAGLEBONE_H
 #define __BOARD_BEAGLEBONE_H
 
diff --git a/arch/arm/boards/ebv-socrates/sequencer_auto.h b/arch/arm/boards/ebv-socrates/sequencer_auto.h
index 59aa9cf816ee..d52e19548a8a 100644
--- a/arch/arm/boards/ebv-socrates/sequencer_auto.h
+++ b/arch/arm/boards/ebv-socrates/sequencer_auto.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #define __RW_MGR_ac_mrs1 0x04
 #define __RW_MGR_ac_mrs3 0x06
 #define __RW_MGR_ac_write_bank_0_col_0_nodata_wl_1 0x1C
diff --git a/arch/arm/boards/ebv-socrates/sequencer_defines.h b/arch/arm/boards/ebv-socrates/sequencer_defines.h
index 1ebbc4801148..bef98641aa2a 100644
--- a/arch/arm/boards/ebv-socrates/sequencer_defines.h
+++ b/arch/arm/boards/ebv-socrates/sequencer_defines.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _SEQUENCER_DEFINES_H_
 #define _SEQUENCER_DEFINES_H_
 
diff --git a/arch/arm/boards/friendlyarm-mini6410/config.h b/arch/arm/boards/friendlyarm-mini6410/config.h
index ee38192041ef..87b6ea4a297f 100644
--- a/arch/arm/boards/friendlyarm-mini6410/config.h
+++ b/arch/arm/boards/friendlyarm-mini6410/config.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* FriendlyARM Mini6410 specific global settings */
 
 #ifndef _MINI6410_CONFIG_H_
diff --git a/arch/arm/boards/friendlyarm-tiny210/config.h b/arch/arm/boards/friendlyarm-tiny210/config.h
index 86aedf0a640e..7437e6bdddb4 100644
--- a/arch/arm/boards/friendlyarm-tiny210/config.h
+++ b/arch/arm/boards/friendlyarm-tiny210/config.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #define S5PCXX_CLOCK_REFERENCE 24000000
 
 #define set_pll(mdiv, pdiv, sdiv)	(1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
diff --git a/arch/arm/boards/friendlyarm-tiny6410/config.h b/arch/arm/boards/friendlyarm-tiny6410/config.h
index 04f68579edc4..22692a30253a 100644
--- a/arch/arm/boards/friendlyarm-tiny6410/config.h
+++ b/arch/arm/boards/friendlyarm-tiny6410/config.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* FriendlyARM Tiny6410 specific global settings */
 
 #ifndef _TINY6410_CONFIG_H_
diff --git a/arch/arm/boards/raspberry-pi/lowlevel.h b/arch/arm/boards/raspberry-pi/lowlevel.h
index 9ef9135b2d06..eacf973fb6fa 100644
--- a/arch/arm/boards/raspberry-pi/lowlevel.h
+++ b/arch/arm/boards/raspberry-pi/lowlevel.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ARCH_ARM_BOARDS_LOWLEVEL_H__
 #define __ARCH_ARM_BOARDS_LOWLEVEL_H__
 
diff --git a/arch/arm/boards/skov-imx6/version.h b/arch/arm/boards/skov-imx6/version.h
index 008410490be3..a5d205fe2e0d 100644
--- a/arch/arm/boards/skov-imx6/version.h
+++ b/arch/arm/boards/skov-imx6/version.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __SKOV_VERSION_H
 #define __SKOV_VERSION_H
 
diff --git a/arch/arm/cpu/entry.h b/arch/arm/cpu/entry.h
index 18110eadf3a1..ba0d3a25feab 100644
--- a/arch/arm/cpu/entry.h
+++ b/arch/arm/cpu/entry.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ENTRY_H__
 #define __ENTRY_H__
 
diff --git a/arch/arm/cpu/mmu-common.h b/arch/arm/cpu/mmu-common.h
index 0a33b138e168..ed7d5bc3168f 100644
--- a/arch/arm/cpu/mmu-common.h
+++ b/arch/arm/cpu/mmu-common.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ARM_MMU_COMMON_H
 #define __ARM_MMU_COMMON_H
 
@@ -17,4 +19,4 @@ static inline void arm_mmu_not_initialized_error(void)
 	panic("MMU not initialized\n");
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/arch/arm/cpu/mmu.h b/arch/arm/cpu/mmu.h
index c85e0ea05033..d48522d166f7 100644
--- a/arch/arm/cpu/mmu.h
+++ b/arch/arm/cpu/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ARM_MMU_H
 #define __ARM_MMU_H
 
diff --git a/arch/arm/cpu/mmu_64.h b/arch/arm/cpu/mmu_64.h
index 9bbb62fc6ba7..e4d81dace41f 100644
--- a/arch/arm/cpu/mmu_64.h
+++ b/arch/arm/cpu/mmu_64.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include "mmu-common.h"
 
diff --git a/arch/arm/include/asm/armlinux.h b/arch/arm/include/asm/armlinux.h
index 6af98968fa57..8d8e05105b08 100644
--- a/arch/arm/include/asm/armlinux.h
+++ b/arch/arm/include/asm/armlinux.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ARCH_ARMLINUX_H
 #define __ARCH_ARMLINUX_H
 
diff --git a/arch/arm/include/asm/asm-offsets.h b/arch/arm/include/asm/asm-offsets.h
index 2f84e8399624..33db5a47e5c2 100644
--- a/arch/arm/include/asm/asm-offsets.h
+++ b/arch/arm/include/asm/asm-offsets.h
@@ -1 +1,3 @@
-#include <generated/asm-offsets.h>
\ No newline at end of file
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <generated/asm-offsets.h>
diff --git a/arch/arm/include/asm/assembler64.h b/arch/arm/include/asm/assembler64.h
index 26182aa5f687..615b25767180 100644
--- a/arch/arm/include/asm/assembler64.h
+++ b/arch/arm/include/asm/assembler64.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_ASSEMBLY_H
 #define __ASM_ARCH_ASSEMBLY_H
 
@@ -18,4 +20,4 @@
 	b.eq	\el1_label
 .endm
 
-#endif /* __ASM_ARCH_ASSEMBLY_H */
\ No newline at end of file
+#endif /* __ASM_ARCH_ASSEMBLY_H */
diff --git a/arch/arm/include/asm/barebox-arm-head.h b/arch/arm/include/asm/barebox-arm-head.h
index 187d12c9fc8d..fcb7e31d8531 100644
--- a/arch/arm/include/asm/barebox-arm-head.h
+++ b/arch/arm/include/asm/barebox-arm-head.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_HEAD_H
 #define __ASM_ARM_HEAD_H
 
diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h
index d8a4d9b66743..2d0d300da2eb 100644
--- a/arch/arm/include/asm/bitops.h
+++ b/arch/arm/include/asm/bitops.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Copyright 1995, Russell King.
  * Various bits and pieces copyrights include:
diff --git a/arch/arm/include/asm/bitsperlong.h b/arch/arm/include/asm/bitsperlong.h
index 6dc0bb0c13b2..bf000a04ccde 100644
--- a/arch/arm/include/asm/bitsperlong.h
+++ b/arch/arm/include/asm/bitsperlong.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/bitsperlong.h>
diff --git a/arch/arm/include/asm/byteorder.h b/arch/arm/include/asm/byteorder.h
index c3489f1e1fc6..751dc0e53090 100644
--- a/arch/arm/include/asm/byteorder.h
+++ b/arch/arm/include/asm/byteorder.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  *  linux/include/asm-arm/byteorder.h
  *
diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
index 9ebe80dc89bc..b63776a74ada 100644
--- a/arch/arm/include/asm/cache.h
+++ b/arch/arm/include/asm/cache.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_CACHE_H
 #define __ASM_CACHE_H
 
diff --git a/arch/arm/include/asm/common.h b/arch/arm/include/asm/common.h
index 1e2729d521ae..9832a6a4d202 100644
--- a/arch/arm/include/asm/common.h
+++ b/arch/arm/include/asm/common.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_COMMON_H
 #define __ASM_ARM_COMMON_H
 
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index f39939bd44da..7dc027c1741b 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_CPUTYPE_H
 #define __ASM_ARM_CPUTYPE_H
 
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 3def5676999b..486275a3361d 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASMARM_ELF_H
 #define __ASMARM_ELF_H
 
diff --git a/arch/arm/include/asm/gic.h b/arch/arm/include/asm/gic.h
index f83f52814107..d7e4c3cbf0b4 100644
--- a/arch/arm/include/asm/gic.h
+++ b/arch/arm/include/asm/gic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __GIC_H__
 #define __GIC_H__
 
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/arch/arm/include/asm/hardware/arm_timer.h
index 8a58390a1949..7911628ba7f0 100644
--- a/arch/arm/include/asm/hardware/arm_timer.h
+++ b/arch/arm/include/asm/hardware/arm_timer.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
 #define __ASM_ARM_HARDWARE_ARM_TIMER_H
 
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 0507db1a9cf8..1c0f522d1d44 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_IO_H
 #define __ASM_ARM_IO_H
 
diff --git a/arch/arm/include/asm/linkage.h b/arch/arm/include/asm/linkage.h
index 5a25632b1bc0..728ebe6f6fc0 100644
--- a/arch/arm/include/asm/linkage.h
+++ b/arch/arm/include/asm/linkage.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_LINKAGE_H
 #define __ASM_LINKAGE_H
 
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 2279306179af..2b454fa67309 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_MEMORY_H
 #define __ASM_ARM_MEMORY_H
 
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index 417808bfcce1..fd8e93f7a3b1 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MMU_H
 #define __ASM_MMU_H
 
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 3ce39bf82b61..a4473ff8b61c 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_ARM_MODULE_H
 #define _ASM_ARM_MODULE_H
 
diff --git a/arch/arm/include/asm/posix_types.h b/arch/arm/include/asm/posix_types.h
index 22cae6230ceb..feaed4247135 100644
--- a/arch/arm/include/asm/posix_types.h
+++ b/arch/arm/include/asm/posix_types.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/posix_types.h>
diff --git a/arch/arm/include/asm/sections.h b/arch/arm/include/asm/sections.h
index 8ab01f2b71e8..15b1a6482a5b 100644
--- a/arch/arm/include/asm/sections.h
+++ b/arch/arm/include/asm/sections.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_SECTIONS_H
 #define __ASM_SECTIONS_H
 
diff --git a/arch/arm/include/asm/secure.h b/arch/arm/include/asm/secure.h
index e0c262372395..fd10c47c6a20 100644
--- a/arch/arm/include/asm/secure.h
+++ b/arch/arm/include/asm/secure.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_SECURE_H
 #define __ASM_ARM_SECURE_H
 
diff --git a/arch/arm/include/asm/semihosting.h b/arch/arm/include/asm/semihosting.h
index b478dadb3afa..9e1606c4aeaa 100644
--- a/arch/arm/include/asm/semihosting.h
+++ b/arch/arm/include/asm/semihosting.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_SEMIHOSTING_H
 #define __ASM_ARM_SEMIHOSTING_H
 
diff --git a/arch/arm/include/asm/stacktrace.h b/arch/arm/include/asm/stacktrace.h
index 602e79ced451..bbcd2a5f8e45 100644
--- a/arch/arm/include/asm/stacktrace.h
+++ b/arch/arm/include/asm/stacktrace.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_STACKTRACE_H
 #define __ASM_STACKTRACE_H
 
diff --git a/arch/arm/include/asm/string.h b/arch/arm/include/asm/string.h
index cd79f6340245..2322b846b29b 100644
--- a/arch/arm/include/asm/string.h
+++ b/arch/arm/include/asm/string.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_STRING_H
 #define __ASM_ARM_STRING_H
 
diff --git a/arch/arm/include/asm/swab.h b/arch/arm/include/asm/swab.h
index 379543783130..8dbde9b30771 100644
--- a/arch/arm/include/asm/swab.h
+++ b/arch/arm/include/asm/swab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  *  arch/arm/include/asm/byteorder.h
  *
diff --git a/arch/arm/include/asm/syscounter.h b/arch/arm/include/asm/syscounter.h
index a644cfaad6b4..16d52269e370 100644
--- a/arch/arm/include/asm/syscounter.h
+++ b/arch/arm/include/asm/syscounter.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_SYSCNT_H_
 #define _ASM_SYSCNT_H_
 
@@ -21,4 +23,4 @@ static inline u32 syscnt_get_cntfrq(void __iomem *syscnt)
 	return readl(syscnt + SYSCNT_CNTFID(0));
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index a0180f2df8e3..9e880015331d 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_SYSTEM_H
 #define __ASM_ARM_SYSTEM_H
 
diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h
index 1e3dfc845c8d..c7f998774812 100644
--- a/arch/arm/include/asm/system_info.h
+++ b/arch/arm/include/asm/system_info.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_SYSTEM_INFO_H
 #define __ASM_ARM_SYSTEM_INFO_H
 
diff --git a/arch/arm/include/asm/types.h b/arch/arm/include/asm/types.h
index 22b96426559e..4adc815bf370 100644
--- a/arch/arm/include/asm/types.h
+++ b/arch/arm/include/asm/types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARM_TYPES_H
 #define __ASM_ARM_TYPES_H
 
diff --git a/arch/arm/include/asm/unaligned.h b/arch/arm/include/asm/unaligned.h
index 44593a894903..b63d39da7f55 100644
--- a/arch/arm/include/asm/unaligned.h
+++ b/arch/arm/include/asm/unaligned.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_ARM_UNALIGNED_H
 #define _ASM_ARM_UNALIGNED_H
 
diff --git a/arch/arm/mach-at91/include/mach/at91sam926x.h b/arch/arm/mach-at91/include/mach/at91sam926x.h
index ab5cf515ef9e..8ef83010d2c3 100644
--- a/arch/arm/mach-at91/include/mach/at91sam926x.h
+++ b/arch/arm/mach-at91/include/mach/at91sam926x.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_AT91SAM926X_H
 #define __MACH_AT91SAM926X_H
 
diff --git a/arch/arm/mach-at91/include/mach/barebox-arm-head.h b/arch/arm/mach-at91/include/mach/barebox-arm-head.h
index e0e07500a277..4a95f89fc9dd 100644
--- a/arch/arm/mach-at91/include/mach/barebox-arm-head.h
+++ b/arch/arm/mach-at91/include/mach/barebox-arm-head.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ARM_HEAD_H
 #define __MACH_ARM_HEAD_H
 
diff --git a/arch/arm/mach-at91/include/mach/early_udelay.h b/arch/arm/mach-at91/include/mach/early_udelay.h
index 1c1b0123fee8..fc9885dd27f5 100644
--- a/arch/arm/mach-at91/include/mach/early_udelay.h
+++ b/arch/arm/mach-at91/include/mach/early_udelay.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __EARLY_UDELAY_H__
 #define __EARLY_UDELAY_H__
 
diff --git a/arch/arm/mach-at91/include/mach/sama5d2_ll.h b/arch/arm/mach-at91/include/mach/sama5d2_ll.h
index 244b1a706594..c78279d7fce9 100644
--- a/arch/arm/mach-at91/include/mach/sama5d2_ll.h
+++ b/arch/arm/mach-at91/include/mach/sama5d2_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_SAMA5D2_LL__
 #define __MACH_SAMA5D2_LL__
 
diff --git a/arch/arm/mach-at91/include/mach/xload.h b/arch/arm/mach-at91/include/mach/xload.h
index bbc70af2108a..e9336d59c918 100644
--- a/arch/arm/mach-at91/include/mach/xload.h
+++ b/arch/arm/mach-at91/include/mach/xload.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_XLOAD_H
 #define __MACH_XLOAD_H
 
diff --git a/arch/arm/mach-clps711x/include/mach/devices.h b/arch/arm/mach-clps711x/include/mach/devices.h
index 18a251a1d9f0..77c43be25c2b 100644
--- a/arch/arm/mach-clps711x/include/mach/devices.h
+++ b/arch/arm/mach-clps711x/include/mach/devices.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_DEVICES_H
 #define __MACH_DEVICES_H
 
diff --git a/arch/arm/mach-ep93xx/include/mach/barebox.lds.h b/arch/arm/mach-ep93xx/include/mach/barebox.lds.h
index 74c4662a57e7..4e497f5e2d3d 100644
--- a/arch/arm/mach-ep93xx/include/mach/barebox.lds.h
+++ b/arch/arm/mach-ep93xx/include/mach/barebox.lds.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 /* the EP93xx expects to find the pattern 'CRUS' at 0x1000 */
 
diff --git a/arch/arm/mach-imx/include/mach/atf.h b/arch/arm/mach-imx/include/mach/atf.h
index 5ca75f8f92d2..09396f46463a 100644
--- a/arch/arm/mach-imx/include/mach/atf.h
+++ b/arch/arm/mach-imx/include/mach/atf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __IMX_ATF_H__
 #define __IMX_ATF_H__
 
diff --git a/arch/arm/mach-imx/include/mach/bbu.h b/arch/arm/mach-imx/include/mach/bbu.h
index f2e326f475cd..207d46e5d18f 100644
--- a/arch/arm/mach-imx/include/mach/bbu.h
+++ b/arch/arm/mach-imx/include/mach/bbu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_BBU_H
 #define __MACH_BBU_H
 
diff --git a/arch/arm/mach-imx/include/mach/ccm.h b/arch/arm/mach-imx/include/mach/ccm.h
index 32254a85b4bf..bbdf7536ee91 100644
--- a/arch/arm/mach-imx/include/mach/ccm.h
+++ b/arch/arm/mach-imx/include/mach/ccm.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __IMX_CCM_H__
 
 /* 0 <= n <= 190 */
@@ -17,4 +19,4 @@
 #define CCM_CCGR_SETTINGn_NEEDED_RUN_WAIT(n)	CCM_CCGR_SETTINGn(n, 0b10)
 #define CCM_CCGR_SETTINGn_NEEDED(n)		CCM_CCGR_SETTINGn(n, 0b11)
 
-#endif
\ No newline at end of file
+#endif
diff --git a/arch/arm/mach-imx/include/mach/clock.h b/arch/arm/mach-imx/include/mach/clock.h
index 304a7c885cc7..af1a6e439a2e 100644
--- a/arch/arm/mach-imx/include/mach/clock.h
+++ b/arch/arm/mach-imx/include/mach/clock.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* nothing, but some drivers need this include */
diff --git a/arch/arm/mach-imx/include/mach/debug_ll.h b/arch/arm/mach-imx/include/mach/debug_ll.h
index a4c57c5d5ae6..98aec5198f4a 100644
--- a/arch/arm/mach-imx/include/mach/debug_ll.h
+++ b/arch/arm/mach-imx/include/mach/debug_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_DEBUG_LL_H__
 #define __MACH_DEBUG_LL_H__
 
diff --git a/arch/arm/mach-imx/include/mach/devices-imx1.h b/arch/arm/mach-imx/include/mach/devices-imx1.h
index e4185bc2818b..2b5cb8bcbd41 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx1.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx1.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <mach/devices.h>
 #include <mach/imx1-regs.h>
 
diff --git a/arch/arm/mach-imx/include/mach/devices-imx21.h b/arch/arm/mach-imx/include/mach/devices-imx21.h
index 5b2dfd750581..429b01165efe 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx21.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx21.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <mach/devices.h>
 #include <mach/imx21-regs.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx25.h b/arch/arm/mach-imx/include/mach/devices-imx25.h
index 7779a02be1e4..ec358fbbfa09 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx25.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx25.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <mach/devices.h>
 #include <mach/imx25-regs.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx27.h b/arch/arm/mach-imx/include/mach/devices-imx27.h
index da2289b191d2..8ea7ea7eb3b1 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx27.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx27.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <mach/devices.h>
 #include <mach/imx27-regs.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx31.h b/arch/arm/mach-imx/include/mach/devices-imx31.h
index 51125d1bca01..37eacb043672 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx31.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx31.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <mach/imx31-regs.h>
 #include <mach/devices.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx35.h b/arch/arm/mach-imx/include/mach/devices-imx35.h
index 922bb589c67a..04aa7775dd34 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx35.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx35.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <mach/devices.h>
 #include <mach/imx35-regs.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx50.h b/arch/arm/mach-imx/include/mach/devices-imx50.h
index 7e5141a107a5..5f534d4aec8f 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx50.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx50.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <mach/devices.h>
 #include <mach/imx50-regs.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx51.h b/arch/arm/mach-imx/include/mach/devices-imx51.h
index 5a968a30006b..1a2363249189 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx51.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx51.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <linux/sizes.h>
 #include <mach/devices.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx53.h b/arch/arm/mach-imx/include/mach/devices-imx53.h
index 3d1e8a27a8af..7b96fb3e2718 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx53.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx53.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <mach/devices.h>
 #include <mach/imx53-regs.h>
diff --git a/arch/arm/mach-imx/include/mach/devices-imx6.h b/arch/arm/mach-imx/include/mach/devices-imx6.h
index 9471f57909de..981dd1c7cace 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx6.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx6.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <mach/devices.h>
 #include <mach/imx6-regs.h>
 
diff --git a/arch/arm/mach-imx/include/mach/devices.h b/arch/arm/mach-imx/include/mach/devices.h
index 4754b92a6f9f..45da5bb6cc83 100644
--- a/arch/arm/mach-imx/include/mach/devices.h
+++ b/arch/arm/mach-imx/include/mach/devices.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <platform_data/eth-fec.h>
 #include <input/matrix_keypad.h>
diff --git a/arch/arm/mach-imx/include/mach/esdctl-v4.h b/arch/arm/mach-imx/include/mach/esdctl-v4.h
index 2e6741e0d5d5..b93621a8d7d6 100644
--- a/arch/arm/mach-imx/include/mach/esdctl-v4.h
+++ b/arch/arm/mach-imx/include/mach/esdctl-v4.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ESDCTL_V4_H
 #define __MACH_ESDCTL_V4_H
 
diff --git a/arch/arm/mach-imx/include/mach/esdctl.h b/arch/arm/mach-imx/include/mach/esdctl.h
index caafa4732314..b0b531aed4a2 100644
--- a/arch/arm/mach-imx/include/mach/esdctl.h
+++ b/arch/arm/mach-imx/include/mach/esdctl.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ESDCTL_V2_H
 #define __MACH_ESDCTL_V2_H
 
diff --git a/arch/arm/mach-imx/include/mach/generic.h b/arch/arm/mach-imx/include/mach/generic.h
index fce7a813200b..12a7c208b782 100644
--- a/arch/arm/mach-imx/include/mach/generic.h
+++ b/arch/arm/mach-imx/include/mach/generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_GENERIC_H
 #define __MACH_GENERIC_H
 
diff --git a/arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h b/arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h
index 60f730f8eca9..0cf017b8ea5d 100644
--- a/arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h
+++ b/arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * This snippet can be included from a i.MX flash header configuration
  * file for generating signed images. The necessary keys/certificates
diff --git a/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf-template.h b/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf-template.h
index 668fb0646f94..a60b48529236 100644
--- a/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf-template.h
+++ b/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf-template.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * This snippet can be included from a i.MX flash header configuration
  * file for generating signed images. The necessary keys/certificates
diff --git a/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h b/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h
index ca741b2736a0..2044f23c7a1f 100644
--- a/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h
+++ b/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #define SETUP_HABV4_ENGINE CAAM
 #define SETUP_HABV4_FEATURES  RNG, MID
diff --git a/arch/arm/mach-imx/include/mach/habv4-imx6ull-gencsf.h b/arch/arm/mach-imx/include/mach/habv4-imx6ull-gencsf.h
index 6a558b880b93..0efd09888fe1 100644
--- a/arch/arm/mach-imx/include/mach/habv4-imx6ull-gencsf.h
+++ b/arch/arm/mach-imx/include/mach/habv4-imx6ull-gencsf.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #define SETUP_HABV4_ENGINE SW
 
diff --git a/arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h b/arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h
index a3917cc74fd7..b50788127eff 100644
--- a/arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h
+++ b/arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * This snippet can be included from a i.MX flash header configuration
  * file for generating signed images. The necessary keys/certificates
diff --git a/arch/arm/mach-imx/include/mach/imx-gpio.h b/arch/arm/mach-imx/include/mach/imx-gpio.h
index 64ac278d6197..a84dee36b816 100644
--- a/arch/arm/mach-imx/include/mach/imx-gpio.h
+++ b/arch/arm/mach-imx/include/mach/imx-gpio.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX_GPIO_H
 #define __MACH_IMX_GPIO_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx-header.h b/arch/arm/mach-imx/include/mach/imx-header.h
index f1e076dab905..8e968e6efba3 100644
--- a/arch/arm/mach-imx/include/mach/imx-header.h
+++ b/arch/arm/mach-imx/include/mach/imx-header.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __IMX_HEADER_H__
 #define __IMX_HEADER_H__
 
diff --git a/arch/arm/mach-imx/include/mach/imx-nand.h b/arch/arm/mach-imx/include/mach/imx-nand.h
index f34799a0119c..97e2bd059fe8 100644
--- a/arch/arm/mach-imx/include/mach/imx-nand.h
+++ b/arch/arm/mach-imx/include/mach/imx-nand.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_NAND_H
 #define __ASM_ARCH_NAND_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx-pll.h b/arch/arm/mach-imx/include/mach/imx-pll.h
index 0ccf41bcaa68..791f86093ba8 100644
--- a/arch/arm/mach-imx/include/mach/imx-pll.h
+++ b/arch/arm/mach-imx/include/mach/imx-pll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INCLUDE_ASM_ARCH_IMX_PLL_H
 #define __INCLUDE_ASM_ARCH_IMX_PLL_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx1-regs.h b/arch/arm/mach-imx/include/mach/imx1-regs.h
index 69e57e3cfd67..c8125fd74614 100644
--- a/arch/arm/mach-imx/include/mach/imx1-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx1-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _IMX1_REGS_H
 #define _IMX1_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx21-regs.h b/arch/arm/mach-imx/include/mach/imx21-regs.h
index 1fa463a256e6..19b2ddfdc370 100644
--- a/arch/arm/mach-imx/include/mach/imx21-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx21-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _IMX21_REGS_H
 #define _IMX21_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx25-fusemap.h b/arch/arm/mach-imx/include/mach/imx25-fusemap.h
index 749b0d17b28d..f21e3d950555 100644
--- a/arch/arm/mach-imx/include/mach/imx25-fusemap.h
+++ b/arch/arm/mach-imx/include/mach/imx25-fusemap.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX25_FUSEMAP_H
 #define __MACH_IMX25_FUSEMAP_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx27-regs.h b/arch/arm/mach-imx/include/mach/imx27-regs.h
index c45befb57ca0..8bb067763bb7 100644
--- a/arch/arm/mach-imx/include/mach/imx27-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx27-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _IMX27_REGS_H
 #define _IMX27_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx5.h b/arch/arm/mach-imx/include/mach/imx5.h
index dd5cfe99cf0b..24ac07e3660b 100644
--- a/arch/arm/mach-imx/include/mach/imx5.h
+++ b/arch/arm/mach-imx/include/mach/imx5.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_MX5_H
 #define __MACH_MX5_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx50-regs.h b/arch/arm/mach-imx/include/mach/imx50-regs.h
index 97ac8e2dad16..b99dba95086c 100644
--- a/arch/arm/mach-imx/include/mach/imx50-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx50-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX50_REGS_H
 #define __MACH_IMX50_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx51-regs.h b/arch/arm/mach-imx/include/mach/imx51-regs.h
index b6685ce065e5..64d56939d54e 100644
--- a/arch/arm/mach-imx/include/mach/imx51-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx51-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX51_REGS_H
 #define __MACH_IMX51_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx53-regs.h b/arch/arm/mach-imx/include/mach/imx53-regs.h
index d45c94370dfd..5fc0b4b90e7a 100644
--- a/arch/arm/mach-imx/include/mach/imx53-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx53-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX53_REGS_H
 #define __MACH_IMX53_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx6-fusemap.h b/arch/arm/mach-imx/include/mach/imx6-fusemap.h
index e14044e98a99..de5eb51e5d47 100644
--- a/arch/arm/mach-imx/include/mach/imx6-fusemap.h
+++ b/arch/arm/mach-imx/include/mach/imx6-fusemap.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX_IMX6_OCOTP_H
 #define __MACH_IMX_IMX6_OCOTP_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx6-mmdc.h b/arch/arm/mach-imx/include/mach/imx6-mmdc.h
index 9385b342c230..bda20aba1741 100644
--- a/arch/arm/mach-imx/include/mach/imx6-mmdc.h
+++ b/arch/arm/mach-imx/include/mach/imx6-mmdc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_MMDC_H
 #define __MACH_MMDC_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx6-regs.h b/arch/arm/mach-imx/include/mach/imx6-regs.h
index 7350ffd16fae..b2753b0fa7dd 100644
--- a/arch/arm/mach-imx/include/mach/imx6-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx6-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX6_REGS_H
 #define __MACH_IMX6_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx6.h b/arch/arm/mach-imx/include/mach/imx6.h
index b65cdaaf40a6..0f3397006a1f 100644
--- a/arch/arm/mach-imx/include/mach/imx6.h
+++ b/arch/arm/mach-imx/include/mach/imx6.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX6_H
 #define __MACH_IMX6_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx7-ccm-regs.h b/arch/arm/mach-imx/include/mach/imx7-ccm-regs.h
index 5c60794ca74f..aecf9a26d017 100644
--- a/arch/arm/mach-imx/include/mach/imx7-ccm-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx7-ccm-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX7_CCM_REGS_H__
 #define __MACH_IMX7_CCM_REGS_H__
 
diff --git a/arch/arm/mach-imx/include/mach/imx7-regs.h b/arch/arm/mach-imx/include/mach/imx7-regs.h
index 21e2830b9763..f11691671728 100644
--- a/arch/arm/mach-imx/include/mach/imx7-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx7-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX7_REGS_H
 #define __MACH_IMX7_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx7.h b/arch/arm/mach-imx/include/mach/imx7.h
index 8518935468c9..bc131805af4c 100644
--- a/arch/arm/mach-imx/include/mach/imx7.h
+++ b/arch/arm/mach-imx/include/mach/imx7.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX7_H
 #define __MACH_IMX7_H
 
@@ -56,4 +58,4 @@ static inline int imx7_cpu_revision(void)
 DEFINE_MX7_CPU_TYPE(mx7s, IMX7_CPUTYPE_IMX7S);
 DEFINE_MX7_CPU_TYPE(mx7d, IMX7_CPUTYPE_IMX7D);
 
-#endif /* __MACH_IMX7_H */
\ No newline at end of file
+#endif /* __MACH_IMX7_H */
diff --git a/arch/arm/mach-imx/include/mach/imx8m-ccm-regs.h b/arch/arm/mach-imx/include/mach/imx8m-ccm-regs.h
index 985391f31ac1..eeb15f4dd074 100644
--- a/arch/arm/mach-imx/include/mach/imx8m-ccm-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx8m-ccm-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX8_CCM_REGS_H__
 #define __MACH_IMX8_CCM_REGS_H__
 
diff --git a/arch/arm/mach-imx/include/mach/imx8m-regs.h b/arch/arm/mach-imx/include/mach/imx8m-regs.h
index e5f466c29141..e1c83ee01ddc 100644
--- a/arch/arm/mach-imx/include/mach/imx8m-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx8m-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX8M_REGS_H
 #define __MACH_IMX8M_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx8mm-regs.h b/arch/arm/mach-imx/include/mach/imx8mm-regs.h
index e10ca42d2dd0..4c6cabe5af5c 100644
--- a/arch/arm/mach-imx/include/mach/imx8mm-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx8mm-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX8MM_REGS_H
 #define __MACH_IMX8MM_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx8mp-regs.h b/arch/arm/mach-imx/include/mach/imx8mp-regs.h
index ad53abbc9d11..08f662bcde15 100644
--- a/arch/arm/mach-imx/include/mach/imx8mp-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx8mp-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX8MP_REGS_H
 #define __MACH_IMX8MP_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx8mq-regs.h b/arch/arm/mach-imx/include/mach/imx8mq-regs.h
index 50d02ba6a288..e2fde2ba0ca9 100644
--- a/arch/arm/mach-imx/include/mach/imx8mq-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx8mq-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX8MQ_REGS_H
 #define __MACH_IMX8MQ_REGS_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx8mq.h b/arch/arm/mach-imx/include/mach/imx8mq.h
index f8f39cdd63fb..d02c5f23cfd2 100644
--- a/arch/arm/mach-imx/include/mach/imx8mq.h
+++ b/arch/arm/mach-imx/include/mach/imx8mq.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX8MQ_H
 #define __MACH_IMX8MQ_H
 
diff --git a/arch/arm/mach-imx/include/mach/imx_cpu_types.h b/arch/arm/mach-imx/include/mach/imx_cpu_types.h
index e9a9d8b38a08..1d5809720988 100644
--- a/arch/arm/mach-imx/include/mach/imx_cpu_types.h
+++ b/arch/arm/mach-imx/include/mach/imx_cpu_types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX_CPU_TYPES_H
 #define __MACH_IMX_CPU_TYPES_H
 
diff --git a/arch/arm/mach-imx/include/mach/imxfb.h b/arch/arm/mach-imx/include/mach/imxfb.h
index 6df7a14ddeda..508155457598 100644
--- a/arch/arm/mach-imx/include/mach/imxfb.h
+++ b/arch/arm/mach-imx/include/mach/imxfb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMXFB_H
 #define __MACH_IMXFB_H
 
diff --git a/arch/arm/mach-imx/include/mach/iomux-mx1.h b/arch/arm/mach-imx/include/mach/iomux-mx1.h
index 51317d35d52d..000b2055eeb9 100644
--- a/arch/arm/mach-imx/include/mach/iomux-mx1.h
+++ b/arch/arm/mach-imx/include/mach/iomux-mx1.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IOMUX_MX1_H
 #define __MACH_IOMUX_MX1_H
 
diff --git a/arch/arm/mach-imx/include/mach/iomux-mx8m.h b/arch/arm/mach-imx/include/mach/iomux-mx8m.h
index de6675064abe..68f276560987 100644
--- a/arch/arm/mach-imx/include/mach/iomux-mx8m.h
+++ b/arch/arm/mach-imx/include/mach/iomux-mx8m.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IOMUX_IMX8M_H__
 #define __MACH_IOMUX_IMX8M_H__
 
diff --git a/arch/arm/mach-imx/include/mach/iomux-v1.h b/arch/arm/mach-imx/include/mach/iomux-v1.h
index 8f75933e3982..132b12976750 100644
--- a/arch/arm/mach-imx/include/mach/iomux-v1.h
+++ b/arch/arm/mach-imx/include/mach/iomux-v1.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IOMUX_V1_H__
 #define __MACH_IOMUX_V1_H__
 
diff --git a/arch/arm/mach-imx/include/mach/ocotp-fusemap.h b/arch/arm/mach-imx/include/mach/ocotp-fusemap.h
index aec50dbf8a54..603bec49fd7e 100644
--- a/arch/arm/mach-imx/include/mach/ocotp-fusemap.h
+++ b/arch/arm/mach-imx/include/mach/ocotp-fusemap.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX_OCOTP_FUSEMAP_H
 #define __MACH_IMX_OCOTP_FUSEMAP_H
 
diff --git a/arch/arm/mach-imx/include/mach/ocotp.h b/arch/arm/mach-imx/include/mach/ocotp.h
index 20205c5da759..7c72edfb22a7 100644
--- a/arch/arm/mach-imx/include/mach/ocotp.h
+++ b/arch/arm/mach-imx/include/mach/ocotp.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX_OCOTP_H
 #define __MACH_IMX_OCOTP_H
 
diff --git a/arch/arm/mach-imx/include/mach/reset-reason.h b/arch/arm/mach-imx/include/mach/reset-reason.h
index 91a81718960c..f27b2ee64e48 100644
--- a/arch/arm/mach-imx/include/mach/reset-reason.h
+++ b/arch/arm/mach-imx/include/mach/reset-reason.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_RESET_REASON_H__
 #define __MACH_RESET_REASON_H__
 
diff --git a/arch/arm/mach-imx/include/mach/revision.h b/arch/arm/mach-imx/include/mach/revision.h
index d9495d967f05..ab42bf17d5f3 100644
--- a/arch/arm/mach-imx/include/mach/revision.h
+++ b/arch/arm/mach-imx/include/mach/revision.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_REVISION_H__
 #define __MACH_REVISION_H__
 
diff --git a/arch/arm/mach-imx/include/mach/spi.h b/arch/arm/mach-imx/include/mach/spi.h
index 08be445e8eb8..294c724ef4ff 100644
--- a/arch/arm/mach-imx/include/mach/spi.h
+++ b/arch/arm/mach-imx/include/mach/spi.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #ifndef __MACH_SPI_H_
 #define __MACH_SPI_H_
diff --git a/arch/arm/mach-imx/include/mach/usb.h b/arch/arm/mach-imx/include/mach/usb.h
index 3209bf9095a4..18040aa0be00 100644
--- a/arch/arm/mach-imx/include/mach/usb.h
+++ b/arch/arm/mach-imx/include/mach/usb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_USB_H_
 #define __MACH_USB_H_
 
diff --git a/arch/arm/mach-imx/include/mach/vf610-ddrmc.h b/arch/arm/mach-imx/include/mach/vf610-ddrmc.h
index 07feb036e5b5..79b88e19fd86 100644
--- a/arch/arm/mach-imx/include/mach/vf610-ddrmc.h
+++ b/arch/arm/mach-imx/include/mach/vf610-ddrmc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_DDRMC_H
 #define __MACH_DDRMC_H
 
diff --git a/arch/arm/mach-imx/include/mach/vf610-fusemap.h b/arch/arm/mach-imx/include/mach/vf610-fusemap.h
index a56faf10cc10..c222a8f27fbf 100644
--- a/arch/arm/mach-imx/include/mach/vf610-fusemap.h
+++ b/arch/arm/mach-imx/include/mach/vf610-fusemap.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_VF610_OCOTP_H
 #define __MACH_VF610_OCOTP_H
 
diff --git a/arch/arm/mach-imx/include/mach/vf610.h b/arch/arm/mach-imx/include/mach/vf610.h
index 7ac10a7b1e0c..6de300a2a090 100644
--- a/arch/arm/mach-imx/include/mach/vf610.h
+++ b/arch/arm/mach-imx/include/mach/vf610.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_VF610_H
 #define __MACH_VF610_H
 
diff --git a/arch/arm/mach-imx/include/mach/weim.h b/arch/arm/mach-imx/include/mach/weim.h
index 22d9c76d6173..d8a7d1194775 100644
--- a/arch/arm/mach-imx/include/mach/weim.h
+++ b/arch/arm/mach-imx/include/mach/weim.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_WEIM_H
 #define __MACH_WEIM_H
 
diff --git a/arch/arm/mach-imx/include/mach/xload.h b/arch/arm/mach-imx/include/mach/xload.h
index f0deaf068aed..03ec23ebbdb0 100644
--- a/arch/arm/mach-imx/include/mach/xload.h
+++ b/arch/arm/mach-imx/include/mach/xload.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_XLOAD_H
 #define __MACH_XLOAD_H
 
diff --git a/arch/arm/mach-layerscape/include/mach/bbu.h b/arch/arm/mach-layerscape/include/mach/bbu.h
index 1ea0cbb11f32..d018ec9a9dbf 100644
--- a/arch/arm/mach-layerscape/include/mach/bbu.h
+++ b/arch/arm/mach-layerscape/include/mach/bbu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_LAYERSCAPE_BBU_H
 #define __MACH_LAYERSCAPE_BBU_H
 
@@ -19,4 +21,4 @@ static inline int ls1046a_bbu_qspi_register_handler(const char *name,
 					    filetype_layerscape_qspi_image);
 }
 
-#endif /* __MACH_LAYERSCAPE_BBU_H */
\ No newline at end of file
+#endif /* __MACH_LAYERSCAPE_BBU_H */
diff --git a/arch/arm/mach-layerscape/include/mach/debug_ll.h b/arch/arm/mach-layerscape/include/mach/debug_ll.h
index 2658a4a7c916..b6630af1431a 100644
--- a/arch/arm/mach-layerscape/include/mach/debug_ll.h
+++ b/arch/arm/mach-layerscape/include/mach/debug_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __INCLUDE_ARCH_DEBUG_LL_H__
 #define __INCLUDE_ARCH_DEBUG_LL_H__
 
diff --git a/arch/arm/mach-layerscape/include/mach/errata.h b/arch/arm/mach-layerscape/include/mach/errata.h
index bdefa22172f7..1ec75b5d8d33 100644
--- a/arch/arm/mach-layerscape/include/mach/errata.h
+++ b/arch/arm/mach-layerscape/include/mach/errata.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ERRATA_H
 #define __MACH_ERRATA_H
 
diff --git a/arch/arm/mach-layerscape/include/mach/layerscape.h b/arch/arm/mach-layerscape/include/mach/layerscape.h
index 1f1da0f66e75..447417a266ff 100644
--- a/arch/arm/mach-layerscape/include/mach/layerscape.h
+++ b/arch/arm/mach-layerscape/include/mach/layerscape.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_LAYERSCAPE_H
 #define __MACH_LAYERSCAPE_H
 
diff --git a/arch/arm/mach-layerscape/include/mach/lowlevel.h b/arch/arm/mach-layerscape/include/mach/lowlevel.h
index 0f5f0f3aad4d..0c077d064b52 100644
--- a/arch/arm/mach-layerscape/include/mach/lowlevel.h
+++ b/arch/arm/mach-layerscape/include/mach/lowlevel.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_LOWLEVEL_H
 #define __MACH_LOWLEVEL_H
 
diff --git a/arch/arm/mach-layerscape/include/mach/xload.h b/arch/arm/mach-layerscape/include/mach/xload.h
index eb2d9988650b..0731681b4318 100644
--- a/arch/arm/mach-layerscape/include/mach/xload.h
+++ b/arch/arm/mach-layerscape/include/mach/xload.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_XLOAD_H
 #define __MACH_XLOAD_H
 
diff --git a/arch/arm/mach-mvebu/include/mach/barebox-arm-head.h b/arch/arm/mach-mvebu/include/mach/barebox-arm-head.h
index 723e2ab4c8b5..12f8cfc5a029 100644
--- a/arch/arm/mach-mvebu/include/mach/barebox-arm-head.h
+++ b/arch/arm/mach-mvebu/include/mach/barebox-arm-head.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/stringify.h>
 #include <mach/common.h>
 
diff --git a/arch/arm/mach-mvebu/include/mach/bbu.h b/arch/arm/mach-mvebu/include/mach/bbu.h
index f23c3269c041..f8f70b6bf693 100644
--- a/arch/arm/mach-mvebu/include/mach/bbu.h
+++ b/arch/arm/mach-mvebu/include/mach/bbu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifdef CONFIG_BAREBOX_UPDATE
 int mvebu_bbu_flash_register_handler(const char *name,
 				     char *devicefile, int version,
diff --git a/arch/arm/mach-mxs/include/mach/debug_ll.h b/arch/arm/mach-mxs/include/mach/debug_ll.h
index 9e3ce1c1cd30..ac7a0e759da1 100644
--- a/arch/arm/mach-mxs/include/mach/debug_ll.h
+++ b/arch/arm/mach-mxs/include/mach/debug_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_DEBUG_LL_H__
 #define __MACH_DEBUG_LL_H__
 
diff --git a/arch/arm/mach-mxs/include/mach/devices.h b/arch/arm/mach-mxs/include/mach/devices.h
index b212aa783e23..4743a4a8c009 100644
--- a/arch/arm/mach-mxs/include/mach/devices.h
+++ b/arch/arm/mach-mxs/include/mach/devices.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_MXS_DEVICES_H
 #define __MACH_MXS_DEVICES_H
 
diff --git a/arch/arm/mach-mxs/include/mach/imx23.h b/arch/arm/mach-mxs/include/mach/imx23.h
index 56e76d5f5030..bdd3ae4407ae 100644
--- a/arch/arm/mach-mxs/include/mach/imx23.h
+++ b/arch/arm/mach-mxs/include/mach/imx23.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX23_H
 #define __MACH_IMX23_H
 
@@ -26,4 +28,4 @@ static inline u32 imx23_get_memsize(void)
 	return (1 << columns) * (1 << rows) * banks * (cs0 + cs1);
 }
 
-#endif /* __MACH_IMX23_H */
\ No newline at end of file
+#endif /* __MACH_IMX23_H */
diff --git a/arch/arm/mach-mxs/include/mach/imx28.h b/arch/arm/mach-mxs/include/mach/imx28.h
index 5816625c89ac..cf2d5fb6efc8 100644
--- a/arch/arm/mach-mxs/include/mach/imx28.h
+++ b/arch/arm/mach-mxs/include/mach/imx28.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_IMX28_H
 #define __MACH_IMX28_H
 
@@ -27,4 +29,4 @@ static inline u32 imx28_get_memsize(void)
 	return (1 << columns) * (1 << rows) * banks * (cs0 + cs1);
 }
 
-#endif /* __MACH_IMX28_H */
\ No newline at end of file
+#endif /* __MACH_IMX28_H */
diff --git a/arch/arm/mach-mxs/include/mach/power.h b/arch/arm/mach-mxs/include/mach/power.h
index f429b3c31c47..9d0ea89bca82 100644
--- a/arch/arm/mach-mxs/include/mach/power.h
+++ b/arch/arm/mach-mxs/include/mach/power.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_POWER_H
 #define __MACH_POWER_H
 
diff --git a/arch/arm/mach-mxs/include/mach/revision.h b/arch/arm/mach-mxs/include/mach/revision.h
index 91f174d8b0e5..65daf3db9871 100644
--- a/arch/arm/mach-mxs/include/mach/revision.h
+++ b/arch/arm/mach-mxs/include/mach/revision.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_REVISION_H__
 #define __MACH_REVISION_H__
 
diff --git a/arch/arm/mach-mxs/include/mach/usb.h b/arch/arm/mach-mxs/include/mach/usb.h
index 2d31b0d0f20d..132fc16eec4a 100644
--- a/arch/arm/mach-mxs/include/mach/usb.h
+++ b/arch/arm/mach-mxs/include/mach/usb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_USB_H
 #define __MACH_USB_H
 
diff --git a/arch/arm/mach-nomadik/include/mach/fsmc.h b/arch/arm/mach-nomadik/include/mach/fsmc.h
index e010c7215ca7..3d46eb2a478b 100644
--- a/arch/arm/mach-nomadik/include/mach/fsmc.h
+++ b/arch/arm/mach-nomadik/include/mach/fsmc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */
 
 #ifndef __ASM_ARCH_FSMC_H
diff --git a/arch/arm/mach-nomadik/include/mach/nand.h b/arch/arm/mach-nomadik/include/mach/nand.h
index 544f0e02c7ae..419db3e33c6d 100644
--- a/arch/arm/mach-nomadik/include/mach/nand.h
+++ b/arch/arm/mach-nomadik/include/mach/nand.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_NAND_H
 #define __ASM_ARCH_NAND_H
 
diff --git a/arch/arm/mach-omap/include/mach/am33xx-generic.h b/arch/arm/mach-omap/include/mach/am33xx-generic.h
index 7e64e74d5c2e..e146bf0909f2 100644
--- a/arch/arm/mach-omap/include/mach/am33xx-generic.h
+++ b/arch/arm/mach-omap/include/mach/am33xx-generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_AM33XX_GENERIC_H
 #define __MACH_AM33XX_GENERIC_H
 
diff --git a/arch/arm/mach-omap/include/mach/am3xxx-silicon.h b/arch/arm/mach-omap/include/mach/am3xxx-silicon.h
index c5f73ad457d6..dba3d634d5c2 100644
--- a/arch/arm/mach-omap/include/mach/am3xxx-silicon.h
+++ b/arch/arm/mach-omap/include/mach/am3xxx-silicon.h
@@ -1,6 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_AM33XX_H
 #define __ASM_ARCH_AM33XX_H
 
 void am3xxx_uart_soft_reset(void __iomem *uart_base);
 
-#endif /* __ASM_ARCH_AM33XX_H */
\ No newline at end of file
+#endif /* __ASM_ARCH_AM33XX_H */
diff --git a/arch/arm/mach-omap/include/mach/bbu.h b/arch/arm/mach-omap/include/mach/bbu.h
index 94d3f96bb452..5ca7ec43cceb 100644
--- a/arch/arm/mach-omap/include/mach/bbu.h
+++ b/arch/arm/mach-omap/include/mach/bbu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_BBU_H
 #define __MACH_BBU_H
 
diff --git a/arch/arm/mach-omap/include/mach/devices.h b/arch/arm/mach-omap/include/mach/devices.h
index 537213fb9043..0f9fdf1ca57b 100644
--- a/arch/arm/mach-omap/include/mach/devices.h
+++ b/arch/arm/mach-omap/include/mach/devices.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_OMAP_DEVICES_H
 #define __MACH_OMAP_DEVICES_H
 
diff --git a/arch/arm/mach-omap/include/mach/generic.h b/arch/arm/mach-omap/include/mach/generic.h
index fe194b39210b..fa391c8d4813 100644
--- a/arch/arm/mach-omap/include/mach/generic.h
+++ b/arch/arm/mach-omap/include/mach/generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _MACH_GENERIC_H
 #define _MACH_GENERIC_H
 
diff --git a/arch/arm/mach-omap/include/mach/mcspi.h b/arch/arm/mach-omap/include/mach/mcspi.h
index dbde67a5daba..febb08db2ac3 100644
--- a/arch/arm/mach-omap/include/mach/mcspi.h
+++ b/arch/arm/mach-omap/include/mach/mcspi.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __OMAP_MCSPI_H
 #define  __OMAP_MCSPI_H
 
diff --git a/arch/arm/mach-omap/include/mach/omap-fb.h b/arch/arm/mach-omap/include/mach/omap-fb.h
index f68dc1a1423c..f727164434b5 100644
--- a/arch/arm/mach-omap/include/mach/omap-fb.h
+++ b/arch/arm/mach-omap/include/mach/omap-fb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef H_BAREBOX_ARCH_ARM_MACH_OMAP_MACH_FB4_H
 #define H_BAREBOX_ARCH_ARM_MACH_OMAP_MACH_FB4_H
 
diff --git a/arch/arm/mach-omap/include/mach/omap3-devices.h b/arch/arm/mach-omap/include/mach/omap3-devices.h
index 8c62c9900564..5d7bc8bf1eeb 100644
--- a/arch/arm/mach-omap/include/mach/omap3-devices.h
+++ b/arch/arm/mach-omap/include/mach/omap3-devices.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_OMAP3_DEVICES_H
 #define __MACH_OMAP3_DEVICES_H
 
diff --git a/arch/arm/mach-omap/include/mach/omap3-generic.h b/arch/arm/mach-omap/include/mach/omap3-generic.h
index 177862e4b117..6304ac7bb831 100644
--- a/arch/arm/mach-omap/include/mach/omap3-generic.h
+++ b/arch/arm/mach-omap/include/mach/omap3-generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_OMAP3_GENERIC_H
 #define __MACH_OMAP3_GENERIC_H
 
diff --git a/arch/arm/mach-omap/include/mach/omap4-clock.h b/arch/arm/mach-omap/include/mach/omap4-clock.h
index 8f49aa376150..6bbb10e83d3e 100644
--- a/arch/arm/mach-omap/include/mach/omap4-clock.h
+++ b/arch/arm/mach-omap/include/mach/omap4-clock.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_OMAP4_CLOCK_H
 #define __MACH_OMAP4_CLOCK_H
 
diff --git a/arch/arm/mach-omap/include/mach/omap4-devices.h b/arch/arm/mach-omap/include/mach/omap4-devices.h
index 7ac940b2d722..22a1eb79fce2 100644
--- a/arch/arm/mach-omap/include/mach/omap4-devices.h
+++ b/arch/arm/mach-omap/include/mach/omap4-devices.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_OMAP4_DEVICES_H
 #define __MACH_OMAP4_DEVICES_H
 
diff --git a/arch/arm/mach-omap/include/mach/omap4-generic.h b/arch/arm/mach-omap/include/mach/omap4-generic.h
index c1d0a3c90050..b6a72cfc5520 100644
--- a/arch/arm/mach-omap/include/mach/omap4-generic.h
+++ b/arch/arm/mach-omap/include/mach/omap4-generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_OMAP4_GENERIC_H
 #define __MACH_OMAP4_GENERIC_H
 
diff --git a/arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h b/arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h
index e5e2d9c22949..0cde30619b84 100644
--- a/arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h
+++ b/arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Copyright (C) 2011 Alexander Aring <a.aring at phytec.de>
  */
diff --git a/arch/arm/mach-pxa/include/mach/mci_pxa2xx.h b/arch/arm/mach-pxa/include/mach/mci_pxa2xx.h
index b24bc58afe91..e5bc211ea8d0 100644
--- a/arch/arm/mach-pxa/include/mach/mci_pxa2xx.h
+++ b/arch/arm/mach-pxa/include/mach/mci_pxa2xx.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 
 struct mci_host;
 struct device_d;
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
index f6a27a20db19..5db786a85aa1 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_MFP_PXA27X_H
 #define __ASM_ARCH_MFP_PXA27X_H
 
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h b/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h
index 658b28ed129b..b01f6188d4e2 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_MFP_PXA2XX_H
 #define __ASM_ARCH_MFP_PXA2XX_H
 
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h b/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h
index 7bdd44db13b4..00eb7247099f 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_MFP_PXA3XX_H
 #define __ASM_ARCH_MFP_PXA3XX_H
 
diff --git a/arch/arm/mach-pxa/include/mach/pxa25x-regs.h b/arch/arm/mach-pxa/include/mach/pxa25x-regs.h
index a7f16bd418bf..f9cbe50007fd 100644
--- a/arch/arm/mach-pxa/include/mach/pxa25x-regs.h
+++ b/arch/arm/mach-pxa/include/mach/pxa25x-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_PXA25X_REGS
 #define __MACH_PXA25X_REGS
 
diff --git a/arch/arm/mach-pxa/include/mach/pxa27x-regs.h b/arch/arm/mach-pxa/include/mach/pxa27x-regs.h
index f4d88d47aba3..a97538d0125a 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x-regs.h
+++ b/arch/arm/mach-pxa/include/mach/pxa27x-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_PXA27X_REGS
 #define __MACH_PXA27X_REGS
 
diff --git a/arch/arm/mach-pxa/include/mach/pxafb.h b/arch/arm/mach-pxa/include/mach/pxafb.h
index 23cbea99c898..44ac3237a30f 100644
--- a/arch/arm/mach-pxa/include/mach/pxafb.h
+++ b/arch/arm/mach-pxa/include/mach/pxafb.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * This structure describes the machine which we are running on.
  */
diff --git a/arch/arm/mach-pxa/include/mach/regs-intc.h b/arch/arm/mach-pxa/include/mach/regs-intc.h
index 68464ce1c1ea..91760b267881 100644
--- a/arch/arm/mach-pxa/include/mach/regs-intc.h
+++ b/arch/arm/mach-pxa/include/mach/regs-intc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MACH_REGS_INTC_H
 #define __ASM_MACH_REGS_INTC_H
 
diff --git a/arch/arm/mach-pxa/include/mach/regs-lcd.h b/arch/arm/mach-pxa/include/mach/regs-lcd.h
index a6d0817ae692..4d473f23ae36 100644
--- a/arch/arm/mach-pxa/include/mach/regs-lcd.h
+++ b/arch/arm/mach-pxa/include/mach/regs-lcd.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_REGS_LCD_H
 #define __ASM_ARCH_REGS_LCD_H
 
diff --git a/arch/arm/mach-pxa/include/mach/regs-ost.h b/arch/arm/mach-pxa/include/mach/regs-ost.h
index a3e5f86ef67e..aefdee44f86a 100644
--- a/arch/arm/mach-pxa/include/mach/regs-ost.h
+++ b/arch/arm/mach-pxa/include/mach/regs-ost.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MACH_REGS_OST_H
 #define __ASM_MACH_REGS_OST_H
 
diff --git a/arch/arm/mach-pxa/include/mach/udc_pxa2xx.h b/arch/arm/mach-pxa/include/mach/udc_pxa2xx.h
index dcdd36a3b46c..1ddfa7b79714 100644
--- a/arch/arm/mach-pxa/include/mach/udc_pxa2xx.h
+++ b/arch/arm/mach-pxa/include/mach/udc_pxa2xx.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * arch/arm/mach-pxa/include/mach/udc_pxa2xx.h
  *
diff --git a/arch/arm/mach-rockchip/include/mach/atf.h b/arch/arm/mach-rockchip/include/mach/atf.h
index 337a8261c89f..ab328cc8d20a 100644
--- a/arch/arm/mach-rockchip/include/mach/atf.h
+++ b/arch/arm/mach-rockchip/include/mach/atf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ATF_H
 #define __MACH_ATF_H
 
diff --git a/arch/arm/mach-rockchip/include/mach/bbu.h b/arch/arm/mach-rockchip/include/mach/bbu.h
index 7fb08a0a9e54..2cc9b74081e4 100644
--- a/arch/arm/mach-rockchip/include/mach/bbu.h
+++ b/arch/arm/mach-rockchip/include/mach/bbu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ROCKCHIP_BBU_H
 #define __MACH_ROCKCHIP_BBU_H
 
diff --git a/arch/arm/mach-rockchip/include/mach/debug_ll.h b/arch/arm/mach-rockchip/include/mach/debug_ll.h
index af6257a674a2..73fc5b5db2ff 100644
--- a/arch/arm/mach-rockchip/include/mach/debug_ll.h
+++ b/arch/arm/mach-rockchip/include/mach/debug_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_DEBUG_LL_H__
 #define __MACH_DEBUG_LL_H__
 
diff --git a/arch/arm/mach-rockchip/include/mach/rk3568-regs.h b/arch/arm/mach-rockchip/include/mach/rk3568-regs.h
index bb2ca7bd9026..edd5ee268d5d 100644
--- a/arch/arm/mach-rockchip/include/mach/rk3568-regs.h
+++ b/arch/arm/mach-rockchip/include/mach/rk3568-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_RK3568_REGS_H
 #define __MACH_RK3568_REGS_H
 
diff --git a/arch/arm/mach-rockchip/include/mach/rockchip.h b/arch/arm/mach-rockchip/include/mach/rockchip.h
index 269d113bc39f..f24db36f0161 100644
--- a/arch/arm/mach-rockchip/include/mach/rockchip.h
+++ b/arch/arm/mach-rockchip/include/mach/rockchip.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ROCKCHIP_H
 #define __MACH_ROCKCHIP_H
 
diff --git a/arch/arm/mach-samsung/include/mach/bbu.h b/arch/arm/mach-samsung/include/mach/bbu.h
index 7ce7052bcf62..ddc72a622d16 100644
--- a/arch/arm/mach-samsung/include/mach/bbu.h
+++ b/arch/arm/mach-samsung/include/mach/bbu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_BBU_H
 #define __MACH_BBU_H
 
diff --git a/arch/arm/mach-socfpga/include/mach/arria10-xload.h b/arch/arm/mach-socfpga/include/mach/arria10-xload.h
index 7575231bbf34..c58ab7f8cfd2 100644
--- a/arch/arm/mach-socfpga/include/mach/arria10-xload.h
+++ b/arch/arm/mach-socfpga/include/mach/arria10-xload.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_ARRIA10_XLOAD_H
 #define __MACH_ARRIA10_XLOAD_H
 
diff --git a/arch/arm/mach-socfpga/include/mach/barebox-arm-head.h b/arch/arm/mach-socfpga/include/mach/barebox-arm-head.h
index 28fb1c92fc77..634d3f109b45 100644
--- a/arch/arm/mach-socfpga/include/mach/barebox-arm-head.h
+++ b/arch/arm/mach-socfpga/include/mach/barebox-arm-head.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 static inline void __barebox_arm_head(void)
 {
 	__asm__ __volatile__ (
diff --git a/arch/arm/mach-socfpga/include/mach/cyclone5-regs.h b/arch/arm/mach-socfpga/include/mach/cyclone5-regs.h
index 1a7d787a27bf..4200e8836018 100644
--- a/arch/arm/mach-socfpga/include/mach/cyclone5-regs.h
+++ b/arch/arm/mach-socfpga/include/mach/cyclone5-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_SOCFPGA_REGS_H
 #define __MACH_SOCFPGA_REGS_H
 
diff --git a/arch/arm/mach-socfpga/include/mach/cyclone5-sdram-config.h b/arch/arm/mach-socfpga/include/mach/cyclone5-sdram-config.h
index a19a837994e2..7b11d8d08899 100644
--- a/arch/arm/mach-socfpga/include/mach/cyclone5-sdram-config.h
+++ b/arch/arm/mach-socfpga/include/mach/cyclone5-sdram-config.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_SDRAM_CONFIG_H
 #define __MACH_SDRAM_CONFIG_H
 
diff --git a/arch/arm/mach-socfpga/include/mach/debug_ll.h b/arch/arm/mach-socfpga/include/mach/debug_ll.h
index 3264934e6d1a..44f56640e89b 100644
--- a/arch/arm/mach-socfpga/include/mach/debug_ll.h
+++ b/arch/arm/mach-socfpga/include/mach/debug_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_DEBUG_LL_H__
 #define   __MACH_DEBUG_LL_H__
 
diff --git a/arch/arm/mach-socfpga/include/mach/generic.h b/arch/arm/mach-socfpga/include/mach/generic.h
index c8ee73fe2e1f..6c359e2abbd7 100644
--- a/arch/arm/mach-socfpga/include/mach/generic.h
+++ b/arch/arm/mach-socfpga/include/mach/generic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_SOCFPGA_GENERIC_H
 #define __MACH_SOCFPGA_GENERIC_H
 
diff --git a/arch/arm/mach-socfpga/include/mach/lowlevel.h b/arch/arm/mach-socfpga/include/mach/lowlevel.h
index 8134a023573b..8f3b682fa433 100644
--- a/arch/arm/mach-socfpga/include/mach/lowlevel.h
+++ b/arch/arm/mach-socfpga/include/mach/lowlevel.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_SOCFPGA_LOWLEVEL_H
 #define __MACH_SOCFPGA_LOWLEVEL_H
 
diff --git a/arch/arm/mach-socfpga/include/mach/pll_config.h b/arch/arm/mach-socfpga/include/mach/pll_config.h
index d6fb60dd2442..ded3c0d09ef6 100644
--- a/arch/arm/mach-socfpga/include/mach/pll_config.h
+++ b/arch/arm/mach-socfpga/include/mach/pll_config.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _MACH_SOCFPGA_PRELOADER_PLL_CONFIG_H_
 #define _MACH_SOCFPGA_PRELOADER_PLL_CONFIG_H_
 
diff --git a/arch/arm/mach-stm32mp/include/mach/bbu.h b/arch/arm/mach-stm32mp/include/mach/bbu.h
index 8b9504400e9e..d49fb045ea06 100644
--- a/arch/arm/mach-stm32mp/include/mach/bbu.h
+++ b/arch/arm/mach-stm32mp/include/mach/bbu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef MACH_STM32MP_BBU_H_
 #define MACH_STM32MP_BBU_H_
 
diff --git a/arch/arm/mach-stm32mp/include/mach/bsec.h b/arch/arm/mach-stm32mp/include/mach/bsec.h
index d3cb91b1fdb1..7206a020998f 100644
--- a/arch/arm/mach-stm32mp/include/mach/bsec.h
+++ b/arch/arm/mach-stm32mp/include/mach/bsec.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_STM32_BSEC_H__
 #define __MACH_STM32_BSEC_H__
 
diff --git a/arch/arm/mach-stm32mp/include/mach/debug_ll.h b/arch/arm/mach-stm32mp/include/mach/debug_ll.h
index 99fedb91fe67..22c5c126335f 100644
--- a/arch/arm/mach-stm32mp/include/mach/debug_ll.h
+++ b/arch/arm/mach-stm32mp/include/mach/debug_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_STM32MP1_DEBUG_LL_H
 #define __MACH_STM32MP1_DEBUG_LL_H
 
diff --git a/arch/arm/mach-stm32mp/include/mach/entry.h b/arch/arm/mach-stm32mp/include/mach/entry.h
index 92e15b5cf4e3..f8d981cca7cd 100644
--- a/arch/arm/mach-stm32mp/include/mach/entry.h
+++ b/arch/arm/mach-stm32mp/include/mach/entry.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _STM32MP_MACH_ENTRY_H_
 #define _STM32MP_MACH_ENTRY_H_
 
diff --git a/arch/arm/mach-stm32mp/include/mach/smc.h b/arch/arm/mach-stm32mp/include/mach/smc.h
index 6b8e62bd5302..c0b86b2203f5 100644
--- a/arch/arm/mach-stm32mp/include/mach/smc.h
+++ b/arch/arm/mach-stm32mp/include/mach/smc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_STM32_SMC_H__
 #define __MACH_STM32_SMC_H__
 
diff --git a/arch/arm/mach-uemd/include/mach/hardware.h b/arch/arm/mach-uemd/include/mach/hardware.h
index 2311ebf1cdc2..5c75b35dde56 100644
--- a/arch/arm/mach-uemd/include/mach/hardware.h
+++ b/arch/arm/mach-uemd/include/mach/hardware.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
diff --git a/arch/arm/mach-versatile/include/mach/init.h b/arch/arm/mach-versatile/include/mach/init.h
index acb0f660a2bd..e47aa857a17d 100644
--- a/arch/arm/mach-versatile/include/mach/init.h
+++ b/arch/arm/mach-versatile/include/mach/init.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #ifndef __VERSATILE_INIT_H__
 #define __VERSATILE_INIT_H__
diff --git a/arch/arm/mach-zynq/include/mach/debug_ll.h b/arch/arm/mach-zynq/include/mach/debug_ll.h
index 6c20dd534de1..1f626cd4132c 100644
--- a/arch/arm/mach-zynq/include/mach/debug_ll.h
+++ b/arch/arm/mach-zynq/include/mach/debug_ll.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * based on mach-imx/include/mach/debug_ll.h
  */
diff --git a/arch/arm/mach-zynq/include/mach/zynq-flash-header.h b/arch/arm/mach-zynq/include/mach/zynq-flash-header.h
index ba4b67f479e9..320037e9b5b9 100644
--- a/arch/arm/mach-zynq/include/mach/zynq-flash-header.h
+++ b/arch/arm/mach-zynq/include/mach/zynq-flash-header.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_FLASH_HEADER_H
 #define __MACH_FLASH_HEADER_H
 
diff --git a/arch/mips/include/asm/asm-offsets.h b/arch/mips/include/asm/asm-offsets.h
index d370ee36a182..33db5a47e5c2 100644
--- a/arch/mips/include/asm/asm-offsets.h
+++ b/arch/mips/include/asm/asm-offsets.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <generated/asm-offsets.h>
diff --git a/arch/mips/include/asm/bitsperlong.h b/arch/mips/include/asm/bitsperlong.h
index 6dc0bb0c13b2..bf000a04ccde 100644
--- a/arch/mips/include/asm/bitsperlong.h
+++ b/arch/mips/include/asm/bitsperlong.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/bitsperlong.h>
diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h
index 4bb39b1cd407..f2f50986c7bf 100644
--- a/arch/mips/include/asm/cache.h
+++ b/arch/mips/include/asm/cache.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_MIPS_CACHE_H
 #define _ASM_MIPS_CACHE_H
 
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 9d94eb346b85..155e254a812a 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * cpu.h: Values of the PRId register used to match up
  *        various MIPS cpu types.
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index c71a087038d0..19d5b3f7bc4d 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_DMA_MAPPING_H
 #define _ASM_DMA_MAPPING_H
 
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 4df9853680a9..0d228aa0f515 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Stolen from the linux-2.6/include/asm-generic/io.h
  */
diff --git a/arch/mips/include/asm/memory.h b/arch/mips/include/asm/memory.h
index 2aa28b76861b..0821b432f84e 100644
--- a/arch/mips/include/asm/memory.h
+++ b/arch/mips/include/asm/memory.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MIPS_MEMORY_H
 #define __ASM_MIPS_MEMORY_H
 
diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h
index 95af87142027..1c2646ebb339 100644
--- a/arch/mips/include/asm/mmu.h
+++ b/arch/mips/include/asm/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MMU_H
 #define __ASM_MMU_H
 
diff --git a/arch/mips/mach-ar231x/include/mach/pbl_macros.h b/arch/mips/mach-ar231x/include/mach/pbl_macros.h
index cb72dbe46696..b93760a81b06 100644
--- a/arch/mips/mach-ar231x/include/mach/pbl_macros.h
+++ b/arch/mips/mach-ar231x/include/mach/pbl_macros.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MACH_AR2312_PBL_MACROS_H
 #define __ASM_MACH_AR2312_PBL_MACROS_H
 
diff --git a/arch/mips/mach-ath79/include/mach/pbl_ll_init_ar9344_1.1.h b/arch/mips/mach-ath79/include/mach/pbl_ll_init_ar9344_1.1.h
index 594ec115537a..08a3256a7916 100644
--- a/arch/mips/mach-ath79/include/mach/pbl_ll_init_ar9344_1.1.h
+++ b/arch/mips/mach-ath79/include/mach/pbl_ll_init_ar9344_1.1.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MACH_ATH79_PBL_LL_INIT_AR9344_1_1_H
 #define __ASM_MACH_ATH79_PBL_LL_INIT_AR9344_1_1_H
 
diff --git a/arch/mips/mach-ath79/include/mach/pbl_ll_init_qca4531.h b/arch/mips/mach-ath79/include/mach/pbl_ll_init_qca4531.h
index 002778b3ec93..18bf26b8ac53 100644
--- a/arch/mips/mach-ath79/include/mach/pbl_ll_init_qca4531.h
+++ b/arch/mips/mach-ath79/include/mach/pbl_ll_init_qca4531.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MACH_ATH79_PBL_LL_INIT_QCA4531_H
 #define __ASM_MACH_ATH79_PBL_LL_INIT_QCA4531_H
 
diff --git a/arch/mips/mach-ath79/include/mach/pbl_macros.h b/arch/mips/mach-ath79/include/mach/pbl_macros.h
index c5f3d4150ea4..f101b41708eb 100644
--- a/arch/mips/mach-ath79/include/mach/pbl_macros.h
+++ b/arch/mips/mach-ath79/include/mach/pbl_macros.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MACH_ATH79_PBL_MACROS_H
 #define __ASM_MACH_ATH79_PBL_MACROS_H
 
diff --git a/arch/mips/mach-loongson/include/mach/pbl_macros.h b/arch/mips/mach-loongson/include/mach/pbl_macros.h
index 93402d1c541a..8e9b231c45e9 100644
--- a/arch/mips/mach-loongson/include/mach/pbl_macros.h
+++ b/arch/mips/mach-loongson/include/mach/pbl_macros.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MACH_LOONGSON1_PBL_MACROS_H
 #define __ASM_MACH_LOONGSON1_PBL_MACROS_H
 
diff --git a/arch/mips/mach-malta/include/mach/mach-gt64120.h b/arch/mips/mach-malta/include/mach/mach-gt64120.h
index 8f20fcf26f9f..e7d230655c26 100644
--- a/arch/mips/mach-malta/include/mach/mach-gt64120.h
+++ b/arch/mips/mach-malta/include/mach/mach-gt64120.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  *  This is a direct copy of the ev96100.h file, with a global
  * search and replace.	The numbers are the same.
diff --git a/arch/mips/mach-xburst/include/mach/devices.h b/arch/mips/mach-xburst/include/mach/devices.h
index 931749d42441..1e5e9476aae1 100644
--- a/arch/mips/mach-xburst/include/mach/devices.h
+++ b/arch/mips/mach-xburst/include/mach/devices.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __MACH_XBURST_DEVICES_H
 #define __MACH_XBURST_DEVICES_H
 
diff --git a/arch/openrisc/boards/generic/config.h b/arch/openrisc/boards/generic/config.h
index f6a054beed82..2d836d0063ed 100644
--- a/arch/openrisc/boards/generic/config.h
+++ b/arch/openrisc/boards/generic/config.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef _GENERIC_NAMES_H_
 #define _GENERIC_NAMES_H_
 
diff --git a/arch/openrisc/include/asm/bitsperlong.h b/arch/openrisc/include/asm/bitsperlong.h
index 6dc0bb0c13b2..bf000a04ccde 100644
--- a/arch/openrisc/include/asm/bitsperlong.h
+++ b/arch/openrisc/include/asm/bitsperlong.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/bitsperlong.h>
diff --git a/arch/openrisc/include/asm/byteorder.h b/arch/openrisc/include/asm/byteorder.h
index 60d14f7e14e2..bd60c438a930 100644
--- a/arch/openrisc/include/asm/byteorder.h
+++ b/arch/openrisc/include/asm/byteorder.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/byteorder/big_endian.h>
diff --git a/arch/openrisc/include/asm/common.h b/arch/openrisc/include/asm/common.h
index 027dca2d5682..06bb4824a268 100644
--- a/arch/openrisc/include/asm/common.h
+++ b/arch/openrisc/include/asm/common.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_COMMON_H
 #define __ASM_COMMON_H
 
diff --git a/arch/openrisc/include/asm/linkage.h b/arch/openrisc/include/asm/linkage.h
index dbe4b4e31a5b..aebd618b27b5 100644
--- a/arch/openrisc/include/asm/linkage.h
+++ b/arch/openrisc/include/asm/linkage.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_LINKAGE_H
 #define __ASM_LINKAGE_H
 
diff --git a/arch/openrisc/include/asm/mmu.h b/arch/openrisc/include/asm/mmu.h
index 95af87142027..1c2646ebb339 100644
--- a/arch/openrisc/include/asm/mmu.h
+++ b/arch/openrisc/include/asm/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MMU_H
 #define __ASM_MMU_H
 
diff --git a/arch/openrisc/include/asm/posix_types.h b/arch/openrisc/include/asm/posix_types.h
index 22cae6230ceb..feaed4247135 100644
--- a/arch/openrisc/include/asm/posix_types.h
+++ b/arch/openrisc/include/asm/posix_types.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/posix_types.h>
diff --git a/arch/openrisc/include/asm/sections.h b/arch/openrisc/include/asm/sections.h
index 2b8c5160388f..c6dd0eead244 100644
--- a/arch/openrisc/include/asm/sections.h
+++ b/arch/openrisc/include/asm/sections.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/sections.h>
diff --git a/arch/openrisc/include/asm/string.h b/arch/openrisc/include/asm/string.h
index 73e265564ae6..cfc2ea1f376e 100644
--- a/arch/openrisc/include/asm/string.h
+++ b/arch/openrisc/include/asm/string.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_OPENRISC_STRING_H
 #define __ASM_OPENRISC_STRING_H
 
diff --git a/arch/openrisc/include/asm/swab.h b/arch/openrisc/include/asm/swab.h
index b07e1d51f121..0b49949db8ea 100644
--- a/arch/openrisc/include/asm/swab.h
+++ b/arch/openrisc/include/asm/swab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_SWAB_H
 #define _ASM_SWAB_H
 
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index af3c61a823eb..814bf50d6343 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * PowerPC atomic operations
  */
diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h
index 2fdd57eff085..543612e6ede3 100644
--- a/arch/powerpc/include/asm/bitops.h
+++ b/arch/powerpc/include/asm/bitops.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * bitops.h: Bit string operations on the ppc
  */
diff --git a/arch/powerpc/include/asm/bitsperlong.h b/arch/powerpc/include/asm/bitsperlong.h
index 6dc0bb0c13b2..bf000a04ccde 100644
--- a/arch/powerpc/include/asm/bitsperlong.h
+++ b/arch/powerpc/include/asm/bitsperlong.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/bitsperlong.h>
diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index 147ceb6714ba..c9066099ab6d 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * include/asm-ppc/cache.h
  */
diff --git a/arch/powerpc/include/asm/common.h b/arch/powerpc/include/asm/common.h
index b91f51e46219..1e1ea4601dcc 100644
--- a/arch/powerpc/include/asm/common.h
+++ b/arch/powerpc/include/asm/common.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_COMMON_H
 #define __ASM_COMMON_H
 
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 30d098702380..88f14b54f4b9 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* originally from linux source.
  * removed the dependencies on CONFIG_ values
  * removed virt_to_phys stuff (and in fact everything surrounded by #if __KERNEL__)
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index c691de1c77b0..81a5d7d55f93 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * PowerPC memory management structures
  */
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index 09c04402c541..e5c10e35da49 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 
 /**/
 struct mod_arch_specific {
diff --git a/arch/powerpc/include/asm/pci_io.h b/arch/powerpc/include/asm/pci_io.h
index 9b738c383f7d..d601a9671e7d 100644
--- a/arch/powerpc/include/asm/pci_io.h
+++ b/arch/powerpc/include/asm/pci_io.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* originally from linux source (asm-ppc/io.h).
  * Sanity added by Rob Taylor, Flying Pig Systems, 2000
  */
diff --git a/arch/powerpc/include/asm/posix_types.h b/arch/powerpc/include/asm/posix_types.h
index 22cae6230ceb..feaed4247135 100644
--- a/arch/powerpc/include/asm/posix_types.h
+++ b/arch/powerpc/include/asm/posix_types.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/posix_types.h>
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index f4677d11e124..b9b73580c41b 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
 
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index b4d599f43bbd..c7800576d53a 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _PPC_PTRACE_H
 #define _PPC_PTRACE_H
 
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 2b8c5160388f..c6dd0eead244 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/sections.h>
diff --git a/arch/powerpc/include/asm/sigcontext.h b/arch/powerpc/include/asm/sigcontext.h
index 4bd66a707da9..78648b089c11 100644
--- a/arch/powerpc/include/asm/sigcontext.h
+++ b/arch/powerpc/include/asm/sigcontext.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_PPC_SIGCONTEXT_H
 #define _ASM_PPC_SIGCONTEXT_H
 
diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h
index b11a28efd149..851fc7d41c8f 100644
--- a/arch/powerpc/include/asm/signal.h
+++ b/arch/powerpc/include/asm/signal.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASMPPC_SIGNAL_H
 #define _ASMPPC_SIGNAL_H
 
diff --git a/arch/powerpc/include/asm/status_led.h b/arch/powerpc/include/asm/status_led.h
index eb81f371c964..129aa6614ab6 100644
--- a/arch/powerpc/include/asm/status_led.h
+++ b/arch/powerpc/include/asm/status_led.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * asm/status_led.h
  *
diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h
index 33d143f04eac..b06bb4cbff4a 100644
--- a/arch/powerpc/include/asm/string.h
+++ b/arch/powerpc/include/asm/string.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _PPC_STRING_H_
 #define _PPC_STRING_H_
 
diff --git a/arch/powerpc/include/asm/types.h b/arch/powerpc/include/asm/types.h
index f3d41905cafe..c2c501828b46 100644
--- a/arch/powerpc/include/asm/types.h
+++ b/arch/powerpc/include/asm/types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _PPC_TYPES_H
 #define _PPC_TYPES_H
 
diff --git a/arch/powerpc/include/asm/unaligned.h b/arch/powerpc/include/asm/unaligned.h
index a41fa8cb4a6b..a28cc24b12ea 100644
--- a/arch/powerpc/include/asm/unaligned.h
+++ b/arch/powerpc/include/asm/unaligned.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_PPC_UNALIGNED_H
 #define _ASM_PPC_UNALIGNED_H
 
diff --git a/arch/powerpc/mach-mpc5xxx/include/mach/clock.h b/arch/powerpc/mach-mpc5xxx/include/mach/clock.h
index b19686f18c6c..1813740eb151 100644
--- a/arch/powerpc/mach-mpc5xxx/include/mach/clock.h
+++ b/arch/powerpc/mach-mpc5xxx/include/mach/clock.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_CLOCKS_H
 #define __ASM_ARCH_CLOCKS_H
 
diff --git a/arch/powerpc/mach-mpc5xxx/include/mach/sdma.h b/arch/powerpc/mach-mpc5xxx/include/mach/sdma.h
index 6a25d79fb61a..02f561675a03 100644
--- a/arch/powerpc/mach-mpc5xxx/include/mach/sdma.h
+++ b/arch/powerpc/mach-mpc5xxx/include/mach/sdma.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * (C) Copyright 2003
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
diff --git a/arch/powerpc/mach-mpc85xx/include/mach/clock.h b/arch/powerpc/mach-mpc85xx/include/mach/clock.h
index 0e68cf6667e5..bfd9cf4d8ecd 100644
--- a/arch/powerpc/mach-mpc85xx/include/mach/clock.h
+++ b/arch/powerpc/mach-mpc85xx/include/mach/clock.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_CLOCKS_H
 #define __ASM_ARCH_CLOCKS_H
 
diff --git a/arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h b/arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h
index 1d9993ace9a4..5491f0b08d64 100644
--- a/arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h
+++ b/arch/powerpc/mach-mpc85xx/include/mach/mpc85xx.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Copyright 2004, 2007 Freescale Semiconductor.
  * Copyright(c) 2003 Motorola Inc.
diff --git a/arch/riscv/include/asm/asm-offsets.h b/arch/riscv/include/asm/asm-offsets.h
index d370ee36a182..33db5a47e5c2 100644
--- a/arch/riscv/include/asm/asm-offsets.h
+++ b/arch/riscv/include/asm/asm-offsets.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <generated/asm-offsets.h>
diff --git a/arch/riscv/include/asm/bitsperlong.h b/arch/riscv/include/asm/bitsperlong.h
index 6dc0bb0c13b2..bf000a04ccde 100644
--- a/arch/riscv/include/asm/bitsperlong.h
+++ b/arch/riscv/include/asm/bitsperlong.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/bitsperlong.h>
diff --git a/arch/riscv/include/asm/byteorder.h b/arch/riscv/include/asm/byteorder.h
index 0be826927bd3..36dfd3752401 100644
--- a/arch/riscv/include/asm/byteorder.h
+++ b/arch/riscv/include/asm/byteorder.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_RISCV_BYTEORDER_H
 #define _ASM_RISCV_BYTEORDER_H
 
diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h
index 795e670e3b9b..978f64434078 100644
--- a/arch/riscv/include/asm/io.h
+++ b/arch/riscv/include/asm/io.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_RISCV_IO_H
 #define __ASM_RISCV_IO_H
 
diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h
index 95af87142027..1c2646ebb339 100644
--- a/arch/riscv/include/asm/mmu.h
+++ b/arch/riscv/include/asm/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MMU_H
 #define __ASM_MMU_H
 
diff --git a/arch/riscv/include/asm/posix_types.h b/arch/riscv/include/asm/posix_types.h
index 22cae6230ceb..feaed4247135 100644
--- a/arch/riscv/include/asm/posix_types.h
+++ b/arch/riscv/include/asm/posix_types.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/posix_types.h>
diff --git a/arch/riscv/include/asm/swab.h b/arch/riscv/include/asm/swab.h
index 60a90120b6e6..0ca746f0f144 100644
--- a/arch/riscv/include/asm/swab.h
+++ b/arch/riscv/include/asm/swab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_SWAB_H
 #define _ASM_SWAB_H
 
diff --git a/arch/riscv/include/asm/types.h b/arch/riscv/include/asm/types.h
index 1ad5904f9178..add1c94fc7ae 100644
--- a/arch/riscv/include/asm/types.h
+++ b/arch/riscv/include/asm/types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_RISCV_TYPES_H
 #define __ASM_RISCV_TYPES_H
 
diff --git a/arch/riscv/include/asm/unaligned.h b/arch/riscv/include/asm/unaligned.h
index c37b71c21ee5..3bc29309894e 100644
--- a/arch/riscv/include/asm/unaligned.h
+++ b/arch/riscv/include/asm/unaligned.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_RISCV_UNALIGNED_H
 #define _ASM_RISCV_UNALIGNED_H
 
diff --git a/arch/sandbox/include/asm/bitsperlong.h b/arch/sandbox/include/asm/bitsperlong.h
index 6dc0bb0c13b2..bf000a04ccde 100644
--- a/arch/sandbox/include/asm/bitsperlong.h
+++ b/arch/sandbox/include/asm/bitsperlong.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/bitsperlong.h>
diff --git a/arch/sandbox/include/asm/byteorder.h b/arch/sandbox/include/asm/byteorder.h
index 3d82bcba6e1b..fdb421c7a53c 100644
--- a/arch/sandbox/include/asm/byteorder.h
+++ b/arch/sandbox/include/asm/byteorder.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _SANDBOX_BYTEORDER_H
 #define _SANDBOX_BYTEORDER_H
 
diff --git a/arch/sandbox/include/asm/common.h b/arch/sandbox/include/asm/common.h
index 9b8bd2d94c63..66ed2f5e9c52 100644
--- a/arch/sandbox/include/asm/common.h
+++ b/arch/sandbox/include/asm/common.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef ASM_COMMON_H
 #define ASM_COMMON_H
 
diff --git a/arch/sandbox/include/asm/elf.h b/arch/sandbox/include/asm/elf.h
index e71a60aeb93f..f08d5930c66d 100644
--- a/arch/sandbox/include/asm/elf.h
+++ b/arch/sandbox/include/asm/elf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_SANDBOX_ELF_H__
 #define __ASM_SANDBOX_ELF_H__
 
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h
index 3e5c0580bc5a..71cf50cd9a03 100644
--- a/arch/sandbox/include/asm/io.h
+++ b/arch/sandbox/include/asm/io.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_SANDBOX_IO_H
 #define __ASM_SANDBOX_IO_H
 
diff --git a/arch/sandbox/include/asm/mmu.h b/arch/sandbox/include/asm/mmu.h
index 95af87142027..1c2646ebb339 100644
--- a/arch/sandbox/include/asm/mmu.h
+++ b/arch/sandbox/include/asm/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MMU_H
 #define __ASM_MMU_H
 
diff --git a/arch/sandbox/include/asm/posix_types.h b/arch/sandbox/include/asm/posix_types.h
index 22cae6230ceb..feaed4247135 100644
--- a/arch/sandbox/include/asm/posix_types.h
+++ b/arch/sandbox/include/asm/posix_types.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/posix_types.h>
diff --git a/arch/sandbox/include/asm/sections.h b/arch/sandbox/include/asm/sections.h
index 2b8c5160388f..c6dd0eead244 100644
--- a/arch/sandbox/include/asm/sections.h
+++ b/arch/sandbox/include/asm/sections.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/sections.h>
diff --git a/arch/sandbox/include/asm/string.h b/arch/sandbox/include/asm/string.h
index 2997587d820c..b3c27a412d69 100644
--- a/arch/sandbox/include/asm/string.h
+++ b/arch/sandbox/include/asm/string.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /* dummy */
diff --git a/arch/sandbox/include/asm/swab.h b/arch/sandbox/include/asm/swab.h
index 60a90120b6e6..0ca746f0f144 100644
--- a/arch/sandbox/include/asm/swab.h
+++ b/arch/sandbox/include/asm/swab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_SWAB_H
 #define _ASM_SWAB_H
 
diff --git a/arch/sandbox/include/asm/types.h b/arch/sandbox/include/asm/types.h
index 7b356a99eb66..e29dde377c1d 100644
--- a/arch/sandbox/include/asm/types.h
+++ b/arch/sandbox/include/asm/types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_SANDBOX_TYPES_H
 #define __ASM_SANDBOX_TYPES_H
 
diff --git a/arch/sandbox/include/asm/unaligned.h b/arch/sandbox/include/asm/unaligned.h
index d02da6e60d2e..7bca3ff8a4aa 100644
--- a/arch/sandbox/include/asm/unaligned.h
+++ b/arch/sandbox/include/asm/unaligned.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_SANDBOX_UNALIGNED_H
 #define _ASM_SANDBOX_UNALIGNED_H
 
diff --git a/arch/sandbox/mach-sandbox/include/mach/hostfile.h b/arch/sandbox/mach-sandbox/include/mach/hostfile.h
index 3ef34bcc1c22..b461d5ebc359 100644
--- a/arch/sandbox/mach-sandbox/include/mach/hostfile.h
+++ b/arch/sandbox/mach-sandbox/include/mach/hostfile.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_HOSTFILE_H
 #define __ASM_ARCH_HOSTFILE_H
 
diff --git a/arch/sandbox/mach-sandbox/include/mach/linux.h b/arch/sandbox/mach-sandbox/include/mach/linux.h
index 453813952e55..1584d8065c7f 100644
--- a/arch/sandbox/mach-sandbox/include/mach/linux.h
+++ b/arch/sandbox/mach-sandbox/include/mach/linux.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_ARCH_LINUX_H
 #define __ASM_ARCH_LINUX_H
 
diff --git a/arch/x86/include/asm/bitsperlong.h b/arch/x86/include/asm/bitsperlong.h
index 6dc0bb0c13b2..bf000a04ccde 100644
--- a/arch/x86/include/asm/bitsperlong.h
+++ b/arch/x86/include/asm/bitsperlong.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/bitsperlong.h>
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index ddde03518817..365e6cd02ba2 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_SANDBOX_ELF_H__
 #define __ASM_SANDBOX_ELF_H__
 
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 0971727bc63d..c28f49a9de7f 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Mostly stolen from the linux kernel
  */
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
index a8d1bdb7de1f..1d78d9169b6a 100644
--- a/arch/x86/include/asm/linkage.h
+++ b/arch/x86/include/asm/linkage.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_LINKAGE_H
 #define __ASM_LINKAGE_H
 
diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h
index 95af87142027..1c2646ebb339 100644
--- a/arch/x86/include/asm/mmu.h
+++ b/arch/x86/include/asm/mmu.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_MMU_H
 #define __ASM_MMU_H
 
diff --git a/arch/x86/include/asm/posix_types.h b/arch/x86/include/asm/posix_types.h
index 22cae6230ceb..feaed4247135 100644
--- a/arch/x86/include/asm/posix_types.h
+++ b/arch/x86/include/asm/posix_types.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/posix_types.h>
diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h
index 2b8c5160388f..c6dd0eead244 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/sections.h>
diff --git a/arch/x86/include/asm/swab.h b/arch/x86/include/asm/swab.h
index 557cd9f00661..e2319d9776f9 100644
--- a/arch/x86/include/asm/swab.h
+++ b/arch/x86/include/asm/swab.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_X86_SWAB_H
 #define _ASM_X86_SWAB_H
 
diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h
index 17947b2ff3fd..52a6e51fd4b1 100644
--- a/arch/x86/include/asm/types.h
+++ b/arch/x86/include/asm/types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef __ASM_I386_TYPES_H
 #define __ASM_I386_TYPES_H
 
diff --git a/arch/x86/include/asm/unaligned.h b/arch/x86/include/asm/unaligned.h
index 7e38706c5db9..a62dc88922af 100644
--- a/arch/x86/include/asm/unaligned.h
+++ b/arch/x86/include/asm/unaligned.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #ifndef _ASM_X86_UNALIGNED_H
 #define _ASM_X86_UNALIGNED_H
 
diff --git a/arch/x86/mach-efi/include/mach/debug_ll.h b/arch/x86/mach-efi/include/mach/debug_ll.h
index e144d86e0008..f7ac98635acd 100644
--- a/arch/x86/mach-efi/include/mach/debug_ll.h
+++ b/arch/x86/mach-efi/include/mach/debug_ll.h
@@ -1 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <efi/debug_ll.h>
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:37 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:37 +0100
Subject: [PATCH 09/11] arch: add SPDX-License-Identifier to all .S files
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-10-a.fatoum@pengutronix.de>

Record GPL-2.0-only as license for all files lacking an explicit license
statement.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/boards/a9m2410/lowlevel_init.S                    | 4 +---
 arch/arm/boards/a9m2440/lowlevel_init.S                    | 4 +---
 arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S            | 2 ++
 arch/arm/boards/freescale-mx27-ads/lowlevel_init.S         | 2 ++
 arch/arm/boards/friendlyarm-mini2440/lowlevel_init.S       | 2 ++
 arch/arm/boards/guf-neso/pll_init.S                        | 2 ++
 arch/arm/cpu/cache-armv4.S                                 | 2 ++
 arch/arm/cpu/cache-armv5.S                                 | 2 ++
 arch/arm/cpu/cache-armv6.S                                 | 2 ++
 arch/arm/cpu/cache-armv7.S                                 | 2 ++
 arch/arm/cpu/entry_ll.S                                    | 2 ++
 arch/arm/cpu/entry_ll_64.S                                 | 2 ++
 arch/arm/cpu/exceptions.S                                  | 2 ++
 arch/arm/cpu/hyp.S                                         | 2 ++
 arch/arm/cpu/lowlevel.S                                    | 2 ++
 arch/arm/cpu/lowlevel_64.S                                 | 2 ++
 arch/arm/cpu/setupc.S                                      | 2 ++
 arch/arm/cpu/setupc_64.S                                   | 2 ++
 arch/arm/cpu/sm_as.S                                       | 2 ++
 arch/arm/lib32/runtime-offset.S                            | 2 ++
 arch/arm/lib32/start-kernel-optee.S                        | 2 ++
 arch/arm/lib64/runtime-offset.S                            | 2 ++
 arch/arm/mach-layerscape/lowlevel.S                        | 2 ++
 arch/arm/mach-layerscape/ppa-entry.S                       | 2 ++
 arch/mips/lib/genex.S                                      | 2 ++
 arch/mips/pbl/piggy.gzip.S                                 | 2 ++
 arch/mips/pbl/piggy.lz4.S                                  | 2 ++
 arch/mips/pbl/piggy.lzo.S                                  | 2 ++
 arch/mips/pbl/piggy.shipped.S                              | 2 ++
 arch/mips/pbl/piggy.xzkern.S                               | 2 ++
 arch/openrisc/lib/ashldi3.S                                | 2 ++
 arch/openrisc/lib/lshrdi3.S                                | 2 ++
 arch/openrisc/lib/muldi3.S                                 | 2 ++
 arch/powerpc/cpu-85xx/resetvec.S                           | 2 ++
 arch/powerpc/lib/misc.S                                    | 1 +
 arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S | 2 ++
 arch/sandbox/board/barebox.lds.S                           | 2 ++
 arch/x86/mach-efi/elf_ia32_efi.lds.S                       | 2 ++
 arch/x86/mach-efi/elf_x86_64_efi.lds.S                     | 2 ++
 39 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boards/a9m2410/lowlevel_init.S b/arch/arm/boards/a9m2410/lowlevel_init.S
index b772b1f7f0c6..4c949b1efacc 100644
--- a/arch/arm/boards/a9m2410/lowlevel_init.S
+++ b/arch/arm/boards/a9m2410/lowlevel_init.S
@@ -1,6 +1,4 @@
-/*
- *
- */
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <config.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/boards/a9m2440/lowlevel_init.S b/arch/arm/boards/a9m2440/lowlevel_init.S
index 2c51e05806f3..585863f9d4d7 100644
--- a/arch/arm/boards/a9m2440/lowlevel_init.S
+++ b/arch/arm/boards/a9m2440/lowlevel_init.S
@@ -1,6 +1,4 @@
-/*
- *
- */
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <config.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S b/arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S
index b3504832d7e1..13e906eea49a 100644
--- a/arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S
+++ b/arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <config.h>
 #include <asm-generic/memory_layout.h>
 #include <mach/imx27-regs.h>
diff --git a/arch/arm/boards/freescale-mx27-ads/lowlevel_init.S b/arch/arm/boards/freescale-mx27-ads/lowlevel_init.S
index e79b96dd2cfb..bd78ebf9e84c 100644
--- a/arch/arm/boards/freescale-mx27-ads/lowlevel_init.S
+++ b/arch/arm/boards/freescale-mx27-ads/lowlevel_init.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * For clock initialization, see chapter 3 of the "MCIMX27 Multimedia
  * Applications Processor Reference Manual, Rev. 0.2".
diff --git a/arch/arm/boards/friendlyarm-mini2440/lowlevel_init.S b/arch/arm/boards/friendlyarm-mini2440/lowlevel_init.S
index 43bf49c12ce1..b26efa12b0b8 100644
--- a/arch/arm/boards/friendlyarm-mini2440/lowlevel_init.S
+++ b/arch/arm/boards/friendlyarm-mini2440/lowlevel_init.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Low level initialization for the FriendlyARM mini2440 board
  */
diff --git a/arch/arm/boards/guf-neso/pll_init.S b/arch/arm/boards/guf-neso/pll_init.S
index 4c6cb67fd48a..fe28c457fc6e 100644
--- a/arch/arm/boards/guf-neso/pll_init.S
+++ b/arch/arm/boards/guf-neso/pll_init.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <config.h>
 #include <mach/imx27-regs.h>
 #include <mach/imx-pll.h>
diff --git a/arch/arm/cpu/cache-armv4.S b/arch/arm/cpu/cache-armv4.S
index db87de17e98b..78a098b2fedf 100644
--- a/arch/arm/cpu/cache-armv4.S
+++ b/arch/arm/cpu/cache-armv4.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <init.h>
 
diff --git a/arch/arm/cpu/cache-armv5.S b/arch/arm/cpu/cache-armv5.S
index 4267f3e37fc9..bcb7ebf466f9 100644
--- a/arch/arm/cpu/cache-armv5.S
+++ b/arch/arm/cpu/cache-armv5.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <init.h>
 
diff --git a/arch/arm/cpu/cache-armv6.S b/arch/arm/cpu/cache-armv6.S
index 7a0675199757..cc720314c07b 100644
--- a/arch/arm/cpu/cache-armv6.S
+++ b/arch/arm/cpu/cache-armv6.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <init.h>
 
diff --git a/arch/arm/cpu/cache-armv7.S b/arch/arm/cpu/cache-armv7.S
index 0f6108426c0b..efd9fe412fc9 100644
--- a/arch/arm/cpu/cache-armv7.S
+++ b/arch/arm/cpu/cache-armv7.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <init.h>
 
diff --git a/arch/arm/cpu/entry_ll.S b/arch/arm/cpu/entry_ll.S
index 8cc7a84f1062..2800174c4526 100644
--- a/arch/arm/cpu/entry_ll.S
+++ b/arch/arm/cpu/entry_ll.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/sections.h>
 
diff --git a/arch/arm/cpu/entry_ll_64.S b/arch/arm/cpu/entry_ll_64.S
index fb8645e0a03f..6530bec5ebe4 100644
--- a/arch/arm/cpu/entry_ll_64.S
+++ b/arch/arm/cpu/entry_ll_64.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/sections.h>
 
diff --git a/arch/arm/cpu/exceptions.S b/arch/arm/cpu/exceptions.S
index 55014c8d460f..749c713aab5c 100644
--- a/arch/arm/cpu/exceptions.S
+++ b/arch/arm/cpu/exceptions.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <config.h>
 #include <linux/linkage.h>
 #include <asm-generic/memory_layout.h>
diff --git a/arch/arm/cpu/hyp.S b/arch/arm/cpu/hyp.S
index 1314b56eab25..b5e480787770 100644
--- a/arch/arm/cpu/hyp.S
+++ b/arch/arm/cpu/hyp.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/system.h>
 #include <asm/opcodes-virt.h>
diff --git a/arch/arm/cpu/lowlevel.S b/arch/arm/cpu/lowlevel.S
index 203a4afc4723..5a7dd3c2093f 100644
--- a/arch/arm/cpu/lowlevel.S
+++ b/arch/arm/cpu/lowlevel.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <init.h>
 #include <asm/system.h>
diff --git a/arch/arm/cpu/lowlevel_64.S b/arch/arm/cpu/lowlevel_64.S
index 6a23132ed140..ed00c8c47057 100644
--- a/arch/arm/cpu/lowlevel_64.S
+++ b/arch/arm/cpu/lowlevel_64.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <init.h>
 #include <asm/system.h>
diff --git a/arch/arm/cpu/setupc.S b/arch/arm/cpu/setupc.S
index 55aa105b2160..eafc9b52c6d0 100644
--- a/arch/arm/cpu/setupc.S
+++ b/arch/arm/cpu/setupc.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/sections.h>
 
diff --git a/arch/arm/cpu/setupc_64.S b/arch/arm/cpu/setupc_64.S
index e24acbd0da70..b5f4a643fa42 100644
--- a/arch/arm/cpu/setupc_64.S
+++ b/arch/arm/cpu/setupc_64.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/sections.h>
 
diff --git a/arch/arm/cpu/sm_as.S b/arch/arm/cpu/sm_as.S
index de6cd0406f4f..f55ac8661c6c 100644
--- a/arch/arm/cpu/sm_as.S
+++ b/arch/arm/cpu/sm_as.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/ptrace.h>
 #include <asm-generic/memory_layout.h>
diff --git a/arch/arm/lib32/runtime-offset.S b/arch/arm/lib32/runtime-offset.S
index f86ca7865eb3..ac104de1195c 100644
--- a/arch/arm/lib32/runtime-offset.S
+++ b/arch/arm/lib32/runtime-offset.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
diff --git a/arch/arm/lib32/start-kernel-optee.S b/arch/arm/lib32/start-kernel-optee.S
index 92da4b63c9b8..261ab39ba7a3 100644
--- a/arch/arm/lib32/start-kernel-optee.S
+++ b/arch/arm/lib32/start-kernel-optee.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 
 ENTRY(start_kernel_optee)
diff --git a/arch/arm/lib64/runtime-offset.S b/arch/arm/lib64/runtime-offset.S
index e2ff5d21036d..822e323c142e 100644
--- a/arch/arm/lib64/runtime-offset.S
+++ b/arch/arm/lib64/runtime-offset.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
diff --git a/arch/arm/mach-layerscape/lowlevel.S b/arch/arm/mach-layerscape/lowlevel.S
index adb3e5436727..e8e6410c525a 100644
--- a/arch/arm/mach-layerscape/lowlevel.S
+++ b/arch/arm/mach-layerscape/lowlevel.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 
 .section .text.ls1046a_init_l2_latency
diff --git a/arch/arm/mach-layerscape/ppa-entry.S b/arch/arm/mach-layerscape/ppa-entry.S
index 18cfa6c37ecf..f5f30b671930 100644
--- a/arch/arm/mach-layerscape/ppa-entry.S
+++ b/arch/arm/mach-layerscape/ppa-entry.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <linux/linkage.h>
 
 .section .text.ppa_entry
diff --git a/arch/mips/lib/genex.S b/arch/mips/lib/genex.S
index 5fb222323133..d75a652e4d6c 100644
--- a/arch/mips/lib/genex.S
+++ b/arch/mips/lib/genex.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm/asm.h>
 #include <asm/regdef.h>
 #include <asm/mipsregs.h>
diff --git a/arch/mips/pbl/piggy.gzip.S b/arch/mips/pbl/piggy.gzip.S
index 1e6bbef66c98..b99ba8aeab6f 100644
--- a/arch/mips/pbl/piggy.gzip.S
+++ b/arch/mips/pbl/piggy.gzip.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm/asm.h>
 
 	.section .data
diff --git a/arch/mips/pbl/piggy.lz4.S b/arch/mips/pbl/piggy.lz4.S
index be9425bf00ac..c3ddbdace01f 100644
--- a/arch/mips/pbl/piggy.lz4.S
+++ b/arch/mips/pbl/piggy.lz4.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm/asm.h>
 
 	.section .data
diff --git a/arch/mips/pbl/piggy.lzo.S b/arch/mips/pbl/piggy.lzo.S
index 6f1af1f314da..2c1f4cb34edc 100644
--- a/arch/mips/pbl/piggy.lzo.S
+++ b/arch/mips/pbl/piggy.lzo.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm/asm.h>
 
 	.section .data
diff --git a/arch/mips/pbl/piggy.shipped.S b/arch/mips/pbl/piggy.shipped.S
index 8a35f6bc052b..fc2859e6739f 100644
--- a/arch/mips/pbl/piggy.shipped.S
+++ b/arch/mips/pbl/piggy.shipped.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm/asm.h>
 
 	.section .data
diff --git a/arch/mips/pbl/piggy.xzkern.S b/arch/mips/pbl/piggy.xzkern.S
index edfa53b86c70..8c99d959f80c 100644
--- a/arch/mips/pbl/piggy.xzkern.S
+++ b/arch/mips/pbl/piggy.xzkern.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm/asm.h>
 
 	.section .data
diff --git a/arch/openrisc/lib/ashldi3.S b/arch/openrisc/lib/ashldi3.S
index 3e422fadc4ff..f6b976bff254 100644
--- a/arch/openrisc/lib/ashldi3.S
+++ b/arch/openrisc/lib/ashldi3.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * (C) Copyright 2011 - Franck JULLIEN <elec4fun at gmail.com>
  *
diff --git a/arch/openrisc/lib/lshrdi3.S b/arch/openrisc/lib/lshrdi3.S
index de30445f4e0f..99aa73ef51ca 100644
--- a/arch/openrisc/lib/lshrdi3.S
+++ b/arch/openrisc/lib/lshrdi3.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * (C) Copyright 2011 - Franck JULLIEN <elec4fun at gmail.com>
  *
diff --git a/arch/openrisc/lib/muldi3.S b/arch/openrisc/lib/muldi3.S
index 902338a242b7..70d0eacf1ed6 100644
--- a/arch/openrisc/lib/muldi3.S
+++ b/arch/openrisc/lib/muldi3.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * (C) Copyright 2011 - Franck JULLIEN <elec4fun at gmail.com>
  *
diff --git a/arch/powerpc/cpu-85xx/resetvec.S b/arch/powerpc/cpu-85xx/resetvec.S
index 29555d4a0092..b21cc0f19d6d 100644
--- a/arch/powerpc/cpu-85xx/resetvec.S
+++ b/arch/powerpc/cpu-85xx/resetvec.S
@@ -1,2 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 	.section .resetvec,"ax"
 	b _start_e500
diff --git a/arch/powerpc/lib/misc.S b/arch/powerpc/lib/misc.S
index bd06ff2062ca..c45f02ba3af0 100644
--- a/arch/powerpc/lib/misc.S
+++ b/arch/powerpc/lib/misc.S
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <asm/ppc_asm.tmpl>
 #include <asm-generic/errno.h>
diff --git a/arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S b/arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S
index 42d0e3ce0825..17213053d2c4 100644
--- a/arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S
+++ b/arch/powerpc/mach-mpc5xxx/firmware_sc_task_bestcomm.impl.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 /*
  * Copyright (C) 2001, Software Center, Motorola China.
  *
diff --git a/arch/sandbox/board/barebox.lds.S b/arch/sandbox/board/barebox.lds.S
index 7a5a8eb1e7ce..84d085a25911 100644
--- a/arch/sandbox/board/barebox.lds.S
+++ b/arch/sandbox/board/barebox.lds.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/barebox.lds.h>
 
 SECTIONS
diff --git a/arch/x86/mach-efi/elf_ia32_efi.lds.S b/arch/x86/mach-efi/elf_ia32_efi.lds.S
index 18ddf1780244..ac89fd89a4d3 100644
--- a/arch/x86/mach-efi/elf_ia32_efi.lds.S
+++ b/arch/x86/mach-efi/elf_ia32_efi.lds.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/barebox.lds.h>
 
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
diff --git a/arch/x86/mach-efi/elf_x86_64_efi.lds.S b/arch/x86/mach-efi/elf_x86_64_efi.lds.S
index ab4a9e815c00..b620ba5b3797 100644
--- a/arch/x86/mach-efi/elf_x86_64_efi.lds.S
+++ b/arch/x86/mach-efi/elf_x86_64_efi.lds.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
 #include <asm-generic/barebox.lds.h>
 
 /* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan  3 04:05:38 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon,  3 Jan 2022 13:05:38 +0100
Subject: [PATCH 10/11] arch: add SPDX-License-Identifier to all .c files
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220103120539.1730644-11-a.fatoum@pengutronix.de>

Record GPL-2.0-only as license for all files lacking an explicit license
statement.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/boards/afi-gf/lowlevel.c                       | 2 ++
 arch/arm/boards/altera-socdk/board.c                    | 2 ++
 arch/arm/boards/altera-socdk/lowlevel.c                 | 2 ++
 arch/arm/boards/at91sam9x5ek/lowlevel.c                 | 2 ++
 arch/arm/boards/beagle/lowlevel.c                       | 2 ++
 arch/arm/boards/beaglebone/lowlevel.c                   | 2 ++
 arch/arm/boards/boundarydevices-nitrogen6/lowlevel.c    | 2 ++
 arch/arm/boards/canon-a1100/lowlevel.c                  | 2 ++
 arch/arm/boards/chumby_falconwing/lowlevel.c            | 2 ++
 arch/arm/boards/cm-fx6/lowlevel.c                       | 2 ++
 arch/arm/boards/crystalfontz-cfa10036/lowlevel.c        | 2 ++
 arch/arm/boards/digi-ccimx6ulsom/lowlevel.c             | 2 ++
 arch/arm/boards/duckbill/lowlevel.c                     | 2 ++
 arch/arm/boards/ebv-socrates/board.c                    | 2 ++
 arch/arm/boards/ebv-socrates/lowlevel.c                 | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_auto_ac_init.c   | 2 ++
 arch/arm/boards/ebv-socrates/sequencer_auto_inst_init.c | 2 ++
 arch/arm/boards/efika-mx-smartbook/lowlevel.c           | 2 ++
 arch/arm/boards/element14-warp7/lowlevel.c              | 2 ++
 arch/arm/boards/embedsky-e9/lowlevel.c                  | 2 ++
 arch/arm/boards/embest-riotboard/lowlevel.c             | 2 ++
 arch/arm/boards/eukrea_cpuimx51/lowlevel.c              | 2 ++
 arch/arm/boards/freescale-mx23-evk/lowlevel.c           | 2 ++
 arch/arm/boards/freescale-mx28-evk/lowlevel.c           | 2 ++
 arch/arm/boards/freescale-mx51-babbage/lowlevel.c       | 2 ++
 arch/arm/boards/freescale-mx51-babbage/power.c          | 2 ++
 arch/arm/boards/freescale-mx53-qsb/lowlevel.c           | 2 ++
 arch/arm/boards/freescale-mx53-smd/lowlevel.c           | 2 ++
 arch/arm/boards/freescale-mx53-vmx53/lowlevel.c         | 2 ++
 arch/arm/boards/freescale-mx6-sabrelite/lowlevel.c      | 2 ++
 arch/arm/boards/freescale-mx6-sabresd/lowlevel.c        | 2 ++
 arch/arm/boards/freescale-mx7-sabresd/lowlevel.c        | 2 ++
 arch/arm/boards/freescale-vf610-twr/lowlevel.c          | 2 ++
 arch/arm/boards/friendlyarm-mini6410/lowlevel.c         | 2 ++
 arch/arm/boards/friendlyarm-tiny6410/lowlevel.c         | 2 ++
 arch/arm/boards/gateworks-ventana/lowlevel.c            | 2 ++
 arch/arm/boards/gk802/lowlevel.c                        | 2 ++
 arch/arm/boards/guf-santaro/lowlevel.c                  | 2 ++
 arch/arm/boards/guf-vincell/lowlevel.c                  | 2 ++
 arch/arm/boards/imx233-olinuxino/lowlevel.c             | 2 ++
 arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c    | 2 ++
 arch/arm/boards/karo-tx28/lowlevel.c                    | 2 ++
 arch/arm/boards/karo-tx53/lowlevel.c                    | 2 ++
 arch/arm/boards/kindle-mx50/lowlevel.c                  | 2 ++
 arch/arm/boards/lubbock/lowlevel.c                      | 2 ++
 arch/arm/boards/mainstone/lowlevel.c                    | 2 ++
 arch/arm/boards/mioa701/lowlevel.c                      | 2 ++
 arch/arm/boards/netgear-rn104/lowlevel.c                | 2 ++
 arch/arm/boards/netgear-rn2120/board.c                  | 2 ++
 arch/arm/boards/nhk8815/lowlevel.c                      | 2 ++
 arch/arm/boards/omap343xdsp/lowlevel.c                  | 2 ++
 arch/arm/boards/omap3evm/lowlevel.c                     | 2 ++
 arch/arm/boards/panda/board.c                           | 2 ++
 arch/arm/boards/panda/mux.c                             | 2 ++
 arch/arm/boards/phytec-phycard-imx27/lowlevel.c         | 2 ++
 arch/arm/boards/phytec-phycard-omap3/lowlevel.c         | 2 ++
 arch/arm/boards/phytec-phycard-omap4/mux.c              | 2 ++
 arch/arm/boards/phytec-phycore-imx7/lowlevel.c          | 2 ++
 arch/arm/boards/phytec-phycore-omap4460/mux.c           | 2 ++
 arch/arm/boards/raspberry-pi/lowlevel.c                 | 2 ++
 arch/arm/boards/reflex-achilles/board.c                 | 2 ++
 arch/arm/boards/reflex-achilles/lowlevel.c              | 2 ++
 arch/arm/boards/reflex-achilles/pinmux-config-arria10.c | 2 ++
 arch/arm/boards/reflex-achilles/pll-config-arria10.c    | 2 ++
 arch/arm/boards/solidrun-microsom/lowlevel.c            | 2 ++
 arch/arm/boards/technexion-pico-hobbit/lowlevel.c       | 2 ++
 arch/arm/boards/terasic-de0-nano-soc/board.c            | 2 ++
 arch/arm/boards/terasic-de0-nano-soc/lowlevel.c         | 2 ++
 arch/arm/boards/terasic-de10-nano/board.c               | 2 ++
 arch/arm/boards/terasic-de10-nano/lowlevel.c            | 2 ++
 arch/arm/boards/terasic-sockit/board.c                  | 2 ++
 arch/arm/boards/terasic-sockit/lowlevel.c               | 2 ++
 arch/arm/boards/tqma53/lowlevel.c                       | 2 ++
 arch/arm/boards/udoo-neo/lowlevel.c                     | 2 ++
 arch/arm/boards/udoo/lowlevel.c                         | 2 ++
 arch/arm/boards/versatile/lowlevel.c                    | 2 ++
 arch/arm/boards/vscom-baltos/lowlevel.c                 | 2 ++
 arch/arm/boards/zii-imx51-rdu1/lowlevel.c               | 2 ++
 arch/arm/boards/zylonite/lowlevel.c                     | 2 ++
 arch/arm/cpu/atf.c                                      | 2 ++
 arch/arm/cpu/cache-l2x0.c                               | 2 ++
 arch/arm/cpu/cache.c                                    | 2 ++
 arch/arm/cpu/entry.c                                    | 2 ++
 arch/arm/cpu/mmu-common.c                               | 2 ++
 arch/arm/cpu/mmu-early.c                                | 2 ++
 arch/arm/cpu/mmu-early_64.c                             | 4 +++-
 arch/arm/cpu/sections.c                                 | 2 ++
 arch/arm/lib32/bootm.c                                  | 2 ++
 arch/arm/lib32/bootu.c                                  | 2 ++
 arch/arm/lib32/bootz.c                                  | 2 ++
 arch/arm/lib32/io.c                                     | 2 ++
 arch/arm/lib32/unwind.c                                 | 2 ++
 arch/arm/lib64/pbl.c                                    | 2 ++
 arch/arm/lib64/string.c                                 | 2 ++
 arch/arm/mach-at91/at91rm9200.c                         | 2 ++
 arch/arm/mach-at91/at91sam9260.c                        | 2 ++
 arch/arm/mach-at91/at91sam9261.c                        | 2 ++
 arch/arm/mach-at91/at91sam9263.c                        | 2 ++
 arch/arm/mach-at91/at91sam9g45.c                        | 2 ++
 arch/arm/mach-at91/at91sam9n12.c                        | 2 ++
 arch/arm/mach-at91/at91sam9x5.c                         | 2 ++
 arch/arm/mach-at91/bootm-barebox.c                      | 2 ++
 arch/arm/mach-at91/sama5d3.c                            | 2 ++
 arch/arm/mach-at91/xload-mmc.c                          | 2 ++
 arch/arm/mach-ep93xx/header.c                           | 2 ++
 arch/arm/mach-imx/atf.c                                 | 2 ++
 arch/arm/mach-imx/devices.c                             | 2 ++
 arch/arm/mach-imx/imx5.c                                | 2 ++
 arch/arm/mach-imx/xload-common.c                        | 2 ++
 arch/arm/mach-imx/xload-spi.c                           | 2 ++
 arch/arm/mach-layerscape/icid.c                         | 2 ++
 arch/arm/mach-layerscape/pblimage.c                     | 2 ++
 arch/arm/mach-mvebu/kwb_bbu.c                           | 2 ++
 arch/arm/mach-mvebu/kwbootimage.c                       | 2 ++
 arch/arm/mach-nomadik/clock.c                           | 2 ++
 arch/arm/mach-omap/am3xxx.c                             | 4 +++-
 arch/arm/mach-omap/omap4_clock.c                        | 2 ++
 arch/arm/mach-omap/omap4_generic.c                      | 2 ++
 arch/arm/mach-omap/omap_devices.c                       | 2 ++
 arch/arm/mach-omap/omap_fb.c                            | 2 ++
 arch/arm/mach-omap/xload.c                              | 2 ++
 arch/arm/mach-rockchip/bootm.c                          | 2 ++
 arch/arm/mach-socfpga/arria10-generic.c                 | 2 ++
 arch/arm/mach-socfpga/arria10-xload-emmc.c              | 2 ++
 arch/arm/mach-socfpga/arria10-xload.c                   | 2 ++
 arch/arm/mach-socfpga/cyclone5-generic.c                | 2 ++
 arch/arm/mach-socfpga/cyclone5-init.c                   | 2 ++
 arch/arm/mach-socfpga/xload.c                           | 2 ++
 arch/arm/mach-stm32mp/stm32image.c                      | 2 ++
 arch/mips/boards/netgear-wg102/ram.c                    | 2 ++
 arch/mips/lib/asm-offsets.c                             | 2 ++
 arch/mips/lib/bootm.c                                   | 2 ++
 arch/mips/lib/sections.c                                | 2 ++
 arch/mips/lib/shutdown.c                                | 2 ++
 arch/mips/lib/traps.c                                   | 2 ++
 arch/mips/mach-malta/pci.c                              | 2 ++
 arch/openrisc/boards/generic/generic.c                  | 1 +
 arch/openrisc/lib/asm-offsets.c                         | 2 ++
 arch/powerpc/lib/kgdb.c                                 | 2 ++
 arch/powerpc/lib/ppclinux.c                             | 2 ++
 arch/powerpc/mach-mpc5xxx/loadtask.c                    | 2 ++
 arch/powerpc/mach-mpc5xxx/reginfo.c                     | 2 ++
 arch/riscv/lib/asm-offsets.c                            | 2 ++
 arch/sandbox/board/dev-random.c                         | 2 ++
 arch/sandbox/board/power.c                              | 2 ++
 arch/sandbox/lib/asm-offsets.c                          | 2 ++
 arch/x86/lib/asm-offsets.c                              | 1 +
 arch/x86/mach-efi/clocksource.c                         | 2 ++
 148 files changed, 296 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boards/afi-gf/lowlevel.c b/arch/arm/boards/afi-gf/lowlevel.c
index da4a00067586..de40f6c5af52 100644
--- a/arch/arm/boards/afi-gf/lowlevel.c
+++ b/arch/arm/boards/afi-gf/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <init.h>
 #include <linux/sizes.h>
 #include <io.h>
diff --git a/arch/arm/boards/altera-socdk/board.c b/arch/arm/boards/altera-socdk/board.c
index f4b1dcd3249f..1c91d2a10dec 100644
--- a/arch/arm/boards/altera-socdk/board.c
+++ b/arch/arm/boards/altera-socdk/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <types.h>
 #include <driver.h>
diff --git a/arch/arm/boards/altera-socdk/lowlevel.c b/arch/arm/boards/altera-socdk/lowlevel.c
index 822c3d8ee60d..537453b6760d 100644
--- a/arch/arm/boards/altera-socdk/lowlevel.c
+++ b/arch/arm/boards/altera-socdk/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include "sdram_config.h"
 #include "pinmux_config.c"
 #include "pll_config.h"
diff --git a/arch/arm/boards/at91sam9x5ek/lowlevel.c b/arch/arm/boards/at91sam9x5ek/lowlevel.c
index ebd417b19cc0..3d266161ec8f 100644
--- a/arch/arm/boards/at91sam9x5ek/lowlevel.c
+++ b/arch/arm/boards/at91sam9x5ek/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/at91_ddrsdrc.h>
diff --git a/arch/arm/boards/beagle/lowlevel.c b/arch/arm/boards/beagle/lowlevel.c
index 30cc1f2c54ff..683ab552f4d5 100644
--- a/arch/arm/boards/beagle/lowlevel.c
+++ b/arch/arm/boards/beagle/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <init.h>
 #include <debug_ll.h>
 #include <io.h>
diff --git a/arch/arm/boards/beaglebone/lowlevel.c b/arch/arm/boards/beaglebone/lowlevel.c
index 31211448f5e8..6642bc4add85 100644
--- a/arch/arm/boards/beaglebone/lowlevel.c
+++ b/arch/arm/boards/beaglebone/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <init.h>
 #include <linux/sizes.h>
 #include <io.h>
diff --git a/arch/arm/boards/boundarydevices-nitrogen6/lowlevel.c b/arch/arm/boards/boundarydevices-nitrogen6/lowlevel.c
index 74ff71fc246a..9312a1d4aa99 100644
--- a/arch/arm/boards/boundarydevices-nitrogen6/lowlevel.c
+++ b/arch/arm/boards/boundarydevices-nitrogen6/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/generic.h>
 #include <mach/esdctl.h>
diff --git a/arch/arm/boards/canon-a1100/lowlevel.c b/arch/arm/boards/canon-a1100/lowlevel.c
index b75a1bfa6090..47a9564e0f84 100644
--- a/arch/arm/boards/canon-a1100/lowlevel.c
+++ b/arch/arm/boards/canon-a1100/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/chumby_falconwing/lowlevel.c b/arch/arm/boards/chumby_falconwing/lowlevel.c
index 0277b5d08326..091dd1955260 100644
--- a/arch/arm/boards/chumby_falconwing/lowlevel.c
+++ b/arch/arm/boards/chumby_falconwing/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/cm-fx6/lowlevel.c b/arch/arm/boards/cm-fx6/lowlevel.c
index fd86e159aaae..27c15f5412e1 100644
--- a/arch/arm/boards/cm-fx6/lowlevel.c
+++ b/arch/arm/boards/cm-fx6/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "cm-fx6: " fmt
 
 #include <common.h>
diff --git a/arch/arm/boards/crystalfontz-cfa10036/lowlevel.c b/arch/arm/boards/crystalfontz-cfa10036/lowlevel.c
index 1bc5947682d5..92b42aa89350 100644
--- a/arch/arm/boards/crystalfontz-cfa10036/lowlevel.c
+++ b/arch/arm/boards/crystalfontz-cfa10036/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/digi-ccimx6ulsom/lowlevel.c b/arch/arm/boards/digi-ccimx6ulsom/lowlevel.c
index 7bf1db8120f9..ba562a501f81 100644
--- a/arch/arm/boards/digi-ccimx6ulsom/lowlevel.c
+++ b/arch/arm/boards/digi-ccimx6ulsom/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/generic.h>
 #include <asm/barebox-arm.h>
diff --git a/arch/arm/boards/duckbill/lowlevel.c b/arch/arm/boards/duckbill/lowlevel.c
index 22987a6cdb22..0f76d9c938aa 100644
--- a/arch/arm/boards/duckbill/lowlevel.c
+++ b/arch/arm/boards/duckbill/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "I2SE Duckbill: " fmt
 #define DEBUG
 
diff --git a/arch/arm/boards/ebv-socrates/board.c b/arch/arm/boards/ebv-socrates/board.c
index 965150f9a3be..c2a8edac98f4 100644
--- a/arch/arm/boards/ebv-socrates/board.c
+++ b/arch/arm/boards/ebv-socrates/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <types.h>
 #include <driver.h>
diff --git a/arch/arm/boards/ebv-socrates/lowlevel.c b/arch/arm/boards/ebv-socrates/lowlevel.c
index 3f12ae806fc8..1f5b835df230 100644
--- a/arch/arm/boards/ebv-socrates/lowlevel.c
+++ b/arch/arm/boards/ebv-socrates/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include "sdram_config.h"
 #include "pinmux_config.c"
 #include "pll_config.h"
diff --git a/arch/arm/boards/ebv-socrates/sequencer_auto_ac_init.c b/arch/arm/boards/ebv-socrates/sequencer_auto_ac_init.c
index 5b5196ad77e4..1a19310dcb6c 100644
--- a/arch/arm/boards/ebv-socrates/sequencer_auto_ac_init.c
+++ b/arch/arm/boards/ebv-socrates/sequencer_auto_ac_init.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 static const uint32_t ac_rom_init_size = 36;
 static const uint32_t ac_rom_init[36] =
 {
diff --git a/arch/arm/boards/ebv-socrates/sequencer_auto_inst_init.c b/arch/arm/boards/ebv-socrates/sequencer_auto_inst_init.c
index e261ecb6c178..c818d725b8e0 100644
--- a/arch/arm/boards/ebv-socrates/sequencer_auto_inst_init.c
+++ b/arch/arm/boards/ebv-socrates/sequencer_auto_inst_init.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 static const uint32_t inst_rom_init_size = 128;
 static const uint32_t inst_rom_init[128] =
 {
diff --git a/arch/arm/boards/efika-mx-smartbook/lowlevel.c b/arch/arm/boards/efika-mx-smartbook/lowlevel.c
index 3881678d8587..5375578c94f5 100644
--- a/arch/arm/boards/efika-mx-smartbook/lowlevel.c
+++ b/arch/arm/boards/efika-mx-smartbook/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/esdctl.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/element14-warp7/lowlevel.c b/arch/arm/boards/element14-warp7/lowlevel.c
index 6ca733a0beaf..94b7eb598b50 100644
--- a/arch/arm/boards/element14-warp7/lowlevel.c
+++ b/arch/arm/boards/element14-warp7/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define DEBUG
 #include <io.h>
 #include <common.h>
diff --git a/arch/arm/boards/embedsky-e9/lowlevel.c b/arch/arm/boards/embedsky-e9/lowlevel.c
index 845c4ec90c29..1cda6e07e2e1 100644
--- a/arch/arm/boards/embedsky-e9/lowlevel.c
+++ b/arch/arm/boards/embedsky-e9/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/embest-riotboard/lowlevel.c b/arch/arm/boards/embest-riotboard/lowlevel.c
index 07f669fc0309..4093bf3bba53 100644
--- a/arch/arm/boards/embest-riotboard/lowlevel.c
+++ b/arch/arm/boards/embest-riotboard/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <common.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/boards/eukrea_cpuimx51/lowlevel.c b/arch/arm/boards/eukrea_cpuimx51/lowlevel.c
index 6762fdad4b82..cecc3f6c833f 100644
--- a/arch/arm/boards/eukrea_cpuimx51/lowlevel.c
+++ b/arch/arm/boards/eukrea_cpuimx51/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/esdctl.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/freescale-mx23-evk/lowlevel.c b/arch/arm/boards/freescale-mx23-evk/lowlevel.c
index 99e08d88c75d..62560bbff733 100644
--- a/arch/arm/boards/freescale-mx23-evk/lowlevel.c
+++ b/arch/arm/boards/freescale-mx23-evk/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <generated/mach-types.h>
diff --git a/arch/arm/boards/freescale-mx28-evk/lowlevel.c b/arch/arm/boards/freescale-mx28-evk/lowlevel.c
index 82411bb51630..7f0bd8a90e7c 100644
--- a/arch/arm/boards/freescale-mx28-evk/lowlevel.c
+++ b/arch/arm/boards/freescale-mx28-evk/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "Freescale MX28evk: " fmt
 #define DEBUG
 
diff --git a/arch/arm/boards/freescale-mx51-babbage/lowlevel.c b/arch/arm/boards/freescale-mx51-babbage/lowlevel.c
index e29a647daa5d..e95324e64505 100644
--- a/arch/arm/boards/freescale-mx51-babbage/lowlevel.c
+++ b/arch/arm/boards/freescale-mx51-babbage/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <mach/clock-imx51_53.h>
 #include <mach/iomux-mx51.h>
diff --git a/arch/arm/boards/freescale-mx51-babbage/power.c b/arch/arm/boards/freescale-mx51-babbage/power.c
index 6edc672a5a22..ce44f3ae423a 100644
--- a/arch/arm/boards/freescale-mx51-babbage/power.c
+++ b/arch/arm/boards/freescale-mx51-babbage/power.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "babbage-power: " fmt
 
 #include <common.h>
diff --git a/arch/arm/boards/freescale-mx53-qsb/lowlevel.c b/arch/arm/boards/freescale-mx53-qsb/lowlevel.c
index c9044011d599..e845fa4a3e3c 100644
--- a/arch/arm/boards/freescale-mx53-qsb/lowlevel.c
+++ b/arch/arm/boards/freescale-mx53-qsb/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/imx53-regs.h>
 #include <mach/esdctl.h>
diff --git a/arch/arm/boards/freescale-mx53-smd/lowlevel.c b/arch/arm/boards/freescale-mx53-smd/lowlevel.c
index fffbfdf0ba8c..b15025ba1863 100644
--- a/arch/arm/boards/freescale-mx53-smd/lowlevel.c
+++ b/arch/arm/boards/freescale-mx53-smd/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/imx53-regs.h>
 #include <mach/esdctl.h>
diff --git a/arch/arm/boards/freescale-mx53-vmx53/lowlevel.c b/arch/arm/boards/freescale-mx53-vmx53/lowlevel.c
index ae94538c9e92..58eca49455e2 100644
--- a/arch/arm/boards/freescale-mx53-vmx53/lowlevel.c
+++ b/arch/arm/boards/freescale-mx53-vmx53/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/esdctl.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/freescale-mx6-sabrelite/lowlevel.c b/arch/arm/boards/freescale-mx6-sabrelite/lowlevel.c
index c2d7a3c8f3da..0d8c51242a9f 100644
--- a/arch/arm/boards/freescale-mx6-sabrelite/lowlevel.c
+++ b/arch/arm/boards/freescale-mx6-sabrelite/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/freescale-mx6-sabresd/lowlevel.c b/arch/arm/boards/freescale-mx6-sabresd/lowlevel.c
index 7f83366e7a1d..d902dbeafb1d 100644
--- a/arch/arm/boards/freescale-mx6-sabresd/lowlevel.c
+++ b/arch/arm/boards/freescale-mx6-sabresd/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <common.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/boards/freescale-mx7-sabresd/lowlevel.c b/arch/arm/boards/freescale-mx7-sabresd/lowlevel.c
index 8db46ca69624..a8733d62091f 100644
--- a/arch/arm/boards/freescale-mx7-sabresd/lowlevel.c
+++ b/arch/arm/boards/freescale-mx7-sabresd/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <io.h>
 #include <common.h>
diff --git a/arch/arm/boards/freescale-vf610-twr/lowlevel.c b/arch/arm/boards/freescale-vf610-twr/lowlevel.c
index 8fec9f4b91bf..9c7fafe4d682 100644
--- a/arch/arm/boards/freescale-vf610-twr/lowlevel.c
+++ b/arch/arm/boards/freescale-vf610-twr/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/friendlyarm-mini6410/lowlevel.c b/arch/arm/boards/friendlyarm-mini6410/lowlevel.c
index ccbdd13795cb..dfb69d2272f2 100644
--- a/arch/arm/boards/friendlyarm-mini6410/lowlevel.c
+++ b/arch/arm/boards/friendlyarm-mini6410/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm.h>
diff --git a/arch/arm/boards/friendlyarm-tiny6410/lowlevel.c b/arch/arm/boards/friendlyarm-tiny6410/lowlevel.c
index ccbdd13795cb..dfb69d2272f2 100644
--- a/arch/arm/boards/friendlyarm-tiny6410/lowlevel.c
+++ b/arch/arm/boards/friendlyarm-tiny6410/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm.h>
diff --git a/arch/arm/boards/gateworks-ventana/lowlevel.c b/arch/arm/boards/gateworks-ventana/lowlevel.c
index 0a79d820499e..50386d8aed87 100644
--- a/arch/arm/boards/gateworks-ventana/lowlevel.c
+++ b/arch/arm/boards/gateworks-ventana/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/gk802/lowlevel.c b/arch/arm/boards/gk802/lowlevel.c
index a41b711e362f..385ec3e73775 100644
--- a/arch/arm/boards/gk802/lowlevel.c
+++ b/arch/arm/boards/gk802/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/guf-santaro/lowlevel.c b/arch/arm/boards/guf-santaro/lowlevel.c
index 30c5e9054a3c..ee39903c80f2 100644
--- a/arch/arm/boards/guf-santaro/lowlevel.c
+++ b/arch/arm/boards/guf-santaro/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <io.h>
diff --git a/arch/arm/boards/guf-vincell/lowlevel.c b/arch/arm/boards/guf-vincell/lowlevel.c
index 04060b20031d..97f1ffc3a97a 100644
--- a/arch/arm/boards/guf-vincell/lowlevel.c
+++ b/arch/arm/boards/guf-vincell/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <debug_ll.h>
 #include <io.h>
diff --git a/arch/arm/boards/imx233-olinuxino/lowlevel.c b/arch/arm/boards/imx233-olinuxino/lowlevel.c
index 253cf1257be4..71fc379f0487 100644
--- a/arch/arm/boards/imx233-olinuxino/lowlevel.c
+++ b/arch/arm/boards/imx233-olinuxino/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c b/arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c
index 8cd6d67f7ee1..4a9eae80d153 100644
--- a/arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c
+++ b/arch/arm/boards/kamstrup-mx7-concentrator/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <io.h>
 #include <common.h>
diff --git a/arch/arm/boards/karo-tx28/lowlevel.c b/arch/arm/boards/karo-tx28/lowlevel.c
index 84cc6818163e..28d96f3e1a5f 100644
--- a/arch/arm/boards/karo-tx28/lowlevel.c
+++ b/arch/arm/boards/karo-tx28/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "KARO TX28: " fmt
 #define DEBUG
 
diff --git a/arch/arm/boards/karo-tx53/lowlevel.c b/arch/arm/boards/karo-tx53/lowlevel.c
index 230f60ebd9db..e1bce4d3296d 100644
--- a/arch/arm/boards/karo-tx53/lowlevel.c
+++ b/arch/arm/boards/karo-tx53/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <debug_ll.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/kindle-mx50/lowlevel.c b/arch/arm/boards/kindle-mx50/lowlevel.c
index 992d1fd1a834..fce23ec6e027 100644
--- a/arch/arm/boards/kindle-mx50/lowlevel.c
+++ b/arch/arm/boards/kindle-mx50/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <io.h>
diff --git a/arch/arm/boards/lubbock/lowlevel.c b/arch/arm/boards/lubbock/lowlevel.c
index abf9e7a98a8b..f93a2ff47b9d 100644
--- a/arch/arm/boards/lubbock/lowlevel.c
+++ b/arch/arm/boards/lubbock/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <io.h>
diff --git a/arch/arm/boards/mainstone/lowlevel.c b/arch/arm/boards/mainstone/lowlevel.c
index 31f9d76513a1..1ec1d1e028aa 100644
--- a/arch/arm/boards/mainstone/lowlevel.c
+++ b/arch/arm/boards/mainstone/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <io.h>
diff --git a/arch/arm/boards/mioa701/lowlevel.c b/arch/arm/boards/mioa701/lowlevel.c
index ee0546ea6329..611699040282 100644
--- a/arch/arm/boards/mioa701/lowlevel.c
+++ b/arch/arm/boards/mioa701/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/netgear-rn104/lowlevel.c b/arch/arm/boards/netgear-rn104/lowlevel.c
index 8a5361501873..c6c8e8402346 100644
--- a/arch/arm/boards/netgear-rn104/lowlevel.c
+++ b/arch/arm/boards/netgear-rn104/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * Copyright (C) 2014  Uwe Kleine-Koenig <uwe at kleine-koenig.org>
  */
diff --git a/arch/arm/boards/netgear-rn2120/board.c b/arch/arm/boards/netgear-rn2120/board.c
index d5756e09694b..8b44b9225796 100644
--- a/arch/arm/boards/netgear-rn2120/board.c
+++ b/arch/arm/boards/netgear-rn2120/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <clock.h>
 #include <init.h>
 #include <of.h>
diff --git a/arch/arm/boards/nhk8815/lowlevel.c b/arch/arm/boards/nhk8815/lowlevel.c
index a9ccf1fff5ae..9ba5bbffadf1 100644
--- a/arch/arm/boards/nhk8815/lowlevel.c
+++ b/arch/arm/boards/nhk8815/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/omap343xdsp/lowlevel.c b/arch/arm/boards/omap343xdsp/lowlevel.c
index fb99ea9278df..271b122d4df8 100644
--- a/arch/arm/boards/omap343xdsp/lowlevel.c
+++ b/arch/arm/boards/omap343xdsp/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <io.h>
diff --git a/arch/arm/boards/omap3evm/lowlevel.c b/arch/arm/boards/omap3evm/lowlevel.c
index e06ece256064..1dcfbc27ba9c 100644
--- a/arch/arm/boards/omap3evm/lowlevel.c
+++ b/arch/arm/boards/omap3evm/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <io.h>
 #include <init.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/boards/panda/board.c b/arch/arm/boards/panda/board.c
index a0a00782d3ea..01189ebd76ae 100644
--- a/arch/arm/boards/panda/board.c
+++ b/arch/arm/boards/panda/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <console.h>
 #include <init.h>
diff --git a/arch/arm/boards/panda/mux.c b/arch/arm/boards/panda/mux.c
index 76d1c5100517..25def93ea22b 100644
--- a/arch/arm/boards/panda/mux.c
+++ b/arch/arm/boards/panda/mux.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <io.h>
diff --git a/arch/arm/boards/phytec-phycard-imx27/lowlevel.c b/arch/arm/boards/phytec-phycard-imx27/lowlevel.c
index 40d39680fda7..8ab682b9db19 100644
--- a/arch/arm/boards/phytec-phycard-imx27/lowlevel.c
+++ b/arch/arm/boards/phytec-phycard-imx27/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * For clock initialization, see chapter 3 of the "MCIMX27 Multimedia
  * Applications Processor Reference Manual, Rev. 0.2".
diff --git a/arch/arm/boards/phytec-phycard-omap3/lowlevel.c b/arch/arm/boards/phytec-phycard-omap3/lowlevel.c
index 546fa787355f..6f24108ef20e 100644
--- a/arch/arm/boards/phytec-phycard-omap3/lowlevel.c
+++ b/arch/arm/boards/phytec-phycard-omap3/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <io.h>
 #include <init.h>
diff --git a/arch/arm/boards/phytec-phycard-omap4/mux.c b/arch/arm/boards/phytec-phycard-omap4/mux.c
index 564944d1ba47..b0bbfa5906cf 100644
--- a/arch/arm/boards/phytec-phycard-omap4/mux.c
+++ b/arch/arm/boards/phytec-phycard-omap4/mux.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <io.h>
diff --git a/arch/arm/boards/phytec-phycore-imx7/lowlevel.c b/arch/arm/boards/phytec-phycore-imx7/lowlevel.c
index 3d2038e4a8d8..f8dcb3ce54d0 100644
--- a/arch/arm/boards/phytec-phycore-imx7/lowlevel.c
+++ b/arch/arm/boards/phytec-phycore-imx7/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define DEBUG
 #include <io.h>
 #include <common.h>
diff --git a/arch/arm/boards/phytec-phycore-omap4460/mux.c b/arch/arm/boards/phytec-phycore-omap4460/mux.c
index ca4ccf39f0c6..9cd10e06f8f5 100644
--- a/arch/arm/boards/phytec-phycore-omap4460/mux.c
+++ b/arch/arm/boards/phytec-phycore-omap4460/mux.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <io.h>
diff --git a/arch/arm/boards/raspberry-pi/lowlevel.c b/arch/arm/boards/raspberry-pi/lowlevel.c
index d58beb605255..29162ff02d54 100644
--- a/arch/arm/boards/raspberry-pi/lowlevel.c
+++ b/arch/arm/boards/raspberry-pi/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <asm/barebox-arm.h>
 #include <asm/cache.h>
 #include <common.h>
diff --git a/arch/arm/boards/reflex-achilles/board.c b/arch/arm/boards/reflex-achilles/board.c
index 2b8186e19f40..43e3a69be725 100644
--- a/arch/arm/boards/reflex-achilles/board.c
+++ b/arch/arm/boards/reflex-achilles/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <io.h>
diff --git a/arch/arm/boards/reflex-achilles/lowlevel.c b/arch/arm/boards/reflex-achilles/lowlevel.c
index f910b67d5fd6..e8d1a9cee4c2 100644
--- a/arch/arm/boards/reflex-achilles/lowlevel.c
+++ b/arch/arm/boards/reflex-achilles/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <io.h>
diff --git a/arch/arm/boards/reflex-achilles/pinmux-config-arria10.c b/arch/arm/boards/reflex-achilles/pinmux-config-arria10.c
index b6a72304b623..146bb5405d62 100644
--- a/arch/arm/boards/reflex-achilles/pinmux-config-arria10.c
+++ b/arch/arm/boards/reflex-achilles/pinmux-config-arria10.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <mach/arria10-pinmux.h>
 
 static uint32_t pinmux[] = {
diff --git a/arch/arm/boards/reflex-achilles/pll-config-arria10.c b/arch/arm/boards/reflex-achilles/pll-config-arria10.c
index 9da41ecdf20f..27dbe01b58c5 100644
--- a/arch/arm/boards/reflex-achilles/pll-config-arria10.c
+++ b/arch/arm/boards/reflex-achilles/pll-config-arria10.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <mach/arria10-clock-manager.h>
 
 static struct arria10_mainpll_cfg mainpll_cfg = {
diff --git a/arch/arm/boards/solidrun-microsom/lowlevel.c b/arch/arm/boards/solidrun-microsom/lowlevel.c
index ea204e15f38f..b8f68fa22c95 100644
--- a/arch/arm/boards/solidrun-microsom/lowlevel.c
+++ b/arch/arm/boards/solidrun-microsom/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <asm/barebox-arm.h>
 #include <common.h>
 #include <mach/esdctl.h>
diff --git a/arch/arm/boards/technexion-pico-hobbit/lowlevel.c b/arch/arm/boards/technexion-pico-hobbit/lowlevel.c
index f59c424dec26..43259675b084 100644
--- a/arch/arm/boards/technexion-pico-hobbit/lowlevel.c
+++ b/arch/arm/boards/technexion-pico-hobbit/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/terasic-de0-nano-soc/board.c b/arch/arm/boards/terasic-de0-nano-soc/board.c
index c6036a41f9a9..4019dae6a4bf 100644
--- a/arch/arm/boards/terasic-de0-nano-soc/board.c
+++ b/arch/arm/boards/terasic-de0-nano-soc/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <types.h>
 #include <driver.h>
diff --git a/arch/arm/boards/terasic-de0-nano-soc/lowlevel.c b/arch/arm/boards/terasic-de0-nano-soc/lowlevel.c
index deac0e9cb289..91bfd1a77679 100644
--- a/arch/arm/boards/terasic-de0-nano-soc/lowlevel.c
+++ b/arch/arm/boards/terasic-de0-nano-soc/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include "sdram_config.h"
 #include "pinmux_config.c"
 #include "pll_config.h"
diff --git a/arch/arm/boards/terasic-de10-nano/board.c b/arch/arm/boards/terasic-de10-nano/board.c
index dc0e8967de83..f8df37eadf4a 100644
--- a/arch/arm/boards/terasic-de10-nano/board.c
+++ b/arch/arm/boards/terasic-de10-nano/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <types.h>
 #include <driver.h>
diff --git a/arch/arm/boards/terasic-de10-nano/lowlevel.c b/arch/arm/boards/terasic-de10-nano/lowlevel.c
index d80cea6f20df..f6a3e3963489 100644
--- a/arch/arm/boards/terasic-de10-nano/lowlevel.c
+++ b/arch/arm/boards/terasic-de10-nano/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include "sdram_config.h"
 #include "pinmux_config.c"
 #include "pll_config.h"
diff --git a/arch/arm/boards/terasic-sockit/board.c b/arch/arm/boards/terasic-sockit/board.c
index 19e67ff933e5..a3537fe6e353 100644
--- a/arch/arm/boards/terasic-sockit/board.c
+++ b/arch/arm/boards/terasic-sockit/board.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <types.h>
 #include <driver.h>
diff --git a/arch/arm/boards/terasic-sockit/lowlevel.c b/arch/arm/boards/terasic-sockit/lowlevel.c
index 1dd7940aebd9..dbe99ac1dff4 100644
--- a/arch/arm/boards/terasic-sockit/lowlevel.c
+++ b/arch/arm/boards/terasic-sockit/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include "sdram_config.h"
 #include "pinmux_config.c"
 #include "pll_config.h"
diff --git a/arch/arm/boards/tqma53/lowlevel.c b/arch/arm/boards/tqma53/lowlevel.c
index 97a7ac556e55..37a098416132 100644
--- a/arch/arm/boards/tqma53/lowlevel.c
+++ b/arch/arm/boards/tqma53/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <debug_ll.h>
 #include <io.h>
diff --git a/arch/arm/boards/udoo-neo/lowlevel.c b/arch/arm/boards/udoo-neo/lowlevel.c
index bb6b7d833278..83530fb190e1 100644
--- a/arch/arm/boards/udoo-neo/lowlevel.c
+++ b/arch/arm/boards/udoo-neo/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <common.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/boards/udoo/lowlevel.c b/arch/arm/boards/udoo/lowlevel.c
index 1f06f7e37f7f..0f9e2d69a45c 100644
--- a/arch/arm/boards/udoo/lowlevel.c
+++ b/arch/arm/boards/udoo/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <mach/generic.h>
diff --git a/arch/arm/boards/versatile/lowlevel.c b/arch/arm/boards/versatile/lowlevel.c
index beab04d234a3..2f8d7b514be9 100644
--- a/arch/arm/boards/versatile/lowlevel.c
+++ b/arch/arm/boards/versatile/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/boards/vscom-baltos/lowlevel.c b/arch/arm/boards/vscom-baltos/lowlevel.c
index 0a220f2628a2..7da2f92efb69 100644
--- a/arch/arm/boards/vscom-baltos/lowlevel.c
+++ b/arch/arm/boards/vscom-baltos/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/boards/zii-imx51-rdu1/lowlevel.c b/arch/arm/boards/zii-imx51-rdu1/lowlevel.c
index c7bb044e0d59..14136358dd59 100644
--- a/arch/arm/boards/zii-imx51-rdu1/lowlevel.c
+++ b/arch/arm/boards/zii-imx51-rdu1/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <mach/clock-imx51_53.h>
 #include <mach/iomux-mx51.h>
diff --git a/arch/arm/boards/zylonite/lowlevel.c b/arch/arm/boards/zylonite/lowlevel.c
index 5b95d879fa65..972fd3476103 100644
--- a/arch/arm/boards/zylonite/lowlevel.c
+++ b/arch/arm/boards/zylonite/lowlevel.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/sizes.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/cpu/atf.c b/arch/arm/cpu/atf.c
index 4753a8a55924..ccd540d32a77 100644
--- a/arch/arm/cpu/atf.c
+++ b/arch/arm/cpu/atf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <asm/atf_common.h>
 #include <asm/system.h>
diff --git a/arch/arm/cpu/cache-l2x0.c b/arch/arm/cpu/cache-l2x0.c
index e975ecffc766..82ae16ba4dab 100644
--- a/arch/arm/cpu/cache-l2x0.c
+++ b/arch/arm/cpu/cache-l2x0.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "l2x0: " fmt
 
 #include <common.h>
diff --git a/arch/arm/cpu/cache.c b/arch/arm/cpu/cache.c
index 2b6e958a4ee7..24a02c68f31e 100644
--- a/arch/arm/cpu/cache.c
+++ b/arch/arm/cpu/cache.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <asm/mmu.h>
diff --git a/arch/arm/cpu/entry.c b/arch/arm/cpu/entry.c
index 0b447de801a0..b863af5757cd 100644
--- a/arch/arm/cpu/entry.c
+++ b/arch/arm/cpu/entry.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <types.h>
 
 #include <asm/cache.h>
diff --git a/arch/arm/cpu/mmu-common.c b/arch/arm/cpu/mmu-common.c
index 5cc5138cfa3d..2ef1fa231f39 100644
--- a/arch/arm/cpu/mmu-common.c
+++ b/arch/arm/cpu/mmu-common.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 
 #define pr_fmt(fmt)	"mmu: " fmt
 
diff --git a/arch/arm/cpu/mmu-early.c b/arch/arm/cpu/mmu-early.c
index b985aa455fe8..0d528b9b9cc3 100644
--- a/arch/arm/cpu/mmu-early.c
+++ b/arch/arm/cpu/mmu-early.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <asm/mmu.h>
 #include <errno.h>
diff --git a/arch/arm/cpu/mmu-early_64.c b/arch/arm/cpu/mmu-early_64.c
index a7598f28aaf4..d1f4a046bbff 100644
--- a/arch/arm/cpu/mmu-early_64.c
+++ b/arch/arm/cpu/mmu-early_64.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <dma-dir.h>
 #include <init.h>
@@ -88,4 +90,4 @@ void mmu_early_disable(void)
 
 	dsb();
 	isb();
-}
\ No newline at end of file
+}
diff --git a/arch/arm/cpu/sections.c b/arch/arm/cpu/sections.c
index a53236d90016..f310578ba272 100644
--- a/arch/arm/cpu/sections.c
+++ b/arch/arm/cpu/sections.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <asm/sections.h>
 #include <linux/types.h>
 
diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c
index 2bba585e964f..e814593dce43 100644
--- a/arch/arm/lib32/bootm.c
+++ b/arch/arm/lib32/bootm.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <bootm.h>
 #include <boot.h>
 #include <common.h>
diff --git a/arch/arm/lib32/bootu.c b/arch/arm/lib32/bootu.c
index 0540a16280df..31c3c56cc597 100644
--- a/arch/arm/lib32/bootu.c
+++ b/arch/arm/lib32/bootu.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <fs.h>
diff --git a/arch/arm/lib32/bootz.c b/arch/arm/lib32/bootz.c
index 486e945a7409..7b3b32d41837 100644
--- a/arch/arm/lib32/bootz.c
+++ b/arch/arm/lib32/bootz.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 #include <fs.h>
diff --git a/arch/arm/lib32/io.c b/arch/arm/lib32/io.c
index abfd887aac58..a12da49c0ab2 100644
--- a/arch/arm/lib32/io.c
+++ b/arch/arm/lib32/io.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <module.h>
 #include <linux/types.h>
 #include <io.h>
diff --git a/arch/arm/lib32/unwind.c b/arch/arm/lib32/unwind.c
index 02fae3c25306..79bf7420d757 100644
--- a/arch/arm/lib32/unwind.c
+++ b/arch/arm/lib32/unwind.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <asm/stacktrace.h>
diff --git a/arch/arm/lib64/pbl.c b/arch/arm/lib64/pbl.c
index 0cef08e4d2e1..78eab33f8d68 100644
--- a/arch/arm/lib64/pbl.c
+++ b/arch/arm/lib64/pbl.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <asm/system.h>
 #include <clock.h>
 #include <common.h>
diff --git a/arch/arm/lib64/string.c b/arch/arm/lib64/string.c
index a2cf09e58ed5..26a284be5a77 100644
--- a/arch/arm/lib64/string.c
+++ b/arch/arm/lib64/string.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <asm/system.h>
 #include <string.h>
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index ba680eb81fe2..ef2430576b6a 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <gpio.h>
 #include <init.h>
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index fdd8ea014e9d..457aecde518e 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <gpio.h>
 #include <init.h>
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 0465ed9524df..840c0be3829a 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <gpio.h>
 #include <init.h>
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index dc5dddfb646a..53523d1f9f90 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <gpio.h>
 #include <init.h>
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index affc624b1d36..ee8650db398c 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <gpio.h>
 #include <init.h>
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index 850d34604a2c..dbaabc0533f5 100644
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <gpio.h>
 #include <init.h>
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 8266b512c999..ecc144a37a0f 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <restart.h>
diff --git a/arch/arm/mach-at91/bootm-barebox.c b/arch/arm/mach-at91/bootm-barebox.c
index 1dccdb86a939..3c99d5813b53 100644
--- a/arch/arm/mach-at91/bootm-barebox.c
+++ b/arch/arm/mach-at91/bootm-barebox.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "at91-bootm-barebox: " fmt
 
 #include <bootm.h>
diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c
index b1e7b2c565fc..0c9d9cb0239a 100644
--- a/arch/arm/mach-at91/sama5d3.c
+++ b/arch/arm/mach-at91/sama5d3.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <gpio.h>
 #include <init.h>
diff --git a/arch/arm/mach-at91/xload-mmc.c b/arch/arm/mach-at91/xload-mmc.c
index 1b641f3a47ac..28d122f0a357 100644
--- a/arch/arm/mach-at91/xload-mmc.c
+++ b/arch/arm/mach-at91/xload-mmc.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/xload.h>
 #include <mach/sama5_bootsource.h>
diff --git a/arch/arm/mach-ep93xx/header.c b/arch/arm/mach-ep93xx/header.c
index a9dde2d8b05b..0d7e68c34b99 100644
--- a/arch/arm/mach-ep93xx/header.c
+++ b/arch/arm/mach-ep93xx/header.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <linux/compiler.h>
 #include <asm/barebox-arm-head.h>
diff --git a/arch/arm/mach-imx/atf.c b/arch/arm/mach-imx/atf.c
index 4b6ac8a2ae5e..9ab9ddd20385 100644
--- a/arch/arm/mach-imx/atf.c
+++ b/arch/arm/mach-imx/atf.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/atf.h>
 
diff --git a/arch/arm/mach-imx/devices.c b/arch/arm/mach-imx/devices.c
index a0609e282a5b..58c0a8aff3ed 100644
--- a/arch/arm/mach-imx/devices.c
+++ b/arch/arm/mach-imx/devices.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <driver.h>
 #include <mach/devices.h>
diff --git a/arch/arm/mach-imx/imx5.c b/arch/arm/mach-imx/imx5.c
index dd6c079fe3a3..072e960e53d5 100644
--- a/arch/arm/mach-imx/imx5.c
+++ b/arch/arm/mach-imx/imx5.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <io.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/mach-imx/xload-common.c b/arch/arm/mach-imx/xload-common.c
index bd6405258e9f..f4bcca1d1483 100644
--- a/arch/arm/mach-imx/xload-common.c
+++ b/arch/arm/mach-imx/xload-common.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <asm/sections.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/mach-imx/xload-spi.c b/arch/arm/mach-imx/xload-spi.c
index e87af81e416f..2a01b0d8065b 100644
--- a/arch/arm/mach-imx/xload-spi.c
+++ b/arch/arm/mach-imx/xload-spi.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <io.h>
 #include <spi/imx-spi.h>
diff --git a/arch/arm/mach-layerscape/icid.c b/arch/arm/mach-layerscape/icid.c
index 644401b18113..d1d623416aa6 100644
--- a/arch/arm/mach-layerscape/icid.c
+++ b/arch/arm/mach-layerscape/icid.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <io.h>
 #include <init.h>
diff --git a/arch/arm/mach-layerscape/pblimage.c b/arch/arm/mach-layerscape/pblimage.c
index deaf7143b92b..26345af27621 100644
--- a/arch/arm/mach-layerscape/pblimage.c
+++ b/arch/arm/mach-layerscape/pblimage.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "pblimage: " fmt
 
 #include <bootm.h>
diff --git a/arch/arm/mach-mvebu/kwb_bbu.c b/arch/arm/mach-mvebu/kwb_bbu.c
index 3de575740c27..eb205b2799b9 100644
--- a/arch/arm/mach-mvebu/kwb_bbu.c
+++ b/arch/arm/mach-mvebu/kwb_bbu.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <bbu.h>
 #include <libfile.h>
 #include <linux/printk.h>
diff --git a/arch/arm/mach-mvebu/kwbootimage.c b/arch/arm/mach-mvebu/kwbootimage.c
index e379d732fed6..7189faa751ba 100644
--- a/arch/arm/mach-mvebu/kwbootimage.c
+++ b/arch/arm/mach-mvebu/kwbootimage.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <bootm.h>
 #include <common.h>
 #include <fcntl.h>
diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c
index f3ea958aeccf..e68097ade867 100644
--- a/arch/arm/mach-nomadik/clock.c
+++ b/arch/arm/mach-nomadik/clock.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * linux/arch/arm/mach-nomadik/clock.c
  *
diff --git a/arch/arm/mach-omap/am3xxx.c b/arch/arm/mach-omap/am3xxx.c
index 75965a8e0e12..60a6e4b825d1 100644
--- a/arch/arm/mach-omap/am3xxx.c
+++ b/arch/arm/mach-omap/am3xxx.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <io.h>
 #include <mach/am3xxx-silicon.h>
@@ -29,4 +31,4 @@ void am3xxx_uart_soft_reset(void __iomem *uart_base)
 }
 
 void am33xx_uart_soft_reset(void __iomem *uart_base)
-	__alias(am3xxx_uart_soft_reset);
\ No newline at end of file
+	__alias(am3xxx_uart_soft_reset);
diff --git a/arch/arm/mach-omap/omap4_clock.c b/arch/arm/mach-omap/omap4_clock.c
index 72f72a17a113..6f53c706d694 100644
--- a/arch/arm/mach-omap/omap4_clock.c
+++ b/arch/arm/mach-omap/omap4_clock.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <io.h>
 #include <mach/syslib.h>
diff --git a/arch/arm/mach-omap/omap4_generic.c b/arch/arm/mach-omap/omap4_generic.c
index 848a664064f5..c9a89c57b7e2 100644
--- a/arch/arm/mach-omap/omap4_generic.c
+++ b/arch/arm/mach-omap/omap4_generic.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <bootsource.h>
 #include <init.h>
diff --git a/arch/arm/mach-omap/omap_devices.c b/arch/arm/mach-omap/omap_devices.c
index f577fa6ea70d..7c36b8819d7b 100644
--- a/arch/arm/mach-omap/omap_devices.c
+++ b/arch/arm/mach-omap/omap_devices.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <driver.h>
 #include <platform_data/serial-ns16550.h>
 #include <asm/armlinux.h>
diff --git a/arch/arm/mach-omap/omap_fb.c b/arch/arm/mach-omap/omap_fb.c
index ae318d85fe1a..0bd51c5f556a 100644
--- a/arch/arm/mach-omap/omap_fb.c
+++ b/arch/arm/mach-omap/omap_fb.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <driver.h>
 #include <common.h>
 #include <linux/ioport.h>
diff --git a/arch/arm/mach-omap/xload.c b/arch/arm/mach-omap/xload.c
index 47aa8275b9ee..0fe78883d1aa 100644
--- a/arch/arm/mach-omap/xload.c
+++ b/arch/arm/mach-omap/xload.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <bootsource.h>
 #include <partition.h>
diff --git a/arch/arm/mach-rockchip/bootm.c b/arch/arm/mach-rockchip/bootm.c
index 5d6181ebd7de..036a3696adbc 100644
--- a/arch/arm/mach-rockchip/bootm.c
+++ b/arch/arm/mach-rockchip/bootm.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "rockchip-bootm-barebox: " fmt
 
 #include <bootm.h>
diff --git a/arch/arm/mach-socfpga/arria10-generic.c b/arch/arm/mach-socfpga/arria10-generic.c
index 38558309f860..d3990e1281d8 100644
--- a/arch/arm/mach-socfpga/arria10-generic.c
+++ b/arch/arm/mach-socfpga/arria10-generic.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <io.h>
 #include <init.h>
diff --git a/arch/arm/mach-socfpga/arria10-xload-emmc.c b/arch/arm/mach-socfpga/arria10-xload-emmc.c
index dcc38cf4a237..98d219b6efd9 100644
--- a/arch/arm/mach-socfpga/arria10-xload-emmc.c
+++ b/arch/arm/mach-socfpga/arria10-xload-emmc.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <linux/sizes.h>
diff --git a/arch/arm/mach-socfpga/arria10-xload.c b/arch/arm/mach-socfpga/arria10-xload.c
index e52fd1ed875b..fb92c01ddb02 100644
--- a/arch/arm/mach-socfpga/arria10-xload.c
+++ b/arch/arm/mach-socfpga/arria10-xload.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <asm/sections.h>
 #include <debug_ll.h>
diff --git a/arch/arm/mach-socfpga/cyclone5-generic.c b/arch/arm/mach-socfpga/cyclone5-generic.c
index dfb1f49e4d36..c494f048ec5b 100644
--- a/arch/arm/mach-socfpga/cyclone5-generic.c
+++ b/arch/arm/mach-socfpga/cyclone5-generic.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <malloc.h>
 #include <envfs.h>
diff --git a/arch/arm/mach-socfpga/cyclone5-init.c b/arch/arm/mach-socfpga/cyclone5-init.c
index 412808b8416f..68fd02430c23 100644
--- a/arch/arm/mach-socfpga/cyclone5-init.c
+++ b/arch/arm/mach-socfpga/cyclone5-init.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <debug_ll.h>
 #include <common.h>
 #include <init.h>
diff --git a/arch/arm/mach-socfpga/xload.c b/arch/arm/mach-socfpga/xload.c
index 5c611ac6e151..81c1a7488625 100644
--- a/arch/arm/mach-socfpga/xload.c
+++ b/arch/arm/mach-socfpga/xload.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <bootsource.h>
 #include <bootstrap.h>
 #include <common.h>
diff --git a/arch/arm/mach-stm32mp/stm32image.c b/arch/arm/mach-stm32mp/stm32image.c
index 207df6894d4e..caff68651c47 100644
--- a/arch/arm/mach-stm32mp/stm32image.c
+++ b/arch/arm/mach-stm32mp/stm32image.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define pr_fmt(fmt) "stm32image: " fmt
 
 #include <bootm.h>
diff --git a/arch/mips/boards/netgear-wg102/ram.c b/arch/mips/boards/netgear-wg102/ram.c
index 4cde573982d7..fe9c88162359 100644
--- a/arch/mips/boards/netgear-wg102/ram.c
+++ b/arch/mips/boards/netgear-wg102/ram.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <linux/sizes.h>
diff --git a/arch/mips/lib/asm-offsets.c b/arch/mips/lib/asm-offsets.c
index 457bc8ab7cee..227d8cf54ef4 100644
--- a/arch/mips/lib/asm-offsets.c
+++ b/arch/mips/lib/asm-offsets.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * offset.c: Calculate pt_regs and task_struct offsets.
  *
diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c
index b71b8d5c38e9..655535737ec8 100644
--- a/arch/mips/lib/bootm.c
+++ b/arch/mips/lib/bootm.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <boot.h>
 #include <bootm.h>
 #include <common.h>
diff --git a/arch/mips/lib/sections.c b/arch/mips/lib/sections.c
index 66d559f94a7d..46fca5ca7914 100644
--- a/arch/mips/lib/sections.c
+++ b/arch/mips/lib/sections.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <asm/sections.h>
 #include <linux/types.h>
diff --git a/arch/mips/lib/shutdown.c b/arch/mips/lib/shutdown.c
index 973cd23c7184..9f993ab7a953 100644
--- a/arch/mips/lib/shutdown.c
+++ b/arch/mips/lib/shutdown.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /**
  * This function is called by shutdown_barebox to get a clean
  * memory/cache state.
diff --git a/arch/mips/lib/traps.c b/arch/mips/lib/traps.c
index 5fc32fe7e429..ff0a54af8e31 100644
--- a/arch/mips/lib/traps.c
+++ b/arch/mips/lib/traps.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <abort.h>
 #include <asm/mipsregs.h>
diff --git a/arch/mips/mach-malta/pci.c b/arch/mips/mach-malta/pci.c
index 4561123d22b4..113b94fe2332 100644
--- a/arch/mips/mach-malta/pci.c
+++ b/arch/mips/mach-malta/pci.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <types.h>
 #include <driver.h>
diff --git a/arch/openrisc/boards/generic/generic.c b/arch/openrisc/boards/generic/generic.c
index ff6f9f4d42ad..1129a7d52e48 100644
--- a/arch/openrisc/boards/generic/generic.c
+++ b/arch/openrisc/boards/generic/generic.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 #include <common.h>
 #include <init.h>
 
diff --git a/arch/openrisc/lib/asm-offsets.c b/arch/openrisc/lib/asm-offsets.c
index 8cee8e00c618..e9d631a35c6a 100644
--- a/arch/openrisc/lib/asm-offsets.c
+++ b/arch/openrisc/lib/asm-offsets.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * OpenRISC asm-offsets.c
  *
diff --git a/arch/powerpc/lib/kgdb.c b/arch/powerpc/lib/kgdb.c
index 762cc7a88c9a..bbe7a80d27c6 100644
--- a/arch/powerpc/lib/kgdb.c
+++ b/arch/powerpc/lib/kgdb.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <command.h>
 
diff --git a/arch/powerpc/lib/ppclinux.c b/arch/powerpc/lib/ppclinux.c
index b4cb59a524d6..9b8404962cea 100644
--- a/arch/powerpc/lib/ppclinux.c
+++ b/arch/powerpc/lib/ppclinux.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #define DEBUG
 
 #include <common.h>
diff --git a/arch/powerpc/mach-mpc5xxx/loadtask.c b/arch/powerpc/mach-mpc5xxx/loadtask.c
index 1458cf7218a1..e2489983eec9 100644
--- a/arch/powerpc/mach-mpc5xxx/loadtask.c
+++ b/arch/powerpc/mach-mpc5xxx/loadtask.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * (C) Copyright 2003
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
diff --git a/arch/powerpc/mach-mpc5xxx/reginfo.c b/arch/powerpc/mach-mpc5xxx/reginfo.c
index 8b646e7d048c..64816faffc22 100644
--- a/arch/powerpc/mach-mpc5xxx/reginfo.c
+++ b/arch/powerpc/mach-mpc5xxx/reginfo.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <stdio.h>
 #include <common.h>
 #include <config.h>
diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
index 4b869690f198..48960e58a6bc 100644
--- a/arch/riscv/lib/asm-offsets.c
+++ b/arch/riscv/lib/asm-offsets.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * Generate definitions needed by assembly language modules.
  * This code generates raw asm output which is post-processed to extract
diff --git a/arch/sandbox/board/dev-random.c b/arch/sandbox/board/dev-random.c
index 60295e9fced2..b62e8cc0d7cc 100644
--- a/arch/sandbox/board/dev-random.c
+++ b/arch/sandbox/board/dev-random.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <mach/linux.h>
 
diff --git a/arch/sandbox/board/power.c b/arch/sandbox/board/power.c
index aa778792c155..009b410eaa06 100644
--- a/arch/sandbox/board/power.c
+++ b/arch/sandbox/board/power.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <driver.h>
 #include <poweroff.h>
diff --git a/arch/sandbox/lib/asm-offsets.c b/arch/sandbox/lib/asm-offsets.c
index 22f382b71e7b..21aab692d083 100644
--- a/arch/sandbox/lib/asm-offsets.c
+++ b/arch/sandbox/lib/asm-offsets.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 /*
  * Generate definitions needed by assembly language modules.
  * This code generates raw asm output which is post-processed to extract
diff --git a/arch/x86/lib/asm-offsets.c b/arch/x86/lib/asm-offsets.c
index 22f382b71e7b..caa4a289d8b3 100644
--- a/arch/x86/lib/asm-offsets.c
+++ b/arch/x86/lib/asm-offsets.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Generate definitions needed by assembly language modules.
  * This code generates raw asm output which is post-processed to extract
diff --git a/arch/x86/mach-efi/clocksource.c b/arch/x86/mach-efi/clocksource.c
index 2023fa19ac53..3d01ff9d1eca 100644
--- a/arch/x86/mach-efi/clocksource.c
+++ b/arch/x86/mach-efi/clocksource.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
 #include <common.h>
 #include <init.h>
 #include <driver.h>
-- 
2.30.2



From u.kleine-koenig at pengutronix.de  Mon Jan  3 04:20:53 2022
From: u.kleine-koenig at pengutronix.de (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Mon, 3 Jan 2022 13:20:53 +0100
Subject: [PATCH 11/11] treewide: add SPDX-License-Identifier for files
 without explicit license
In-Reply-To: <20220103120539.1730644-12-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
 <20220103120539.1730644-12-a.fatoum@pengutronix.de>
Message-ID: <20220103122053.ry32inulqtx2wwsj@pengutronix.de>

On Mon, Jan 03, 2022 at 01:05:39PM +0100, Ahmad Fatoum wrote:
> diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
> index 04fef71d7be9..fcfc0ed192e1 100644
> --- a/arch/arm/tools/gen-mach-types
> +++ b/arch/arm/tools/gen-mach-types
> @@ -1,5 +1,7 @@
>  #!/bin/awk
>  #
> +# SPDX-License-Identifier: GPL-2.0-only
> +#

I would prefer to have the license identifier in the 2nd line. Not sure
what the standard tells, but ISTR that in Linux the is no "empty" line,
too.

Otherwise thanks for your effort,
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/barebox/attachments/20220103/67bb76ac/attachment.sig>

From rhi at pengutronix.de  Mon Jan  3 07:24:08 2022
From: rhi at pengutronix.de (Roland Hieber)
Date: Mon, 3 Jan 2022 16:24:08 +0100
Subject: Howto implement bootchooser <-> rauc interaction
In-Reply-To: <527cfa29-69bf-876b-b716-4ed1180b0166@pengutronix.de>
References: <9215c9815f25cc3328a05d6c9553ac36@inside-m2m.de>
 <CAMHeXxOoXjqtSGXdE73oROUk9ybFmFv7gi8PtzLsKn=iH+FXLA@mail.gmail.com>
 <20211205225529.5rf5zqpbg7trovst@pengutronix.de>
 <c4d432350649f31dbc9b732e96034785@inside-m2m.de>
 <527cfa29-69bf-876b-b716-4ed1180b0166@pengutronix.de>
Message-ID: <20220103152408.xllanhgvyoozhsxq@pengutronix.de>

On Wed, Dec 15, 2021 at 11:56:21AM +0100, Ahmad Fatoum wrote:
> On 14.12.21 22:40, Konstantin Kletschke wrote:
> > On 2021-12-05 23:55, Roland Hieber wrote:
> > 
> >> You probably also want to delete your bootchooser variables from the env
> > 
> > Are you shure about that? I read some example/documentation at bootlin.com
> > doing/presenting a nice phytec device tree for EEPROM state but later on it points out to
> > "[...]add bootchooser variables associated to both targets in arch/arm/<board>/env/nv[...]"
> 
> I think Roland meant that you shouldn't rely on the _mutable_ environment
> for production. It's nice to test out stuff, but once you have figured
> out what you need, add it to the built-in environment (e.g.
> arch/arm/<board/myenv or CONFIG_DEFAULT_ENVIRONMENT_PATH).
> 
> Mutating the environment is mostly a development convenience.

No, I was confusing the "bootchooser" variables with "bootstate"
variables, which should come from state, not from nv. But generally what
Ahmad writes sounds reasonable to me :-) Sorry for the confusion!

 - Roland

>  
> > When I utilize "devinfo state" (with all global/nv bootchoser variables removed) I get
> > 
> > barebox at TI AM335x BeagleBone black:/ devinfo state
> > Parameters:
> > ? bootstate.last_chosen: 0 (type: uint32)
> > ? bootstate.system0.ok: 0 (type: uint32)
> > ? bootstate.system0.priority: 21 (type: uint32)
> > ? bootstate.system0.remaining_attempts: 3 (type: uint32)
> > ? bootstate.system1.ok: 0 (type: uint32)
> > ? bootstate.system1.priority: 20 (type: uint32)
> > ? bootstate.system1.remaining_attempts: 3 (type: uint32)
> > ? dirty: 0 (type: bool)
> > ? init_from_defaults: 0 (type: bool)
> > ? save_on_shutdown: 1 (type: bool)
> > 
> > 
> > Is bootchooser smart enough to gather system0 and system1 as bootable entries/possibilities?
> > For bootchooser.targets...
> > 
> > My system is not proven to work (I just sent a different mail with my other issues to this thread)
> > yet, may be there are other issues hidden, but I do not get this part.
> > 
> > I created two boot entries system0 and system1 in /env/boot/ with content mmc1.1 (for system0) and
> > mmc1.2 (for system1.2). Both are bootloader-spec-enabled partitions. What me bothers is, "boot mmc1.1" works,
> > "boot system0" not. How do I properly make a bootchoser entry for mmc1.1?
> > 
> > If no variables are required, where could be the cuplrit for this:
> > 
> > barebox at TI AM335x BeagleBone black:/ bootchooser
> > ERROR: bootchooser: Target list $global.bootchooser.targets is empty
> > No bootchooser found
> 
> Doing it in the environment is how it's meant to be used.
> Just do it at compile-time. Having devices in the field with differing
> mutated environments is a lot of headache. Differing barebox-state on the other
> hand is manageable, because you restrict what variables are available
> and how they interact with the rest of the system.
> 
> Cheers,
> Ahmad
> 
> > 
> > 
> > 
> > Kind Regards,
> > Konsti

-- 
Roland Hieber, Pengutronix e.K.          | r.hieber at pengutronix.de     |
Steuerwalder Str. 21                     | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686         | Fax:   +49-5121-206917-5555 |


From sam at ravnborg.org  Mon Jan  3 08:11:53 2022
From: sam at ravnborg.org (Sam Ravnborg)
Date: Mon, 3 Jan 2022 17:11:53 +0100
Subject: [PATCH master 1/5] pwm: atmel: point MMIO accesses at correct
 address
In-Reply-To: <20220103115718.1723730-2-a.fatoum@pengutronix.de>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
 <20220103115718.1723730-2-a.fatoum@pengutronix.de>
Message-ID: <YdMgSbOoD/1csUNT@ravnborg.org>

Hi Ahmad,

On Mon, Jan 03, 2022 at 12:57:14PM +0100, Ahmad Fatoum wrote:
> The base address for MMIO writes was the address of the resource struct,
> not the start address pointed at by it.
> 
> Change untested, but it doesn't look like this driver could ever have
> worked.

You are right that I never got around to see backlight dimming work.
I recall that backlight worked and then the pwm driver was added as part
of several other patches for barebox.
I should have dropped the patch until I had seen it actually work.

But nice catch!

I may try to dust of the skov board where this is used to test it.
But these days I play with an i.MX6 board which has a bit more power,
so no promises.

	Sam


From sam at ravnborg.org  Mon Jan  3 08:18:28 2022
From: sam at ravnborg.org (Sam Ravnborg)
Date: Mon, 3 Jan 2022 17:18:28 +0100
Subject: [PATCH master 1/5] pwm: atmel: point MMIO accesses at correct
 address
In-Reply-To: <YdMgSbOoD/1csUNT@ravnborg.org>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
 <20220103115718.1723730-2-a.fatoum@pengutronix.de>
 <YdMgSbOoD/1csUNT@ravnborg.org>
Message-ID: <YdMh1FIPwhP9ga9C@ravnborg.org>

On Mon, Jan 03, 2022 at 05:11:53PM +0100, Sam Ravnborg wrote:
> Hi Ahmad,
> 
> On Mon, Jan 03, 2022 at 12:57:14PM +0100, Ahmad Fatoum wrote:
> > The base address for MMIO writes was the address of the resource struct,
> > not the start address pointed at by it.
> > 
> > Change untested, but it doesn't look like this driver could ever have
> > worked.
> 
> You are right that I never got around to see backlight dimming work.
> I recall that backlight worked and then the pwm driver was added as part
> of several other patches for barebox.
> I should have dropped the patch until I had seen it actually work.
> 
> But nice catch!
> 
> I may try to dust of the skov board where this is used to test it.
> But these days I play with an i.MX6 board which has a bit more power,
> so no promises.

For the patch btw:
Reviewed-by: Sam Ravnborg <sam at ravnborg.org>


From rhi at pengutronix.de  Mon Jan  3 08:50:39 2022
From: rhi at pengutronix.de (Roland Hieber)
Date: Mon, 3 Jan 2022 17:50:39 +0100
Subject: [PATCH 11/11] treewide: add SPDX-License-Identifier for files
 without explicit license
In-Reply-To: <20220103122053.ry32inulqtx2wwsj@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
 <20220103120539.1730644-12-a.fatoum@pengutronix.de>
 <20220103122053.ry32inulqtx2wwsj@pengutronix.de>
Message-ID: <20220103165039.p5cqln44got6ybrg@pengutronix.de>

On Mon, Jan 03, 2022 at 01:20:53PM +0100, Uwe Kleine-K?nig wrote:
> On Mon, Jan 03, 2022 at 01:05:39PM +0100, Ahmad Fatoum wrote:
> > diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
> > index 04fef71d7be9..fcfc0ed192e1 100644
> > --- a/arch/arm/tools/gen-mach-types
> > +++ b/arch/arm/tools/gen-mach-types
> > @@ -1,5 +1,7 @@
> >  #!/bin/awk
> >  #
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +#
> 
> I would prefer to have the license identifier in the 2nd line. Not sure
> what the standard tells, but ISTR that in Linux the is no "empty" line,
> too.

I was stumbling over this one too, but the standard says "at or near the
top of the file" [1], so I think, this is okay.

Otherwise didn't notice anything strange while scrolling through this
series, except a few newline changes at ends of files here and there,
but I think those are okay too.

[1]: https://spdx.github.io/spdx-spec/using-SPDX-short-identifiers-in-source-files/#e2-format-for-spdx-license-identifier

> Otherwise thanks for your effort,

Yes, thank you!

 - Roland

-- 
Roland Hieber, Pengutronix e.K.          | r.hieber at pengutronix.de     |
Steuerwalder Str. 21                     | https://www.pengutronix.de/ |
31137 Hildesheim, Germany                | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686         | Fax:   +49-5121-206917-5555 |


From frank-w at public-files.de  Tue Jan  4 00:39:05 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Tue, 4 Jan 2022 09:39:05 +0100
Subject: barebox - rk3568
Message-ID: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>

Hi,

i have a prototype rk3568 board (bpi-r2-pro).

is it possible to flash only barebox instead of uboot? in documentation i found only "creating SD-card", but i dont want to break existing partitions.

https://www.barebox.org/doc/latest/boards/rockchip.html#rockchip-rk3568

says it starts from sector 32, my first block for uboot (idblock.bin=spl+raminit) starts at 64, full uboot in partition at 8M.

As it differs a bit from evb can i add new dts like in uboot?

regards Frank


From sha at pengutronix.de  Tue Jan  4 02:51:23 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Tue, 4 Jan 2022 11:51:23 +0100
Subject: barebox - rk3568
In-Reply-To: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
References: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
Message-ID: <20220104105123.GI6003@pengutronix.de>

Hi Frank,

On Tue, Jan 04, 2022 at 09:39:05AM +0100, Frank Wunderlich wrote:
> Hi,
> 
> i have a prototype rk3568 board (bpi-r2-pro).
> 
> is it possible to flash only barebox instead of uboot? in documentation i found only "creating SD-card", but i dont want to break existing partitions.

The rk3568 has a fixed boot order of eMMC, SD, USB. The EVB board has a
pushbutton to shortcircuit a pin of the eMMC. When pushed, the eMMC
becomes invalid and the board boots from SD card. I could imagine it's
the same on your board, so you could create an SD card and boot from
that. Other than that an image that starts from SD card can also start
from eMMC, the images are the same.
You could also start from USB, the barebox tree has a rk3568 USB loader
tool.

> 
> https://www.barebox.org/doc/latest/boards/rockchip.html#rockchip-rk3568
> 
> says it starts from sector 32, my first block for uboot (idblock.bin=spl+raminit) starts at 64, full uboot in partition at 8M.
> 
> As it differs a bit from evb can i add new dts like in uboot?

Yes, you can. See
https://www.barebox.org/doc/latest/devel/porting.html?highlight=new%20board
for more information how. Also have a look at commit b9f1bb8563ba
which adds the EVB board support. You'll have to do the same for your
board.
One thing you'll need is a sdram-init.bin file. You can extract it from
your BSP.

Regards,
  Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From frank-w at public-files.de  Tue Jan  4 03:20:51 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Tue, 4 Jan 2022 12:20:51 +0100
Subject: Aw: Re: barebox - rk3568
In-Reply-To: <20220104105123.GI6003@pengutronix.de>
References: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
 <20220104105123.GI6003@pengutronix.de>
Message-ID: <trinity-08e4162e-f564-43b8-859c-2e24b4247c1c-1641295251349@3c-app-gmx-bap27>

Hi,

thanks, got it compiled and booting...currently looking around how to do things ;)
have successful booted linux+dtb+initrd manually and pinged my router as network test.

now i looks how to include scripts that i don't need to write all again and again...

documentation says that a direktory will be used in boards directory, but this seems not working

so i used the config-approach

DEFAULT_ENVIRONMENT_PATH=arch/arm/boards/rockchip-rk3568-evb/defaultenv

i'm not sure how the saveenv works (where the environment is stored...i have no /dev/env0). in uboot i can define a device (mmc), partition (1:1), filename (uboot.env) for storing environment onto a fat-partition. i guess you have something similar too

regards Frank


> Gesendet: Dienstag, 04. Januar 2022 um 11:51 Uhr
> Von: "Sascha Hauer" <sha at pengutronix.de>
> An: "Frank Wunderlich" <frank-w at public-files.de>
> Cc: barebox at lists.infradead.org
> Betreff: Re: barebox - rk3568
>
> Hi Frank,
>
> On Tue, Jan 04, 2022 at 09:39:05AM +0100, Frank Wunderlich wrote:
> > Hi,
> >
> > i have a prototype rk3568 board (bpi-r2-pro).
> >
> > is it possible to flash only barebox instead of uboot? in documentation i found only "creating SD-card", but i dont want to break existing partitions.
>
> The rk3568 has a fixed boot order of eMMC, SD, USB. The EVB board has a
> pushbutton to shortcircuit a pin of the eMMC. When pushed, the eMMC
> becomes invalid and the board boots from SD card. I could imagine it's
> the same on your board, so you could create an SD card and boot from
> that. Other than that an image that starts from SD card can also start
> from eMMC, the images are the same.
> You could also start from USB, the barebox tree has a rk3568 USB loader
> tool.
>
> >
> > https://www.barebox.org/doc/latest/boards/rockchip.html#rockchip-rk3568
> >
> > says it starts from sector 32, my first block for uboot (idblock.bin=spl+raminit) starts at 64, full uboot in partition at 8M.
> >
> > As it differs a bit from evb can i add new dts like in uboot?
>
> Yes, you can. See
> https://www.barebox.org/doc/latest/devel/porting.html?highlight=new%20board
> for more information how. Also have a look at commit b9f1bb8563ba
> which adds the EVB board support. You'll have to do the same for your
> board.
> One thing you'll need is a sdram-init.bin file. You can extract it from
> your BSP.
>
> Regards,
>   Sascha
>
> --
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>


From sha at pengutronix.de  Tue Jan  4 06:16:20 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Tue, 4 Jan 2022 15:16:20 +0100
Subject: barebox - rk3568
In-Reply-To: <trinity-08e4162e-f564-43b8-859c-2e24b4247c1c-1641295251349@3c-app-gmx-bap27>
References: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
 <20220104105123.GI6003@pengutronix.de>
 <trinity-08e4162e-f564-43b8-859c-2e24b4247c1c-1641295251349@3c-app-gmx-bap27>
Message-ID: <20220104141620.GA22780@pengutronix.de>

On Tue, Jan 04, 2022 at 12:20:51PM +0100, Frank Wunderlich wrote:
> Hi,
> 
> thanks, got it compiled and booting...currently looking around how to do things ;)
> have successful booted linux+dtb+initrd manually and pinged my router as network test.
> 
> now i looks how to include scripts that i don't need to write all again and again...
> 
> documentation says that a direktory will be used in boards directory, but this seems not working
> 
> so i used the config-approach
> 
> DEFAULT_ENVIRONMENT_PATH=arch/arm/boards/rockchip-rk3568-evb/defaultenv
> 
> i'm not sure how the saveenv works (where the environment is
> stored...i have no /dev/env0). in uboot i can define a device (mmc),
> partition (1:1), filename (uboot.env) for storing environment onto a
> fat-partition. i guess you have something similar too

You don't need a /dev/env0. The EVB device tree has:

               environment-sd {
                       compatible = "barebox,environment";
                       device-path = &environment_sd;
                       status = "disabled";
               };

               environment-emmc {
                       compatible = "barebox,environment";
                       device-path = &environment_emmc;
                       status = "disabled";
               };

One of these nodes will be enabled based on the current bootsource:

       if (bootsource == BOOTSOURCE_MMC && instance == 1)
               of_device_enable_path("/chosen/environment-sd");
       else
               of_device_enable_path("/chosen/environment-emmc");

As you have exchanged the device tree you either don't have the nodes
in your device tree or the device tree doesn't match the board code:

The EVB board code has:

static const struct of_device_id rk3568_evb_of_match[] = {
       { .compatible = "rockchip,rk3568-evb1-v10" },
       { /* Sentinel */},
};

Which matches the EVB device tree:

       compatible = "rockchip,rk3568-evb1-v10", "rockchip,rk3568";

I don't know exactly what you have changed and what not, but I think your
problem is somewhere here.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Tue Jan  4 23:28:56 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 5 Jan 2022 08:28:56 +0100
Subject: [PATCH master 0/5] misc fixes
In-Reply-To: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
References: <20220103115718.1723730-1-a.fatoum@pengutronix.de>
Message-ID: <20220105072856.GL6003@pengutronix.de>

On Mon, Jan 03, 2022 at 12:57:13PM +0100, Ahmad Fatoum wrote:
> Collection of fixes for master.
> 
> Ahmad Fatoum (4):
>   pwm: atmel: point MMIO accesses at correct address
>   clk: fixed: record parent name in clk_register_fixed_rate
>   imx-bbu-nand-fcb: suppress compiler warning about uninitialized use
>   regulator: fix broken reference counting on disable
> 
> Enrico Jorns (1):
>   regulator: respect "regulator-always-on" property

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Tue Jan  4 23:56:25 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 5 Jan 2022 08:56:25 +0100
Subject: [PATCH 0/4] include: misc clean up
In-Reply-To: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
References: <20220103115824.1725086-1-a.fatoum@pengutronix.de>
Message-ID: <20220105075625.GM6003@pengutronix.de>

On Mon, Jan 03, 2022 at 12:58:20PM +0100, Ahmad Fatoum wrote:
> Ahmad Fatoum (4):
>   include: <linux/overflow.h>: add missing include
>   include: spinlock.h: define dummy for DEFINE_SPINLOCK
>   include: <linux/compiler.h>: delete __ADDRESSABLE macro
>   x86: remove reference to empty file

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Wed Jan  5 00:00:45 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 5 Jan 2022 09:00:45 +0100
Subject: [PATCH 00/11] treewide: SPDXify files without license statement
In-Reply-To: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
References: <20220103120539.1730644-1-a.fatoum@pengutronix.de>
Message-ID: <20220105080045.GN6003@pengutronix.de>

On Mon, Jan 03, 2022 at 01:05:28PM +0100, Ahmad Fatoum wrote:
> SPDX for tests, scripts and Documentation will follow. This series
> covers everything else.
> 
> Ahmad Fatoum (11):
>   commands: set SPDX-License-Identifier for files without license
>     statement
>   treewide: add SPDX-License-Identifier for Kbuild/Kconfig
>   treewide: add SPDX-License-Identifier for .gitignore
>   images: add SPDX-License-Identifiers
>   fs: jffs2: add SPDX-License-Identifier: GPL-2.0-only
>   include: add SPDX-License-Identifier
>   ARM: i.MX: add SPDX-License-Identifier for DCD
>   arch: add SPDX-License-Identifier to all headers
>   arch: add SPDX-License-Identifier to all .S files
>   arch: add SPDX-License-Identifier to all .c files
>   treewide: add SPDX-License-Identifier for files without explicit
>     license

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Wed Jan  5 00:01:35 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 5 Jan 2022 09:01:35 +0100
Subject: [PATCH] parseopt: drop unused, duplicate, parseopt_u16
In-Reply-To: <20220103120205.1728778-1-a.fatoum@pengutronix.de>
References: <20220103120205.1728778-1-a.fatoum@pengutronix.de>
Message-ID: <20220105080135.GO6003@pengutronix.de>

On Mon, Jan 03, 2022 at 01:02:05PM +0100, Ahmad Fatoum wrote:
> We always have sizeof(unsigned short) == sizeof(uint16_t), so
> parseopt_u16() is exactly equivalent to parseopt_hu().
> 
> The former is unused anyway, so just drop it.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  include/parseopt.h |  1 -
>  lib/parseopt.c     | 31 -------------------------------
>  2 files changed, 32 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Jan  5 00:44:20 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed,  5 Jan 2022 09:44:20 +0100
Subject: [PATCH] getopt: Add support for '+' in optstring
Message-ID: <20220105084420.2691855-1-s.hauer@pengutronix.de>

Stop option parsing at nonoptions when the first character of optstring is
'+'. This is analog to getopt(3).

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 lib/getopt.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/getopt.c b/lib/getopt.c
index 55852ba133..356fc2ff4e 100644
--- a/lib/getopt.c
+++ b/lib/getopt.c
@@ -61,13 +61,24 @@ int getopt(int argc, char *argv[], const char *optstring)
 {
 	char curopt;   /* current option character */
 	const char *curoptp; /* pointer to the current option in optstring */
+	bool stop_nonopt = false;
+
+	if (*optstring == '+') {
+		stop_nonopt = true;
+		optstring++;
+	}
 
 	while(1) {
 		debug("optindex: %d nonopts: %d optind: %d\n", optindex, nonopts, optind);
 
-		if (optindex == 1 && argv[optind] && !strcmp(argv[optind], "--")) {
-			optind++;
-			return -1;
+		if (optindex == 1 && argv[optind]) {
+			if (!strcmp(argv[optind], "--")) {
+				optind++;
+				return -1;
+			}
+
+			if (stop_nonopt && *argv[optind] != '-')
+				return -1;
 		}
 
 		/* first put nonopts to the end */
-- 
2.30.2



From sha at pengutronix.de  Wed Jan  5 00:50:23 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 5 Jan 2022 09:50:23 +0100
Subject: [PATCH] commands: time: add -n option for nanoseconds output
In-Reply-To: <20220103120310.1729050-1-a.fatoum@pengutronix.de>
References: <20220103120310.1729050-1-a.fatoum@pengutronix.de>
Message-ID: <20220105085023.GP6003@pengutronix.de>

On Mon, Jan 03, 2022 at 01:03:10PM +0100, Ahmad Fatoum wrote:
> The current millisecond output may be too coarse for debugging timing
> of barebox functionality. Add an optional nanosecond output.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  commands/time.c | 21 ++++++++++++++-------
>  1 file changed, 14 insertions(+), 7 deletions(-)
> 
> diff --git a/commands/time.c b/commands/time.c
> index 25ba2da15ed5..2d9fb75e7a8c 100644
> --- a/commands/time.c
> +++ b/commands/time.c
> @@ -9,7 +9,7 @@ static int do_time(int argc, char *argv[])
>  	int i;
>  	unsigned char *buf;
>  	u64 start, end, diff64;
> -	unsigned long diff;
> +	bool nanoseconds = false;
>  	int len = 1; /* '\0' */
>  
>  	if (argc < 2)
> @@ -20,7 +20,13 @@ static int do_time(int argc, char *argv[])
>  
>  	buf = xzalloc(len);

The argv[] elements are copied into a string allocated here. The number
of bytes needed is calculated before the option parsing, so the space
allocated here unnecessarily includes the space for the options. Not a
big deal, but I think it's more consistent to move the option parsing
before calculating the needed buffer space.

>  
> -	for (i = 1; i < argc; i++) {
> +	i = 1;
> +	if (!strcmp(argv[i], "-n")) {
> +		nanoseconds = true;
> +		i++;
> +	}

I just created a patch to support '+' as the first character of
optstring. This allows you to use regular getopt for option parsing
here.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Wed Jan  5 01:14:24 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 5 Jan 2022 10:14:24 +0100
Subject: [PATCH] commands: regulator: add support for enabling/disabling
 regulators
In-Reply-To: <20220103120336.1729791-1-a.fatoum@pengutronix.de>
References: <20220103120336.1729791-1-a.fatoum@pengutronix.de>
Message-ID: <20220105091423.GQ6003@pengutronix.de>

On Mon, Jan 03, 2022 at 01:03:36PM +0100, Ahmad Fatoum wrote:
> For testing regulator drivers, it can be handy to enable/disable them
> from the shell prompt. Extend the regulator command to support this.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  commands/regulator.c     | 38 +++++++++++++++++++++++++++++++++++---
>  drivers/regulator/core.c |  8 ++++++++
>  include/regulator.h      |  1 +
>  3 files changed, 44 insertions(+), 3 deletions(-)
> 
> diff --git a/commands/regulator.c b/commands/regulator.c
> index 3e2595f8bfc1..e6b2f4852db4 100644
> --- a/commands/regulator.c
> +++ b/commands/regulator.c
> @@ -6,16 +6,48 @@
>  #include <common.h>
>  #include <command.h>
>  #include <regulator.h>
> +#include <getopt.h>
>  
>  static int do_regulator(int argc, char *argv[])
>  {
> -	regulators_print();
> +	struct regulator *chosen;
> +	int opt, ret;
> +
> +	while ((opt = getopt(argc, argv, "e:d:")) > 0) {
> +		switch (opt) {
> +		case 'e':
> +		case 'd':
> +			chosen = regulator_get_name(optarg);
> +			if (IS_ERR_OR_NULL(chosen)) {
> +				printf("regulator not found\n");
> +				return COMMAND_ERROR;
> +			}
> +
> +			ret = opt == 'e' ? regulator_enable(chosen)
> +				         : regulator_disable(chosen);
> +			regulator_put(chosen);
> +			return ret;

The barebox regulator core distinguishes between struct regulator and
struct regulator_internal. regulator_internal represents the physical
regulator whereas regulator is allocated for each consumer. If the
regulator core were a bit more sophisticated then a regulator would
have it's own enable count and you would be warned when a regulators
enable count goes below zero.

I agree that controlling regulators on the command line would be useful,
but I also don't want to block extending the regulator core in such a
way.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Jan  5 01:21:21 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 5 Jan 2022 10:21:21 +0100
Subject: [PATCH] commands: regulator: add support for enabling/disabling
 regulators
In-Reply-To: <20220105091423.GQ6003@pengutronix.de>
References: <20220103120336.1729791-1-a.fatoum@pengutronix.de>
 <20220105091423.GQ6003@pengutronix.de>
Message-ID: <089dca59-c852-751a-00c6-df572a832d62@pengutronix.de>

Hi,

On 05.01.22 10:14, Sascha Hauer wrote:
> On Mon, Jan 03, 2022 at 01:03:36PM +0100, Ahmad Fatoum wrote:
>> For testing regulator drivers, it can be handy to enable/disable them
>> from the shell prompt. Extend the regulator command to support this.
>>
>> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
>> ---
>>  commands/regulator.c     | 38 +++++++++++++++++++++++++++++++++++---
>>  drivers/regulator/core.c |  8 ++++++++
>>  include/regulator.h      |  1 +
>>  3 files changed, 44 insertions(+), 3 deletions(-)
>>
>> diff --git a/commands/regulator.c b/commands/regulator.c
>> index 3e2595f8bfc1..e6b2f4852db4 100644
>> --- a/commands/regulator.c
>> +++ b/commands/regulator.c
>> @@ -6,16 +6,48 @@
>>  #include <common.h>
>>  #include <command.h>
>>  #include <regulator.h>
>> +#include <getopt.h>
>>  
>>  static int do_regulator(int argc, char *argv[])
>>  {
>> -	regulators_print();
>> +	struct regulator *chosen;
>> +	int opt, ret;
>> +
>> +	while ((opt = getopt(argc, argv, "e:d:")) > 0) {
>> +		switch (opt) {
>> +		case 'e':
>> +		case 'd':
>> +			chosen = regulator_get_name(optarg);
>> +			if (IS_ERR_OR_NULL(chosen)) {
>> +				printf("regulator not found\n");
>> +				return COMMAND_ERROR;
>> +			}
>> +
>> +			ret = opt == 'e' ? regulator_enable(chosen)
>> +				         : regulator_disable(chosen);
>> +			regulator_put(chosen);
>> +			return ret;
> 
> The barebox regulator core distinguishes between struct regulator and
> struct regulator_internal. regulator_internal represents the physical
> regulator whereas regulator is allocated for each consumer. If the
> regulator core were a bit more sophisticated then a regulator would
> have it's own enable count and you would be warned when a regulators
> enable count goes below zero.
> 
> I agree that controlling regulators on the command line would be useful,
> but I also don't want to block extending the regulator core in such a
> way.

Should I move the command implementation then into drivers/regulator/core.c?

That's what I did here[1], but I seem to recall that you objected to
moving the command into drivers/ to access internals, when the API
should suffice/be extended. I can't find the mail right now though or
perhaps my recollection is erroneous.

So how to proceed?

[1]: https://lore.barebox.org/barebox/20191106094459.w32tgsl22ty34vhe at pengutronix.de/#t

Cheers,
Ahmad

> 
> Sascha
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Wed Jan  5 03:20:31 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 5 Jan 2022 12:20:31 +0100
Subject: [PATCH] i2c: add Rockchip i2c controller support
In-Reply-To: <20220103120015.1727051-1-a.fatoum@pengutronix.de>
References: <20220103120015.1727051-1-a.fatoum@pengutronix.de>
Message-ID: <20220105112031.GT6003@pengutronix.de>

On Mon, Jan 03, 2022 at 01:00:15PM +0100, Ahmad Fatoum wrote:
> For addressing the PMIC on Rockchip platforms, add an i2c controller
> driver. Tested with rk3399 and rk808.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/i2c/busses/Kconfig        |   8 +
>  drivers/i2c/busses/Makefile       |   1 +
>  drivers/i2c/busses/i2c-rockchip.c | 472 ++++++++++++++++++++++++++++++
>  3 files changed, 481 insertions(+)
>  create mode 100644 drivers/i2c/busses/i2c-rockchip.c
> 
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index c1e76a04096e..a551df537a69 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -62,4 +62,12 @@ config I2C_STM32
>  	depends on HAVE_CLK
>  	depends on ARCH_STM32MP || COMPILE_TEST
>  
> +config I2C_RK3X
> +	tristate "Rockchip RK3xxx I2C adapter"
> +	depends on HAVE_CLK
> +	depends on ARCH_ROCKCHIP || COMPILE_TEST
> +	help
> +	  Say Y here to include support for the I2C adapter in Rockchip RK3xxx
> +	  SoCs.
> +
>  endmenu
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 34a12fcbea96..d6273f3d8679 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
>  obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
>  obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o
>  obj-$(CONFIG_I2C_STM32)		+= i2c-stm32.o
> +obj-$(CONFIG_I2C_RK3X)		+= i2c-rockchip.o
> diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
> new file mode 100644
> index 000000000000..ba7397b19967
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-rockchip.c
> @@ -0,0 +1,472 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * (C) Copyright 2015 Google, Inc
> + *
> + * (C) Copyright 2008-2014 Rockchip Electronics
> + * Peter, Software Engineering, <superpeter.cai at gmail.com>.
> + */
> +
> +#include <common.h>
> +#include <i2c/i2c.h>
> +#include <linux/iopoll.h>
> +#include <errno.h>
> +#include <linux/err.h>
> +#include <driver.h>
> +#include <io.h>
> +#include <linux/clk.h>
> +#include <mfd/syscon.h>
> +#include <regmap.h>
> +#include <linux/sizes.h>
> +
> +struct i2c_regs {
> +	u32 con;
> +	u32 clkdiv;
> +	u32 mrxaddr;
> +	u32 mrxraddr;
> +	u32 mtxcnt;
> +	u32 mrxcnt;
> +	u32 ien;
> +	u32 ipd;
> +	u32 fcnt;
> +	u32 reserved0[0x37];
> +	u32 txdata[8];
> +	u32 reserved1[0x38];
> +	u32 rxdata[8];
> +};
> +
> +/* Control register */
> +#define I2C_CON_EN		(1 << 0)
> +#define I2C_CON_MOD(mod)	((mod) << 1)
> +#define I2C_MODE_TX		0x00
> +#define I2C_MODE_TRX		0x01
> +#define I2C_MODE_RX		0x02
> +#define I2C_MODE_RRX		0x03
> +#define I2C_CON_MASK		(3 << 1)
> +
> +#define I2C_CON_START		(1 << 3)
> +#define I2C_CON_STOP		(1 << 4)
> +#define I2C_CON_LASTACK		(1 << 5)
> +#define I2C_CON_ACTACK		(1 << 6)
> +
> +/* Clock dividor register */

s/dividor/divider/

> +#define I2C_CLKDIV_VAL(divl, divh) \
> +	(((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))
> +
> +/* the slave address accessed  for master rx mode */
> +#define I2C_MRXADDR_SET(vld, addr)	(((vld) << 24) | (addr))
> +
> +/* the slave register address accessed  for master rx mode */
> +#define I2C_MRXRADDR_SET(vld, raddr)	(((vld) << 24) | (raddr))
> +
> +/* interrupt enable register */
> +#define I2C_BTFIEN		(1 << 0)
> +#define I2C_BRFIEN		(1 << 1)
> +#define I2C_MBTFIEN		(1 << 2)
> +#define I2C_MBRFIEN		(1 << 3)
> +#define I2C_STARTIEN		(1 << 4)
> +#define I2C_STOPIEN		(1 << 5)
> +#define I2C_NAKRCVIEN		(1 << 6)
> +
> +/* interrupt pending register */
> +#define I2C_BTFIPD              (1 << 0)
> +#define I2C_BRFIPD              (1 << 1)
> +#define I2C_MBTFIPD             (1 << 2)
> +#define I2C_MBRFIPD             (1 << 3)
> +#define I2C_STARTIPD            (1 << 4)
> +#define I2C_STOPIPD             (1 << 5)
> +#define I2C_NAKRCVIPD           (1 << 6)
> +#define I2C_IPD_ALL_CLEAN       0x7f
> +
> +/* i2c timerout */

s/timerout/timeout/

> +#define I2C_TIMEOUT		(100 * MSECOND)
> +#define I2C_RETRY_COUNT		3

unused

> +
> +/* rk i2c fifo max transfer bytes */
> +#define RK_I2C_FIFO_SIZE	32
> +
> +struct rk_i2c {
> +	struct i2c_adapter	adapter;
> +	struct clk *clk;
> +	struct i2c_regs *regs;
> +	unsigned int speed;
> +};
> +
> +static inline struct rk_i2c *to_rk_i2c(struct i2c_adapter *adapter)
> +{
> +	return container_of(adapter, struct rk_i2c, adapter);
> +}
> +
> +static inline void rk_i2c_get_div(int div, int *divh, int *divl)
> +{
> +	*divl = div / 2;
> +	if (div % 2 == 0)
> +		*divh = div / 2;

Why special case this? DIV_ROUND_UP(div, 2) should work for even numbers
as well.

> +	else
> +		*divh = DIV_ROUND_UP(div, 2);
> +}
> +
> +/*
> + * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
> + * SCL = PCLK / SCLK Divisor
> + * i2c_rate = PCLK
> + */
> +static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
> +{
> +	struct device_d *dev = i2c->adapter.dev.parent;
> +	uint32_t i2c_rate;
> +	int div, divl, divh;
> +
> +	/* First get i2c rate from pclk */
> +	i2c_rate = clk_get_rate(i2c->clk);
> +
> +	div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
> +	divh = 0;
> +	divl = 0;
> +	if (div >= 0)
> +		rk_i2c_get_div(div, &divh, &divl);
> +	writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
> +
> +	dev_dbg(dev, "rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
> +		scl_rate);
> +	dev_dbg(dev, "set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
> +	dev_dbg(dev, "set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
> +}
> +
> +static void rk_i2c_show_regs(struct rk_i2c *i2c)
> +{
> +	struct device_d *dev = &i2c->adapter.dev;
> +	struct i2c_regs *regs = i2c->regs;
> +	int i;
> +
> +	dev_dbg(dev, "i2c_con: 0x%08x\n", readl(&regs->con));
> +	dev_dbg(dev, "i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
> +	dev_dbg(dev, "i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
> +	dev_dbg(dev, "i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
> +	dev_dbg(dev, "i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
> +	dev_dbg(dev, "i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
> +	dev_dbg(dev, "i2c_ien: 0x%08x\n", readl(&regs->ien));
> +	dev_dbg(dev, "i2c_ipd: 0x%08x\n", readl(&regs->ipd));
> +	dev_dbg(dev, "i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
> +
> +	for (i = 0; i < 8; i++)
> +		dev_dbg(dev, "i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
> +	for (i = 0; i < 8; i++)
> +		dev_dbg(dev, "i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
> +}
> +
> +static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
> +{
> +	struct device_d *dev = &i2c->adapter.dev;
> +	struct i2c_regs *regs = i2c->regs;
> +	u64 start;
> +
> +	dev_dbg(dev, "I2c Send Start bit.\n");
> +	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
> +
> +	writel(I2C_CON_EN | I2C_CON_START, &regs->con);
> +	writel(I2C_STARTIEN, &regs->ien);
> +
> +	for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
> +		if (readl(&regs->ipd) & I2C_STARTIPD) {
> +			writel(I2C_STARTIPD, &regs->ipd);
> +			return 0;
> +		}
> +		udelay(1);

Unnecessary udelay()

> +	}
> +
> +	dev_dbg(dev, "I2C Send Start Bit Timeout\n");
> +	rk_i2c_show_regs(i2c);
> +	return -ETIMEDOUT;
> +}
> +
> +static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
> +{
> +	struct device_d *dev = &i2c->adapter.dev;
> +	struct i2c_regs *regs = i2c->regs;
> +	u64 start;
> +
> +	dev_dbg(dev, "I2c Send Stop bit.\n");
> +	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
> +
> +	writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
> +	writel(I2C_CON_STOP, &regs->ien);
> +
> +	for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
> +		if (readl(&regs->ipd) & I2C_STOPIPD) {
> +			writel(I2C_STOPIPD, &regs->ipd);
> +			return 0;
> +		}
> +		udelay(1);

ditto

> +	}
> +
> +	dev_dbg(dev, "I2C Send Start Bit Timeout\n");
> +	rk_i2c_show_regs(i2c);
> +	return -ETIMEDOUT;
> +}
> +
> +static inline void rk_i2c_disable(struct rk_i2c *i2c)
> +{
> +	writel(0, &i2c->regs->con);
> +}
> +
> +static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
> +		       uchar *buf, uint b_len)
> +{
> +	struct device_d *dev = &i2c->adapter.dev;
> +	struct i2c_regs *regs = i2c->regs;
> +	uchar *pbuf = buf;
> +	uint bytes_remain_len = b_len;
> +	uint bytes_xferred = 0;
> +	uint words_xferred = 0;
> +	u64 start;
> +	uint con = 0;
> +	uint rxdata;
> +	uint i, j;
> +	int err;
> +	bool snd_chunk = false;
> +
> +	dev_dbg(dev, "rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
> +	      chip, reg, r_len, b_len);
> +
> +	err = rk_i2c_send_start_bit(i2c);
> +	if (err)
> +		return err;
> +
> +	writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
> +	if (r_len == 0) {
> +		writel(0, &regs->mrxraddr);
> +	} else if (r_len < 4) {
> +		writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
> +	} else {
> +		dev_dbg(dev, "I2C Read: addr len %d not supported\n", r_len);
> +		return -EIO;
> +	}
> +
> +	while (bytes_remain_len) {
> +		if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
> +			con = I2C_CON_EN;
> +			bytes_xferred = 32;

bytes_xferred = RK_I2C_FIFO_SIZE

> +		} else {
> +			/*
> +			 * The hw can read up to 32 bytes at a time. If we need
> +			 * more than one chunk, send an ACK after the last byte.
> +			 */
> +			con = I2C_CON_EN | I2C_CON_LASTACK;
> +			bytes_xferred = bytes_remain_len;
> +		}
> +		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
> +
> +		/*
> +		 * make sure we are in plain RX mode if we read a second chunk
> +		 */
> +		if (snd_chunk)
> +			con |= I2C_CON_MOD(I2C_MODE_RX);
> +		else
> +			con |= I2C_CON_MOD(I2C_MODE_TRX);
> +
> +		writel(con, &regs->con);
> +		writel(bytes_xferred, &regs->mrxcnt);
> +		writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
> +
> +		err = -ETIMEDOUT;
> +		for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
> +			if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
> +				writel(I2C_NAKRCVIPD, &regs->ipd);
> +				err = -EREMOTEIO;

Does it make sense to stay in the loop here?

> +			}
> +			if (readl(&regs->ipd) & I2C_MBRFIPD) {
> +				writel(I2C_MBRFIPD, &regs->ipd);
> +				err = 0;
> +				break;
> +			}
> +			udelay(1);

Unnecessary udelay().

> +		}
> +
> +		if (err) {
> +			dev_dbg(dev, "I2C Read Data Timeout\n");
> +			rk_i2c_show_regs(i2c);
> +			goto i2c_exit;
> +		}

It's easier to follow when you just exit the loop with

	if (is_timeout()) {
		err = -ETIMEDOUT;
		goto i2c_exit;
	}

> +
> +		for (i = 0; i < words_xferred; i++) {
> +			rxdata = readl(&regs->rxdata[i]);
> +			dev_dbg(dev, "I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
> +			for (j = 0; j < 4; j++) {
> +				if ((i * 4 + j) == bytes_xferred)
> +					break;
> +				*pbuf++ = (rxdata >> (j * 8)) & 0xff;
> +			}
> +		}
> +
> +		bytes_remain_len -= bytes_xferred;
> +		snd_chunk = true;
> +		dev_dbg(dev, "I2C Read bytes_remain_len %d\n", bytes_remain_len);
> +	}
> +
> +i2c_exit:
> +	rk_i2c_disable(i2c);
> +
> +	return err;
> +}
> +
> +static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
> +			uchar *buf, uint b_len)
> +{
> +	struct device_d *dev = &i2c->adapter.dev;
> +	struct i2c_regs *regs = i2c->regs;
> +	int err;
> +	uchar *pbuf = buf;
> +	uint bytes_remain_len = b_len + r_len + 1;
> +	uint bytes_xferred = 0;
> +	uint words_xferred = 0;
> +	u64 start;
> +	uint txdata;
> +	uint i, j;
> +
> +	dev_dbg(dev, "rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
> +	      chip, reg, r_len, b_len);
> +	err = rk_i2c_send_start_bit(i2c);
> +	if (err)
> +		return err;
> +
> +	while (bytes_remain_len) {
> +		if (bytes_remain_len > RK_I2C_FIFO_SIZE)
> +			bytes_xferred = RK_I2C_FIFO_SIZE;
> +		else
> +			bytes_xferred = bytes_remain_len;
> +		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
> +
> +		for (i = 0; i < words_xferred; i++) {
> +			txdata = 0;
> +			for (j = 0; j < 4; j++) {
> +				if ((i * 4 + j) == bytes_xferred)
> +					break;
> +
> +				if (i == 0 && j == 0 && pbuf == buf) {
> +					txdata |= (chip << 1);
> +				} else if (i == 0 && j <= r_len && pbuf == buf) {
> +					txdata |= (reg &
> +						(0xff << ((j - 1) * 8))) << 8;
> +				} else {
> +					txdata |= (*pbuf++)<<(j * 8);
> +				}
> +			}
> +			writel(txdata, &regs->txdata[i]);
> +			dev_dbg(dev, "I2c Write TXDATA[%d] = 0x%08x\n", i, txdata);
> +		}
> +
> +		writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
> +		writel(bytes_xferred, &regs->mtxcnt);
> +		writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
> +
> +		err = -ETIMEDOUT;
> +		for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
> +			if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
> +				writel(I2C_NAKRCVIPD, &regs->ipd);
> +				err = -EREMOTEIO;
> +			}

Same as above, need to stay in the loop here?

> +			if (readl(&regs->ipd) & I2C_MBTFIPD) {
> +				writel(I2C_MBTFIPD, &regs->ipd);
> +				err = 0;
> +				break;
> +			}
> +			udelay(1);

Drop the udelay()

> +		}
> +
> +		if (err) {
> +			dev_dbg(dev, "I2C Write Data Timeout\n");
> +			rk_i2c_show_regs(i2c);
> +			goto i2c_exit;
> +		}

Test for timeout in the loop.

> +
> +		bytes_remain_len -= bytes_xferred;
> +		dev_dbg(dev, "I2C Write bytes_remain_len %d\n", bytes_remain_len);
> +	}
> +
> +i2c_exit:
> +	rk_i2c_disable(i2c);
> +
> +	return err;
> +}
> +
> +static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
> +			     int nmsgs)
> +{
> +	struct rk_i2c *i2c = to_rk_i2c(adapter);
> +	struct device_d *dev = &adapter->dev;
> +	int ret;
> +
> +	dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
> +	for (; nmsgs > 0; nmsgs--, msg++) {
> +		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
> +		if (msg->flags & I2C_M_RD) {
> +			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
> +					  msg->len);
> +		} else {
> +			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
> +					   msg->len);
> +		}
> +		if (ret) {
> +			dev_dbg(dev, "i2c_write: error sending\n");
> +			return -EREMOTEIO;

Print the error code? Forward the error?

> +		}
> +	}
> +
> +	rk_i2c_send_stop_bit(i2c);
> +	rk_i2c_disable(i2c);
> +
> +	return 0;
> +}
> +
> +static int rk_i2c_probe(struct device_d *dev)
> +{
> +	struct device_node *np = dev->device_node;
> +	struct resource *iores;
> +	struct rk_i2c *i2c;
> +	unsigned bitrate;
> +
> +	iores = dev_request_mem_resource(dev, 0);
> +	if (IS_ERR(iores))
> +		return PTR_ERR(iores);
> +
> +	i2c = kzalloc(sizeof(struct rk_i2c), GFP_KERNEL);
> +	if (!i2c)
> +		return -ENOMEM;
> +
> +	dev->priv = i2c;
> +	i2c->regs = IOMEM(iores->start);
> +
> +	/* Only one clock to use for bus clock and peripheral clock */
> +	i2c->clk = clk_get(dev, NULL);
> +	if (IS_ERR(i2c->clk))
> +		return dev_err_probe(dev, PTR_ERR(i2c->clk), "Can't get bus clk\n");
> +
> +	/* Setup i2c_fsl driver structure */

copy/paste, it's not i2c_fsl

> +	i2c->adapter.master_xfer = rockchip_i2c_xfer;
> +	i2c->adapter.nr = dev->id;
> +	i2c->adapter.dev.parent = dev;
> +	i2c->adapter.dev.device_node = np;
> +
> +	/* Set up clock divider */
> +	bitrate = 100000;
> +	of_property_read_u32(np, "clock-frequency", &bitrate);
> +
> +	rk_i2c_set_clk(i2c, bitrate);
> +
> +	return i2c_add_numbered_adapter(&i2c->adapter);
> +}
> +
> +static const struct of_device_id rk_i2c_match[] = {
> +	{ .compatible = "rockchip,rv1108-i2c" },
> +	{ .compatible = "rockchip,rk3228-i2c" },
> +	{ .compatible = "rockchip,rk3288-i2c" },
> +	{ .compatible = "rockchip,rk3399-i2c" },
> +	{},
> +};
> +
> +static struct driver_d rk_i2c_driver = {
> +	.name  = "rk3x-i2c",
> +	.of_compatible = rk_i2c_match,
> +	.probe   = rk_i2c_probe,
> +};
> +coredevice_platform_driver(rk_i2c_driver);
> -- 
> 2.30.2
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Jan  5 04:08:24 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 5 Jan 2022 13:08:24 +0100
Subject: barebox - rk3568
In-Reply-To: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
References: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
Message-ID: <5692a978-e5e5-c46d-978e-49438ee28782@pengutronix.de>

Hello Frank,

On 04.01.22 09:39, Frank Wunderlich wrote:
> Hi,
> 
> i have a prototype rk3568 board (bpi-r2-pro).
> 
> is it possible to flash only barebox instead of uboot? in documentation i found only "creating SD-card", but i dont want to break existing partitions.
> 
> https://www.barebox.org/doc/latest/boards/rockchip.html#rockchip-rk3568
> 
> says it starts from sector 32, my first block for uboot (idblock.bin=spl+raminit) starts at 64, full uboot in partition at 8M.

You probably figured it out by now, but the discrepancy is likely due to differing
block sizes. barebox documentation has `dd bs=1024`, while the default is 512.
boot firmware is a single chunk with barebox, so no separate second stage bootloader
partition.

> As it differs a bit from evb can i add new dts like in uboot?

You can check out the commit adding the EVB or the Pine64 Quartz64:
8d14f8e898b4 ("arm: rockchip: add support for the quartz64 board")

Feel free to send patches for your board along the same lines. :)

Cheers,
Ahmad

> 
> regards Frank
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From frank-w at public-files.de  Wed Jan  5 07:20:43 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Wed, 5 Jan 2022 16:20:43 +0100
Subject: barebox extending boot-scripts
Message-ID: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>

Hi,

i'm making my first steps and try to add more boot-scripts (to land in /env/boot)

i added a scipt in

arch/arm/boards/rockchip-rk3568-evb/defaultenv/mmc-linux

and set

DEFAULT_ENVIRONMENT_PATH [=arch/arm/boards/rockchip-rk3568-evb/defaultenv]

but if i boot the board /env/boot only contains the 2 default scripts

barebox at Rockchip RK3568 EVB:/ ls /env/boot/
bnet    net

so maybe the dir/config-option i used is for defining variables only right? should this point to an directory or a file?

i see this file which looks like the source of it

./defaultenv/defaultenv-2-base/boot/net

I've put them there and they appear, but this is not board specific, so if i later want to upstream one this is maybe not the right place.

./defaultenv/defaultenv-2-menu/menu/10-boot-all/net

seems to be a menu entry, but have not yet figured out how i can define one to add my scripts too

have not found anything for it in the documentation yet

btw. is there a way to use ls with wildcard without printing the path?

ls /mnt/sd.1/extlinux/
Image_5.16            Image_5.16-next.gz    Image_5.16.gz

ls /mnt/sd.1/extlinux/Image*
/mnt/sd.1/extlinux/Image_5.16
/mnt/sd.1/extlinux/Image_5.16-next.gz
/mnt/sd.1/extlinux/Image_5.16.gz

i want to list only files matching Image*, but without path....number of columns does not matter

regards Frank



From frank-w at public-files.de  Wed Jan  5 07:42:02 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Wed, 5 Jan 2022 16:42:02 +0100
Subject: Aw: Re: barebox - rk3568
In-Reply-To: <5692a978-e5e5-c46d-978e-49438ee28782@pengutronix.de>
References: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
 <5692a978-e5e5-c46d-978e-49438ee28782@pengutronix.de>
Message-ID: <trinity-cf421ba4-410b-4e0e-bb2f-60fef962bc97-1641397322119@3c-app-gmx-bs58>

> Gesendet: Mittwoch, 05. Januar 2022 um 13:08 Uhr
> Von: "Ahmad Fatoum" <a.fatoum at pengutronix.de>
> An: "Frank Wunderlich" <frank-w at public-files.de>, barebox at lists.infradead.org
> Betreff: Re: barebox - rk3568

> > https://www.barebox.org/doc/latest/boards/rockchip.html#rockchip-rk3568
> >
> > says it starts from sector 32, my first block for uboot (idblock.bin=spl+raminit) starts at 64, full uboot in partition at 8M.
>
> You probably figured it out by now, but the discrepancy is likely due to differing
> block sizes. barebox documentation has `dd bs=1024`, while the default is 512.
> boot firmware is a single chunk with barebox, so no separate second stage bootloader
> partition.

thanks, this indeed explain the different offset, which is same after resolving the double blocksize

> > As it differs a bit from evb can i add new dts like in uboot?
>
> You can check out the commit adding the EVB or the Pine64 Quartz64:
> 8d14f8e898b4 ("arm: rockchip: add support for the quartz64 board")
>
> Feel free to send patches for your board along the same lines. :)

currently evb is working well, so i try to add bootscripts and maybe an menu (if i found out how) :)

regards Frank


From a.fatoum at pengutronix.de  Wed Jan  5 08:07:22 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 5 Jan 2022 17:07:22 +0100
Subject: barebox extending boot-scripts
In-Reply-To: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
Message-ID: <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>

Hi,

On 05.01.22 16:20, Frank Wunderlich wrote:
> Hi,
> 
> i'm making my first steps and try to add more boot-scripts (to land in /env/boot)
> 
> i added a scipt in
> 
> arch/arm/boards/rockchip-rk3568-evb/defaultenv/mmc-linux

This should be defaultenv/boot/mmc-linux instead.

> and set
> 
> DEFAULT_ENVIRONMENT_PATH [=arch/arm/boards/rockchip-rk3568-evb/defaultenv]
> 
> but if i boot the board /env/boot only contains the 2 default scripts
> 
> barebox at Rockchip RK3568 EVB:/ ls /env/boot/
> bnet    net

Try ls -R /env, you should see mmc-linux at top-level with your
current setup.

> so maybe the dir/config-option i used is for defining variables only right?

Top level is only meant for directories. There are directories for the different
stuff, e.g. variables go into /env/nv/

> should this point to an directory or a file?

The config option is meant for use with external build systems, e.g. buildroot
or PTXdist. For boards in-tree, you can add bbenv-y in the Makefile and call

  // assuming directory is called defaultenv-myboard
  defaultenv_append_directory(defaultenv_myboard);

in the board code, see e.g. arch/arm/boards/embest-marsboard for an example.

The reason for avoiding the config option for in-tree boards is that a single barebox
configuration can build multiple boards in one go:
extreme case: imx_v7_defconfig, which builds marsboard also builds more than 100 other images.

The config option is global, but by explicitly calling defaultenv_append_directory,
you can have board-specific environments.

> i see this file which looks like the source of it
> 
> ./defaultenv/defaultenv-2-base/boot/net
> 
> I've put them there and they appear, but this is not board specific

Ye, you can use this for debugging, but stuff upstreamed there must be generally
applicable.

> so if i later want to upstream one this is maybe not the right place.

Boot scripts for publicly available evaluation kits are often not good candidates
for upstreaming, because everybody using the EVKs has different thoughts on how to
boot. The best way would be to use bootloader spec. It's one or more files you
place at a known location that describe where your kernel and device tree are and
what command line arguments to use and barebox can then automatically generate
boot entries from all available bootloader spec files.

See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
of how to set this up. This is what I'd recommend instead of writing your own
scripts.

> ./defaultenv/defaultenv-2-menu/menu/10-boot-all/net
> 
> seems to be a menu entry, but have not yet figured out how i can define one to add my scripts too
> 
> have not found anything for it in the documentation yet

The default boot menu is populated with the boot entries extracted from
the contents of $global.boot.default.

boot -m will display that menu. It will also include all bootloader spec files.
If that suffices, you won't need to create your own menu. If you want though,
check the help text of the menutree command.

To boot into the boot menu, set nv autoboot=menu. "Detect bootsources" will
list boot sources known to the barebox boot command.

See magicvar for a listing of all magic variables, or refer to the documentation.

> btw. is there a way to use ls with wildcard without printing the path?
> 
> ls /mnt/sd.1/extlinux/
> Image_5.16            Image_5.16-next.gz    Image_5.16.gz
> 
> ls /mnt/sd.1/extlinux/Image*
> /mnt/sd.1/extlinux/Image_5.16
> /mnt/sd.1/extlinux/Image_5.16-next.gz
> /mnt/sd.1/extlinux/Image_5.16.gz
> 
> i want to list only files matching Image*, but without path....number of columns does not matter

Yes, cd /mnt/sd.1/extlinux

Cheers,
Ahmad

> 
> regards Frank
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Jan  5 08:08:45 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 5 Jan 2022 17:08:45 +0100
Subject: Aw: Re: barebox - rk3568
In-Reply-To: <trinity-cf421ba4-410b-4e0e-bb2f-60fef962bc97-1641397322119@3c-app-gmx-bs58>
References: <trinity-c26cce2b-95ff-45dc-9d60-3a1eebfa088b-1641285545326@3c-app-gmx-bap27>
 <5692a978-e5e5-c46d-978e-49438ee28782@pengutronix.de>
 <trinity-cf421ba4-410b-4e0e-bb2f-60fef962bc97-1641397322119@3c-app-gmx-bs58>
Message-ID: <d6b21243-ad8f-f84f-b41c-c2854b64e011@pengutronix.de>

On 05.01.22 16:42, Frank Wunderlich wrote:
>> Gesendet: Mittwoch, 05. Januar 2022 um 13:08 Uhr
>> Von: "Ahmad Fatoum" <a.fatoum at pengutronix.de>
>> An: "Frank Wunderlich" <frank-w at public-files.de>, barebox at lists.infradead.org
>> Betreff: Re: barebox - rk3568
> 
>>> https://www.barebox.org/doc/latest/boards/rockchip.html#rockchip-rk3568
>>>
>>> says it starts from sector 32, my first block for uboot (idblock.bin=spl+raminit) starts at 64, full uboot in partition at 8M.
>>
>> You probably figured it out by now, but the discrepancy is likely due to differing
>> block sizes. barebox documentation has `dd bs=1024`, while the default is 512.
>> boot firmware is a single chunk with barebox, so no separate second stage bootloader
>> partition.
> 
> thanks, this indeed explain the different offset, which is same after resolving the double blocksize
> 
>>> As it differs a bit from evb can i add new dts like in uboot?
>>
>> You can check out the commit adding the EVB or the Pine64 Quartz64:
>> 8d14f8e898b4 ("arm: rockchip: add support for the quartz64 board")
>>
>> Feel free to send patches for your board along the same lines. :)
> 
> currently evb is working well, so i try to add bootscripts and maybe an menu (if i found out how) :)

It's not EVB anymore though, if you replace the device tree and skip the board code. ;)

> 
> regards Frank
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Jan  5 09:50:17 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 5 Jan 2022 18:50:17 +0100
Subject: Howto implement bootchooser <-> rauc interaction
In-Reply-To: <YcMwk6mncQ8fSwTJ@Hephaistos>
References: <9215c9815f25cc3328a05d6c9553ac36@inside-m2m.de>
 <CAMHeXxOoXjqtSGXdE73oROUk9ybFmFv7gi8PtzLsKn=iH+FXLA@mail.gmail.com>
 <c4ae26b8698992ad37f201101795b1bb@inside-m2m.de>
 <53bdfd89-f363-5cec-4cb1-417c25c90eaf@pengutronix.de>
 <297b3425baa118783dccb6446900fbfa@inside-m2m.de>
 <cf1e6cf6a51dc13ec5275d94e18d23c1@inside-m2m.de>
 <ef8a2a82-91f5-5401-a564-a0ab20da4772@pengutronix.de>
 <YbyGBHs1YWVcgE5X@Hephaistos>
 <68358567-7665-bd5c-00fe-b410b4ec2518@pengutronix.de>
 <YbyczaAWK6juc0VO@Hephaistos> <YcMwk6mncQ8fSwTJ@Hephaistos>
Message-ID: <c55ef6c5-c7ea-0663-47b9-141773985ba2@pengutronix.de>

Hello Konstantin,

On 22.12.21 15:05, Konstantin Kletschke wrote:
> I switched from doing the state in the onboard EEPROM (as said, it
> is write protected in production use) to save the state in a dead space
> in the onboard eMMC chip between MBR and first partition:
> 
> / {
> 	aliases {
> 		state = &state_eeprom;
> 	};
> 
> 	state_eeprom: state_eeprom {
> 		#address-cells = <1>;
> 		#size-cells = <1>;
> 		compatible = "barebox,state";
> 		magic = <0xcafebabe>;
> 		backend-type = "raw";
> 		backend = <&backend_state_mmc2>;
> 		backend-storage-type = "direct";
> 		backend-stridesize = <54>;
> 		last_chosen {

Here last_chosen is toplevel.


> Compiled in (relevant) variables:
> 
> * boot.default: bootchooser insidem2m_1 insidem2m_2
>   boot.watchdog_timeout: 0
>   bootchooser.default_attempts: 3
>   bootchooser.default_priority: 1
>   bootchooser.disable_on_zero_attempts: 0
>   bootchooser.reset_attempts:  (list: "power-on", "all-zero")
>   bootchooser.reset_priorities: 
>   bootchooser.retry: 0
> * bootchooser.state_prefix: state

Here you say they are inside state.*

> The userspace is no amused, however:
> 
> rauc status output:
> 
> (rauc:583): rauc-WARNING **: 18:51:57.389: Failed getting primary slot: Failed getting primary slot: No content to read

Yes RAUC has:

  #define BOOTSTATE_PREFIX "bootstate"

So that's what you need to use.

> barebox-state:
> 
> last_chosen=2
> system0.remaining_attempts=0
> system0.priority=21
> system0.ok=0
> system1.remaining_attempts=2
> system1.priority=20
> system1.ok=0

But state works correctly regardless, you can place
all sort of stuff there.

> ################ PLAN B ##################
> 
> I had a previous state device tree setup, which made userspace happy,
> but not barebox. I had a parent bootstate section containing system0 and
> system1:
> 
> / {
> 	aliases {
> 		state = &state_eeprom;
> 	};
> 
> 	state_eeprom: state_eeprom {
> 		#address-cells = <1>;
> 		#size-cells = <1>;
> 		compatible = "barebox,state";
> 		magic = <0xcafebabe>;
> 		backend-type = "raw";
> 		backend = <&backend_state_mmc2>;
> 		backend-storage-type = "direct";
> 		backend-stridesize = <54>;
> 		bootstate {

Here you have a correctly named container.

> With this device tree barebox bootschooser is unhappy:

Did you set bootchooser.boot_prefix?

> But userspace is fine:

As expected.

> I assume this has to do with bootchooser.state_prefix. If I change from
> state to bootstate (yes, brute force) I get:
> 
> global excerpt:
> 
> * bootchooser.state_prefix: bootstate
> 
> devinfo state looks the same as previous.
> 
> boot:
> 
> barebox at TI AM335x BeagleBone black:/ boot
> ERROR: bootchooser: Cannot get state 'bootstate'
> Nothing bootable found on 'bootchooser'
> Booting entry 'insidem2m_1'
> ext4 ext40: EXT2 rev 1, inode_size 256, descriptor size 64
> mounted /dev/mmc1.1 on /mnt/mmc1.1
> [...]
> 
> 
> 
> When I set:
> 
> * bootchooser.state_prefix: state.bootstate
> 
> I get best of both worlds!

Exactly. :-)

> Wall of text, two questions:
> 
> Is this resulting setup (DT with bootstate parent, state_prefix:
> state.bootstate) sane?

Ye, the final setup looks good now.

> Can the variant without the boostate variant work too? If it was the
> other way around, userspace working w/o the bootstate variant but bnot
> _with_ I would say additional configuration required or something, but
> this way... I would like to understand this fully.

RAUC hardcodes bootstate, so that's what you need to use, unless you patch
RAUC.

Cheers,
Ahmad

> 
> 
> Kind Regards
> Konstantin
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From frank-w at public-files.de  Wed Jan  5 10:13:22 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Wed, 5 Jan 2022 19:13:22 +0100
Subject: Aw: Re: barebox extending boot-scripts
In-Reply-To: <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
Message-ID: <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>

Hi,

> Gesendet: Mittwoch, 05. Januar 2022 um 17:07 Uhr
> Von: "Ahmad Fatoum" <a.fatoum at pengutronix.de>
> An: "Frank Wunderlich" <frank-w at public-files.de>, barebox at lists.infradead.org
> Betreff: Re: barebox extending boot-scripts
>
> Hi,
>
> On 05.01.22 16:20, Frank Wunderlich wrote:
> > Hi,
> >
> > i'm making my first steps and try to add more boot-scripts (to land in /env/boot)
> >
> > i added a scipt in
> >
> > arch/arm/boards/rockchip-rk3568-evb/defaultenv/mmc-linux
>
> This should be defaultenv/boot/mmc-linux instead.
>
> > and set
> >
> > DEFAULT_ENVIRONMENT_PATH [=arch/arm/boards/rockchip-rk3568-evb/defaultenv]
> >
> > but if i boot the board /env/boot only contains the 2 default scripts
> >
> > barebox at Rockchip RK3568 EVB:/ ls /env/boot/
> > bnet    net
>
> Try ls -R /env, you should see mmc-linux at top-level with your
> current setup.
>
> > so maybe the dir/config-option i used is for defining variables only right?
>
> Top level is only meant for directories. There are directories for the different
> stuff, e.g. variables go into /env/nv/
>
> > should this point to an directory or a file?
>
> The config option is meant for use with external build systems, e.g. buildroot
> or PTXdist. For boards in-tree, you can add bbenv-y in the Makefile and call
>
>   // assuming directory is called defaultenv-myboard
>   defaultenv_append_directory(defaultenv_myboard);
>
> in the board code, see e.g. arch/arm/boards/embest-marsboard for an example.
>
> The reason for avoiding the config option for in-tree boards is that a single barebox
> configuration can build multiple boards in one go:
> extreme case: imx_v7_defconfig, which builds marsboard also builds more than 100 other images.
>
> The config option is global, but by explicitly calling defaultenv_append_directory,
> you can have board-specific environments.

will try this approach, thanks

> > i see this file which looks like the source of it
> >
> > ./defaultenv/defaultenv-2-base/boot/net
> >
> > I've put them there and they appear, but this is not board specific
>
> Ye, you can use this for debugging, but stuff upstreamed there must be generally
> applicable.
>
> > so if i later want to upstream one this is maybe not the right place.
>
> Boot scripts for publicly available evaluation kits are often not good candidates
> for upstreaming, because everybody using the EVKs has different thoughts on how to
> boot. The best way would be to use bootloader spec. It's one or more files you
> place at a known location that describe where your kernel and device tree are and
> what command line arguments to use and barebox can then automatically generate
> boot entries from all available bootloader spec files.
>
> See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
> of how to set this up. This is what I'd recommend instead of writing your own
> scripts.
>
> > ./defaultenv/defaultenv-2-menu/menu/10-boot-all/net
> >
> > seems to be a menu entry, but have not yet figured out how i can define one to add my scripts too
> >
> > have not found anything for it in the documentation yet
>
> The default boot menu is populated with the boot entries extracted from
> the contents of $global.boot.default.

currently only net is listed there

barebox at Rockchip RK3568 EVB:/ echo $global.boot.default
net

but in /env/boot i have my 2 new scripts

barebox at Rockchip RK3568 EVB:/ ls /env/boot
bnet          mmc-linux     net           tftp-linux

> boot -m will display that menu. It will also include all bootloader spec files.
> If that suffices, you won't need to create your own menu. If you want though,
> check the help text of the menutree command.

needed to add this option, and now it prints only "net" and "back",not my own scripts ;(

do i need my scripts to ./defaultenv/defaultenv-2-menu/menu/10-boot-all/ too?

> To boot into the boot menu, set nv autoboot=menu. "Detect bootsources" will
> list boot sources known to the barebox boot command.

is this stored anywhere so that is persistent on next reboot?

btw. how does saveenv exactly work (which part/filename/offset is used)? sasha told me that device will be enumerated to the current boot device, but where on this device is the env stored?

> See magicvar for a listing of all magic variables, or refer to the documentation.
>
> > btw. is there a way to use ls with wildcard without printing the path?
> >
> > ls /mnt/sd.1/extlinux/
> > Image_5.16            Image_5.16-next.gz    Image_5.16.gz
> >
> > ls /mnt/sd.1/extlinux/Image*
> > /mnt/sd.1/extlinux/Image_5.16
> > /mnt/sd.1/extlinux/Image_5.16-next.gz
> > /mnt/sd.1/extlinux/Image_5.16.gz
> >
> > i want to list only files matching Image*, but without path....number of columns does not matter
>
> Yes, cd /mnt/sd.1/extlinux
>
> Cheers,
> Ahmad

mhm, simple ;) can i store the active directory to restore it after script was run (if needed, e.g. on error booting)?

pwd shows current directory, but i cannot put it into an var...the bash approach does not work

barebox at Rockchip RK3568 EVB:/mnt/sd.1/extlinux pwd
/mnt/sd.1/extlinux
barebox at Rockchip RK3568 EVB:/mnt/sd.1/extlinux thisdir=$(pwd)
barebox at Rockchip RK3568 EVB:/mnt/sd.1/extlinux echo $thisdir
$(pwd)
barebox at Rockchip RK3568 EVB:/mnt/sd.1/extlinux

regards Frank


From sha at pengutronix.de  Thu Jan  6 00:08:38 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 6 Jan 2022 09:08:38 +0100
Subject: barebox extending boot-scripts
In-Reply-To: <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
Message-ID: <20220106080838.GV6003@pengutronix.de>

On Wed, Jan 05, 2022 at 07:13:22PM +0100, Frank Wunderlich wrote:
> Hi,
> 
> > Gesendet: Mittwoch, 05. Januar 2022 um 17:07 Uhr
> > Von: "Ahmad Fatoum" <a.fatoum at pengutronix.de>
> > An: "Frank Wunderlich" <frank-w at public-files.de>, barebox at lists.infradead.org
> > Betreff: Re: barebox extending boot-scripts
> >
> > Hi,
> >
> > On 05.01.22 16:20, Frank Wunderlich wrote:
> > > Hi,
> > >
> > > i'm making my first steps and try to add more boot-scripts (to land in /env/boot)
> > >
> > > i added a scipt in
> > >
> > > arch/arm/boards/rockchip-rk3568-evb/defaultenv/mmc-linux
> >
> > This should be defaultenv/boot/mmc-linux instead.
> >
> > > and set
> > >
> > > DEFAULT_ENVIRONMENT_PATH [=arch/arm/boards/rockchip-rk3568-evb/defaultenv]
> > >
> > > but if i boot the board /env/boot only contains the 2 default scripts
> > >
> > > barebox at Rockchip RK3568 EVB:/ ls /env/boot/
> > > bnet    net
> >
> > Try ls -R /env, you should see mmc-linux at top-level with your
> > current setup.
> >
> > > so maybe the dir/config-option i used is for defining variables only right?
> >
> > Top level is only meant for directories. There are directories for the different
> > stuff, e.g. variables go into /env/nv/
> >
> > > should this point to an directory or a file?
> >
> > The config option is meant for use with external build systems, e.g. buildroot
> > or PTXdist. For boards in-tree, you can add bbenv-y in the Makefile and call
> >
> >   // assuming directory is called defaultenv-myboard
> >   defaultenv_append_directory(defaultenv_myboard);
> >
> > in the board code, see e.g. arch/arm/boards/embest-marsboard for an example.
> >
> > The reason for avoiding the config option for in-tree boards is that a single barebox
> > configuration can build multiple boards in one go:
> > extreme case: imx_v7_defconfig, which builds marsboard also builds more than 100 other images.
> >
> > The config option is global, but by explicitly calling defaultenv_append_directory,
> > you can have board-specific environments.
> 
> will try this approach, thanks
> 
> > > i see this file which looks like the source of it
> > >
> > > ./defaultenv/defaultenv-2-base/boot/net
> > >
> > > I've put them there and they appear, but this is not board specific
> >
> > Ye, you can use this for debugging, but stuff upstreamed there must be generally
> > applicable.
> >
> > > so if i later want to upstream one this is maybe not the right place.
> >
> > Boot scripts for publicly available evaluation kits are often not good candidates
> > for upstreaming, because everybody using the EVKs has different thoughts on how to
> > boot. The best way would be to use bootloader spec. It's one or more files you
> > place at a known location that describe where your kernel and device tree are and
> > what command line arguments to use and barebox can then automatically generate
> > boot entries from all available bootloader spec files.
> >
> > See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
> > of how to set this up. This is what I'd recommend instead of writing your own
> > scripts.
> >
> > > ./defaultenv/defaultenv-2-menu/menu/10-boot-all/net
> > >
> > > seems to be a menu entry, but have not yet figured out how i can define one to add my scripts too
> > >
> > > have not found anything for it in the documentation yet
> >
> > The default boot menu is populated with the boot entries extracted from
> > the contents of $global.boot.default.
> 
> currently only net is listed there
> 
> barebox at Rockchip RK3568 EVB:/ echo $global.boot.default
> net
> 
> but in /env/boot i have my 2 new scripts
> 
> barebox at Rockchip RK3568 EVB:/ ls /env/boot
> bnet          mmc-linux     net           tftp-linux
> 
> > boot -m will display that menu. It will also include all bootloader spec files.
> > If that suffices, you won't need to create your own menu. If you want though,
> > check the help text of the menutree command.
> 
> needed to add this option, and now it prints only "net" and "back",not my own scripts ;(
> 
> do i need my scripts to ./defaultenv/defaultenv-2-menu/menu/10-boot-all/ too?
> 
> > To boot into the boot menu, set nv autoboot=menu. "Detect bootsources" will
> > list boot sources known to the barebox boot command.
> 
> is this stored anywhere so that is persistent on next reboot?

Variables beginning with 'nv.' are stored in the environment
automatically.

> 
> btw. how does saveenv exactly work (which part/filename/offset is
> used)? sasha told me that device will be enumerated to the current
> boot device, but where on this device is the env stored?

Normally it's described in the device tree:

	environment-emmc {
		compatible = "barebox,environment";
		device-path = &environment_emmc;
	};

The device-path property points to a partition on the eMMC:

&sdhci {
	...
	partitions {
		compatible = "fixed-partitions";

		environment_emmc: partition at 408000 {
			label = "barebox-environment";
			reg = <0x0 0x408000 0x0 0x8000>;
		};
	};
};


> 
> > See magicvar for a listing of all magic variables, or refer to the documentation.
> >
> > > btw. is there a way to use ls with wildcard without printing the path?
> > >
> > > ls /mnt/sd.1/extlinux/
> > > Image_5.16            Image_5.16-next.gz    Image_5.16.gz
> > >
> > > ls /mnt/sd.1/extlinux/Image*
> > > /mnt/sd.1/extlinux/Image_5.16
> > > /mnt/sd.1/extlinux/Image_5.16-next.gz
> > > /mnt/sd.1/extlinux/Image_5.16.gz
> > >
> > > i want to list only files matching Image*, but without path....number of columns does not matter

It works for example with:

for i in /mnt/sd.1/extlinux/Image*; do basename $i b; echo $b; done

But anyway, I'm with Ahmad here, you should rather look into bootloader
spec. The shell is nice to have, but it's even nicer to not have to use
it.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From konstantin.kletschke at inside-m2m.de  Thu Jan  6 01:59:42 2022
From: konstantin.kletschke at inside-m2m.de (Konstantin Kletschke)
Date: Thu, 6 Jan 2022 10:59:42 +0100
Subject: Howto implement bootchooser <-> rauc interaction
In-Reply-To: <c55ef6c5-c7ea-0663-47b9-141773985ba2@pengutronix.de>
References: <c4ae26b8698992ad37f201101795b1bb@inside-m2m.de>
 <53bdfd89-f363-5cec-4cb1-417c25c90eaf@pengutronix.de>
 <297b3425baa118783dccb6446900fbfa@inside-m2m.de>
 <cf1e6cf6a51dc13ec5275d94e18d23c1@inside-m2m.de>
 <ef8a2a82-91f5-5401-a564-a0ab20da4772@pengutronix.de>
 <YbyGBHs1YWVcgE5X@Hephaistos>
 <68358567-7665-bd5c-00fe-b410b4ec2518@pengutronix.de>
 <YbyczaAWK6juc0VO@Hephaistos> <YcMwk6mncQ8fSwTJ@Hephaistos>
 <c55ef6c5-c7ea-0663-47b9-141773985ba2@pengutronix.de>
Message-ID: <Yda9jr1/Od0ULKiZ@Hephaistos>

On Wed, Jan 05, 2022 at 06:50:17PM +0100, Ahmad Fatoum wrote:

> RAUC hardcodes bootstate, so that's what you need to use, unless you patch
> RAUC.

Dear Ahmad, thanks again for your technical advise.
My wall of text indeed was intended to ask for this detail, I realized.
If this "bootstate" id hardcoded (Yes, it is) I understand, what's going
on. Nice!

Kind Regards
Happy new year

Konstantin


-- 
INSIDE M2M GmbH
Konstantin Kletschke
Berenbosteler Stra?e 76 B
30823 Garbsen

Telefon: +49 (0) 5137 90950136
Mobil: +49 (0) 151 15256238
Fax: +49 (0) 5137 9095010

konstantin.kletschke at inside-m2m.de
http://www.inside-m2m.de 

Gesch?ftsf?hrung: Michael Emmert, Ingo Haase, Dr. Fred K?nemann, Derek Uhlig
HRB: 111204, AG Hannover



From frank-w at public-files.de  Thu Jan  6 04:41:39 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Thu, 6 Jan 2022 13:41:39 +0100
Subject: Aw: Re: Re: barebox extending boot-scripts
In-Reply-To: <20220106080838.GV6003@pengutronix.de>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
Message-ID: <trinity-7a53a76e-9836-482e-861e-31439f242e2d-1641472899713@3c-app-gmx-bs51>

Hi,
thanks for answer. tried to strip mail it a bit down ;)
> Gesendet: Donnerstag, 06. Januar 2022 um 09:08 Uhr
> Von: "Sascha Hauer" <sha at pengutronix.de>
> On Wed, Jan 05, 2022 at 07:13:22PM +0100, Frank Wunderlich wrote:

> > > > DEFAULT_ENVIRONMENT_PATH [=arch/arm/boards/rockchip-rk3568-evb/defaultenv]
> > > The config option is meant for use with external build systems, e.g. buildroot
> > > or PTXdist. For boards in-tree, you can add bbenv-y in the Makefile and call
> > >
> > >   // assuming directory is called defaultenv-myboard
> > >   defaultenv_append_directory(defaultenv_myboard);
> > >
> > > in the board code, see e.g. arch/arm/boards/embest-marsboard for an example.

if i understand it right i need to create a dir

arch/arm/boards/rockchip-rk3568-evb/defaultenv-rk3568

with dirs nv (variables) and boot (bootscripts)

and add
bbenv-y += defaultenv-rk3568
in
arch/arm/boards/rockchip-rk3568-evb/Makefile

> > > Boot scripts for publicly available evaluation kits are often not good candidates
> > > for upstreaming, because everybody using the EVKs has different thoughts on how to
> > > boot. The best way would be to use bootloader spec. It's one or more files you
> > > place at a known location that describe where your kernel and device tree are and
> > > what command line arguments to use and barebox can then automatically generate
> > > boot entries from all available bootloader spec files.

is extlinux (i used in uboot and conf-file is already present) supported here?

> > > See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
> > > of how to set this up. This is what I'd recommend instead of writing your own
> > > scripts.

i do not fully understand the bootloader spec in the pdf as config file seems to be

/mnt/mmc0.4/loader/entries/stm32mp157c-dk2.conf

and then
boot -d mmc0.4

is run...so the path (loader/entries) seems to be fixed and all files there will be processed (which order)?
how is root appended (/dev/mmcblkXpY|uuid|...) when linux-appendroot is set to true?

sorry for asking dumb questions but i want to understand how to do it right and not only doing anything ;)

> > > > ./defaultenv/defaultenv-2-menu/menu/10-boot-all/net
> > > >
> > > > seems to be a menu entry, but have not yet figured out how i can define one to add my scripts too
> > > >
> > > > have not found anything for it in the documentation yet
> > >
> > > The default boot menu is populated with the boot entries extracted from
> > > the contents of $global.boot.default.
> >
> > currently only net is listed there
> >
> > barebox at Rockchip RK3568 EVB:/ echo $global.boot.default
> > net
> >
> > but in /env/boot i have my 2 new scripts
> >
> > barebox at Rockchip RK3568 EVB:/ ls /env/boot
> > bnet          mmc-linux     net           tftp-linux
> >
> > > boot -m will display that menu. It will also include all bootloader spec files.
> > > If that suffices, you won't need to create your own menu. If you want though,
> > > check the help text of the menutree command.
> >
> > needed to add this option, and now it prints only "net" and "back",not my own scripts ;(
> >
> > do i need my scripts to ./defaultenv/defaultenv-2-menu/menu/10-boot-all/ too?

do i need to propagate my own scripts somewhere to be listed in the bootmenu?

in cmdline i had tried this:

global.boot.default="net mmc-linux tftp-linux"
boot -m

which works, but how can i set this variable at compile-time?

is the right way creating a file
defaultenv/defaultenv-2-base/nv/boot.default (or arch/arm/boards/rockchip-rk3568-evb/defaultenv-rk3568/nv/boot.default)
with the content i want? so it looks like in the pdf above ("global.variable s, these are initialized from the
correspoding non-volatile nv.variable s")

> > > To boot into the boot menu, set nv autoboot=menu. "Detect bootsources" will
> > > list boot sources known to the barebox boot command.
> >
> > is this stored anywhere so that is persistent on next reboot?
>
> Variables beginning with 'nv.' are stored in the environment
> automatically.
>
> >
> > btw. how does saveenv exactly work (which part/filename/offset is
> > used)? sasha told me that device will be enumerated to the current
> > boot device, but where on this device is the env stored?
>
> Normally it's described in the device tree:
>
> 	environment-emmc {
> 		compatible = "barebox,environment";
> 		device-path = &environment_emmc;
> 	};
>
> The device-path property points to a partition on the eMMC:
>
> &sdhci {
> 	...
> 	partitions {
> 		compatible = "fixed-partitions";
>
> 		environment_emmc: partition at 408000 {
> 			label = "barebox-environment";
> 			reg = <0x0 0x408000 0x0 0x8000>;
> 		};
> 	};
> };

thx, if i understand it right, then it's an offset/size defined in dts by reg-property. My board uses the same values which is iirc a bit above the 4M position (0x408000,4M=0x400000).
As i don't have a real partition there (first partition is at 8M), so i guess it is directly written (no file, like ENV_OFFSET in uboot). The 0x8000 should be the size (32kByte like ENV_SIZE), right?

> > > See magicvar for a listing of all magic variables, or refer to the documentation.
> > >
> > > > btw. is there a way to use ls with wildcard without printing the path?
>
> It works for example with:
>
> for i in /mnt/sd.1/extlinux/Image*; do basename $i b; echo $b; done

nice, that makes it a bit more usable like using numbers to choose

i=0;for f in /mnt/sd.1/extlinux/Image*; do basename $f b; echo "$i:$b";let i++; done

> But anyway, I'm with Ahmad here, you should rather look into bootloader
> spec. The shell is nice to have, but it's even nicer to not have to use
> it.

this is for testing multiple kernels with changing filenames (very dynamic process, e.g. using 1 kernel binary with multiple dtb) and to avoid adding a bootmenu entry everytime....this is not for end-user :)

and here scripting is imho the best way...this allows me to add extra params to cmdline too (like debug level,dumping offsets) without changing a distroboot config

for fixed kernels i have defined an extlinux.conf for uboot, but i'm unsure if barebox can use this file too. have not found anything about extlinux/syslinux in barebox yet.


From a.fatoum at pengutronix.de  Thu Jan  6 22:36:44 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri,  7 Jan 2022 07:36:44 +0100
Subject: [PATCH master] x86: <asm/io.h>: fix outl/outsl access size
Message-ID: <20220107063644.22595-1-a.fatoum@pengutronix.de>

outl so far behaved like outb, probably due to a copy-paste error when
it was first added. We have three users in-tree for outl:

* drivers/serial/serial_ns16550_pci.c
  only for handling a Quatech qurik, which probably no one ever needed

* drivers/serial/serial_ns16550.c
  For platform drivers with a 4 byte I/O port resource. Only possible
  user is x86 and that has a 1 byte I/O port resource. Thus no one
  used this either.

* drivers/watchdog/itco_wdt.c
  Here it indeed triggers a bug, although in my testing the WDAT
  was functional without.

Fix this up so new code doesn't have to track this down.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
Cc: Steffen Trumtrar <str at pengutronix.de>
---
 arch/x86/include/asm/io.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 0971727bc63d..23854128cb06 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -63,13 +63,13 @@ BUILDIO(l, , int)
 
 #define outb	outb
 #define outw	outw
-#define outl	outb
+#define outl	outl
 #define inb	inb
 #define inw	inw
 #define inl	inl
 #define outsb	outsb
 #define outsw	outsw
-#define outsl	outsb
+#define outsl	outsl
 #define insb	insb
 #define insw	insw
 #define insl	insl
-- 
2.20.1



From ahmad at a3f.at  Fri Jan  7 00:01:04 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri,  7 Jan 2022 09:01:04 +0100
Subject: [PATCH] drivers: virtio: import list of newer Virtio IDs
Message-ID: <20220107080104.135200-1-ahmad@a3f.at>

These are unused now.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 include/uapi/linux/virtio_ids.h | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index bc1c0621f5ed..80d76b75bccd 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,8 +51,34 @@
 #define VIRTIO_ID_PSTORE		22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU			23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM			24 /* virtio mem */
+#define VIRTIO_ID_SOUND			25 /* virtio sound */
 #define VIRTIO_ID_FS			26 /* virtio filesystem */
 #define VIRTIO_ID_PMEM			27 /* virtio pmem */
+#define VIRTIO_ID_RPMB			28 /* virtio rpmb */
 #define VIRTIO_ID_MAC80211_HWSIM	29 /* virtio mac80211-hwsim */
+#define VIRTIO_ID_VIDEO_ENCODER		30 /* virtio video encoder */
+#define VIRTIO_ID_VIDEO_DECODER		31 /* virtio video decoder */
+#define VIRTIO_ID_SCMI			32 /* virtio SCMI */
+#define VIRTIO_ID_NITRO_SEC_MOD		33 /* virtio nitro secure module*/
+#define VIRTIO_ID_I2C_ADAPTER		34 /* virtio i2c adapter */
+#define VIRTIO_ID_WATCHDOG		35 /* virtio watchdog */
+#define VIRTIO_ID_CAN			36 /* virtio can */
+#define VIRTIO_ID_DMABUF		37 /* virtio dmabuf */
+#define VIRTIO_ID_PARAM_SERV		38 /* virtio parameter server */
+#define VIRTIO_ID_AUDIO_POLICY		39 /* virtio audio policy */
+#define VIRTIO_ID_BT			40 /* virtio bluetooth */
+#define VIRTIO_ID_GPIO			41 /* virtio gpio */
+
+/*
+ * Virtio Transitional IDs
+ */
+
+#define VIRTIO_TRANS_ID_NET		1000 /* transitional virtio net */
+#define VIRTIO_TRANS_ID_BLOCK		1001 /* transitional virtio block */
+#define VIRTIO_TRANS_ID_BALLOON		1002 /* transitional virtio balloon */
+#define VIRTIO_TRANS_ID_CONSOLE		1003 /* transitional virtio console */
+#define VIRTIO_TRANS_ID_SCSI		1004 /* transitional virtio SCSI */
+#define VIRTIO_TRANS_ID_RNG		1005 /* transitional virtio rng */
+#define VIRTIO_TRANS_ID_9P		1009 /* transitional virtio 9p console */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
-- 
2.33.0



From enguerrand.de-ribaucourt at savoirfairelinux.com  Fri Jan  7 01:27:29 2022
From: enguerrand.de-ribaucourt at savoirfairelinux.com (Enguerrand de Ribaucourt)
Date: Fri,  7 Jan 2022 10:27:29 +0100
Subject: [PATCH] commands: hashsum: Fix endif typos
Message-ID: <20220107092729.17929-1-enguerrand.de-ribaucourt@savoirfairelinux.com>

Fix the comments in endif to correspond to the symbol of their
ifdef.

Signed-off-by: Enguerrand de Ribaucourt <enguerrand.de-ribaucourt at savoirfairelinux.com>
---
 commands/hashsum.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/commands/hashsum.c b/commands/hashsum.c
index bfacee0b9..308faa172 100644
--- a/commands/hashsum.c
+++ b/commands/hashsum.c
@@ -74,7 +74,7 @@ BAREBOX_CMD_START(md5sum)
 	BAREBOX_CMD_HELP(cmd_md5sum_help)
 BAREBOX_CMD_END
 
-#endif /* CMD_CMD_MD5SUM */
+#endif /* CONFIG_CMD_MD5SUM */
 
 #ifdef CONFIG_CMD_SHA1SUM
 
@@ -95,7 +95,7 @@ BAREBOX_CMD_START(sha1sum)
 	BAREBOX_CMD_HELP(cmd_sha1sum_help)
 BAREBOX_CMD_END
 
-#endif /* CMD_CMD_SHA1SUM */
+#endif /* CONFIG_CMD_SHA1SUM */
 
 #ifdef CONFIG_CMD_SHA224SUM
 
@@ -116,7 +116,7 @@ BAREBOX_CMD_START(sha224sum)
 	BAREBOX_CMD_HELP(cmd_sha224sum_help)
 BAREBOX_CMD_END
 
-#endif /* CMD_CMD_SHA224SUM */
+#endif /* CONFIG_CMD_SHA224SUM */
 
 #ifdef CONFIG_CMD_SHA256SUM
 
@@ -137,7 +137,7 @@ BAREBOX_CMD_START(sha256sum)
 	BAREBOX_CMD_HELP(cmd_sha256sum_help)
 BAREBOX_CMD_END
 
-#endif /* CMD_CMD_SHA256SUM */
+#endif /* CONFIG_CMD_SHA256SUM */
 
 #ifdef CONFIG_CMD_SHA384SUM
 
@@ -158,7 +158,7 @@ BAREBOX_CMD_START(sha384sum)
 	BAREBOX_CMD_HELP(cmd_sha384sum_help)
 BAREBOX_CMD_END
 
-#endif /* CMD_CMD_SHA384SUM */
+#endif /* CONFIG_CMD_SHA384SUM */
 
 #ifdef CONFIG_CMD_SHA512SUM
 
@@ -179,4 +179,4 @@ BAREBOX_CMD_START(sha512sum)
 	BAREBOX_CMD_HELP(cmd_sha512sum_help)
 BAREBOX_CMD_END
 
-#endif /* CMD_CMD_SHA512SUM */
+#endif /* CONFIG_CMD_SHA512SUM */
-- 
2.25.1



From sha at pengutronix.de  Fri Jan  7 05:07:51 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 7 Jan 2022 14:07:51 +0100
Subject: barebox extending boot-scripts
In-Reply-To: <trinity-7a53a76e-9836-482e-861e-31439f242e2d-1641472899713@3c-app-gmx-bs51>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
 <trinity-7a53a76e-9836-482e-861e-31439f242e2d-1641472899713@3c-app-gmx-bs51>
Message-ID: <20220107130751.GW6003@pengutronix.de>

On Thu, Jan 06, 2022 at 01:41:39PM +0100, Frank Wunderlich wrote:
> Hi,
> thanks for answer. tried to strip mail it a bit down ;)
> > Gesendet: Donnerstag, 06. Januar 2022 um 09:08 Uhr
> > Von: "Sascha Hauer" <sha at pengutronix.de>
> > On Wed, Jan 05, 2022 at 07:13:22PM +0100, Frank Wunderlich wrote:
> 
> > > > > DEFAULT_ENVIRONMENT_PATH [=arch/arm/boards/rockchip-rk3568-evb/defaultenv]
> > > > The config option is meant for use with external build systems, e.g. buildroot
> > > > or PTXdist. For boards in-tree, you can add bbenv-y in the Makefile and call
> > > >
> > > >   // assuming directory is called defaultenv-myboard
> > > >   defaultenv_append_directory(defaultenv_myboard);
> > > >
> > > > in the board code, see e.g. arch/arm/boards/embest-marsboard for an example.
> 
> if i understand it right i need to create a dir
> 
> arch/arm/boards/rockchip-rk3568-evb/defaultenv-rk3568

Yes.

> 
> with dirs nv (variables) and boot (bootscripts)
> 
> and add
> bbenv-y += defaultenv-rk3568
> in
> arch/arm/boards/rockchip-rk3568-evb/Makefile

Yes. Furthermore you have to add to the board code:

	defaultenv_append_directory(defaultenv_rk3568);

> 
> > > > Boot scripts for publicly available evaluation kits are often not good candidates
> > > > for upstreaming, because everybody using the EVKs has different thoughts on how to
> > > > boot. The best way would be to use bootloader spec. It's one or more files you
> > > > place at a known location that describe where your kernel and device tree are and
> > > > what command line arguments to use and barebox can then automatically generate
> > > > boot entries from all available bootloader spec files.
> 
> is extlinux (i used in uboot and conf-file is already present) supported here?
> 
> > > > See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
> > > > of how to set this up. This is what I'd recommend instead of writing your own
> > > > scripts.
> 
> i do not fully understand the bootloader spec in the pdf as config file seems to be
> 
> /mnt/mmc0.4/loader/entries/stm32mp157c-dk2.conf
> 
> and then
> boot -d mmc0.4
> 
> is run...so the path (loader/entries) seems to be fixed and all files there will be processed (which order)?

Yes. No particular order, I guess it would be the order it is on the
filesystem.

> how is root appended (/dev/mmcblkXpY|uuid|...) when linux-appendroot is set to true?

When root is appended it is assumed to be the same fs that also has the
bootloader spec file, so the rootfs also has the entry and the kernel.

> > > needed to add this option, and now it prints only "net" and "back",not my own scripts ;(
> > >
> > > do i need my scripts to ./defaultenv/defaultenv-2-menu/menu/10-boot-all/ too?
> 
> do i need to propagate my own scripts somewhere to be listed in the bootmenu?
> 
> in cmdline i had tried this:
> 
> global.boot.default="net mmc-linux tftp-linux"
> boot -m
> 
> which works, but how can i set this variable at compile-time?

By creating the file defaultenv/defaultenv-2-base/nv/boot.default with
the content "net mmc-linux tftp-linux". Alternatively you can also
create your own board specific env overlay like discussed above using
the bbenv-y approach.

> 
> is the right way creating a file
> defaultenv/defaultenv-2-base/nv/boot.default (or arch/arm/boards/rockchip-rk3568-evb/defaultenv-rk3568/nv/boot.default)
> with the content i want? so it looks like in the pdf above ("global.variable s, these are initialized from the
> correspoding non-volatile nv.variable s")

Yes.

> > &sdhci {
> > 	...
> > 	partitions {
> > 		compatible = "fixed-partitions";
> >
> > 		environment_emmc: partition at 408000 {
> > 			label = "barebox-environment";
> > 			reg = <0x0 0x408000 0x0 0x8000>;
> > 		};
> > 	};
> > };
> 
> thx, if i understand it right, then it's an offset/size defined in dts by reg-property. My board uses the same values which is iirc a bit above the 4M position (0x408000,4M=0x400000).

Yes. It's the fixed partition binding normally used for raw NOR/NAND
flashes.

> As i don't have a real partition there (first partition is at 8M), so i guess it is directly written (no file, like ENV_OFFSET in uboot). The 0x8000 should be the size (32kByte like ENV_SIZE), right?

Right.

> 
> > > > See magicvar for a listing of all magic variables, or refer to the documentation.
> > > >
> > > > > btw. is there a way to use ls with wildcard without printing the path?
> >
> > It works for example with:
> >
> > for i in /mnt/sd.1/extlinux/Image*; do basename $i b; echo $b; done
> 
> nice, that makes it a bit more usable like using numbers to choose
> 
> i=0;for f in /mnt/sd.1/extlinux/Image*; do basename $f b; echo "$i:$b";let i++; done
> 
> > But anyway, I'm with Ahmad here, you should rather look into bootloader
> > spec. The shell is nice to have, but it's even nicer to not have to use
> > it.
> 
> this is for testing multiple kernels with changing filenames (very
> dynamic process, e.g. using 1 kernel binary with multiple dtb) and to
> avoid adding a bootmenu entry everytime....this is not for end-user :)

In that case you could also use bootm directly.

> 
> and here scripting is imho the best way...this allows me to add extra
> params to cmdline too (like debug level,dumping offsets) without
> changing a distroboot config

Not sure if you know already, but barebox concatenates all variables in
the "global.linux.bootargs." namespace to the kernel command line, so
you can easily add or remove a variable to add/remove kernel options
without affecting unrelated options.

> 
> for fixed kernels i have defined an extlinux.conf for uboot, but i'm
> unsure if barebox can use this file too. have not found anything about
> extlinux/syslinux in barebox yet.

No, not yet.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.trumtrar at pengutronix.de  Fri Jan  7 05:42:18 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Fri,  7 Jan 2022 14:42:18 +0100
Subject: [PATCH 1/2] acpi.h: add defines for adr_space and gas
Message-ID: <20220107134219.1031552-1-s.trumtrar@pengutronix.de>

>From linux v5.15-rc1.

Signed-off-by: Steffen Trumtrar <str at pengutronix.de>
---
 include/acpi.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/include/acpi.h b/include/acpi.h
index b8e73b35df..04f722da23 100644
--- a/include/acpi.h
+++ b/include/acpi.h
@@ -10,6 +10,78 @@
 #include <linux/types.h>
 #include <driver.h>
 
+/* Names within the namespace are 4 bytes long */
+
+#define ACPI_NAMESEG_SIZE               4	/* Fixed by ACPI spec */
+#define ACPI_PATH_SEGMENT_LENGTH        5	/* 4 chars for name + 1 char for separator */
+#define ACPI_PATH_SEPARATOR             '.'
+
+/* Sizes for ACPI table headers */
+
+#define ACPI_OEM_ID_SIZE                6
+#define ACPI_OEM_TABLE_ID_SIZE          8
+
+/*
+ * Algorithm to obtain access bit or byte width.
+ * Can be used with access_width of struct acpi_generic_address and access_size of
+ * struct acpi_resource_generic_register.
+ */
+#define ACPI_ACCESS_BIT_WIDTH(size)     (1 << ((size) + 2))
+#define ACPI_ACCESS_BYTE_WIDTH(size)    (1 << ((size) - 1))
+
+/* Address Space (Operation Region) Types */
+
+typedef u8 acpi_adr_space_type;
+#define ACPI_ADR_SPACE_SYSTEM_MEMORY    (acpi_adr_space_type) 0
+#define ACPI_ADR_SPACE_SYSTEM_IO        (acpi_adr_space_type) 1
+#define ACPI_ADR_SPACE_PCI_CONFIG       (acpi_adr_space_type) 2
+#define ACPI_ADR_SPACE_EC               (acpi_adr_space_type) 3
+#define ACPI_ADR_SPACE_SMBUS            (acpi_adr_space_type) 4
+#define ACPI_ADR_SPACE_CMOS             (acpi_adr_space_type) 5
+#define ACPI_ADR_SPACE_PCI_BAR_TARGET   (acpi_adr_space_type) 6
+#define ACPI_ADR_SPACE_IPMI             (acpi_adr_space_type) 7
+#define ACPI_ADR_SPACE_GPIO             (acpi_adr_space_type) 8
+#define ACPI_ADR_SPACE_GSBUS            (acpi_adr_space_type) 9
+#define ACPI_ADR_SPACE_PLATFORM_COMM    (acpi_adr_space_type) 10
+#define ACPI_ADR_SPACE_PLATFORM_RT      (acpi_adr_space_type) 11
+
+/*******************************************************************************
+ *
+ * Master ACPI Table Header. This common header is used by all ACPI tables
+ * except the RSDP and FACS.
+ *
+ ******************************************************************************/
+
+struct __packed acpi_table_header {
+	char signature[ACPI_NAMESEG_SIZE];	/* ASCII table signature */
+	u32 length;		/* Length of table in bytes, including this header */
+	u8 revision;		/* ACPI Specification minor version number */
+	u8 checksum;		/* To make sum of entire table == 0 */
+	char oem_id[ACPI_OEM_ID_SIZE];	/* ASCII OEM identification */
+	char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];	/* ASCII OEM table identification */
+	u32 oem_revision;	/* OEM revision number */
+	char asl_compiler_id[ACPI_NAMESEG_SIZE];	/* ASCII ASL compiler vendor ID */
+	u32 asl_compiler_revision;	/* ASL compiler version */
+};
+
+/*******************************************************************************
+ *
+ * GAS - Generic Address Structure (ACPI 2.0+)
+ *
+ * Note: Since this structure is used in the ACPI tables, it is byte aligned.
+ * If misaligned access is not supported by the hardware, accesses to the
+ * 64-bit Address field must be performed with care.
+ *
+ ******************************************************************************/
+
+struct __packed acpi_generic_address {
+	u8 space_id;		/* Address space where struct or register exists */
+	u8 bit_width;		/* Size in bits of given register */
+	u8 bit_offset;		/* Bit offset within the register */
+	u8 access_width;	/* Minimum Access size (ACPI 3.0) */
+	u64 address;		/* 64-bit address of struct or register */
+};
+
 typedef char acpi_sig_t[4];
 
 struct __packed acpi_rsdp { /* root system description pointer */
-- 
2.30.2



From s.trumtrar at pengutronix.de  Fri Jan  7 05:42:19 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Fri,  7 Jan 2022 14:42:19 +0100
Subject: [PATCH 2/2] watchdog: add support for wdat_wdt
In-Reply-To: <20220107134219.1031552-1-s.trumtrar@pengutronix.de>
References: <20220107134219.1031552-1-s.trumtrar@pengutronix.de>
Message-ID: <20220107134219.1031552-2-s.trumtrar@pengutronix.de>

Add support for systems with the ACPI Watchdog Action Table (wdat).
Based on Linux v5.15-rc1 drivers/watchdog/wdat_wdt.c

Signed-off-by: Steffen Trumtrar <str at pengutronix.de>
---
 This patch depends on
  x86: <asm/io.h>: fix outl/outsl access size
  https://lore.barebox.org/20220107063644.22595-1-a.fatoum at pengutronix.de

 drivers/watchdog/Kconfig    |  10 +
 drivers/watchdog/Makefile   |   1 +
 drivers/watchdog/wdat_wdt.c | 496 ++++++++++++++++++++++++++++++++++++
 3 files changed, 507 insertions(+)
 create mode 100644 drivers/watchdog/wdat_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index f91a2571d9..68dbded3ec 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -149,4 +149,14 @@ config STARFIVE_WDT
 	  If you say yes here you get support for the watchdog device
 	  on StarFive SoCs.
 
+config WDAT_WDT
+	bool "ACPI Watchdog Action Table (WDAT)"
+	depends on X86
+	depends on ACPI
+	help
+	  This driver adds support for systems with ACPI Watchdog Action
+	  Table (WDAT) table. Servers typically have this but it can be
+	  found on some desktop machines as well. This driver will take
+	  over the native iTCO watchdog driver found on many Intel CPUs.
+
 endif
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 54a833447c..aaebc459e6 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
 obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
 obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
 obj-$(CONFIG_STARFIVE_WDT) += starfive_wdt.o
+obj-$(CONFIG_WDAT_WDT) += wdat_wdt.o
diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c
new file mode 100644
index 0000000000..39e8cc4a3d
--- /dev/null
+++ b/drivers/watchdog/wdat_wdt.c
@@ -0,0 +1,496 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ACPI Hardware Watchdog (WDAT) driver.
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg at linux.intel.com>
+ */
+#include <common.h>
+#include <acpi.h>
+#include <errno.h>
+#include <init.h>
+#include <io.h>
+#include <malloc.h>
+#include <of.h>
+#include <watchdog.h>
+
+enum acpi_wdat_actions {
+	ACPI_WDAT_RESET = 1,
+	ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4,
+	ACPI_WDAT_GET_COUNTDOWN = 5,
+	ACPI_WDAT_SET_COUNTDOWN = 6,
+	ACPI_WDAT_GET_RUNNING_STATE = 8,
+	ACPI_WDAT_SET_RUNNING_STATE = 9,
+	ACPI_WDAT_GET_STOPPED_STATE = 10,
+	ACPI_WDAT_SET_STOPPED_STATE = 11,
+	ACPI_WDAT_GET_REBOOT = 16,
+	ACPI_WDAT_SET_REBOOT = 17,
+	ACPI_WDAT_GET_SHUTDOWN = 18,
+	ACPI_WDAT_SET_SHUTDOWN = 19,
+	ACPI_WDAT_GET_STATUS = 32,
+	ACPI_WDAT_SET_STATUS = 33,
+	ACPI_WDAT_ACTION_RESERVED = 34	/* 34 and greater are reserved */
+};
+
+enum acpi_wdat_instructions {
+	ACPI_WDAT_READ_VALUE = 0,
+	ACPI_WDAT_READ_COUNTDOWN = 1,
+	ACPI_WDAT_WRITE_VALUE = 2,
+	ACPI_WDAT_WRITE_COUNTDOWN = 3,
+	ACPI_WDAT_INSTRUCTION_RESERVED = 4,	/* 4 and greater are reserved */
+	ACPI_WDAT_PRESERVE_REGISTER = 0x80	/* Except for this value */
+};
+
+#define MAX_WDAT_ACTIONS ACPI_WDAT_ACTION_RESERVED
+
+#define WDAT_DEFAULT_TIMEOUT	30
+
+/* WDAT Instruction Entries (actions) */
+
+struct __packed acpi_wdat_entry {
+	u8 				action;
+	u8 				instruction;
+	u16 				reserved;
+	struct acpi_generic_address 	register_region;
+	u32 				value;		/* Value used with Read/Write register */
+	u32 				mask;		/* Bitmask required for this register instruction */
+};
+
+/**
+ * struct wdat_instruction - Single ACPI WDAT instruction
+ * @entry: Copy of the ACPI table instruction
+ * @reg: Register the instruction is accessing
+ * @node: Next instruction in action sequence
+ */
+struct wdat_instruction {
+	struct acpi_wdat_entry entry;
+	void __iomem *reg;
+	struct list_head node;
+};
+
+/**
+ * struct wdat_wdt - ACPI WDAT watchdog device
+ * @dev: Parent platform device
+ * @wdd: Watchdog core device
+ * @period: How long is one watchdog period in ms
+ * @stopped_in_sleep: Is this watchdog stopped by the firmware in S1-S5
+ * @stopped: Was the watchdog stopped by the driver in suspend
+ * @instructions: An array of instruction lists indexed by an action number from
+ *                the WDAT table. There can be %NULL entries for not implemented
+ *                actions.
+ */
+struct wdat_wdt {
+	struct watchdog		wdd;
+	unsigned int		period;
+	bool 			stopped_in_sleep;
+	bool			stopped;
+	struct list_head	*instructions[MAX_WDAT_ACTIONS];
+};
+
+struct __packed acpi_table_wdat {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32			 header_length;	/* Watchdog Header Length */
+	u16 			 pci_segment;	/* PCI Segment number */
+	u8 			 pci_bus;	/* PCI Bus number */
+	u8 			 pci_device;	/* PCI Device number */
+	u8 			 pci_function;	/* PCI Function number */
+	u8 			 reserved[3];
+	u32 			 timer_period;	/* Period of one timer count (msec) */
+	u32 			 max_count;	/* Maximum counter value supported */
+	u32 			 min_count;	/* Minimum counter value */
+	u8 			 flags;
+	u8 			 reserved2[3];
+	u32 			 nr_entries;	/* Number of watchdog entries that follow */
+	struct acpi_wdat_entry   entries[];
+};
+
+#define ACPI_WDAT_ENABLED           (1)
+#define ACPI_WDAT_STOPPED           0x80
+
+#define IO_COND(instr, is_pio, is_mmio) do {					\
+	const struct acpi_generic_address *gas = &instr->entry.register_region; \
+	unsigned long port = (unsigned long __force)instr->reg;			\
+	if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {			\
+		is_mmio;							\
+	} else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {			\
+		is_pio;								\
+	}									\
+} while (0)
+
+static unsigned int read8(const struct wdat_instruction *instr)
+{
+	IO_COND(instr, return inb(port), return readb(instr->reg));
+	return 0xff;
+}
+
+static unsigned int read16(const struct wdat_instruction *instr)
+{
+	IO_COND(instr, return inw(port), return readw(instr->reg));
+	return 0xffff;
+}
+
+static unsigned int read32(const struct wdat_instruction *instr)
+{
+	IO_COND(instr, return inl(port), return readl(instr->reg));
+	return 0xffffffff;
+}
+
+static void write8(u8 val, const struct wdat_instruction *instr)
+{
+	IO_COND(instr, outb(val,port), writeb(val, instr->reg));
+}
+
+static void write16(u16 val, const struct wdat_instruction *instr)
+{
+	IO_COND(instr, outw(val,port), writew(val, instr->reg));
+}
+
+static void write32(u32 val, const struct wdat_instruction *instr)
+{
+	IO_COND(instr, outl(val,port), writel(val, instr->reg));
+}
+
+static int wdat_wdt_read(struct wdat_wdt *wdat,
+		       const struct wdat_instruction *instr, u32 *value)
+{
+	const struct acpi_generic_address *gas = &instr->entry.register_region;
+
+	switch (gas->access_width) {
+	case 1:
+		*value = read8(instr);
+		break;
+	case 2:
+		*value = read16(instr);
+		break;
+	case 3:
+		*value = read32(instr);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(wdat->wdd.hwdev, "Read %#x from 0x%08llx\n", *value,
+		gas->address);
+
+	return 0;
+}
+
+static int wdat_wdt_write(struct wdat_wdt *wdat,
+			const struct wdat_instruction *instr, u32 value)
+{
+	const struct acpi_generic_address *gas = &instr->entry.register_region;
+
+	switch (gas->access_width) {
+	case 1:
+		write8((u8)value, instr);
+		break;
+	case 2:
+		write16((u16)value, instr);
+		break;
+	case 3:
+		write32(value, instr);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(wdat->wdd.hwdev, "Wrote %#x to 0x%08llx\n", value,
+		gas->address);
+
+	return 0;
+}
+
+static int wdat_wdt_run_action(struct wdat_wdt *wdat, unsigned int action,
+			       u32 param, u32 *retval)
+{
+	struct wdat_instruction *instr;
+
+	if (action >= ARRAY_SIZE(wdat->instructions)) {
+		dev_dbg(wdat->wdd.hwdev, "Invalid action %#x\n", action);
+		return -EINVAL;
+	}
+
+	if (!wdat->instructions[action]) {
+		dev_dbg(wdat->wdd.hwdev, "Unsupported action %#x\n", action);
+		return -EOPNOTSUPP;
+	}
+
+	dev_dbg(wdat->wdd.hwdev, "Running action %#x\n", action);
+
+	/* Run each instruction sequentially */
+	list_for_each_entry(instr, wdat->instructions[action], node) {
+		const struct acpi_wdat_entry *entry = &instr->entry;
+		const struct acpi_generic_address *gas;
+		u32 flags, value, mask, x, y;
+		bool preserve;
+		int ret;
+
+		gas = &entry->register_region;
+
+		preserve = entry->instruction & ACPI_WDAT_PRESERVE_REGISTER;
+		flags = entry->instruction & ~ACPI_WDAT_PRESERVE_REGISTER;
+		value = entry->value;
+		mask = entry->mask;
+
+		switch (flags) {
+		case ACPI_WDAT_READ_VALUE:
+			ret = wdat_wdt_read(wdat, instr, &x);
+			if (ret)
+				return ret;
+			x >>= gas->bit_offset;
+			x &= mask;
+			if (retval)
+				*retval = x == value;
+			break;
+
+		case ACPI_WDAT_READ_COUNTDOWN:
+			ret = wdat_wdt_read(wdat, instr, &x);
+			if (ret)
+				return ret;
+			x >>= gas->bit_offset;
+			x &= mask;
+			if (retval)
+				*retval = x;
+			break;
+
+		case ACPI_WDAT_WRITE_VALUE:
+			x = value & mask;
+			x <<= gas->bit_offset;
+			if (preserve) {
+				ret = wdat_wdt_read(wdat, instr, &y);
+				if (ret)
+					return ret;
+				y = y & ~(mask << gas->bit_offset);
+				x |= y;
+			}
+			ret = wdat_wdt_write(wdat, instr, x);
+			if (ret)
+				return ret;
+			break;
+
+		case ACPI_WDAT_WRITE_COUNTDOWN:
+			x = param;
+			x &= mask;
+			x <<= gas->bit_offset;
+			if (preserve) {
+				ret = wdat_wdt_read(wdat, instr, &y);
+				if (ret)
+					return ret;
+				y = y & ~(mask << gas->bit_offset);
+				x |= y;
+			}
+			ret = wdat_wdt_write(wdat, instr, x);
+			if (ret)
+				return ret;
+			break;
+
+		default:
+			dev_err(wdat->wdd.hwdev, "Unknown instruction: %u\n",
+				flags);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void wdat_wdt_boot_status(struct wdat_wdt *wdat)
+{
+	u32 boot_status = 0;
+	int ret;
+
+	ret = wdat_wdt_run_action(wdat, ACPI_WDAT_GET_STATUS, 0, &boot_status);
+	if (ret && ret != -EOPNOTSUPP) {
+		dev_err(wdat->wdd.hwdev, "Failed to read boot status\n");
+		return;
+	}
+
+	/* Clear the boot status in case BIOS did not do it */
+	ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_STATUS, 0, NULL);
+	if (ret && ret != -EOPNOTSUPP)
+		dev_err(wdat->wdd.hwdev, "Failed to clear boot status\n");
+}
+
+static int wdat_wdt_start(struct watchdog *wdd)
+{
+	struct wdat_wdt *wdat = container_of(wdd, struct wdat_wdt, wdd);
+
+	return wdat_wdt_run_action(wdat, ACPI_WDAT_SET_RUNNING_STATE, 0, NULL);
+}
+
+static int wdat_wdt_stop(struct watchdog *wdd)
+{
+	struct wdat_wdt *wdat = container_of(wdd, struct wdat_wdt, wdd);
+
+	return wdat_wdt_run_action(wdat, ACPI_WDAT_SET_STOPPED_STATE, 0, NULL);
+}
+
+static void wdat_wdt_set_running(struct wdat_wdt *wdat)
+{
+	u32 running = 0;
+	int ret;
+
+	ret = wdat_wdt_run_action(wdat, ACPI_WDAT_GET_RUNNING_STATE, 0,
+				  &running);
+	if (ret && ret != -EOPNOTSUPP)
+		dev_err(wdat->wdd.hwdev, "Failed to read running state\n");
+
+	dev_dbg(wdat->wdd.hwdev, "Running state: %d\n", running);
+
+	wdat->wdd.running = running ? WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING;
+}
+
+static int wdat_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout)
+{
+	struct wdat_wdt *wdat = container_of(wdd, struct wdat_wdt, wdd);
+	unsigned int periods;
+	int ret;
+
+	if (timeout == 0)
+		return wdat_wdt_stop(wdd);
+
+	periods = timeout * 1000 / wdat->period;
+	ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_COUNTDOWN, periods, NULL);
+	if (ret)
+		return ret;
+
+	if (wdat->wdd.running == WDOG_HW_NOT_RUNNING) {
+		wdat_wdt_start(wdd);
+		wdat->wdd.running = WDOG_HW_RUNNING;
+	}
+
+	return wdat_wdt_run_action(wdat, ACPI_WDAT_RESET, 0, NULL);
+}
+
+static int wdat_wdt_enable_reboot(struct wdat_wdt *wdat)
+{
+	int ret;
+
+	/*
+	 * WDAT specification says that the watchdog is required to reboot
+	 * the system when it fires. However, it also states that it is
+	 * recommeded to make it configurable through hardware register. We
+	 * enable reboot now if it is configrable, just in case.
+	 */
+	ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_REBOOT, 0, NULL);
+	if (ret && ret != -EOPNOTSUPP) {
+		dev_err(wdat->wdd.hwdev,
+			"Failed to enable reboot when watchdog triggers\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wdat_wdt_probe(struct device_d *const dev)
+{
+	const struct acpi_wdat_entry *entries;
+	struct acpi_table_wdat *tbl;
+	struct wdat_wdt *wdat;
+	int i, ret;
+
+	dev_dbg(dev, "driver initializing...\n");
+
+	tbl = (struct acpi_table_wdat __force *)dev_request_mem_region_by_name(dev, "SDT");
+	if (IS_ERR(tbl)) {
+		dev_err(dev, "no SDT resource available: %pe\n", tbl);
+		return PTR_ERR(tbl);
+	}
+
+	dev_dbg(dev, "SDT is at 0x%p\n", tbl);
+
+	wdat = xzalloc(sizeof(*wdat));
+
+	/* WDAT specification wants to have >= 1ms period */
+	if (tbl->timer_period < 1) {
+		dev_dbg(dev, "timer_period is less than 1: %d\n", tbl->timer_period);
+		return -EINVAL;
+	}
+	if (tbl->min_count > tbl->max_count) {
+		dev_dbg(dev, "min_count must be greater than max_count\n");
+		return -EINVAL;
+	}
+
+	wdat->period = tbl->timer_period;
+	wdat->stopped_in_sleep = tbl->flags & ACPI_WDAT_STOPPED;
+	wdat->wdd.set_timeout = wdat_wdt_set_timeout;
+	wdat->wdd.hwdev = dev;
+	wdat->wdd.timeout_max = U32_MAX;
+
+	entries = tbl->entries;
+
+	for (i = 0; i < tbl->nr_entries; i++) {
+		const struct acpi_generic_address *gas;
+		struct wdat_instruction *instr;
+		struct list_head *instructions;
+		struct resource *res;
+		unsigned int action;
+		struct resource r;
+
+		action = entries[i].action;
+		if (action >= MAX_WDAT_ACTIONS) {
+			dev_dbg(dev, "Skipping unknown action: %u\n", action);
+			continue;
+		}
+
+		instr = xzalloc(sizeof(*instr));
+
+		INIT_LIST_HEAD(&instr->node);
+		instr->entry = entries[i];
+
+		gas = &entries[i].register_region;
+
+		memset(&r, 0, sizeof(r));
+		r.start = gas->address;
+		r.end = r.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;
+		if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+			res = request_iomem_region(dev_name(dev), r.start, r.end);
+		} else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+			res = request_ioport_region(dev_name(dev), r.start, r.end);
+		} else {
+			dev_dbg(dev, "Unsupported address space: %d\n",
+				gas->space_id);
+			continue;
+		}
+
+		/*
+		 * Some entries have the same gas->address.
+		 * We want the action but can't request the region multiple times.
+		 */
+		if (IS_ERR(res) && (PTR_ERR(res) != -EBUSY))
+			return PTR_ERR(res);
+
+		instr->reg = IOMEM(r.start);
+
+		instructions = wdat->instructions[action];
+		if (!instructions) {
+			instructions = xzalloc(sizeof(*instructions));
+			if (!instructions)
+				return -ENOMEM;
+
+			INIT_LIST_HEAD(instructions);
+			wdat->instructions[action] = instructions;
+		}
+
+		list_add_tail(&instr->node, instructions);
+	}
+
+	wdat_wdt_boot_status(wdat);
+	wdat_wdt_set_running(wdat);
+
+	ret = wdat_wdt_enable_reboot(wdat);
+	if (ret)
+		return ret;
+
+	return watchdog_register(&wdat->wdd);
+}
+
+
+static struct acpi_driver wdat_wdt_driver = {
+	.signature = "WDAT",
+	.driver = {
+		.name = "wdat-wdt",
+		.probe = wdat_wdt_probe,
+	}
+};
+device_acpi_driver(wdat_wdt_driver);
-- 
2.30.2



From frank-w at public-files.de  Fri Jan  7 08:42:22 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Fri, 7 Jan 2022 17:42:22 +0100
Subject: Aw: Re: Re: Re: barebox extending boot-scripts
In-Reply-To: <20220107130751.GW6003@pengutronix.de>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
 <trinity-7a53a76e-9836-482e-861e-31439f242e2d-1641472899713@3c-app-gmx-bs51>
 <20220107130751.GW6003@pengutronix.de>
Message-ID: <trinity-f8991630-17eb-4ae0-9dfa-9a66bc41b02e-1641573741990@3c-app-gmx-bs48>

Hi

missed the defaultenv_append_directory(defaultenv_rk3568); in board-file...after adding that it seems to work

> Gesendet: Freitag, 07. Januar 2022 um 14:07 Uhr
> Von: "Sascha Hauer" <sha at pengutronix.de>
>
> Yes. Furthermore you have to add to the board code:
>
> 	defaultenv_append_directory(defaultenv_rk3568);

maybe this is the part i've missed. i thought it were 2 ways...either link via makefile or add to boards code

> > > > > Boot scripts for publicly available evaluation kits are often not good candidates
> > > > > for upstreaming, because everybody using the EVKs has different thoughts on how to
> > > > > boot. The best way would be to use bootloader spec. It's one or more files you
> > > > > place at a known location that describe where your kernel and device tree are and
> > > > > what command line arguments to use and barebox can then automatically generate
> > > > > boot entries from all available bootloader spec files.
> >
> > is extlinux (i used in uboot and conf-file is already present) supported here?
> >
> > > > > See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
> > > > > of how to set this up. This is what I'd recommend instead of writing your own
> > > > > scripts.
> >
> > i do not fully understand the bootloader spec in the pdf as config file seems to be
> >
> > /mnt/mmc0.4/loader/entries/stm32mp157c-dk2.conf
> >
> > and then
> > boot -d mmc0.4
> >
> > is run...so the path (loader/entries) seems to be fixed and all files there will be processed (which order)?
>
> Yes. No particular order, I guess it would be the order it is on the
> filesystem.
>
> > how is root appended (/dev/mmcblkXpY|uuid|...) when linux-appendroot is set to true?
>
> When root is appended it is assumed to be the same fs that also has the
> bootloader spec file, so the rootfs also has the entry and the kernel.

ok, then this is not usable for me, as i have a boot-partition (bootloader+kernel+dtb) and separate rootfs-partition

> > this is for testing multiple kernels with changing filenames (very
> > dynamic process, e.g. using 1 kernel binary with multiple dtb) and to
> > avoid adding a bootmenu entry everytime....this is not for end-user :)
>
> In that case you could also use bootm directly.

yes but my approach is to list the available kernels before and ask to enter the filename to not everytime look for correct commands ;)

> > and here scripting is imho the best way...this allows me to add extra
> > params to cmdline too (like debug level,dumping offsets) without
> > changing a distroboot config
>
> Not sure if you know already, but barebox concatenates all variables in
> the "global.linux.bootargs." namespace to the kernel command line, so
> you can easily add or remove a variable to add/remove kernel options
> without affecting unrelated options.

i know some options from documentation like this i've used to get a earlycon for tftp

global linux.bootargs.debug="earlycon=uart8250,mmio32,0xfe660000 earlyprintk"

> > for fixed kernels i have defined an extlinux.conf for uboot, but i'm
> > unsure if barebox can use this file too. have not found anything about
> > extlinux/syslinux in barebox yet.
>
> No, not yet.

ok, i created a bootloader-config like described in the pdf:

cat /mnt/sd.1/loader/entries/linux-gz.conf
title Linux GZip
version 5.16
options earlycon=uart8250,mmio32,0xfe660000 console=ttyS2,1500000n8
linux /extlinux/Image_5.16.gz
devicetree /extlinux/dtb_5.16
initrd /rootfs.cpio.lz4

but on starting it is skipped due to devicetree mismatch

boot -d sd.1
blspec: ignoring entry with incompatible devicetree "rockchip,rk3568-bpi-r2pro"
blspec: ignoring entry with incompatible devicetree "rockchip,rk3568-bpi-r2pro"
Nothing bootable found on 'sd.1'
Nothing bootable found

in barebox i use the evb whereas in linux i already have a separate dts. Can i override the compatible for the bootloader or do i need to add my board (as copy of evb first)?

btw. don't you get my direct messages (regarding vop2 driver for rk3568 and the result of my barebox environment-tests)?

regards Frank


From a.fatoum at pengutronix.de  Sat Jan  8 09:13:56 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:13:56 +0100
Subject: [PATCH 2/2] ARM64: qemu-virt64: disable MMU
In-Reply-To: <20220108171356.586099-1-a.fatoum@pengutronix.de>
References: <20220108171356.586099-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171356.586099-2-a.fatoum@pengutronix.de>

We have CFI flash at address 0 till start of RAM. Until we have a scheme
to remap the flash, so it's usable at that address, just disable the MMU
in the defconfig. Currently the defconfig prints a couple of error
messages on every start up for cfi-flash as well as environment and
state that depend on it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/configs/qemu_virt64_defconfig | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/arch/arm/configs/qemu_virt64_defconfig b/arch/arm/configs/qemu_virt64_defconfig
index 57e715bf8d09..3802ead279cd 100644
--- a/arch/arm/configs/qemu_virt64_defconfig
+++ b/arch/arm/configs/qemu_virt64_defconfig
@@ -1,8 +1,5 @@
 CONFIG_ARCH_ARM64_VIRT=y
-CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
 CONFIG_ARM_PSCI_CLIENT=y
-CONFIG_MMU=y
-# CONFIG_MMU_EARLY is not set
 CONFIG_MALLOC_SIZE=0x0
 CONFIG_KALLSYMS=y
 CONFIG_PROMPT=""
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:13:55 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:13:55 +0100
Subject: [PATCH 1/2] common: boards: qemu-virt: fix dtc warning
Message-ID: <20220108171356.586099-1-a.fatoum@pengutronix.de>

DTC complains about a Warning (chosen_node_is_root):

  /fragment at 1/__overlay__/chosen: chosen node must be at root node

As /chosen is already available in the device tree of all of:

  - ARM 32-Bit QEMU Virt
  - ARM 64-Bit QEMU Virt
  - RISC-V 32-Bit QEMU Virt
  - RISC-V 64-Bit QEMU Virt

Just reference that in a new fragment to silence the warning.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/boards/qemu-virt/overlay-of-flash.dts | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/common/boards/qemu-virt/overlay-of-flash.dts b/common/boards/qemu-virt/overlay-of-flash.dts
index b3cdf6893f8a..ace2c7026b7a 100644
--- a/common/boards/qemu-virt/overlay-of-flash.dts
+++ b/common/boards/qemu-virt/overlay-of-flash.dts
@@ -37,15 +37,20 @@
 			};
 		};
 	};
+
 	fragment at 1 {
-		target-path="/";
+		target-path = "/chosen";
 		__overlay__ {
-			chosen {
-				environment {
-					compatible = "barebox,environment";
-					device-path = ENV_DEVICE_PATH;
-				};
+			environment {
+				compatible = "barebox,environment";
+				device-path = ENV_DEVICE_PATH;
 			};
+		};
+	};
+
+	fragment at 2 {
+		target-path = "/";
+		__overlay__ {
 			aliases {
 				state = "/state";
 			};
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:14:24 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:14:24 +0100
Subject: [PATCH 1/3] tlsf: dump stack on assertion failure
Message-ID: <20220108171426.586330-1-a.fatoum@pengutronix.de>

We only support AddressSanitizer on ARM, ARM64 and sandbox. For other
platforms TLSF assertions may detect some nconsistency, like some double
frees. Make the reports more useful by dumping stack in that case.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/tlsf.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/tlsf.h b/include/tlsf.h
index 7015de0eb525..161176d5ac84 100644
--- a/include/tlsf.h
+++ b/include/tlsf.h
@@ -42,9 +42,12 @@
 extern "C" {
 #endif
 
+#include <printk.h>
+
 #define tlsf_assert(expr) do {                              \
         if (unlikely(!(expr))) {                            \
                 printf(#expr "%s %d\n", __FILE__, __LINE__); \
+                dump_stack();                               \
         }                                                   \
 } while (0)
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:14:25 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:14:25 +0100
Subject: [PATCH 2/3] driver: have CONFIG_DEBUG_PROBES report device unbind as
 well
In-Reply-To: <20220108171426.586330-1-a.fatoum@pengutronix.de>
References: <20220108171426.586330-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171426.586330-2-a.fatoum@pengutronix.de>

This aligns it with DEBUG_INITCALLS, which also traces exitcalls.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/Kconfig        | 10 ++++++++--
 drivers/base/driver.c |  4 ++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/common/Kconfig b/common/Kconfig
index d0055e2d2182..802bd9bfbb2e 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1503,9 +1503,15 @@ config DEBUG_INITCALLS
 	  If enabled this will print initcall traces.
 
 config DEBUG_PROBES
-	bool "Trace driver probes"
+	bool "Trace driver probes/removes"
 	help
-	  If enabled this will print driver probe traces.
+	  If enabled this will log driver probe and remove traces. If DEBUG_LL is enabled,
+	  probes will be printed even before registering consoles. If it's disabled, they
+	  will be collected in the log and written out once a console is active.
+
+	  Removes are written to the log and will be printed as long as consoles exist.
+	  Most consoles do not implement a remove callback to remain operable until
+	  the very end. Consoles using DMA, however, must be removed.
 
 config PBL_BREAK
 	bool "Execute software break on pbl start"
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index dd965eb165ee..bb07e96dcaf4 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -502,11 +502,15 @@ EXPORT_SYMBOL_GPL(dev_set_name);
 static void devices_shutdown(void)
 {
 	struct device_d *dev;
+	int depth = 0;
 
 	list_for_each_entry(dev, &active, active) {
 		if (dev->bus->remove) {
+			depth++;
+			pr_report_probe("%*sremove-> %s\n", depth * 4, "", dev_name(dev));
 			dev->bus->remove(dev);
 			dev->driver = NULL;
+			depth--;
 		}
 	}
 }
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:14:26 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:14:26 +0100
Subject: [PATCH 3/3] commands: add new devunbind debugging command
In-Reply-To: <20220108171426.586330-1-a.fatoum@pengutronix.de>
References: <20220108171426.586330-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171426.586330-3-a.fatoum@pengutronix.de>

Memory corruption around device removal may go unnoticed, because
barebox is shutting down anyway and doing no new allocations.

Add a new devunbind command that should help with debugging such issues
by allowing selective unbinding and removal of devices.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/Kconfig      | 12 +++++++
 commands/Makefile     |  1 +
 commands/devunbind.c  | 74 +++++++++++++++++++++++++++++++++++++++++++
 drivers/base/driver.c |  7 ++--
 include/driver.h      |  4 +++
 5 files changed, 95 insertions(+), 3 deletions(-)
 create mode 100644 commands/devunbind.c

diff --git a/commands/Kconfig b/commands/Kconfig
index e2c36949347e..9abd97271952 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -68,6 +68,18 @@ config CMD_DEVINFO
 	  If called with a device path being the argument, devinfo shows more
 	  default information about this device and its parameters.
 
+config CMD_DEVUNBIND
+	tristate
+	default y
+	prompt "devunbind"
+	help
+	  Debugging aid to unbind device from driver at runtime
+
+	  devunbind [-f] DEVICE
+
+	  Options:
+	    -f   unbind driver and force removal of device and children
+
 config CMD_DMESG
 	tristate
 	prompt "dmesg"
diff --git a/commands/Makefile b/commands/Makefile
index 0b7c1563b534..875826743ffe 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_CMD_MIITOOL)	+= miitool.o
 obj-$(CONFIG_CMD_DETECT)	+= detect.o
 obj-$(CONFIG_CMD_BOOT)		+= boot.o
 obj-$(CONFIG_CMD_DEVINFO)	+= devinfo.o
+obj-$(CONFIG_CMD_DEVUNBIND)	+= devunbind.o
 obj-$(CONFIG_CMD_DRVINFO)	+= drvinfo.o
 obj-$(CONFIG_CMD_READF)		+= readf.o
 obj-$(CONFIG_CMD_MENUTREE)	+= menutree.o
diff --git a/commands/devunbind.c b/commands/devunbind.c
new file mode 100644
index 000000000000..4bebb27e8e68
--- /dev/null
+++ b/commands/devunbind.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: ? 2021 Ahmad Fatoum <a.fatoum at pengutronix.de>, Pengutronix
+
+#include <command.h>
+#include <common.h>
+#include <complete.h>
+#include <driver.h>
+#include <getopt.h>
+
+static int do_devunbind(int argc, char *argv[])
+{
+	bool unregister = false;
+	struct device_d *dev;
+	int ret = COMMAND_SUCCESS, i, opt;
+
+	while ((opt = getopt(argc, argv, "fl")) > 0) {
+		switch (opt) {
+		case 'f':
+			unregister = true;
+			break;
+		case 'l':
+			list_for_each_entry(dev, &active_device_list, active) {
+				BUG_ON(!dev->driver);
+				if (dev->bus->remove)
+					printf("%pS(%s, %s)\n", dev->bus->remove,
+					       dev->driver->name, dev_name(dev));
+			}
+			return 0;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	if (!argv[optind])
+		return COMMAND_ERROR_USAGE;
+
+	for (i = optind; i < argc; i++) {
+		dev = get_device_by_name(argv[i]);
+		if (!dev)
+			return -ENODEV;
+
+		if (unregister)
+			return unregister_device(dev);
+
+		if (!dev->driver || !dev->bus->remove) {
+			printf("skipping unbound %s\n", argv[i]);
+			ret = COMMAND_ERROR;
+			continue;
+		}
+
+		dev->bus->remove(dev);
+		dev->driver = NULL;
+		list_del(&dev->active);
+	}
+
+	return ret;
+}
+
+BAREBOX_CMD_HELP_START(devunbind)
+BAREBOX_CMD_HELP_TEXT("Debugging aid to unbind device from driver at runtime")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-f",  "unbind driver and force removal of device and children")
+BAREBOX_CMD_HELP_OPT ("-l",  "list remove callbacks in shutdown order")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(devunbind)
+	.cmd		= do_devunbind,
+	BAREBOX_CMD_DESC("unbind device(s) from driver")
+	BAREBOX_CMD_OPTS("[-fl] DEVICES..")
+	BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+	BAREBOX_CMD_HELP(cmd_devunbind_help)
+	BAREBOX_CMD_COMPLETE(device_complete)
+BAREBOX_CMD_END
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index bb07e96dcaf4..f54f4d0b3746 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -41,7 +41,8 @@ EXPORT_SYMBOL(device_list);
 LIST_HEAD(driver_list);
 EXPORT_SYMBOL(driver_list);
 
-static LIST_HEAD(active);
+LIST_HEAD(active_device_list);
+EXPORT_SYMBOL(active_device_list);
 static LIST_HEAD(deferred);
 
 struct device_d *get_device_by_name(const char *name)
@@ -91,7 +92,7 @@ int device_probe(struct device_d *dev)
 	pinctrl_select_state_default(dev);
 	of_clk_set_defaults(dev->device_node, false);
 
-	list_add(&dev->active, &active);
+	list_add(&dev->active, &active_device_list);
 
 	ret = dev->bus->probe(dev);
 	if (ret == 0)
@@ -504,7 +505,7 @@ static void devices_shutdown(void)
 	struct device_d *dev;
 	int depth = 0;
 
-	list_for_each_entry(dev, &active, active) {
+	list_for_each_entry(dev, &active_device_list, active) {
 		if (dev->bus->remove) {
 			depth++;
 			pr_report_probe("%*sremove-> %s\n", depth * 4, "", dev_name(dev));
diff --git a/include/driver.h b/include/driver.h
index 4f6d40e17c14..1215a2d57ab3 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -328,6 +328,10 @@ extern struct list_head device_list;
  */
 extern struct list_head driver_list;
 
+/* linear list over all active devices
+ */
+extern struct list_head active_device_list;
+
 /* Iterate over all devices
  */
 #define for_each_device(dev) list_for_each_entry(dev, &device_list, list)
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:14:37 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:14:37 +0100
Subject: [PATCH] include <printk.h>: include <linux/types.h> for size_t
 definition
Message-ID: <20220108171437.586532-1-a.fatoum@pengutronix.de>

size_t is used without previous definition relying on header include
order. Fix that up.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/printk.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/printk.h b/include/printk.h
index baf2cca20213..046b456a9d2b 100644
--- a/include/printk.h
+++ b/include/printk.h
@@ -2,6 +2,8 @@
 #ifndef __PRINTK_H
 #define __PRINTK_H
 
+#include <linux/types.h>
+
 #define KERN_EMERG      ""   /* system is unusable                   */
 #define KERN_ALERT      ""   /* action must be taken immediately     */
 #define KERN_CRIT       ""   /* critical conditions                  */
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:14:45 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:14:45 +0100
Subject: [PATCH] include: <asm/csr.h>: sync with upstream
Message-ID: <20220108171445.586681-1-a.fatoum@pengutronix.de>

We don't define CONFIG_RISCV_PRIV_1_9, so deleted stuff by the sync is
unused anyway. No functional change.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/include/asm/csr.h | 213 ++++++++++++++++++++++++++---------
 1 file changed, 161 insertions(+), 52 deletions(-)

diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 1a15089cae95..8bba809e454e 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -13,13 +13,12 @@
 
 /* Status register flags */
 #define SR_SIE		_AC(0x00000002, UL) /* Supervisor Interrupt Enable */
+#define SR_MIE		_AC(0x00000008, UL) /* Machine Interrupt Enable */
 #define SR_SPIE		_AC(0x00000020, UL) /* Previous Supervisor IE */
+#define SR_MPIE		_AC(0x00000080, UL) /* Previous Machine IE */
 #define SR_SPP		_AC(0x00000100, UL) /* Previously Supervisor */
-#ifdef CONFIG_RISCV_PRIV_1_9
-#define SR_PUM		_AC(0x00040000, UL) /* Protect User Memory Access */
-#else
+#define SR_MPP		_AC(0x00001800, UL) /* Previously Machine */
 #define SR_SUM		_AC(0x00040000, UL) /* Supervisor User Memory Access */
-#endif
 
 #define SR_FS		_AC(0x00006000, UL) /* Floating-point Status */
 #define SR_FS_OFF	_AC(0x00000000, UL)
@@ -33,22 +32,6 @@
 #define SR_XS_CLEAN	_AC(0x00010000, UL)
 #define SR_XS_DIRTY	_AC(0x00018000, UL)
 
-#ifdef CONFIG_RISCV_PRIV_1_9
-#define SR_VM		_AC(0x1F000000, UL) /* Virtualization Management */
-#define SR_VM_MODE_BARE	_AC(0x00000000, UL) /* No translation or protection */
-#define SR_VM_MODE_BB	_AC(0x01000000, UL) /* Single base-and-bound */
-/* Separate instruction and data base-and-bound */
-#define SR_VM_MODE_BBID	_AC(0x02000000, UL)
-#ifndef CONFIG_64BIT
-#define SR_VM_MODE_32	_AC(0x08000000, UL)
-#define SR_VM_MODE	SR_VM_MODE_32
-#else
-#define SR_VM_MODE_39	_AC(0x09000000, UL)
-#define SR_VM_MODE_48	_AC(0x0A000000, UL)
-#define SR_VM_MODE	SR_VM_MODE_39
-#endif
-#endif
-
 #ifndef CONFIG_64BIT
 #define SR_SD		_AC(0x80000000, UL) /* FS/XS dirty */
 #else
@@ -56,51 +39,127 @@
 #endif
 
 /* SATP flags */
-#ifndef CONFIG_RISCV_PRIV_1_9
 #ifndef CONFIG_64BIT
 #define SATP_PPN	_AC(0x003FFFFF, UL)
 #define SATP_MODE_32	_AC(0x80000000, UL)
 #define SATP_MODE	SATP_MODE_32
+#define SATP_ASID_BITS	9
+#define SATP_ASID_SHIFT	22
+#define SATP_ASID_MASK	_AC(0x1FF, UL)
 #else
 #define SATP_PPN	_AC(0x00000FFFFFFFFFFF, UL)
 #define SATP_MODE_39	_AC(0x8000000000000000, UL)
 #define SATP_MODE	SATP_MODE_39
-#endif
+#define SATP_ASID_BITS	16
+#define SATP_ASID_SHIFT	44
+#define SATP_ASID_MASK	_AC(0xFFFF, UL)
 #endif
 
-/* SCAUSE */
-#define SCAUSE_IRQ_FLAG		(_AC(1, UL) << (__riscv_xlen - 1))
+/* Exception cause high bit - is an interrupt if set */
+#define CAUSE_IRQ_FLAG		(_AC(1, UL) << (__riscv_xlen - 1))
 
 #define IRQ_U_SOFT		0
+/* Interrupt causes (minus the high bit) */
 #define IRQ_S_SOFT		1
+#define IRQ_VS_SOFT		2
 #define IRQ_M_SOFT		3
 #define IRQ_U_TIMER		4
 #define IRQ_S_TIMER		5
+#define IRQ_VS_TIMER		6
 #define IRQ_M_TIMER		7
 #define IRQ_U_EXT		8
 #define IRQ_S_EXT		9
+#define IRQ_VS_EXT		10
 #define IRQ_M_EXT		11
 
+/* Exception causes */
 #define EXC_INST_MISALIGNED	0
 #define EXC_INST_ACCESS		1
+#define EXC_INST_ILLEGAL	2
 #define EXC_BREAKPOINT		3
 #define EXC_LOAD_ACCESS		5
 #define EXC_STORE_ACCESS	7
 #define EXC_SYSCALL		8
+#define EXC_HYPERVISOR_SYSCALL	9
+#define EXC_SUPERVISOR_SYSCALL	10
 #define EXC_INST_PAGE_FAULT	12
 #define EXC_LOAD_PAGE_FAULT	13
 #define EXC_STORE_PAGE_FAULT	15
+#define EXC_INST_GUEST_PAGE_FAULT	20
+#define EXC_LOAD_GUEST_PAGE_FAULT	21
+#define EXC_VIRTUAL_INST_FAULT		22
+#define EXC_STORE_GUEST_PAGE_FAULT	23
+
+/* PMP configuration */
+#define PMP_R			0x01
+#define PMP_W			0x02
+#define PMP_X			0x04
+#define PMP_A			0x18
+#define PMP_A_TOR		0x08
+#define PMP_A_NA4		0x10
+#define PMP_A_NAPOT		0x18
+#define PMP_L			0x80
+
+/* HSTATUS flags */
+#ifdef CONFIG_64BIT
+#define HSTATUS_VSXL		_AC(0x300000000, UL)
+#define HSTATUS_VSXL_SHIFT	32
+#endif
+#define HSTATUS_VTSR		_AC(0x00400000, UL)
+#define HSTATUS_VTW		_AC(0x00200000, UL)
+#define HSTATUS_VTVM		_AC(0x00100000, UL)
+#define HSTATUS_VGEIN		_AC(0x0003f000, UL)
+#define HSTATUS_VGEIN_SHIFT	12
+#define HSTATUS_HU		_AC(0x00000200, UL)
+#define HSTATUS_SPVP		_AC(0x00000100, UL)
+#define HSTATUS_SPV		_AC(0x00000080, UL)
+#define HSTATUS_GVA		_AC(0x00000040, UL)
+#define HSTATUS_VSBE		_AC(0x00000020, UL)
+
+/* HGATP flags */
+#define HGATP_MODE_OFF		_AC(0, UL)
+#define HGATP_MODE_SV32X4	_AC(1, UL)
+#define HGATP_MODE_SV39X4	_AC(8, UL)
+#define HGATP_MODE_SV48X4	_AC(9, UL)
+
+#define HGATP32_MODE_SHIFT	31
+#define HGATP32_VMID_SHIFT	22
+#define HGATP32_VMID_MASK	_AC(0x1FC00000, UL)
+#define HGATP32_PPN		_AC(0x003FFFFF, UL)
+
+#define HGATP64_MODE_SHIFT	60
+#define HGATP64_VMID_SHIFT	44
+#define HGATP64_VMID_MASK	_AC(0x03FFF00000000000, UL)
+#define HGATP64_PPN		_AC(0x00000FFFFFFFFFFF, UL)
+
+#define HGATP_PAGE_SHIFT	12
 
-/* SIE (Interrupt Enable) and SIP (Interrupt Pending) flags */
-#define MIE_MSIE		(_AC(0x1, UL) << IRQ_M_SOFT)
-#define SIE_SSIE		(_AC(0x1, UL) << IRQ_S_SOFT)
-#define SIE_STIE		(_AC(0x1, UL) << IRQ_S_TIMER)
-#define SIE_SEIE		(_AC(0x1, UL) << IRQ_S_EXT)
+#ifdef CONFIG_64BIT
+#define HGATP_PPN		HGATP64_PPN
+#define HGATP_VMID_SHIFT	HGATP64_VMID_SHIFT
+#define HGATP_VMID_MASK		HGATP64_VMID_MASK
+#define HGATP_MODE_SHIFT	HGATP64_MODE_SHIFT
+#else
+#define HGATP_PPN		HGATP32_PPN
+#define HGATP_VMID_SHIFT	HGATP32_VMID_SHIFT
+#define HGATP_VMID_MASK		HGATP32_VMID_MASK
+#define HGATP_MODE_SHIFT	HGATP32_MODE_SHIFT
+#endif
+
+/* VSIP & HVIP relation */
+#define VSIP_TO_HVIP_SHIFT	(IRQ_VS_SOFT - IRQ_S_SOFT)
+#define VSIP_VALID_MASK		((_AC(1, UL) << IRQ_S_SOFT) | \
+				 (_AC(1, UL) << IRQ_S_TIMER) | \
+				 (_AC(1, UL) << IRQ_S_EXT))
 
-#define CSR_FCSR		0x003
+/* symbolic CSR names: */
 #define CSR_CYCLE		0xc00
 #define CSR_TIME		0xc01
 #define CSR_INSTRET		0xc02
+#define CSR_CYCLEH		0xc80
+#define CSR_TIMEH		0xc81
+#define CSR_INSTRETH		0xc82
+
 #define CSR_SSTATUS		0x100
 #define CSR_SIE			0x104
 #define CSR_STVEC		0x105
@@ -110,40 +169,90 @@
 #define CSR_SCAUSE		0x142
 #define CSR_STVAL		0x143
 #define CSR_SIP			0x144
-#ifdef CONFIG_RISCV_PRIV_1_9
-#define CSR_SPTBR		0x180
-#else
 #define CSR_SATP		0x180
-#endif
+
+#define CSR_VSSTATUS		0x200
+#define CSR_VSIE		0x204
+#define CSR_VSTVEC		0x205
+#define CSR_VSSCRATCH		0x240
+#define CSR_VSEPC		0x241
+#define CSR_VSCAUSE		0x242
+#define CSR_VSTVAL		0x243
+#define CSR_VSIP		0x244
+#define CSR_VSATP		0x280
+
+#define CSR_HSTATUS		0x600
+#define CSR_HEDELEG		0x602
+#define CSR_HIDELEG		0x603
+#define CSR_HIE			0x604
+#define CSR_HTIMEDELTA		0x605
+#define CSR_HCOUNTEREN		0x606
+#define CSR_HGEIE		0x607
+#define CSR_HTIMEDELTAH		0x615
+#define CSR_HTVAL		0x643
+#define CSR_HIP			0x644
+#define CSR_HVIP		0x645
+#define CSR_HTINST		0x64a
+#define CSR_HGATP		0x680
+#define CSR_HGEIP		0xe12
+
 #define CSR_MSTATUS		0x300
 #define CSR_MISA		0x301
 #define CSR_MIE			0x304
 #define CSR_MTVEC		0x305
-#ifdef CONFIG_RISCV_PRIV_1_9
-#define CSR_MUCOUNTEREN         0x320
-#define CSR_MSCOUNTEREN         0x321
-#define CSR_MHCOUNTEREN         0x322
-#else
-#define CSR_MCOUNTEREN		0x306
-#endif
 #define CSR_MSCRATCH		0x340
 #define CSR_MEPC		0x341
 #define CSR_MCAUSE		0x342
 #define CSR_MTVAL		0x343
 #define CSR_MIP			0x344
-#ifdef CONFIG_RISCV_PRIV_1_9
-#define CSR_MBASE		0x380
-#define CSR_MBOUND		0x381
-#define CSR_MIBASE		0x382
-#define CSR_MIBOUND		0x383
-#define CSR_MDBASE		0x384
-#define CSR_MDBOUND		0x385
-#endif
-#define CSR_CYCLEH		0xc80
-#define CSR_TIMEH		0xc81
-#define CSR_INSTRETH		0xc82
+#define CSR_PMPCFG0		0x3a0
+#define CSR_PMPADDR0		0x3b0
+#define CSR_MVENDORID		0xf11
+#define CSR_MARCHID		0xf12
+#define CSR_MIMPID		0xf13
 #define CSR_MHARTID		0xf14
 
+#ifdef CONFIG_RISCV_M_MODE
+# define CSR_STATUS	CSR_MSTATUS
+# define CSR_IE		CSR_MIE
+# define CSR_TVEC	CSR_MTVEC
+# define CSR_SCRATCH	CSR_MSCRATCH
+# define CSR_EPC	CSR_MEPC
+# define CSR_CAUSE	CSR_MCAUSE
+# define CSR_TVAL	CSR_MTVAL
+# define CSR_IP		CSR_MIP
+
+# define SR_IE		SR_MIE
+# define SR_PIE		SR_MPIE
+# define SR_PP		SR_MPP
+
+# define RV_IRQ_SOFT		IRQ_M_SOFT
+# define RV_IRQ_TIMER	IRQ_M_TIMER
+# define RV_IRQ_EXT		IRQ_M_EXT
+#else /* CONFIG_RISCV_M_MODE */
+# define CSR_STATUS	CSR_SSTATUS
+# define CSR_IE		CSR_SIE
+# define CSR_TVEC	CSR_STVEC
+# define CSR_SCRATCH	CSR_SSCRATCH
+# define CSR_EPC	CSR_SEPC
+# define CSR_CAUSE	CSR_SCAUSE
+# define CSR_TVAL	CSR_STVAL
+# define CSR_IP		CSR_SIP
+
+# define SR_IE		SR_SIE
+# define SR_PIE		SR_SPIE
+# define SR_PP		SR_SPP
+
+# define RV_IRQ_SOFT		IRQ_S_SOFT
+# define RV_IRQ_TIMER	IRQ_S_TIMER
+# define RV_IRQ_EXT		IRQ_S_EXT
+#endif /* CONFIG_RISCV_M_MODE */
+
+/* IE/IP (Supervisor/Machine Interrupt Enable/Pending) flags */
+#define IE_SIE		(_AC(0x1, UL) << RV_IRQ_SOFT)
+#define IE_TIE		(_AC(0x1, UL) << RV_IRQ_TIMER)
+#define IE_EIE		(_AC(0x1, UL) << RV_IRQ_EXT)
+
 #ifndef __ASSEMBLY__
 
 #define csr_swap(csr, val)					\
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:16 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:16 +0100
Subject: [PATCH 1/9] RISC-V: virt: activate all consoles
Message-ID: <20220108171524.587144-1-a.fatoum@pengutronix.de>

While CONSOLE_ACTIVATE_NONE + stdout-path is usually the way to go, main
console on this platform can be virtio console, which can't be
referenced as is in DT, so just enable all consoles.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/configs/virt32_defconfig | 1 +
 arch/riscv/configs/virt64_defconfig | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/riscv/configs/virt32_defconfig b/arch/riscv/configs/virt32_defconfig
index 1d7b70fc0fbc..ea7d1de8be68 100644
--- a/arch/riscv/configs/virt32_defconfig
+++ b/arch/riscv/configs/virt32_defconfig
@@ -10,6 +10,7 @@ CONFIG_HUSH_FANCY_PROMPT=y
 CONFIG_CMDLINE_EDITING=y
 CONFIG_AUTO_COMPLETE=y
 CONFIG_MENU=y
+CONFIG_CONSOLE_ACTIVATE_ALL=y
 CONFIG_CONSOLE_ALLOW_COLOR=y
 CONFIG_PBL_CONSOLE=y
 CONFIG_PARTITION_DISK_EFI=y
diff --git a/arch/riscv/configs/virt64_defconfig b/arch/riscv/configs/virt64_defconfig
index 8c66e3e574ff..b1c7a6712ac3 100644
--- a/arch/riscv/configs/virt64_defconfig
+++ b/arch/riscv/configs/virt64_defconfig
@@ -11,6 +11,7 @@ CONFIG_HUSH_FANCY_PROMPT=y
 CONFIG_CMDLINE_EDITING=y
 CONFIG_AUTO_COMPLETE=y
 CONFIG_MENU=y
+CONFIG_CONSOLE_ACTIVATE_ALL=y
 CONFIG_CONSOLE_ALLOW_COLOR=y
 CONFIG_PBL_CONSOLE=y
 CONFIG_PARTITION_DISK_EFI=y
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:17 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:17 +0100
Subject: [PATCH 2/9] power: reset: add RISC-V/UC Berkely HTIF poweroff driver
 support
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-2-a.fatoum@pengutronix.de>

We already have a driver in board code and device tree passed by
emulator already has a node for it. Match against it and create a proper
driver.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/boards/riscvemu/board.c  | 15 ----------
 arch/riscv/configs/virt32_defconfig |  1 +
 arch/riscv/configs/virt64_defconfig |  1 +
 arch/riscv/include/asm/htif.h       | 31 +++++++++++++++++++
 drivers/power/reset/Kconfig         |  7 +++++
 drivers/power/reset/Makefile        |  1 +
 drivers/power/reset/htif-poweroff.c | 46 +++++++++++++++++++++++++++++
 7 files changed, 87 insertions(+), 15 deletions(-)
 create mode 100644 arch/riscv/include/asm/htif.h
 create mode 100644 drivers/power/reset/htif-poweroff.c

diff --git a/arch/riscv/boards/riscvemu/board.c b/arch/riscv/boards/riscvemu/board.c
index 7dbf9afe4c2d..73d787a8335a 100644
--- a/arch/riscv/boards/riscvemu/board.c
+++ b/arch/riscv/boards/riscvemu/board.c
@@ -16,18 +16,6 @@ struct riscvemu_priv {
 
 };
 
-#define HTIF_BASE_ADDR		IOMEM(0x40008000)
-#define HTIF_TOHOST_LOW		(HTIF_BASE_ADDR + 0)
-#define HTIF_TOHOST_HIGH	(HTIF_BASE_ADDR + 4)
-
-static void __noreturn riscvemu_poweroff(struct poweroff_handler *pwr)
-{
-	writel(1, HTIF_TOHOST_LOW);
-	writel(0, HTIF_TOHOST_HIGH);
-
-	__builtin_unreachable();
-}
-
 static void __noreturn riscvemu_restart(struct restart_handler *rst)
 {
 	struct riscvemu_priv *priv = container_of(rst, struct riscvemu_priv, rst);
@@ -46,9 +34,6 @@ static int riscvemu_probe(struct device_d *dev)
 	struct riscvemu_priv *priv;
 	u64 start;
 
-	if (of_find_compatible_node(NULL, NULL, "ucb,htif0"))
-		poweroff_handler_register_fn(riscvemu_poweroff);
-
 	of_chosen = of_find_node_by_path("/chosen");
 
 	if (of_property_read_u64(of_chosen, "riscv,kernel-start", &start))
diff --git a/arch/riscv/configs/virt32_defconfig b/arch/riscv/configs/virt32_defconfig
index ea7d1de8be68..bfea7771efd8 100644
--- a/arch/riscv/configs/virt32_defconfig
+++ b/arch/riscv/configs/virt32_defconfig
@@ -109,6 +109,7 @@ CONFIG_BLK_DEV_NVME=y
 CONFIG_SYSCON_REBOOT_MODE=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+CONFIG_POWER_RESET_HTIF_POWEROFF=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_FS_EXT4=y
 CONFIG_FS_TFTP=y
diff --git a/arch/riscv/configs/virt64_defconfig b/arch/riscv/configs/virt64_defconfig
index b1c7a6712ac3..2ddc174b8a65 100644
--- a/arch/riscv/configs/virt64_defconfig
+++ b/arch/riscv/configs/virt64_defconfig
@@ -110,6 +110,7 @@ CONFIG_BLK_DEV_NVME=y
 CONFIG_SYSCON_REBOOT_MODE=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+CONFIG_POWER_RESET_HTIF_POWEROFF=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_FS_EXT4=y
 CONFIG_FS_TFTP=y
diff --git a/arch/riscv/include/asm/htif.h b/arch/riscv/include/asm/htif.h
new file mode 100644
index 000000000000..7312f09d2e6e
--- /dev/null
+++ b/arch/riscv/include/asm/htif.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2021 Ahmad Fatoum, Pengutronix
+ */
+
+#ifndef __ASM_HTIF_LL__
+#define __ASM_HTIF_LL__
+
+#define HTIF_DEFAULT_BASE_ADDR		0x40008000
+
+#define HTIF_DEV_SYSCALL		0
+#define		HTIF_CMD_SYSCALL	0
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <io-64-nonatomic-lo-hi.h>
+
+static inline void __htif_tohost(void __iomem *htif, u8 device, u8 command, u64 arg)
+{
+	writeq(((u64)device << 56) | ((u64)command << 48) | arg, htif);
+}
+
+static inline void htif_tohost(u8 device, u8 command, u64 arg)
+{
+	__htif_tohost(IOMEM(HTIF_DEFAULT_BASE_ADDR), device, command, arg);
+}
+
+#endif
+
+#endif
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index e4151d8bc608..968d4b8ba47d 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -54,3 +54,10 @@ config POWER_RESET_GPIO_RESTART
 	  This driver supports restarting your board via a GPIO line.
 	  If your board needs a GPIO high/low to restart, say Y and
 	  create a binding in your devicetree.
+
+config POWER_RESET_HTIF_POWEROFF
+	bool "HTIF poweroff driver"
+	depends on RISCV
+	help
+	  Adds poweroff support via the syscall device on systems
+	  supporting the UC Berkely Host/Target Interface (HTIF).
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 10d6f2a41e22..c581382be86d 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
 obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o
 obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
 obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
+obj-$(CONFIG_POWER_RESET_HTIF_POWEROFF) += htif-poweroff.o
diff --git a/drivers/power/reset/htif-poweroff.c b/drivers/power/reset/htif-poweroff.c
new file mode 100644
index 000000000000..8df060d5079f
--- /dev/null
+++ b/drivers/power/reset/htif-poweroff.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <poweroff.h>
+#include <asm/htif.h>
+
+static void __iomem *htif = IOMEM(HTIF_DEFAULT_BASE_ADDR);
+
+static void __noreturn riscvemu_poweroff(struct poweroff_handler *pwr)
+{
+	shutdown_barebox();
+
+	__htif_tohost(htif, HTIF_DEV_SYSCALL, 0, 1);
+
+	__builtin_unreachable();
+}
+
+static int htif_poweroff_probe(struct device_d *dev)
+{
+	struct resource *iores;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (!IS_ERR(iores))
+		htif = IOMEM(iores->start);
+	else if (PTR_ERR(iores) != -ENOENT)
+		return PTR_ERR(iores);
+
+	return poweroff_handler_register_fn(riscvemu_poweroff);
+}
+
+
+static const struct of_device_id htif_poweroff_of_match[] = {
+	{ .compatible = "ucb,htif0" },
+	{}
+};
+
+static struct driver_d htif_poweroff_driver = {
+	.name = "htif-poweroff",
+	.of_compatible = htif_poweroff_of_match,
+	.probe = htif_poweroff_probe,
+};
+coredevice_platform_driver(htif_poweroff_driver);
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:18 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:18 +0100
Subject: [PATCH 3/9] RISC-V: virt: riscvemu: add HTIF DEBUG_LL support
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-3-a.fatoum@pengutronix.de>

Default console of riscvemu is available Virt I/O console and as a HTIF
blocking character device. We already support Virt I/O console, but the
HTIF is easier to support for very early low level debugging. Add
DEBUG_LL support to facilitate using it.

Note: when using a framebuffer, riscvemu doesn't allocate a default
console, so barebox calling into HTIF will segfault the emulator.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/include/asm/debug_ll.h | 11 +++++++++++
 arch/riscv/include/asm/htif.h     |  9 +++++++++
 common/Kconfig                    |  9 +++++++++
 3 files changed, 29 insertions(+)

diff --git a/arch/riscv/include/asm/debug_ll.h b/arch/riscv/include/asm/debug_ll.h
index 867c96d79724..de9bc5f5fd33 100644
--- a/arch/riscv/include/asm/debug_ll.h
+++ b/arch/riscv/include/asm/debug_ll.h
@@ -53,6 +53,17 @@ static inline void PUTC_LL(char ch)
 
 #include <asm/debug_ll_litex.h>
 
+#elif defined CONFIG_DEBUG_RISCVEMU_HTIF
+
+#include <asm/htif.h>
+
+#ifndef __ASSEMBLY__
+static inline void PUTC_LL(char ch)
+{
+	htif_putc(IOMEM(HTIF_DEFAULT_BASE_ADDR), ch);
+}
+#endif
+
 #endif
 
 #ifndef debug_ll_init
diff --git a/arch/riscv/include/asm/htif.h b/arch/riscv/include/asm/htif.h
index 7312f09d2e6e..b35afdd98e1d 100644
--- a/arch/riscv/include/asm/htif.h
+++ b/arch/riscv/include/asm/htif.h
@@ -11,6 +11,10 @@
 #define HTIF_DEV_SYSCALL		0
 #define		HTIF_CMD_SYSCALL	0
 
+#define HTIF_DEV_CONSOLE		1 /* blocking character device */
+#define		HTIF_CMD_GETCHAR	0
+#define		HTIF_CMD_PUTCHAR	1
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
@@ -26,6 +30,11 @@ static inline void htif_tohost(u8 device, u8 command, u64 arg)
 	__htif_tohost(IOMEM(HTIF_DEFAULT_BASE_ADDR), device, command, arg);
 }
 
+static inline void htif_putc(void __iomem *base, int c)
+{
+	__htif_tohost(base, HTIF_DEV_CONSOLE, HTIF_CMD_PUTCHAR, c);
+}
+
 #endif
 
 #endif
diff --git a/common/Kconfig b/common/Kconfig
index 802bd9bfbb2e..2f014509da0d 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1403,6 +1403,15 @@ config DEBUG_RISCV_VIRT
 	depends on SOC_VIRT
 	select DEBUG_LL_NS16550
 
+config DEBUG_RISCVEMU_HTIF
+	bool "riscvemu HTIF port"
+	depends on SOC_VIRT
+	help
+	  When run without graphics support, tinyemu will expose access
+	  to the Virt I/O console as HTIF blocking console device as well.
+	  This is useful for low level debugging before Virt I/O DMA is
+	  initialized.
+
 config DEBUG_SIFIVE
 	bool "SiFive serial0 port"
 	depends on SOC_SIFIVE
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:22 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:22 +0100
Subject: [PATCH 7/9] RISC-V: don't use x8/s0/fp in assembly
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-7-a.fatoum@pengutronix.de>

Free up the register to allow building a configuration with x8/s0 used
as the frame pointer.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/include/asm/debug_ll_litex.h   | 12 +++---
 arch/riscv/include/asm/debug_ll_ns16550.h |  8 ++--
 arch/riscv/include/asm/riscv_nmon.h       | 50 +++++++++++------------
 3 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/arch/riscv/include/asm/debug_ll_litex.h b/arch/riscv/include/asm/debug_ll_litex.h
index 2fcdd9b0ec3e..295477fc1010 100644
--- a/arch/riscv/include/asm/debug_ll_litex.h
+++ b/arch/riscv/include/asm/debug_ll_litex.h
@@ -90,11 +90,11 @@ static inline void PUTC_LL(char ch)
 	li	t0, DEBUG_LL_UART_ADDR
 
 	/* get line status and check for data present */
-	lbu	s0, UART_RXEMPTY(t0)
-	bnez    s0, 243f
-	li	s0, 1
+	lbu	s1, UART_RXEMPTY(t0)
+	bnez    s1, 243f
+	li	s1, 1
 	j	244f
-243:	li	s0, 0
+243:	li	s1, 0
 244:	nop
 #endif /* CONFIG_DEBUG_LL */
 .endm
@@ -109,10 +109,10 @@ static inline void PUTC_LL(char ch)
 	debug_ll_tstc
 
 	/* try again */
-	beqz	s0, 204b
+	beqz	s1, 204b
 
 	/* read a character */
-	lb	s0, UART_RXTX(t0)
+	lb	s1, UART_RXTX(t0)
 	li      t1, UART_EV_RX
 	sb	t1, UART_EV_PENDING(t0)
 
diff --git a/arch/riscv/include/asm/debug_ll_ns16550.h b/arch/riscv/include/asm/debug_ll_ns16550.h
index e208ef4fb1e1..47f0be328ce8 100644
--- a/arch/riscv/include/asm/debug_ll_ns16550.h
+++ b/arch/riscv/include/asm/debug_ll_ns16550.h
@@ -143,8 +143,8 @@ static inline void debug_ll_ns16550_init(void)
 	li      t0, DEBUG_LL_UART_ADDR
 
 	/* get line status and check for data present */
-	UART_REG_L	s0, UART_LSR(DEBUG_LL_UART_SHIFT)(t0)
-	andi	s0, s0, UART_LSR_DR
+	UART_REG_L	s1, UART_LSR(DEBUG_LL_UART_SHIFT)(t0)
+	andi	s1, s1, UART_LSR_DR
 
 #endif /* CONFIG_DEBUG_LL */
 .endm
@@ -159,10 +159,10 @@ static inline void debug_ll_ns16550_init(void)
 	debug_ll_tstc
 
 	/* try again */
-	beqz	s0, 204b
+	beqz	s1, 204b
 
 	/* read a character */
-	UART_REG_L	s0, UART_RBR(DEBUG_LL_UART_SHIFT)(t0)
+	UART_REG_L	s1, UART_RBR(DEBUG_LL_UART_SHIFT)(t0)
 
 #endif /* CONFIG_DEBUG_LL */
 .endm
diff --git a/arch/riscv/include/asm/riscv_nmon.h b/arch/riscv/include/asm/riscv_nmon.h
index 8a44e216d72d..3e349025febc 100644
--- a/arch/riscv/include/asm/riscv_nmon.h
+++ b/arch/riscv/include/asm/riscv_nmon.h
@@ -84,7 +84,7 @@ nmon_main:
 	debug_ll_getc
 
 	li	a0, 'q'
-	bne	s0, a0, 3f
+	bne	s1, a0, 3f
 
 	jal	a2, _nmon_outc_a0
 
@@ -92,13 +92,13 @@ nmon_main:
 
 3:
 	li	a0, 'd'
-	beq	s0, a0, nmon_cmd_d
+	beq	s1, a0, nmon_cmd_d
 
 	li	a0, 'w'
-	beq	s0, a0, nmon_cmd_w
+	beq	s1, a0, nmon_cmd_w
 
 	li	a0, 'g'
-	beq	s0, a0, nmon_cmd_g
+	beq	s1, a0, nmon_cmd_g
 
 	j	nmon_main_help
 
@@ -112,7 +112,7 @@ nmon_cmd_d:
 
 	nmon_outs	msg_nl
 
-	lw	a0, (s0)
+	lw	a0, (s1)
 	debug_ll_outhexw
 
 	j	nmon_main
@@ -124,13 +124,13 @@ nmon_cmd_w:
 	jal	a2, _nmon_outc_a0
 
 	jal	a2, _nmon_gethexw
-	move	s2, s0
+	move	s3, s1
 
 	li	a0, ' '
 	jal	a2, _nmon_outc_a0
 	jal	a2, _nmon_gethexw
 
-	sw	s0, 0(s2)
+	sw	s1, 0(s3)
 	j	nmon_main
 
 nmon_cmd_g:
@@ -140,11 +140,11 @@ nmon_cmd_g:
 	jal	a2, _nmon_outc_a0
 
 	jal	a2, _nmon_gethexw
-	move	s2, s0
+	move	s3, s1
 
 	nmon_outs	msg_nl
 
-	jalr	s2
+	jalr	s3
 	j	nmon_main
 
 _nmon_outc_a0:
@@ -169,37 +169,37 @@ _nmon_gethexw:
 _get_hex_digit:
 	debug_ll_getc
 
-	li	s1, CODE_ESC
-	beq	s0, s1, nmon_main
+	li	s2, CODE_ESC
+	beq	s1, s2, nmon_main
 
-	li	s1, '0'
-	bge	s0, s1, 0f
+	li	s2, '0'
+	bge	s1, s2, 0f
 	j	_get_hex_digit
 
 0:
-	li	s1, '9'
-	ble	s0, s1, 9f
+	li	s2, '9'
+	ble	s1, s2, 9f
 
-	li	s1, 'f'
-	ble	s0, s1, 1f
+	li	s2, 'f'
+	ble	s1, s2, 1f
 	j	_get_hex_digit
 
 1:
-	li	s1, 'a'
-	bge	s0, s1, 8f
+	li	s2, 'a'
+	bge	s1, s2, 8f
 
 	j	_get_hex_digit
 
-8: /* s0 \in {'a', 'b' ... 'f'} */
-	sub	a3, s0, s1
+8: /* s1 \in {'a', 'b' ... 'f'} */
+	sub	a3, s1, s2
 	addi	a3, a3, 0xa
 	j	0f
 
-9: /* s0 \in {'0', '1' ... '9'} */
+9: /* s1 \in {'0', '1' ... '9'} */
 	li	a3, '0'
-	sub	a3, s0, a3
+	sub	a3, s1, a3
 
-0:	move	a0, s0
+0:	move	a0, s1
 	debug_ll_outc_a0
 
 	sll	t2, t2, 4
@@ -212,7 +212,7 @@ _get_hex_digit:
 	j	_get_hex_digit
 
 0:
-	move	s0, t2
+	move	s1, t2
 
 _nmon_jr_ra_exit:
 	jr	a2
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:19 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:19 +0100
Subject: [PATCH 4/9] RISC-V: virt: riscvemu: repurpose 64k low RAM for
 state/environment
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-4-a.fatoum@pengutronix.de>

TinyEMU's RISC-V machine emulates a 64K SRAM at address 0.
First 4K page is unused, then a maximum of 0x40 bytes for boot ROM
(trampoline that passes FDT), then the FDT. The remainder of the 64K is
unused. Make use of that space for storing state and environment.

We start the mtd-ram at 0x1000 to easily allow for a faulting zero page.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/boards/riscvemu/Makefile           |   1 +
 arch/riscv/boards/riscvemu/board.c            |   9 ++
 .../riscv/boards/riscvemu/overlay-of-sram.dts | 119 ++++++++++++++++++
 arch/riscv/configs/virt32_defconfig           |   1 +
 arch/riscv/configs/virt64_defconfig           |   1 +
 5 files changed, 131 insertions(+)
 create mode 100644 arch/riscv/boards/riscvemu/overlay-of-sram.dts

diff --git a/arch/riscv/boards/riscvemu/Makefile b/arch/riscv/boards/riscvemu/Makefile
index ad283446eaf1..75f52ada8f37 100644
--- a/arch/riscv/boards/riscvemu/Makefile
+++ b/arch/riscv/boards/riscvemu/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 obj-y += board.o
+obj-y += overlay-of-sram.dtb.o
diff --git a/arch/riscv/boards/riscvemu/board.c b/arch/riscv/boards/riscvemu/board.c
index 73d787a8335a..60c93716a2bc 100644
--- a/arch/riscv/boards/riscvemu/board.c
+++ b/arch/riscv/boards/riscvemu/board.c
@@ -7,6 +7,7 @@
 #include <driver.h>
 #include <poweroff.h>
 #include <restart.h>
+#include <deep-probe.h>
 #include <asm/system.h>
 #include <asm/barebox-riscv.h>
 
@@ -28,12 +29,19 @@ static void __noreturn riscvemu_restart(struct restart_handler *rst)
 	priv->restart(riscv_hartid(), barebox_riscv_boot_dtb());
 }
 
+extern char __dtb_overlay_of_sram_start[];
+
 static int riscvemu_probe(struct device_d *dev)
 {
 	struct device_node *of_chosen;
+	struct device_node *overlay;
 	struct riscvemu_priv *priv;
 	u64 start;
 
+	overlay = of_unflatten_dtb(__dtb_overlay_of_sram_start, INT_MAX);
+	of_overlay_apply_tree(dev->device_node, overlay);
+	/* of_probe() will happen later at of_populate_initcall */
+
 	of_chosen = of_find_node_by_path("/chosen");
 
 	if (of_property_read_u64(of_chosen, "riscv,kernel-start", &start))
@@ -52,6 +60,7 @@ static const struct of_device_id riscvemu_of_match[] = {
 	{ .compatible = "ucbbar,riscvemu-bar_dev" },
 	{ /* sentinel */ },
 };
+BAREBOX_DEEP_PROBE_ENABLE(riscvemu_of_match);
 
 static struct driver_d riscvemu_board_driver = {
 	.name = "board-riscvemu",
diff --git a/arch/riscv/boards/riscvemu/overlay-of-sram.dts b/arch/riscv/boards/riscvemu/overlay-of-sram.dts
new file mode 100644
index 000000000000..839887fef24c
--- /dev/null
+++ b/arch/riscv/boards/riscvemu/overlay-of-sram.dts
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+	fragment at 0 {
+		target-path = "/soc";
+		__overlay__ {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			sram at 0 {
+				compatible = "mtd-ram";
+				reg = <0 0x1000 0 0x10000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					partition at 0 {
+						label = "bootrom";
+						reg = <0x0 0x40>;
+					};
+
+					partition at 40 {
+						label = "fdt";
+						reg = <0x40 0x1fc0>;
+					};
+
+					environment_sram: partition at 3000 {
+						label = "barebox-environment";
+						reg = <0x3000 0xb000>;
+					};
+
+					backend_state_sram: partition at e000 {
+						label = "barebox-state";
+						reg = <0xe000 0x1000>;
+					};
+				};
+			};
+		};
+	};
+
+	fragment at 2 {
+		target-path = "/chosen";
+		__overlay__ {
+			environment {
+				compatible = "barebox,environment";
+				device-path = "/soc/sram at 0/partitions/partition at 3000";
+			};
+		};
+	};
+
+	fragment at 3 {
+		target-path = "/";
+		__overlay__ {
+			aliases {
+				state = "/state";
+			};
+
+			state {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "barebox,state";
+				magic = <0x290cf8c6>;
+				backend-type = "raw";
+				backend = <&backend_state_sram>;
+				backend-stridesize = <64>;
+
+				bootstate {
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					system0 {
+						#address-cells = <1>;
+						#size-cells = <1>;
+
+						remaining_attempts at 0 {
+							reg = <0x0 0x4>;
+							type = "uint32";
+							default = <3>;
+						};
+
+						priority at 4 {
+							reg = <0x4 0x4>;
+							type = "uint32";
+							default = <20>;
+						};
+					};
+
+					system1 {
+						#address-cells = <1>;
+						#size-cells = <1>;
+
+						remaining_attempts at 8 {
+							reg = <0x8 0x4>;
+							type = "uint32";
+							default = <3>;
+						};
+
+						priority at c {
+							reg = <0xc 0x4>;
+							type = "uint32";
+							default = <21>;
+						};
+					};
+
+					last_chosen at 10 {
+						reg = <0x10 0x4>;
+						type = "uint32";
+					};
+				};
+			};
+		};
+	};
+};
diff --git a/arch/riscv/configs/virt32_defconfig b/arch/riscv/configs/virt32_defconfig
index bfea7771efd8..28a20673e9b7 100644
--- a/arch/riscv/configs/virt32_defconfig
+++ b/arch/riscv/configs/virt32_defconfig
@@ -88,6 +88,7 @@ CONFIG_MTD=y
 # CONFIG_MTD_OOB_DEVICE is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_M25P80=y
+CONFIG_MTD_MTDRAM=y
 CONFIG_DRIVER_CFI=y
 CONFIG_DRIVER_CFI_BANK_WIDTH_8=y
 CONFIG_DISK=y
diff --git a/arch/riscv/configs/virt64_defconfig b/arch/riscv/configs/virt64_defconfig
index 2ddc174b8a65..17588f61fa35 100644
--- a/arch/riscv/configs/virt64_defconfig
+++ b/arch/riscv/configs/virt64_defconfig
@@ -89,6 +89,7 @@ CONFIG_MTD=y
 # CONFIG_MTD_OOB_DEVICE is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_M25P80=y
+CONFIG_MTD_MTDRAM=y
 CONFIG_DRIVER_CFI=y
 CONFIG_DRIVER_CFI_BANK_WIDTH_8=y
 CONFIG_DISK=y
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:23 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:23 +0100
Subject: [PATCH 8/9] RISC-V: add stacktrace support via frame pointer walking
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-8-a.fatoum@pengutronix.de>

Make debugging more convenient by implementing stack_dump() and changing
exception handlers to print stack trace along with the register dump.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Makefile                                    |  5 ++
 arch/riscv/Kconfig                          | 10 +++
 arch/riscv/cpu/interrupts.c                 |  3 +
 arch/riscv/include/asm/barebox-riscv-head.h |  1 +
 arch/riscv/include/asm/ptrace.h             | 10 +--
 arch/riscv/include/asm/unwind.h             |  8 ++-
 arch/riscv/lib/Makefile                     |  1 +
 arch/riscv/lib/stacktrace.c                 | 79 +++++++++++++++++++++
 common/Kconfig                              | 12 ++++
 9 files changed, 123 insertions(+), 6 deletions(-)
 create mode 100644 arch/riscv/lib/stacktrace.c

diff --git a/Makefile b/Makefile
index ab9d3e677e19..a6b6a5be20aa 100644
--- a/Makefile
+++ b/Makefile
@@ -632,6 +632,11 @@ endif # need-config
 
 KBUILD_CFLAGS		+= -ggdb3
 
+ifdef CONFIG_FRAME_POINTER
+KBUILD_CFLAGS	+= -fno-omit-frame-pointer -fno-optimize-sibling-calls
+KBUILD_CFLAGS	+= $(call cc-disable-warning,frame-address,)
+endif
+
 # Force gcc to behave correct even for buggy distributions
 KBUILD_CFLAGS          += $(call cc-option, -fno-stack-protector)
 
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index e093ed4226de..1190cd42723f 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -85,6 +85,16 @@ config RISCV_EXCEPTIONS
 	default y
 	select ARCH_HAS_DATA_ABORT_MASK
 
+config RISCV_UNWIND
+	bool "enable stack unwinding support"
+	select ARCH_HAS_STACK_DUMP
+	select ARCH_WANT_FRAME_POINTERS
+	help
+	  This option enables stack unwinding support in barebox
+	  using the information automatically generated by the
+	  compiler. The resulting kernel image is slightly bigger but
+	  the performance is not affected.
+
 config HAS_NMON
 	bool
 
diff --git a/arch/riscv/cpu/interrupts.c b/arch/riscv/cpu/interrupts.c
index 1f2d7b885737..0bb56d441d96 100644
--- a/arch/riscv/cpu/interrupts.c
+++ b/arch/riscv/cpu/interrupts.c
@@ -14,6 +14,7 @@
 #include <asm/ptrace.h>
 #include <asm/irq.h>
 #include <asm/csr.h>
+#include <asm/unwind.h>
 #include <abort.h>
 #include <pbl.h>
 
@@ -81,6 +82,8 @@ static void report_trap(const struct pt_regs *regs)
 	       regs->epc, regs->ra, regs->badaddr);
 
 	show_regs(regs);
+
+	unwind_backtrace(regs);
 }
 
 
diff --git a/arch/riscv/include/asm/barebox-riscv-head.h b/arch/riscv/include/asm/barebox-riscv-head.h
index a4c33472cd53..4d62c20d1b2d 100644
--- a/arch/riscv/include/asm/barebox-riscv-head.h
+++ b/arch/riscv/include/asm/barebox-riscv-head.h
@@ -23,6 +23,7 @@
 		".ascii \"" magic2 "\"\n"      /* magic 2 */                          \
 		".word 0\n"                    /* reserved (PE-COFF offset) */        \
 		"1:\n"                                                                \
+		"li fp, 0\n"                                                          \
 	)
 
 #define __barebox_riscv_header(instr, load_offset, version, magic1, magic2) \
diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h
index b5e792f6669b..319c50f946a8 100644
--- a/arch/riscv/include/asm/ptrace.h
+++ b/arch/riscv/include/asm/ptrace.h
@@ -61,7 +61,7 @@ struct pt_regs {
 #define MAX_REG_OFFSET offsetof(struct pt_regs, cause)
 
 /* Helpers for working with the instruction pointer */
-static inline unsigned long instruction_pointer(struct pt_regs *regs)
+static inline unsigned long instruction_pointer(const struct pt_regs *regs)
 {
 	return regs->epc;
 }
@@ -74,7 +74,7 @@ static inline void instruction_pointer_set(struct pt_regs *regs,
 #define profile_pc(regs) instruction_pointer(regs)
 
 /* Helpers for working with the user stack pointer */
-static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+static inline unsigned long user_stack_pointer(const struct pt_regs *regs)
 {
 	return regs->sp;
 }
@@ -85,13 +85,13 @@ static inline void user_stack_pointer_set(struct pt_regs *regs,
 }
 
 /* Valid only for Kernel mode traps. */
-static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
+static inline unsigned long kernel_stack_pointer(const struct pt_regs *regs)
 {
 	return regs->sp;
 }
 
 /* Helpers for working with the frame pointer */
-static inline unsigned long frame_pointer(struct pt_regs *regs)
+static inline unsigned long frame_pointer(const struct pt_regs *regs)
 {
 	return regs->s0;
 }
@@ -101,7 +101,7 @@ static inline void frame_pointer_set(struct pt_regs *regs,
 	regs->s0 = val;
 }
 
-static inline unsigned long regs_return_value(struct pt_regs *regs)
+static inline unsigned long regs_return_value(const struct pt_regs *regs)
 {
 	return regs->a0;
 }
diff --git a/arch/riscv/include/asm/unwind.h b/arch/riscv/include/asm/unwind.h
index 9e5c8b542094..00f7845147b1 100644
--- a/arch/riscv/include/asm/unwind.h
+++ b/arch/riscv/include/asm/unwind.h
@@ -4,6 +4,12 @@
 
 struct pt_regs;
 
-void unwind_backtrace(struct pt_regs *regs);
+#if defined CONFIG_RISCV_UNWIND && !defined __PBL__
+void unwind_backtrace(const struct pt_regs *regs);
+#else
+static inline void unwind_backtrace(const struct pt_regs *regs)
+{
+}
+#endif
 
 #endif
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index a399de7399cb..f3db5320f751 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_RISCV_OPTIMZED_STRING_FUNCTIONS) += memcpy.o memset.o memmove.o
 obj-$(CONFIG_RISCV_SBI) += sbi.o
 obj-$(CONFIG_CMD_RISCV_CPUINFO) += cpuinfo.o
 obj-$(CONFIG_BOOTM) += bootm.o
+obj-$(CONFIG_RISCV_UNWIND) += stacktrace.o
diff --git a/arch/riscv/lib/stacktrace.c b/arch/riscv/lib/stacktrace.c
new file mode 100644
index 000000000000..663938019ee6
--- /dev/null
+++ b/arch/riscv/lib/stacktrace.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2008 ARM Limited
+ * Copyright (C) 2014 Regents of the University of California
+ * Copyright (C) 2021 Ahmad Fatoum, Pengutronix
+ *
+ * Framepointer assisted stack unwinder
+ */
+
+#include <linux/kernel.h>
+#include <printk.h>
+#include <asm/unwind.h>
+#include <asm/ptrace.h>
+#include <asm-generic/memory_layout.h>
+#include <asm/sections.h>
+
+struct stackframe {
+	unsigned long fp;
+	unsigned long ra;
+};
+
+static void dump_backtrace_entry(unsigned long where, unsigned long from)
+{
+#ifdef CONFIG_KALLSYMS
+	printf("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
+#else
+	printf("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
+#endif
+}
+
+static int unwind_frame(struct stackframe *frame, unsigned long *sp)
+{
+	unsigned long low, high;
+	unsigned long fp = frame->fp;
+
+	low = *sp;
+	high = ALIGN(low, STACK_SIZE);
+
+	if (fp < low || fp > high - sizeof(struct stackframe) || fp & 0x7)
+		return -1;
+
+	*frame = *((struct stackframe *)fp - 1);
+	*sp = fp;
+
+	return 0;
+}
+
+void unwind_backtrace(const struct pt_regs *regs)
+{
+        struct stackframe frame = {};
+	register unsigned long current_sp asm ("sp");
+	unsigned long sp = 0;
+
+	if (regs) {
+		frame.fp = frame_pointer(regs);
+		frame.ra = regs->ra;
+	} else {
+		sp = current_sp;
+		frame.fp = (unsigned long)__builtin_frame_address(0);
+		frame.ra = (unsigned long)unwind_backtrace;
+	}
+
+	printf("Call trace:\n");
+	for (;;) {
+		unsigned long where = frame.ra;
+		int ret;
+
+		ret = unwind_frame(&frame, &sp);
+		if (ret < 0)
+			break;
+
+		dump_backtrace_entry(where, frame.ra);
+	}
+}
+
+void dump_stack(void)
+{
+	unwind_backtrace(NULL);
+}
diff --git a/common/Kconfig b/common/Kconfig
index 2f014509da0d..060e21d9fedf 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1209,6 +1209,18 @@ config DEBUG_LL
 	  platform *will not work*, so this option should not be enabled
 	  for builds that are intended to be portable.
 
+config ARCH_WANT_FRAME_POINTERS
+	bool
+
+config FRAME_POINTER
+	bool "Compile barebox with frame pointers" if COMPILE_TEST
+	default y if ARCH_WANT_FRAME_POINTERS
+	help
+	  Selected by platforms that expect frame pointer usage, e.g.
+	  when stack unwinding is enabled. The resulting barebox image
+	  will be slightly larger and slower, but it can give precise
+	  debugging information when print stack traces.
+
 choice
 	prompt "Kernel low-level debugging port"
 	depends on DEBUG_LL
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:21 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:21 +0100
Subject: [PATCH 6/9] RISC-V: virt: riscvemu: clear frame buffer before jumping
 to reset vector
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-6-a.fatoum@pengutronix.de>

Our poor man's reset just resumes execution at the reset vector, so the
framebuffer will maintain its contents over reset, leading to artifacts.
Clear screen before reset to avoid this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/boards/riscvemu/board.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/riscv/boards/riscvemu/board.c b/arch/riscv/boards/riscvemu/board.c
index 60c93716a2bc..31d0c70be643 100644
--- a/arch/riscv/boards/riscvemu/board.c
+++ b/arch/riscv/boards/riscvemu/board.c
@@ -21,6 +21,9 @@ static void __noreturn riscvemu_restart(struct restart_handler *rst)
 {
 	struct riscvemu_priv *priv = container_of(rst, struct riscvemu_priv, rst);
 
+	/* clear screen on graphic console */
+	puts("\e[J");
+
 	/*
 	 * barebox PBL relocates itself to end of RAM early on, so unless
 	 * something explicitly scrubbed the initial PBL, we can jump back to
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:20 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:20 +0100
Subject: [PATCH 5/9] RISC-V: virt: riscvemu: be explicit about HTIF base
 address
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-5-a.fatoum@pengutronix.de>

The normal riscvemu console is Virt I/O, which isn't really suitable to
poke from the command line as part of the incoming jsbarebox tutorial.

The HTIF on the other hand can be poked quite comfortably. To make it
look more like normal devices, fix up an address. No functional change.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/boards/riscvemu/overlay-of-sram.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/riscv/boards/riscvemu/overlay-of-sram.dts b/arch/riscv/boards/riscvemu/overlay-of-sram.dts
index 839887fef24c..506d45bde9b6 100644
--- a/arch/riscv/boards/riscvemu/overlay-of-sram.dts
+++ b/arch/riscv/boards/riscvemu/overlay-of-sram.dts
@@ -116,4 +116,14 @@
 			};
 		};
 	};
+
+	fragment at 4 {
+		target-path = "/htif";
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		__overlay__ {
+			reg = <0 0x40008000 0 0x8>;
+		};
+	};
 };
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:24 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:24 +0100
Subject: [PATCH 9/9] RISC-V: Virt: enable more useful options
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171524.587144-9-a.fatoum@pengutronix.de>

Incoming tutorial will showcase some barebox features, so enable them in
the config for use.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/riscv/configs/virt32_defconfig | 6 ++++++
 arch/riscv/configs/virt64_defconfig | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/arch/riscv/configs/virt32_defconfig b/arch/riscv/configs/virt32_defconfig
index 28a20673e9b7..b5044cf34aa5 100644
--- a/arch/riscv/configs/virt32_defconfig
+++ b/arch/riscv/configs/virt32_defconfig
@@ -10,11 +10,15 @@ CONFIG_HUSH_FANCY_PROMPT=y
 CONFIG_CMDLINE_EDITING=y
 CONFIG_AUTO_COMPLETE=y
 CONFIG_MENU=y
+CONFIG_BOOTM_VERBOSE=y
+CONFIG_BOOTM_INITRD=y
+CONFIG_BLSPEC=y
 CONFIG_CONSOLE_ACTIVATE_ALL=y
 CONFIG_CONSOLE_ALLOW_COLOR=y
 CONFIG_PBL_CONSOLE=y
 CONFIG_PARTITION_DISK_EFI=y
 CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_IKCONFIG=y
 CONFIG_STATE=y
 CONFIG_STATE_CRYPTO=y
 CONFIG_BOOTCHOOSER=y
@@ -46,6 +50,7 @@ CONFIG_CMD_MSLEEP=y
 CONFIG_CMD_SLEEP=y
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_ECHO_E=y
 CONFIG_CMD_EDIT=y
 CONFIG_CMD_SPLASH=y
 CONFIG_CMD_FBTEST=y
@@ -101,6 +106,7 @@ CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT=y
 CONFIG_CLOCKSOURCE_DUMMY_RATE=60000
 CONFIG_STATE_DRV=y
 CONFIG_EEPROM_AT24=y
+CONFIG_VIRTIO_INPUT=y
 CONFIG_HWRNG=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
diff --git a/arch/riscv/configs/virt64_defconfig b/arch/riscv/configs/virt64_defconfig
index 17588f61fa35..c2edd2dc2898 100644
--- a/arch/riscv/configs/virt64_defconfig
+++ b/arch/riscv/configs/virt64_defconfig
@@ -11,11 +11,15 @@ CONFIG_HUSH_FANCY_PROMPT=y
 CONFIG_CMDLINE_EDITING=y
 CONFIG_AUTO_COMPLETE=y
 CONFIG_MENU=y
+CONFIG_BOOTM_VERBOSE=y
+CONFIG_BOOTM_INITRD=y
+CONFIG_BLSPEC=y
 CONFIG_CONSOLE_ACTIVATE_ALL=y
 CONFIG_CONSOLE_ALLOW_COLOR=y
 CONFIG_PBL_CONSOLE=y
 CONFIG_PARTITION_DISK_EFI=y
 CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW_IKCONFIG=y
 CONFIG_STATE=y
 CONFIG_STATE_CRYPTO=y
 CONFIG_BOOTCHOOSER=y
@@ -47,6 +51,7 @@ CONFIG_CMD_MSLEEP=y
 CONFIG_CMD_SLEEP=y
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_ECHO_E=y
 CONFIG_CMD_EDIT=y
 CONFIG_CMD_SPLASH=y
 CONFIG_CMD_FBTEST=y
@@ -102,6 +107,7 @@ CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT=y
 CONFIG_CLOCKSOURCE_DUMMY_RATE=60000
 CONFIG_STATE_DRV=y
 CONFIG_EEPROM_AT24=y
+CONFIG_VIRTIO_INPUT=y
 CONFIG_HWRNG=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:54 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:54 +0100
Subject: [PATCH 1/2] fs: implement pushd/popd chdir wrappers
Message-ID: <20220108171555.588426-1-a.fatoum@pengutronix.de>

We don't have dirfd's, so running operations relative to the current
working directory always involves some allocation/freeing boilerplate.

Add pushd/popd helpers to move the boilerplate out of the callsites.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/fs.c          | 30 ++++++++++++++++++++++++++++++
 include/unistd.h |  2 ++
 2 files changed, 32 insertions(+)

diff --git a/fs/fs.c b/fs/fs.c
index 7da3a050c1cb..60fdb29078d6 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2846,6 +2846,36 @@ out:
 }
 EXPORT_SYMBOL(chdir);
 
+char *pushd(const char *dir)
+{
+	char *oldcwd;
+	int ret;
+
+	oldcwd = strdup(getcwd());
+	if (!oldcwd)
+		return NULL;
+
+	ret = chdir(dir);
+	if (ret) {
+		free(oldcwd);
+		return NULL;
+	}
+
+	return oldcwd;
+}
+
+int popd(char *oldcwd)
+{
+	int ret;
+
+	if (!oldcwd)
+		return 0;
+
+	ret = chdir(oldcwd);
+	free(oldcwd);
+	return ret;
+}
+
 static char *get_linux_mmcblkdev(struct fs_device_d *fsdev)
 {
 	struct cdev *cdevm, *cdev;
diff --git a/include/unistd.h b/include/unistd.h
index 06ce3558099f..f7fe737d002b 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -20,6 +20,8 @@ int rmdir (const char *pathname);
 int symlink(const char *pathname, const char *newpath);
 int readlink(const char *path, char *buf, size_t bufsiz);
 int chdir(const char *pathname);
+char *pushd(const char *dir);
+int popd(char *dir);
 const char *getcwd(void);
 int ftruncate(int fd, loff_t length);
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 09:15:55 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat,  8 Jan 2022 18:15:55 +0100
Subject: [PATCH 2/2] commands: add new tutorial command
In-Reply-To: <20220108171555.588426-1-a.fatoum@pengutronix.de>
References: <20220108171555.588426-1-a.fatoum@pengutronix.de>
Message-ID: <20220108171555.588426-2-a.fatoum@pengutronix.de>

We have a web demo at http://barebox.org/jsbarebox and it would
be nice to have a tutorial there. Add a new tutorial command that
cycles through a number of tips.

Tutorial will follow later.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/Kconfig    |   7 ++
 commands/Makefile   |   1 +
 commands/tutorial.c | 160 ++++++++++++++++++++++++++++++++++++++++++++
 common/complete.c   |  21 ++++--
 include/complete.h  |   1 +
 5 files changed, 184 insertions(+), 6 deletions(-)
 create mode 100644 commands/tutorial.c

diff --git a/commands/Kconfig b/commands/Kconfig
index 9abd97271952..87583db31f90 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -23,6 +23,13 @@ menu "Commands"
 
 menu "Information"
 
+config CMD_TUTORIAL
+	bool "barebox tutorial (next command)"
+	default SANDBOX
+	help
+	  Help navigate a barebox tutorial available
+	  in /env/data/tutorial/
+
 config CMD_AT91CLK
 	bool "at91clk"
 	default y
diff --git a/commands/Makefile b/commands/Makefile
index 875826743ffe..db78d0b877f6 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -135,5 +135,6 @@ obj-$(CONFIG_CMD_IP_ROUTE_GET)  += ip-route-get.o
 obj-$(CONFIG_CMD_BTHREAD)	+= bthread.o
 obj-$(CONFIG_CMD_UBSAN)		+= ubsan.o
 obj-$(CONFIG_CMD_SELFTEST)	+= selftest.o
+obj-$(CONFIG_CMD_TUTORIAL)	+= tutorial.o
 
 UBSAN_SANITIZE_ubsan.o := y
diff --git a/commands/tutorial.c b/commands/tutorial.c
new file mode 100644
index 000000000000..81e2f93716cd
--- /dev/null
+++ b/commands/tutorial.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: (c) 2021 Ahmad Fatoum
+
+#include <common.h>
+#include <command.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <complete.h>
+#include <sys/stat.h>
+#include <glob.h>
+#include <getopt.h>
+#include <magicvar.h>
+#include <globalvar.h>
+
+static int next_step;
+BAREBOX_MAGICVAR(global.tutorial.step, "Next tutorial step.");
+
+#define BUFSIZE 1024
+
+static glob_t steps;
+
+static int register_tutorial_vars(void)
+{
+	char *oldcwd;
+	int ret = 0;
+
+	oldcwd = pushd("/env/data/tutorial");
+	if (!oldcwd)
+		return 0;
+
+	ret = glob("*", 0, NULL, &steps);
+	if (ret)
+		goto out;
+
+	ret = globalvar_add_simple_enum("tutorial.step", &next_step,
+					(const char **)steps.gl_pathv, steps.gl_pathc);
+
+out:
+	popd(oldcwd);
+	return ret;
+
+}
+postenvironment_initcall(register_tutorial_vars);
+
+static int print_tutorial_step(const char *step)
+{
+	bool highlight = false;
+	int fd, ret, i;
+	char *buf;
+
+	fd = open(step, O_RDONLY);
+	if (fd < 0) {
+		printf("could not open /env/data/tutorial/%s\n", step);
+		return -errno;
+	}
+
+	buf = malloc(BUFSIZE);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	printf("%s\n", step);
+
+	while((ret = read(fd, buf, BUFSIZE)) > 0) {
+		for(i = 0; i < ret; i++) {
+			if (buf[i] != '`') {
+				putchar(buf[i]);
+				continue;
+			}
+
+			puts(highlight ? "\e[0m" : "\e[1;31m");
+			highlight = !highlight;
+		}
+	}
+
+	free(buf);
+out:
+	close(fd);
+
+	return ret;
+}
+
+static int do_tutorial_next(int argc, char *argv[])
+{
+	int opt, i;
+	char *step = NULL;
+	char *oldcwd;
+	ssize_t ret = 0;
+	bool is_prev = *argv[0] == 'p';
+
+	while ((opt = getopt(argc, argv, "rh")) > 0) {
+		switch (opt) {
+		case 'r':
+			if (steps.gl_pathc) {
+				globalvar_remove("tutorial.step");
+				next_step = 0;
+				globfree(&steps);
+				steps.gl_pathc = 0;
+			}
+			ret = register_tutorial_vars();
+			if (ret == 0 && steps.gl_pathc == 0)
+				ret = -ENOENT;
+			if (ret)
+				printf("could not load /env/data/tutorial/\n");
+			return ret;
+		case 'h':
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	if (optind > argc + 1)
+		return COMMAND_ERROR_USAGE;
+
+	oldcwd = pushd("/env/data/tutorial");
+	if (!oldcwd)
+		return ret;
+
+	if (is_prev)
+		next_step = next_step > 0 ? next_step - 1 : 0;
+
+	if (optind == argc) {
+		step = steps.gl_pathv[next_step];
+		ret = print_tutorial_step(step);
+		if (ret == 0 && !is_prev)
+			next_step = (next_step + 1) % steps.gl_pathc;
+	} else {
+		for (i = optind; i < argc; i++) {
+			step = strdup(argv[i]);
+			ret = print_tutorial_step(step);
+			if (ret)
+				break;
+		}
+	}
+
+	popd(oldcwd);
+
+	return ret;
+}
+
+BAREBOX_CMD_HELP_START(next)
+BAREBOX_CMD_HELP_TEXT("Help navigate the barebox tutorial")
+BAREBOX_CMD_HELP_TEXT("Without a parameter, the next or previous tutorial step is printed")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT("-h\t", "show usage text")
+BAREBOX_CMD_HELP_OPT("-r\t", "rewind and reload tutorial")
+BAREBOX_CMD_HELP_END
+
+static __maybe_unused const char *const prev_alias[] = { "prev", NULL};
+
+BAREBOX_CMD_START(next)
+	.cmd		= do_tutorial_next,
+	.aliases	= prev_alias,
+	BAREBOX_CMD_DESC("print next tip for barebox tutorial")
+	BAREBOX_CMD_OPTS("[-hr] [STEP]")
+	BAREBOX_CMD_HELP(cmd_next_help)
+	BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+	BAREBOX_CMD_COMPLETE(tutorial_complete)
+BAREBOX_CMD_END
diff --git a/common/complete.c b/common/complete.c
index e504b7560668..17c0ddb04a02 100644
--- a/common/complete.c
+++ b/common/complete.c
@@ -14,17 +14,18 @@
 #include <command.h>
 #include <environment.h>
 
-static int file_complete(struct string_list *sl, char *instr, int exec)
+static int file_complete(struct string_list *sl, char *instr,
+			 const char *dirn, int exec)
 {
 	char *path = strdup(instr);
 	struct stat s;
 	DIR *dir;
 	struct dirent *d;
 	char tmp[PATH_MAX];
-	char *base, *dirn;
+	char *base;
 
 	base = basename(instr);
-	dirn = dirname(path);
+	dirn = dirn ?: dirname(path);
 
 	dir = opendir(dirn);
 	if (!dir)
@@ -250,7 +251,15 @@ EXPORT_SYMBOL(devicetree_complete);
 int devicetree_file_complete(struct string_list *sl, char *instr)
 {
 	devicetree_complete(sl, instr);
-	file_complete(sl, instr, 0);
+	file_complete(sl, instr, NULL, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL(devicetree_file_complete);
+
+int tutorial_complete(struct string_list *sl, char *instr)
+{
+	file_complete(sl, instr, "/env/data/tutorial", 0);
 
 	return 0;
 }
@@ -392,11 +401,11 @@ int complete(char *instr, char **outstr)
 	if (!instr) {
 		instr = t;
 		if (t && (t[0] == '/' || !strncmp(t, "./", 2))) {
-			file_complete(&sl, t, 1);
+			file_complete(&sl, t, NULL, 1);
 			instr = t;
 		} else if ((t = strrchr(t, ' '))) {
 			t++;
-			file_complete(&sl, t, 0);
+			file_complete(&sl, t, NULL, 0);
 			instr = t;
 		} else {
 			command_complete(&sl, instr);
diff --git a/include/complete.h b/include/complete.h
index 75a92fc86aa0..b0e675b5599f 100644
--- a/include/complete.h
+++ b/include/complete.h
@@ -23,5 +23,6 @@ int devicetree_nodepath_complete(struct string_list *sl, char *instr);
 int devicetree_complete(struct string_list *sl, char *instr);
 int devicetree_file_complete(struct string_list *sl, char *instr);
 int env_param_noeval_complete(struct string_list *sl, char *instr);
+int tutorial_complete(struct string_list *sl, char *instr);
 
 #endif /* __COMPLETE_ */
-- 
2.30.2



From a.fatoum at pengutronix.de  Sat Jan  8 10:25:03 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat, 8 Jan 2022 19:25:03 +0100
Subject: [PATCH 7/9] RISC-V: don't use x8/s0/fp in assembly
In-Reply-To: <20220108171524.587144-7-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
 <20220108171524.587144-7-a.fatoum@pengutronix.de>
Message-ID: <6136d698-30cd-12a7-58e4-a6598ff3a86e@pengutronix.de>

Hello Antony,

On 08.01.22 18:15, Ahmad Fatoum wrote:
> Free up the register to allow building a configuration with x8/s0 used
> as the frame pointer.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  arch/riscv/include/asm/debug_ll_litex.h   | 12 +++---
>  arch/riscv/include/asm/debug_ll_ns16550.h |  8 ++--
>  arch/riscv/include/asm/riscv_nmon.h       | 50 +++++++++++------------

I just bumped the s register: s2 -> s3, s1 -> s2, s0 -> s1 to
clear s0. Is that ok?

>  3 files changed, 35 insertions(+), 35 deletions(-)
> 
> diff --git a/arch/riscv/include/asm/debug_ll_litex.h b/arch/riscv/include/asm/debug_ll_litex.h
> index 2fcdd9b0ec3e..295477fc1010 100644
> --- a/arch/riscv/include/asm/debug_ll_litex.h
> +++ b/arch/riscv/include/asm/debug_ll_litex.h
> @@ -90,11 +90,11 @@ static inline void PUTC_LL(char ch)
>  	li	t0, DEBUG_LL_UART_ADDR
>  
>  	/* get line status and check for data present */
> -	lbu	s0, UART_RXEMPTY(t0)
> -	bnez    s0, 243f
> -	li	s0, 1
> +	lbu	s1, UART_RXEMPTY(t0)
> +	bnez    s1, 243f
> +	li	s1, 1
>  	j	244f
> -243:	li	s0, 0
> +243:	li	s1, 0
>  244:	nop
>  #endif /* CONFIG_DEBUG_LL */
>  .endm
> @@ -109,10 +109,10 @@ static inline void PUTC_LL(char ch)
>  	debug_ll_tstc
>  
>  	/* try again */
> -	beqz	s0, 204b
> +	beqz	s1, 204b
>  
>  	/* read a character */
> -	lb	s0, UART_RXTX(t0)
> +	lb	s1, UART_RXTX(t0)
>  	li      t1, UART_EV_RX
>  	sb	t1, UART_EV_PENDING(t0)
>  
> diff --git a/arch/riscv/include/asm/debug_ll_ns16550.h b/arch/riscv/include/asm/debug_ll_ns16550.h
> index e208ef4fb1e1..47f0be328ce8 100644
> --- a/arch/riscv/include/asm/debug_ll_ns16550.h
> +++ b/arch/riscv/include/asm/debug_ll_ns16550.h
> @@ -143,8 +143,8 @@ static inline void debug_ll_ns16550_init(void)
>  	li      t0, DEBUG_LL_UART_ADDR
>  
>  	/* get line status and check for data present */
> -	UART_REG_L	s0, UART_LSR(DEBUG_LL_UART_SHIFT)(t0)
> -	andi	s0, s0, UART_LSR_DR
> +	UART_REG_L	s1, UART_LSR(DEBUG_LL_UART_SHIFT)(t0)
> +	andi	s1, s1, UART_LSR_DR
>  
>  #endif /* CONFIG_DEBUG_LL */
>  .endm
> @@ -159,10 +159,10 @@ static inline void debug_ll_ns16550_init(void)
>  	debug_ll_tstc
>  
>  	/* try again */
> -	beqz	s0, 204b
> +	beqz	s1, 204b
>  
>  	/* read a character */
> -	UART_REG_L	s0, UART_RBR(DEBUG_LL_UART_SHIFT)(t0)
> +	UART_REG_L	s1, UART_RBR(DEBUG_LL_UART_SHIFT)(t0)
>  
>  #endif /* CONFIG_DEBUG_LL */
>  .endm
> diff --git a/arch/riscv/include/asm/riscv_nmon.h b/arch/riscv/include/asm/riscv_nmon.h
> index 8a44e216d72d..3e349025febc 100644
> --- a/arch/riscv/include/asm/riscv_nmon.h
> +++ b/arch/riscv/include/asm/riscv_nmon.h
> @@ -84,7 +84,7 @@ nmon_main:
>  	debug_ll_getc
>  
>  	li	a0, 'q'
> -	bne	s0, a0, 3f
> +	bne	s1, a0, 3f
>  
>  	jal	a2, _nmon_outc_a0
>  
> @@ -92,13 +92,13 @@ nmon_main:
>  
>  3:
>  	li	a0, 'd'
> -	beq	s0, a0, nmon_cmd_d
> +	beq	s1, a0, nmon_cmd_d
>  
>  	li	a0, 'w'
> -	beq	s0, a0, nmon_cmd_w
> +	beq	s1, a0, nmon_cmd_w
>  
>  	li	a0, 'g'
> -	beq	s0, a0, nmon_cmd_g
> +	beq	s1, a0, nmon_cmd_g
>  
>  	j	nmon_main_help
>  
> @@ -112,7 +112,7 @@ nmon_cmd_d:
>  
>  	nmon_outs	msg_nl
>  
> -	lw	a0, (s0)
> +	lw	a0, (s1)
>  	debug_ll_outhexw
>  
>  	j	nmon_main
> @@ -124,13 +124,13 @@ nmon_cmd_w:
>  	jal	a2, _nmon_outc_a0
>  
>  	jal	a2, _nmon_gethexw
> -	move	s2, s0
> +	move	s3, s1
>  
>  	li	a0, ' '
>  	jal	a2, _nmon_outc_a0
>  	jal	a2, _nmon_gethexw
>  
> -	sw	s0, 0(s2)
> +	sw	s1, 0(s3)
>  	j	nmon_main
>  
>  nmon_cmd_g:
> @@ -140,11 +140,11 @@ nmon_cmd_g:
>  	jal	a2, _nmon_outc_a0
>  
>  	jal	a2, _nmon_gethexw
> -	move	s2, s0
> +	move	s3, s1
>  
>  	nmon_outs	msg_nl
>  
> -	jalr	s2
> +	jalr	s3
>  	j	nmon_main
>  
>  _nmon_outc_a0:
> @@ -169,37 +169,37 @@ _nmon_gethexw:
>  _get_hex_digit:
>  	debug_ll_getc
>  
> -	li	s1, CODE_ESC
> -	beq	s0, s1, nmon_main
> +	li	s2, CODE_ESC
> +	beq	s1, s2, nmon_main
>  
> -	li	s1, '0'
> -	bge	s0, s1, 0f
> +	li	s2, '0'
> +	bge	s1, s2, 0f
>  	j	_get_hex_digit
>  
>  0:
> -	li	s1, '9'
> -	ble	s0, s1, 9f
> +	li	s2, '9'
> +	ble	s1, s2, 9f
>  
> -	li	s1, 'f'
> -	ble	s0, s1, 1f
> +	li	s2, 'f'
> +	ble	s1, s2, 1f
>  	j	_get_hex_digit
>  
>  1:
> -	li	s1, 'a'
> -	bge	s0, s1, 8f
> +	li	s2, 'a'
> +	bge	s1, s2, 8f
>  
>  	j	_get_hex_digit
>  
> -8: /* s0 \in {'a', 'b' ... 'f'} */
> -	sub	a3, s0, s1
> +8: /* s1 \in {'a', 'b' ... 'f'} */
> +	sub	a3, s1, s2
>  	addi	a3, a3, 0xa
>  	j	0f
>  
> -9: /* s0 \in {'0', '1' ... '9'} */
> +9: /* s1 \in {'0', '1' ... '9'} */
>  	li	a3, '0'
> -	sub	a3, s0, a3
> +	sub	a3, s1, a3
>  
> -0:	move	a0, s0
> +0:	move	a0, s1
>  	debug_ll_outc_a0
>  
>  	sll	t2, t2, 4
> @@ -212,7 +212,7 @@ _get_hex_digit:
>  	j	_get_hex_digit
>  
>  0:
> -	move	s0, t2
> +	move	s1, t2
>  
>  _nmon_jr_ra_exit:
>  	jr	a2
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sam at ravnborg.org  Sun Jan  9 10:38:38 2022
From: sam at ravnborg.org (Sam Ravnborg)
Date: Sun, 9 Jan 2022 19:38:38 +0100
Subject: Q about bootstrap support for at91sam92* boards and proposal for
 retirement
Message-ID: <Ydsrrj76kk6tmD2X@ravnborg.org>

Hi all.

This little detour started because Ahmad pointed out I had made
a stupid mistake in pwm-atmel.
So I decided I wanted to give it a spin to verify if it actually works
now.

The first challenge I encountered was that said driver had bit-rotted
as it used the old pwm framework - so I updated it from the Linux
kernel.
I have the code locally - but this time I will not have it posted before
it is tested.

Then I cloned the latest at91bootstrap - but they no longer support old
at91sam92xx CPUs.
So it was time to enable bootstrap support for at91sam9263.

In the past I had something working, but alas no luck this time.

Can anyone (Ahmad?) help me a little how to get the bootstrap
functionality working on the at91sam9263?

I do not expect patches, but I hope for something that can point me in
the right way to do it.

I have skov-arm9cpu boards (plenty - as they are mostly retired by SKOV)
and one at91sam9263ek where I can test.

We see very little interest in at91sam92* boards and we could decide
to retire all the boards that are not updated to multi-image.
This could simplify things - and if there is interest the missing boards
can be brought back to life provided they are updated to multi image.
Any comments on this?
I am happy to type the patches - and verify that the boards I have works.

	Sam



From sam at ravnborg.org  Sun Jan  9 11:53:49 2022
From: sam at ravnborg.org (Sam Ravnborg)
Date: Sun, 9 Jan 2022 20:53:49 +0100
Subject: Q about bootstrap support for at91sam92* boards and proposal for
 retirement
In-Reply-To: <Ydsrrj76kk6tmD2X@ravnborg.org>
References: <Ydsrrj76kk6tmD2X@ravnborg.org>
Message-ID: <Yds9TY1wPddN1oNT@ravnborg.org>

Hi, 
> 
> Can anyone (Ahmad?) help me a little how to get the bootstrap
> functionality working on the at91sam9263?

To answer the obvious questions - what have I done so far.

- I have an at91bootstrap generated BOOT.BIN that works.
  This ruins out a lot of possible issues with the SD card
  as the board boots from the SD card with the at91bootstrap based
  BOOT.BIN.

- The toolchain used is generated from buildroot, and I do not have any
  proof that it works as I have not had any successes.
  So far I have assumed that it works.

- The configuration used is pasted below.

- The board I use is the skov-arm9cpu which I know works as it boots
  barebox with the at91bootstrap BOOT.BIN

- I have only a limited set of patches - pasted below.

- Latest barebox from the master branch

- I have tried to power cycle and reset of the board - no change

- There is a ">RomBOOT" prompt - but nothing else

	Sam


diff --git a/arch/arm/boards/skov-arm9cpu/lowlevel.c b/arch/arm/boards/skov-arm9cpu/lowlevel.c
index d335953a7..8d5c0b025 100644
--- a/arch/arm/boards/skov-arm9cpu/lowlevel.c
+++ b/arch/arm/boards/skov-arm9cpu/lowlevel.c
@@ -3,14 +3,20 @@
 
 #include <linux/sizes.h>
 
+#include <debug_ll.h>
+
 #include <asm/barebox-arm.h>
 
 #include <mach/at91sam926x_board_init.h>
 #include <mach/at91sam9263_matrix.h>
+#include <mach/at91_dbgu.h>
+#include <mach/iomux.h>
 
 #define MASTER_PLL_MUL		171
 #define MASTER_PLL_DIV		14
 
+#define MASTER_CLOCK            (200000000/2)
+
 static void __bare_init skovarm9cpu_board_config(struct at91sam926x_board_cfg *cfg)
 {
 	/* Disable Watchdog */
@@ -96,6 +102,18 @@ static void __bare_init skovarm9cpu_board_config(struct at91sam926x_board_cfg *c
 		AT91_RSTC_RSTTYP_WATCHDOG;
 }
 
+static void dbgu_init(void)
+{
+	void __iomem *pio = IOMEM(AT91SAM9263_BASE_PIOC);
+	// Setup DBGU uart
+	at91_mux_pio3_pin(pio, pin_to_mask(AT91_PIN_PC30), AT91_MUX_PERIPH_A, GPIO_PULL_UP); // DRXD
+	at91_mux_pio3_pin(pio, pin_to_mask(AT91_PIN_PC31), AT91_MUX_PERIPH_A, 0); // DTXD
+
+	at91_dbgu_setup_ll(IOMEM(AT91_BASE_DBGU1), MASTER_CLOCK, 115200);
+	pbl_set_putc(at91_dbgu_putc, IOMEM(AT91_BASE_DBGU1));
+	putc_ll('#');
+}
+
 static void __bare_init skov_arm9cpu_init(void *fdt)
 {
 	struct at91sam926x_board_cfg cfg;
@@ -108,6 +126,8 @@ static void __bare_init skov_arm9cpu_init(void *fdt)
 	skovarm9cpu_board_config(&cfg);
 	at91sam9263_board_init(&cfg);
 
+	dbgu_init();
+
 	barebox_arm_entry(AT91_CHIPSELECT_1, at91_get_sdram_size(cfg.sdramc),
 			  fdt);
 }

#
# Automatically generated file; DO NOT EDIT.
# Barebox/arm 2021.12.0 Configuration
#
CONFIG_ARM=y
CONFIG_HAVE_MACH_ARM_HEAD=y
CONFIG_ARM_USE_COMPRESSED_DTB=y
CONFIG_TEXT_BASE=0x0

#
# System Type
#
CONFIG_ARCH_AT91=y
# CONFIG_ARCH_BCM283X is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_DIGIC is not set
# CONFIG_ARCH_EP93XX is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_LAYERSCAPE is not set
# CONFIG_ARCH_MVEBU is not set
# CONFIG_ARCH_MXS is not set
# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_OMAP is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_ROCKCHIP is not set
# CONFIG_ARCH_SOCFPGA is not set
# CONFIG_ARCH_S3C24xx is not set
# CONFIG_ARCH_S5PCxx is not set
# CONFIG_ARCH_S3C64xx is not set
# CONFIG_ARCH_STM32MP is not set
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_VEXPRESS is not set
# CONFIG_ARCH_TEGRA is not set
# CONFIG_ARCH_UEMD is not set
# CONFIG_ARCH_ZYNQ is not set
# CONFIG_ARCH_ZYNQMP is not set
# CONFIG_ARCH_ARM64_VIRT is not set

#
# Processor Type
#
CONFIG_CPU_32=y
CONFIG_CPU_ARM926T=y
CONFIG_CPU_32v5=y

#
# processor features
#
# CONFIG_BOOT_ENDIANNESS_SWITCH is not set
CONFIG_HAVE_AT91_UTMI=y
CONFIG_HAVE_AT91_USB_CLK=y
CONFIG_COMMON_CLK_AT91=y
CONFIG_HAVE_AT91_SMD=y
CONFIG_HAVE_AT91_BOOTSTRAP=y
CONFIG_AT91SAM926X_BOARD_INIT=y
CONFIG_AT91SAM9_SMC=y
CONFIG_HAVE_AT91SAM9_RST=y
CONFIG_SOC_AT91SAM9=y
CONFIG_ARCH_TEXT_BASE=0x23f00000
CONFIG_HAVE_AT91_LOAD_BAREBOX_SRAM=y

#
# Atmel AT91 System-on-Chip
#
CONFIG_SOC_AT91SAM9263=y
CONFIG_AT91_MULTI_BOARDS=y
CONFIG_MACH_SKOV_ARM9CPU=y
# CONFIG_MACH_AT91SAM9263EK is not set
# CONFIG_MACH_AT91SAM9X5EK is not set
# CONFIG_MACH_MICROCHIP_KSZ9477_EVB is not set
# CONFIG_MACH_SAMA5D3_XPLAINED is not set
# CONFIG_MACH_SAMA5D27_SOM1 is not set
# CONFIG_MACH_SAMA5D27_GIANTBOARD is not set

#
# AT91 Board Options
#
CONFIG_AT91_BOOTSTRAP=y
# CONFIG_AT91_LOAD_BAREBOX_SRAM is not set
CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x40000
# CONFIG_BOARD_ARM_GENERIC_DT is not set
# CONFIG_AEABI is not set
# end of System Type

#
# ARM specific settings
#
# CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS is not set
CONFIG_ARM_EXCEPTIONS=y
# CONFIG_ARM_SEMIHOSTING is not set
# end of ARM specific settings

CONFIG_GREGORIAN_CALENDER=y
CONFIG_HAS_KALLSYMS=y
CONFIG_HAS_MODULES=y
CONFIG_HAS_CACHE=y
CONFIG_HAS_DMA=y
CONFIG_HAS_ARCH_SJLJ=y
CONFIG_GENERIC_GPIO=y
CONFIG_BLOCK=y
CONFIG_BLOCK_WRITE=y
CONFIG_USE_COMPRESSED_DTB=y
CONFIG_FILETYPE=y

#
# General Settings
#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_BANNER=y
CONFIG_MEMINFO=y
# CONFIG_ENVIRONMENT_VARIABLES is not set
# CONFIG_GLOBALVAR is not set

#
# memory layout
#
CONFIG_HAVE_PBL_IMAGE=y
CONFIG_HAVE_PBL_MULTI_IMAGES=y
CONFIG_HAVE_IMAGE_COMPRESSION=y
CONFIG_PBL_IMAGE=y
CONFIG_PBL_MULTI_IMAGES=y
CONFIG_PBL_RELOCATABLE=y
CONFIG_IMAGE_COMPRESSION=y
# CONFIG_IMAGE_COMPRESSION_LZ4 is not set
CONFIG_IMAGE_COMPRESSION_LZO=y
# CONFIG_IMAGE_COMPRESSION_GZIP is not set
# CONFIG_IMAGE_COMPRESSION_XZKERN is not set
# CONFIG_IMAGE_COMPRESSION_NONE is not set
# CONFIG_MMU is not set
CONFIG_BAREBOX_MAX_PBL_SIZE=0xffffffff
CONFIG_BAREBOX_MAX_BARE_INIT_SIZE=0xffffffff
CONFIG_STACK_SIZE=0x8000
CONFIG_MALLOC_SIZE=0x400000
# end of memory layout

# CONFIG_EXPERIMENTAL is not set
# CONFIG_MALLOC_DLMALLOC is not set
CONFIG_MALLOC_TLSF=y
# CONFIG_MALLOC_DUMMY is not set
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
# CONFIG_KALLSYMS is not set
CONFIG_RELOCATABLE=y
# CONFIG_PANIC_HANG is not set
CONFIG_PROMPT="barebox:"
CONFIG_BAUDRATE=115200
CONFIG_SIMPLE_READLINE=y
CONFIG_CBSIZE=1024
# CONFIG_SHELL_HUSH is not set
# CONFIG_SHELL_SIMPLE is not set
CONFIG_SHELL_NONE=y
# CONFIG_GLOB is not set
# CONFIG_PASSWORD is not set
CONFIG_ERRNO_MESSAGES=y
CONFIG_TIMESTAMP=y
# CONFIG_BOOTM is not set
# CONFIG_BAREBOX_UPDATE is not set
# CONFIG_IMD is not set
# CONFIG_CONSOLE_FULL is not set
CONFIG_CONSOLE_SIMPLE=y
# CONFIG_CONSOLE_NONE is not set
# CONFIG_CONSOLE_ALLOW_COLOR is not set
# CONFIG_CONSOLE_DISABLE_INPUT is not set
CONFIG_PBL_CONSOLE=y
CONFIG_PARTITION=y
CONFIG_PARTITION_DISK=y
CONFIG_PARTITION_DISK_DOS=y
# CONFIG_PARTITION_DISK_EFI is not set
# CONFIG_ENV_HANDLING is not set
# CONFIG_DEFAULT_ENVIRONMENT is not set
# CONFIG_DEFAULT_COMPRESSION_GZIP is not set
# CONFIG_DEFAULT_COMPRESSION_LZO is not set
CONFIG_DEFAULT_COMPRESSION_NONE=y
CONFIG_HAS_SCHED=y
CONFIG_POLLER=y
# CONFIG_BTHREAD is not set
# CONFIG_STATE is not set
# CONFIG_BOOTCHOOSER is not set
CONFIG_EXTERNAL_DTS_FRAGMENTS=""

#
# OP-TEE loading
#
# CONFIG_PBL_OPTEE is not set
# end of OP-TEE loading
# end of General Settings

#
# Debugging
#
CONFIG_COMPILE_LOGLEVEL=6
CONFIG_DEFAULT_LOGLEVEL=7
CONFIG_DEBUG_LL=y
CONFIG_DEBUG_AT91_UART=y
CONFIG_DEBUG_AT91_UART_BASE=0xffffee00
# CONFIG_DEBUG_INITCALLS is not set
# CONFIG_DEBUG_PROBES is not set
# CONFIG_PBL_BREAK is not set
# CONFIG_PRINTF_FULL is not set
# CONFIG_UBSAN is not set
CONFIG_HAVE_ARCH_KASAN=y
CONFIG_CC_HAS_KASAN_GENERIC=y
# CONFIG_KASAN is not set
# CONFIG_COMPILE_TEST is not set
# end of Debugging

#
# EFI (Extensible Firmware Interface) Support
#
# end of EFI (Extensible Firmware Interface) Support

CONFIG_HAS_DEBUG_LL=y
# CONFIG_NET is not set

#
# Drivers
#
CONFIG_OFTREE=y
CONFIG_OFTREE_MEM_GENERIC=y
CONFIG_DTC=y
CONFIG_OFDEVICE=y
CONFIG_OF_GPIO=y
# CONFIG_OF_OVERLAY is not set
# CONFIG_AIODEV is not set

#
# serial drivers
#
# CONFIG_DRIVER_SERIAL_ARM_DCC is not set
# CONFIG_DRIVER_SERIAL_NS16550 is not set
CONFIG_DRIVER_SERIAL_ATMEL=y
# CONFIG_DRIVER_SERIAL_CADENCE is not set
# CONFIG_SERIAL_SIFIVE is not set
# end of serial drivers

CONFIG_HAS_MACB=y

#
# SPI drivers
#
# CONFIG_SPI is not set
# end of SPI drivers

# CONFIG_I2C is not set
# CONFIG_MTD is not set
CONFIG_DISK=y
CONFIG_DISK_WRITE=y

#
# drive types
#
# CONFIG_DISK_ATA is not set
# CONFIG_DISK_AHCI is not set

#
# interface types
#
# CONFIG_DISK_INTF_PLATFORM_IDE is not set
# CONFIG_USB_HOST is not set
# CONFIG_USB_GADGET is not set
# CONFIG_USB_MUSB is not set
CONFIG_VIDEO=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
CONFIG_DRIVER_VIDEO_ATMEL=y
# CONFIG_DRIVER_VIDEO_ATMEL_HLCD is not set
# CONFIG_DRIVER_VIDEO_BOCHS_ISA is not set
# CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT is not set
# CONFIG_DRIVER_VIDEO_SIMPLEFB is not set
# CONFIG_DRIVER_VIDEO_EDID is not set
CONFIG_DRIVER_VIDEO_BACKLIGHT=y

#
# Video encoder chips
#
# CONFIG_DRIVER_VIDEO_SIMPLE_PANEL is not set
# CONFIG_SOUND is not set
CONFIG_MCI=y

#
# --- Feature list ---
#
# CONFIG_MCI_STARTUP is not set
CONFIG_MCI_WRITE=y
CONFIG_MCI_MMC_BOOT_PARTITIONS=y
# CONFIG_MCI_MMC_GPP_PARTITIONS is not set

#
# --- MCI host drivers ---
#
# CONFIG_MCI_DW is not set
# CONFIG_MCI_ROCKCHIP_DWCMSHC is not set
CONFIG_MCI_ATMEL=y
# CONFIG_MCI_ATMEL_SDHCI is not set
# CONFIG_MCI_ARASAN is not set
CONFIG_HAVE_CLK=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_OF_PROVIDER=y

#
# Clocksource
#
CONFIG_CLOCKSOURCE_DUMMY_RATE=1000
CONFIG_CLOCKSOURCE_ATMEL_PIT=y
# CONFIG_CLOCKSOURCE_DW_APB_TIMER is not set
# end of Clocksource

#
# Multifunction device drivers
#
CONFIG_MFD_SYSCON=y
# CONFIG_MFD_ATMEL_FLEXCOM is not set
# end of Multifunction device drivers

#
# Misc devices
#
# CONFIG_JTAG is not set
CONFIG_SRAM=y
# CONFIG_DEV_MEM is not set
# CONFIG_UBOOTVAR is not set
# end of Misc devices

CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_LED_GPIO_OF=y
# CONFIG_LED_GPIO_RGB is not set
# CONFIG_LED_GPIO_BICOLOR is not set
CONFIG_LED_TRIGGERS=y

#
# EEPROM support
#
# end of EEPROM support

#
# Input device support
#
CONFIG_INPUT=y
CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_SPECIALKEYS is not set
# end of Input device support

# CONFIG_WATCHDOG is not set
# CONFIG_PWM is not set
# CONFIG_HWRNG is not set

#
# DMA support
#
# end of DMA support

CONFIG_GPIOLIB=y

#
# GPIO
#
# CONFIG_GPIO_74XX_MMIO is not set
# CONFIG_GPIO_GENERIC_PLATFORM is not set
# CONFIG_GPIO_DESIGNWARE is not set
# CONFIG_GPIO_SIFIVE is not set
# end of GPIO

# CONFIG_W1 is not set

#
# Pin controllers
#
CONFIG_PINCTRL=y
CONFIG_PINCTRL_AT91=y
# CONFIG_PINCTRL_AT91PIO4 is not set
# CONFIG_PINCTRL_SINGLE is not set
# end of Pin controllers

# CONFIG_NVMEM is not set

#
# Bus devices
#
# end of Bus devices

# CONFIG_REGULATOR is not set

#
# Remoteproc drivers
#
# CONFIG_REMOTEPROC is not set
# end of Remoteproc drivers

# CONFIG_RESET_CONTROLLER is not set
# CONFIG_RTC_CLASS is not set

#
# Firmware Drivers
#
# end of Firmware Drivers

#
# FPGA Configuration Support
#
# CONFIG_FPGA is not set
# end of FPGA Configuration Support

# CONFIG_GENERIC_PHY is not set
# CONFIG_CRYPTO_HW is not set

#
# Memory controller drivers
#
# end of Memory controller drivers

#
# i.MX SoC drivers
#
# end of i.MX SoC drivers

#
# NVME Support
#
# end of NVME Support

# CONFIG_SYSCON_REBOOT_MODE is not set
# CONFIG_POWER_RESET_SYSCON is not set
# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
# CONFIG_POWER_RESET_GPIO is not set
# CONFIG_POWER_RESET_GPIO_RESTART is not set
# CONFIG_VIRTIO_MENU is not set
# end of Drivers

#
# Filesystem support
#
CONFIG_FS=y
CONFIG_FS_LEGACY=y

#
# Some selected filesystems still use the legacy FS API.
#

#
# Consider updating them.
#
# CONFIG_FS_CRAMFS is not set
# CONFIG_FS_EXT4 is not set
# CONFIG_FS_RAMFS is not set
# CONFIG_FS_DEVFS is not set
CONFIG_FS_FAT=y
CONFIG_FS_FAT_WRITE=y
CONFIG_FS_FAT_LFN=y
# CONFIG_FS_BPKFS is not set
# CONFIG_FS_UIMAGEFS is not set
# CONFIG_FS_PSTORE is not set
# CONFIG_FS_SQUASHFS is not set

#
# ZLIB support disabled
#

#
# LZ4 support disabled
#

#
# LZO support disabled
#

#
# XZ support disabled
#

#
# ZSTD support disabled
#
# end of Filesystem support

#
# Library routines
#
CONFIG_UNCOMPRESS=y
CONFIG_ZLIB=y
# CONFIG_BZLIB is not set
# CONFIG_LZ4_DECOMPRESS is not set
# CONFIG_ZSTD_DECOMPRESS is not set
# CONFIG_XZ_DECOMPRESS is not set
# CONFIG_BASE64 is not set
CONFIG_LZO_DECOMPRESS=y
# CONFIG_ALLOW_PRNG_FALLBACK is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC8 is not set

#
# Library gui routines
#
# end of Library gui routines

# CONFIG_BAREBOX_LOGO is not set
CONFIG_BOOTSTRAP=y
CONFIG_BOOTSTRAP_DEVFS=y
CONFIG_BOOTSTRAP_DISK=y
# CONFIG_NLS is not set
# CONFIG_BLOBGEN is not set
CONFIG_ARCH_HAS_DATA_ABORT_MASK=y
# end of Library routines

#
# Crypto support
#
# CONFIG_DIGEST is not set
# CONFIG_CRYPTO_KEYSTORE is not set
# end of Crypto support

#
# Firmware files
#
CONFIG_EXTRA_FIRMWARE_DIR="firmware"
# end of Firmware files

#
# Host Tools
#
# CONFIG_COMPILE_HOST_TOOLS is not set
# end of Host Tools

#
# Target Tools
#
# CONFIG_KERNEL_INSTALL_TARGET is not set
# CONFIG_BAREBOXENV_TARGET is not set
# CONFIG_BAREBOXCRC32_TARGET is not set
# CONFIG_MVEBU_KWBOOT_TARGET is not set
# end of Target Tools

# CONFIG_TEST is not set


From o.rempel at pengutronix.de  Sun Jan  9 21:33:36 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Mon, 10 Jan 2022 06:33:36 +0100
Subject: Q about bootstrap support for at91sam92* boards and proposal for
 retirement
In-Reply-To: <Yds9TY1wPddN1oNT@ravnborg.org>
References: <Ydsrrj76kk6tmD2X@ravnborg.org>
 <Yds9TY1wPddN1oNT@ravnborg.org>
Message-ID: <20220110053336.GA3326@pengutronix.de>

Hi Sam,

On Sun, Jan 09, 2022 at 08:53:49PM +0100, Sam Ravnborg wrote:
> Hi, 
> > 
> > Can anyone (Ahmad?) help me a little how to get the bootstrap
> > functionality working on the at91sam9263?
> 
> To answer the obvious questions - what have I done so far.
> 
> - I have an at91bootstrap generated BOOT.BIN that works.
>   This ruins out a lot of possible issues with the SD card
>   as the board boots from the SD card with the at91bootstrap based
>   BOOT.BIN.
> 
> - The toolchain used is generated from buildroot, and I do not have any
>   proof that it works as I have not had any successes.
>   So far I have assumed that it works.
> 
> - The configuration used is pasted below.
> 
> - The board I use is the skov-arm9cpu which I know works as it boots
>   barebox with the at91bootstrap BOOT.BIN
> 
> - I have only a limited set of patches - pasted below.
> 
> - Latest barebox from the master branch
> 
> - I have tried to power cycle and reset of the board - no change
> 
> - There is a ">RomBOOT" prompt - but nothing else
> 
> 	Sam

By porting sama5d3 I noticed that bootROM is resetting configuration for
at least some of ip cores. So, the main question is, do everything needed
for uart is still pre-configured? For example pllc and clk settings?

I would recommend to measure with scope the uart lines and see if you
get something and if it is at expected frequency. JTAG would probably
help as well to see what code is currently executed and if register
configurations are in expected state.

As soon as UART is working, every thing else will be not really hard to
do :)

> diff --git a/arch/arm/boards/skov-arm9cpu/lowlevel.c b/arch/arm/boards/skov-arm9cpu/lowlevel.c
> index d335953a7..8d5c0b025 100644
> --- a/arch/arm/boards/skov-arm9cpu/lowlevel.c
> +++ b/arch/arm/boards/skov-arm9cpu/lowlevel.c
> @@ -3,14 +3,20 @@
>  
>  #include <linux/sizes.h>
>  
> +#include <debug_ll.h>
> +
>  #include <asm/barebox-arm.h>
>  
>  #include <mach/at91sam926x_board_init.h>
>  #include <mach/at91sam9263_matrix.h>
> +#include <mach/at91_dbgu.h>
> +#include <mach/iomux.h>
>  
>  #define MASTER_PLL_MUL		171
>  #define MASTER_PLL_DIV		14
>  
> +#define MASTER_CLOCK            (200000000/2)
> +
>  static void __bare_init skovarm9cpu_board_config(struct at91sam926x_board_cfg *cfg)
>  {
>  	/* Disable Watchdog */
> @@ -96,6 +102,18 @@ static void __bare_init skovarm9cpu_board_config(struct at91sam926x_board_cfg *c
>  		AT91_RSTC_RSTTYP_WATCHDOG;
>  }
>  
> +static void dbgu_init(void)
> +{
> +	void __iomem *pio = IOMEM(AT91SAM9263_BASE_PIOC);
> +	// Setup DBGU uart
> +	at91_mux_pio3_pin(pio, pin_to_mask(AT91_PIN_PC30), AT91_MUX_PERIPH_A, GPIO_PULL_UP); // DRXD
> +	at91_mux_pio3_pin(pio, pin_to_mask(AT91_PIN_PC31), AT91_MUX_PERIPH_A, 0); // DTXD
> +
> +	at91_dbgu_setup_ll(IOMEM(AT91_BASE_DBGU1), MASTER_CLOCK, 115200);
> +	pbl_set_putc(at91_dbgu_putc, IOMEM(AT91_BASE_DBGU1));
> +	putc_ll('#');
> +}
> +
>  static void __bare_init skov_arm9cpu_init(void *fdt)
>  {
>  	struct at91sam926x_board_cfg cfg;
> @@ -108,6 +126,8 @@ static void __bare_init skov_arm9cpu_init(void *fdt)
>  	skovarm9cpu_board_config(&cfg);
>  	at91sam9263_board_init(&cfg);
>  
> +	dbgu_init();
> +
>  	barebox_arm_entry(AT91_CHIPSELECT_1, at91_get_sdram_size(cfg.sdramc),
>  			  fdt);
>  }
> 
> #
> # Automatically generated file; DO NOT EDIT.
> # Barebox/arm 2021.12.0 Configuration
> #
> CONFIG_ARM=y
> CONFIG_HAVE_MACH_ARM_HEAD=y
> CONFIG_ARM_USE_COMPRESSED_DTB=y
> CONFIG_TEXT_BASE=0x0
> 
> #
> # System Type
> #
> CONFIG_ARCH_AT91=y
> # CONFIG_ARCH_BCM283X is not set
> # CONFIG_ARCH_CLPS711X is not set
> # CONFIG_ARCH_DAVINCI is not set
> # CONFIG_ARCH_DIGIC is not set
> # CONFIG_ARCH_EP93XX is not set
> # CONFIG_ARCH_IMX is not set
> # CONFIG_ARCH_LAYERSCAPE is not set
> # CONFIG_ARCH_MVEBU is not set
> # CONFIG_ARCH_MXS is not set
> # CONFIG_ARCH_NOMADIK is not set
> # CONFIG_ARCH_OMAP is not set
> # CONFIG_ARCH_PXA is not set
> # CONFIG_ARCH_ROCKCHIP is not set
> # CONFIG_ARCH_SOCFPGA is not set
> # CONFIG_ARCH_S3C24xx is not set
> # CONFIG_ARCH_S5PCxx is not set
> # CONFIG_ARCH_S3C64xx is not set
> # CONFIG_ARCH_STM32MP is not set
> # CONFIG_ARCH_VERSATILE is not set
> # CONFIG_ARCH_VEXPRESS is not set
> # CONFIG_ARCH_TEGRA is not set
> # CONFIG_ARCH_UEMD is not set
> # CONFIG_ARCH_ZYNQ is not set
> # CONFIG_ARCH_ZYNQMP is not set
> # CONFIG_ARCH_ARM64_VIRT is not set
> 
> #
> # Processor Type
> #
> CONFIG_CPU_32=y
> CONFIG_CPU_ARM926T=y
> CONFIG_CPU_32v5=y
> 
> #
> # processor features
> #
> # CONFIG_BOOT_ENDIANNESS_SWITCH is not set
> CONFIG_HAVE_AT91_UTMI=y
> CONFIG_HAVE_AT91_USB_CLK=y
> CONFIG_COMMON_CLK_AT91=y
> CONFIG_HAVE_AT91_SMD=y
> CONFIG_HAVE_AT91_BOOTSTRAP=y
> CONFIG_AT91SAM926X_BOARD_INIT=y
> CONFIG_AT91SAM9_SMC=y
> CONFIG_HAVE_AT91SAM9_RST=y
> CONFIG_SOC_AT91SAM9=y
> CONFIG_ARCH_TEXT_BASE=0x23f00000
> CONFIG_HAVE_AT91_LOAD_BAREBOX_SRAM=y
> 
> #
> # Atmel AT91 System-on-Chip
> #
> CONFIG_SOC_AT91SAM9263=y
> CONFIG_AT91_MULTI_BOARDS=y
> CONFIG_MACH_SKOV_ARM9CPU=y
> # CONFIG_MACH_AT91SAM9263EK is not set
> # CONFIG_MACH_AT91SAM9X5EK is not set
> # CONFIG_MACH_MICROCHIP_KSZ9477_EVB is not set
> # CONFIG_MACH_SAMA5D3_XPLAINED is not set
> # CONFIG_MACH_SAMA5D27_SOM1 is not set
> # CONFIG_MACH_SAMA5D27_GIANTBOARD is not set
> 
> #
> # AT91 Board Options
> #
> CONFIG_AT91_BOOTSTRAP=y
> # CONFIG_AT91_LOAD_BAREBOX_SRAM is not set
> CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x40000
> # CONFIG_BOARD_ARM_GENERIC_DT is not set
> # CONFIG_AEABI is not set
> # end of System Type
> 
> #
> # ARM specific settings
> #
> # CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS is not set
> CONFIG_ARM_EXCEPTIONS=y
> # CONFIG_ARM_SEMIHOSTING is not set
> # end of ARM specific settings
> 
> CONFIG_GREGORIAN_CALENDER=y
> CONFIG_HAS_KALLSYMS=y
> CONFIG_HAS_MODULES=y
> CONFIG_HAS_CACHE=y
> CONFIG_HAS_DMA=y
> CONFIG_HAS_ARCH_SJLJ=y
> CONFIG_GENERIC_GPIO=y
> CONFIG_BLOCK=y
> CONFIG_BLOCK_WRITE=y
> CONFIG_USE_COMPRESSED_DTB=y
> CONFIG_FILETYPE=y
> 
> #
> # General Settings
> #
> CONFIG_LOCALVERSION=""
> CONFIG_LOCALVERSION_AUTO=y
> CONFIG_BANNER=y
> CONFIG_MEMINFO=y
> # CONFIG_ENVIRONMENT_VARIABLES is not set
> # CONFIG_GLOBALVAR is not set
> 
> #
> # memory layout
> #
> CONFIG_HAVE_PBL_IMAGE=y
> CONFIG_HAVE_PBL_MULTI_IMAGES=y
> CONFIG_HAVE_IMAGE_COMPRESSION=y
> CONFIG_PBL_IMAGE=y
> CONFIG_PBL_MULTI_IMAGES=y
> CONFIG_PBL_RELOCATABLE=y
> CONFIG_IMAGE_COMPRESSION=y
> # CONFIG_IMAGE_COMPRESSION_LZ4 is not set
> CONFIG_IMAGE_COMPRESSION_LZO=y
> # CONFIG_IMAGE_COMPRESSION_GZIP is not set
> # CONFIG_IMAGE_COMPRESSION_XZKERN is not set
> # CONFIG_IMAGE_COMPRESSION_NONE is not set
> # CONFIG_MMU is not set
> CONFIG_BAREBOX_MAX_PBL_SIZE=0xffffffff
> CONFIG_BAREBOX_MAX_BARE_INIT_SIZE=0xffffffff
> CONFIG_STACK_SIZE=0x8000
> CONFIG_MALLOC_SIZE=0x400000
> # end of memory layout
> 
> # CONFIG_EXPERIMENTAL is not set
> # CONFIG_MALLOC_DLMALLOC is not set
> CONFIG_MALLOC_TLSF=y
> # CONFIG_MALLOC_DUMMY is not set
> CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
> # CONFIG_KALLSYMS is not set
> CONFIG_RELOCATABLE=y
> # CONFIG_PANIC_HANG is not set
> CONFIG_PROMPT="barebox:"
> CONFIG_BAUDRATE=115200
> CONFIG_SIMPLE_READLINE=y
> CONFIG_CBSIZE=1024
> # CONFIG_SHELL_HUSH is not set
> # CONFIG_SHELL_SIMPLE is not set
> CONFIG_SHELL_NONE=y
> # CONFIG_GLOB is not set
> # CONFIG_PASSWORD is not set
> CONFIG_ERRNO_MESSAGES=y
> CONFIG_TIMESTAMP=y
> # CONFIG_BOOTM is not set
> # CONFIG_BAREBOX_UPDATE is not set
> # CONFIG_IMD is not set
> # CONFIG_CONSOLE_FULL is not set
> CONFIG_CONSOLE_SIMPLE=y
> # CONFIG_CONSOLE_NONE is not set
> # CONFIG_CONSOLE_ALLOW_COLOR is not set
> # CONFIG_CONSOLE_DISABLE_INPUT is not set
> CONFIG_PBL_CONSOLE=y
> CONFIG_PARTITION=y
> CONFIG_PARTITION_DISK=y
> CONFIG_PARTITION_DISK_DOS=y
> # CONFIG_PARTITION_DISK_EFI is not set
> # CONFIG_ENV_HANDLING is not set
> # CONFIG_DEFAULT_ENVIRONMENT is not set
> # CONFIG_DEFAULT_COMPRESSION_GZIP is not set
> # CONFIG_DEFAULT_COMPRESSION_LZO is not set
> CONFIG_DEFAULT_COMPRESSION_NONE=y
> CONFIG_HAS_SCHED=y
> CONFIG_POLLER=y
> # CONFIG_BTHREAD is not set
> # CONFIG_STATE is not set
> # CONFIG_BOOTCHOOSER is not set
> CONFIG_EXTERNAL_DTS_FRAGMENTS=""
> 
> #
> # OP-TEE loading
> #
> # CONFIG_PBL_OPTEE is not set
> # end of OP-TEE loading
> # end of General Settings
> 
> #
> # Debugging
> #
> CONFIG_COMPILE_LOGLEVEL=6
> CONFIG_DEFAULT_LOGLEVEL=7
> CONFIG_DEBUG_LL=y
> CONFIG_DEBUG_AT91_UART=y
> CONFIG_DEBUG_AT91_UART_BASE=0xffffee00
> # CONFIG_DEBUG_INITCALLS is not set
> # CONFIG_DEBUG_PROBES is not set
> # CONFIG_PBL_BREAK is not set
> # CONFIG_PRINTF_FULL is not set
> # CONFIG_UBSAN is not set
> CONFIG_HAVE_ARCH_KASAN=y
> CONFIG_CC_HAS_KASAN_GENERIC=y
> # CONFIG_KASAN is not set
> # CONFIG_COMPILE_TEST is not set
> # end of Debugging
> 
> #
> # EFI (Extensible Firmware Interface) Support
> #
> # end of EFI (Extensible Firmware Interface) Support
> 
> CONFIG_HAS_DEBUG_LL=y
> # CONFIG_NET is not set
> 
> #
> # Drivers
> #
> CONFIG_OFTREE=y
> CONFIG_OFTREE_MEM_GENERIC=y
> CONFIG_DTC=y
> CONFIG_OFDEVICE=y
> CONFIG_OF_GPIO=y
> # CONFIG_OF_OVERLAY is not set
> # CONFIG_AIODEV is not set
> 
> #
> # serial drivers
> #
> # CONFIG_DRIVER_SERIAL_ARM_DCC is not set
> # CONFIG_DRIVER_SERIAL_NS16550 is not set
> CONFIG_DRIVER_SERIAL_ATMEL=y
> # CONFIG_DRIVER_SERIAL_CADENCE is not set
> # CONFIG_SERIAL_SIFIVE is not set
> # end of serial drivers
> 
> CONFIG_HAS_MACB=y
> 
> #
> # SPI drivers
> #
> # CONFIG_SPI is not set
> # end of SPI drivers
> 
> # CONFIG_I2C is not set
> # CONFIG_MTD is not set
> CONFIG_DISK=y
> CONFIG_DISK_WRITE=y
> 
> #
> # drive types
> #
> # CONFIG_DISK_ATA is not set
> # CONFIG_DISK_AHCI is not set
> 
> #
> # interface types
> #
> # CONFIG_DISK_INTF_PLATFORM_IDE is not set
> # CONFIG_USB_HOST is not set
> # CONFIG_USB_GADGET is not set
> # CONFIG_USB_MUSB is not set
> CONFIG_VIDEO=y
> # CONFIG_FRAMEBUFFER_CONSOLE is not set
> CONFIG_DRIVER_VIDEO_ATMEL=y
> # CONFIG_DRIVER_VIDEO_ATMEL_HLCD is not set
> # CONFIG_DRIVER_VIDEO_BOCHS_ISA is not set
> # CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT is not set
> # CONFIG_DRIVER_VIDEO_SIMPLEFB is not set
> # CONFIG_DRIVER_VIDEO_EDID is not set
> CONFIG_DRIVER_VIDEO_BACKLIGHT=y
> 
> #
> # Video encoder chips
> #
> # CONFIG_DRIVER_VIDEO_SIMPLE_PANEL is not set
> # CONFIG_SOUND is not set
> CONFIG_MCI=y
> 
> #
> # --- Feature list ---
> #
> # CONFIG_MCI_STARTUP is not set
> CONFIG_MCI_WRITE=y
> CONFIG_MCI_MMC_BOOT_PARTITIONS=y
> # CONFIG_MCI_MMC_GPP_PARTITIONS is not set
> 
> #
> # --- MCI host drivers ---
> #
> # CONFIG_MCI_DW is not set
> # CONFIG_MCI_ROCKCHIP_DWCMSHC is not set
> CONFIG_MCI_ATMEL=y
> # CONFIG_MCI_ATMEL_SDHCI is not set
> # CONFIG_MCI_ARASAN is not set
> CONFIG_HAVE_CLK=y
> CONFIG_CLKDEV_LOOKUP=y
> CONFIG_COMMON_CLK=y
> CONFIG_COMMON_CLK_OF_PROVIDER=y
> 
> #
> # Clocksource
> #
> CONFIG_CLOCKSOURCE_DUMMY_RATE=1000
> CONFIG_CLOCKSOURCE_ATMEL_PIT=y
> # CONFIG_CLOCKSOURCE_DW_APB_TIMER is not set
> # end of Clocksource
> 
> #
> # Multifunction device drivers
> #
> CONFIG_MFD_SYSCON=y
> # CONFIG_MFD_ATMEL_FLEXCOM is not set
> # end of Multifunction device drivers
> 
> #
> # Misc devices
> #
> # CONFIG_JTAG is not set
> CONFIG_SRAM=y
> # CONFIG_DEV_MEM is not set
> # CONFIG_UBOOTVAR is not set
> # end of Misc devices
> 
> CONFIG_LED=y
> CONFIG_LED_GPIO=y
> CONFIG_LED_GPIO_OF=y
> # CONFIG_LED_GPIO_RGB is not set
> # CONFIG_LED_GPIO_BICOLOR is not set
> CONFIG_LED_TRIGGERS=y
> 
> #
> # EEPROM support
> #
> # end of EEPROM support
> 
> #
> # Input device support
> #
> CONFIG_INPUT=y
> CONFIG_KEYBOARD_GPIO=y
> # CONFIG_INPUT_SPECIALKEYS is not set
> # end of Input device support
> 
> # CONFIG_WATCHDOG is not set
> # CONFIG_PWM is not set
> # CONFIG_HWRNG is not set
> 
> #
> # DMA support
> #
> # end of DMA support
> 
> CONFIG_GPIOLIB=y
> 
> #
> # GPIO
> #
> # CONFIG_GPIO_74XX_MMIO is not set
> # CONFIG_GPIO_GENERIC_PLATFORM is not set
> # CONFIG_GPIO_DESIGNWARE is not set
> # CONFIG_GPIO_SIFIVE is not set
> # end of GPIO
> 
> # CONFIG_W1 is not set
> 
> #
> # Pin controllers
> #
> CONFIG_PINCTRL=y
> CONFIG_PINCTRL_AT91=y
> # CONFIG_PINCTRL_AT91PIO4 is not set
> # CONFIG_PINCTRL_SINGLE is not set
> # end of Pin controllers
> 
> # CONFIG_NVMEM is not set
> 
> #
> # Bus devices
> #
> # end of Bus devices
> 
> # CONFIG_REGULATOR is not set
> 
> #
> # Remoteproc drivers
> #
> # CONFIG_REMOTEPROC is not set
> # end of Remoteproc drivers
> 
> # CONFIG_RESET_CONTROLLER is not set
> # CONFIG_RTC_CLASS is not set
> 
> #
> # Firmware Drivers
> #
> # end of Firmware Drivers
> 
> #
> # FPGA Configuration Support
> #
> # CONFIG_FPGA is not set
> # end of FPGA Configuration Support
> 
> # CONFIG_GENERIC_PHY is not set
> # CONFIG_CRYPTO_HW is not set
> 
> #
> # Memory controller drivers
> #
> # end of Memory controller drivers
> 
> #
> # i.MX SoC drivers
> #
> # end of i.MX SoC drivers
> 
> #
> # NVME Support
> #
> # end of NVME Support
> 
> # CONFIG_SYSCON_REBOOT_MODE is not set
> # CONFIG_POWER_RESET_SYSCON is not set
> # CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
> # CONFIG_POWER_RESET_GPIO is not set
> # CONFIG_POWER_RESET_GPIO_RESTART is not set
> # CONFIG_VIRTIO_MENU is not set
> # end of Drivers
> 
> #
> # Filesystem support
> #
> CONFIG_FS=y
> CONFIG_FS_LEGACY=y
> 
> #
> # Some selected filesystems still use the legacy FS API.
> #
> 
> #
> # Consider updating them.
> #
> # CONFIG_FS_CRAMFS is not set
> # CONFIG_FS_EXT4 is not set
> # CONFIG_FS_RAMFS is not set
> # CONFIG_FS_DEVFS is not set
> CONFIG_FS_FAT=y
> CONFIG_FS_FAT_WRITE=y
> CONFIG_FS_FAT_LFN=y
> # CONFIG_FS_BPKFS is not set
> # CONFIG_FS_UIMAGEFS is not set
> # CONFIG_FS_PSTORE is not set
> # CONFIG_FS_SQUASHFS is not set
> 
> #
> # ZLIB support disabled
> #
> 
> #
> # LZ4 support disabled
> #
> 
> #
> # LZO support disabled
> #
> 
> #
> # XZ support disabled
> #
> 
> #
> # ZSTD support disabled
> #
> # end of Filesystem support
> 
> #
> # Library routines
> #
> CONFIG_UNCOMPRESS=y
> CONFIG_ZLIB=y
> # CONFIG_BZLIB is not set
> # CONFIG_LZ4_DECOMPRESS is not set
> # CONFIG_ZSTD_DECOMPRESS is not set
> # CONFIG_XZ_DECOMPRESS is not set
> # CONFIG_BASE64 is not set
> CONFIG_LZO_DECOMPRESS=y
> # CONFIG_ALLOW_PRNG_FALLBACK is not set
> # CONFIG_CRC_CCITT is not set
> # CONFIG_CRC8 is not set
> 
> #
> # Library gui routines
> #
> # end of Library gui routines
> 
> # CONFIG_BAREBOX_LOGO is not set
> CONFIG_BOOTSTRAP=y
> CONFIG_BOOTSTRAP_DEVFS=y
> CONFIG_BOOTSTRAP_DISK=y
> # CONFIG_NLS is not set
> # CONFIG_BLOBGEN is not set
> CONFIG_ARCH_HAS_DATA_ABORT_MASK=y
> # end of Library routines
> 
> #
> # Crypto support
> #
> # CONFIG_DIGEST is not set
> # CONFIG_CRYPTO_KEYSTORE is not set
> # end of Crypto support
> 
> #
> # Firmware files
> #
> CONFIG_EXTRA_FIRMWARE_DIR="firmware"
> # end of Firmware files
> 
> #
> # Host Tools
> #
> # CONFIG_COMPILE_HOST_TOOLS is not set
> # end of Host Tools
> 
> #
> # Target Tools
> #
> # CONFIG_KERNEL_INSTALL_TARGET is not set
> # CONFIG_BAREBOXENV_TARGET is not set
> # CONFIG_BAREBOXCRC32_TARGET is not set
> # CONFIG_MVEBU_KWBOOT_TARGET is not set
> # end of Target Tools
> 
> # CONFIG_TEST is not set
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:18:33 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:18:33 +0100
Subject: [PATCH master] x86: <asm/io.h>: fix outl/outsl access size
In-Reply-To: <20220107063644.22595-1-a.fatoum@pengutronix.de>
References: <20220107063644.22595-1-a.fatoum@pengutronix.de>
Message-ID: <20220110081833.GY6003@pengutronix.de>

On Fri, Jan 07, 2022 at 07:36:44AM +0100, Ahmad Fatoum wrote:
> outl so far behaved like outb, probably due to a copy-paste error when
> it was first added. We have three users in-tree for outl:
> 
> * drivers/serial/serial_ns16550_pci.c
>   only for handling a Quatech qurik, which probably no one ever needed
> 
> * drivers/serial/serial_ns16550.c
>   For platform drivers with a 4 byte I/O port resource. Only possible
>   user is x86 and that has a 1 byte I/O port resource. Thus no one
>   used this either.
> 
> * drivers/watchdog/itco_wdt.c
>   Here it indeed triggers a bug, although in my testing the WDAT
>   was functional without.
> 
> Fix this up so new code doesn't have to track this down.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> Cc: Steffen Trumtrar <str at pengutronix.de>
> ---
>  arch/x86/include/asm/io.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:19:08 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:19:08 +0100
Subject: [PATCH] drivers: virtio: import list of newer Virtio IDs
In-Reply-To: <20220107080104.135200-1-ahmad@a3f.at>
References: <20220107080104.135200-1-ahmad@a3f.at>
Message-ID: <20220110081908.GZ6003@pengutronix.de>

On Fri, Jan 07, 2022 at 09:01:04AM +0100, Ahmad Fatoum wrote:
> These are unused now.
> 
> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
> ---
>  include/uapi/linux/virtio_ids.h | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:20:12 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:20:12 +0100
Subject: [PATCH] commands: hashsum: Fix endif typos
In-Reply-To: <20220107092729.17929-1-enguerrand.de-ribaucourt@savoirfairelinux.com>
References: <20220107092729.17929-1-enguerrand.de-ribaucourt@savoirfairelinux.com>
Message-ID: <20220110082012.GA6003@pengutronix.de>

On Fri, Jan 07, 2022 at 10:27:29AM +0100, Enguerrand de Ribaucourt wrote:
> Fix the comments in endif to correspond to the symbol of their
> ifdef.
> 
> Signed-off-by: Enguerrand de Ribaucourt <enguerrand.de-ribaucourt at savoirfairelinux.com>
> ---
>  commands/hashsum.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:42:15 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:42:15 +0100
Subject: [PATCH 1/2] acpi.h: add defines for adr_space and gas
In-Reply-To: <20220107134219.1031552-1-s.trumtrar@pengutronix.de>
References: <20220107134219.1031552-1-s.trumtrar@pengutronix.de>
Message-ID: <20220110084215.GB6003@pengutronix.de>

On Fri, Jan 07, 2022 at 02:42:18PM +0100, Steffen Trumtrar wrote:
> From linux v5.15-rc1.
> 
> Signed-off-by: Steffen Trumtrar <str at pengutronix.de>
> ---
>  include/acpi.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 72 insertions(+)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:48:22 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:48:22 +0100
Subject: [PATCH 1/2] common: boards: qemu-virt: fix dtc warning
In-Reply-To: <20220108171356.586099-1-a.fatoum@pengutronix.de>
References: <20220108171356.586099-1-a.fatoum@pengutronix.de>
Message-ID: <20220110084822.GC6003@pengutronix.de>

On Sat, Jan 08, 2022 at 06:13:55PM +0100, Ahmad Fatoum wrote:
> DTC complains about a Warning (chosen_node_is_root):
> 
>   /fragment at 1/__overlay__/chosen: chosen node must be at root node
> 
> As /chosen is already available in the device tree of all of:
> 
>   - ARM 32-Bit QEMU Virt
>   - ARM 64-Bit QEMU Virt
>   - RISC-V 32-Bit QEMU Virt
>   - RISC-V 64-Bit QEMU Virt
> 
> Just reference that in a new fragment to silence the warning.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  common/boards/qemu-virt/overlay-of-flash.dts | 17 +++++++++++------
>  1 file changed, 11 insertions(+), 6 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:56:34 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:56:34 +0100
Subject: [PATCH 3/3] commands: add new devunbind debugging command
In-Reply-To: <20220108171426.586330-3-a.fatoum@pengutronix.de>
References: <20220108171426.586330-1-a.fatoum@pengutronix.de>
 <20220108171426.586330-3-a.fatoum@pengutronix.de>
Message-ID: <20220110085634.GD6003@pengutronix.de>

On Sat, Jan 08, 2022 at 06:14:26PM +0100, Ahmad Fatoum wrote:
> Memory corruption around device removal may go unnoticed, because
> barebox is shutting down anyway and doing no new allocations.
> 
> Add a new devunbind command that should help with debugging such issues
> by allowing selective unbinding and removal of devices.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  commands/Kconfig      | 12 +++++++
>  commands/Makefile     |  1 +
>  commands/devunbind.c  | 74 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/base/driver.c |  7 ++--
>  include/driver.h      |  4 +++
>  5 files changed, 95 insertions(+), 3 deletions(-)
>  create mode 100644 commands/devunbind.c
> 
> diff --git a/commands/Kconfig b/commands/Kconfig
> index e2c36949347e..9abd97271952 100644
> --- a/commands/Kconfig
> +++ b/commands/Kconfig
> @@ -68,6 +68,18 @@ config CMD_DEVINFO
>  	  If called with a device path being the argument, devinfo shows more
>  	  default information about this device and its parameters.
>  
> +config CMD_DEVUNBIND
> +	tristate
> +	default y
> +	prompt "devunbind"
> +	help
> +	  Debugging aid to unbind device from driver at runtime
> +
> +	  devunbind [-f] DEVICE
> +
> +	  Options:
> +	    -f   unbind driver and force removal of device and children
> +
>  config CMD_DMESG
>  	tristate
>  	prompt "dmesg"
> diff --git a/commands/Makefile b/commands/Makefile
> index 0b7c1563b534..875826743ffe 100644
> --- a/commands/Makefile
> +++ b/commands/Makefile
> @@ -107,6 +107,7 @@ obj-$(CONFIG_CMD_MIITOOL)	+= miitool.o
>  obj-$(CONFIG_CMD_DETECT)	+= detect.o
>  obj-$(CONFIG_CMD_BOOT)		+= boot.o
>  obj-$(CONFIG_CMD_DEVINFO)	+= devinfo.o
> +obj-$(CONFIG_CMD_DEVUNBIND)	+= devunbind.o
>  obj-$(CONFIG_CMD_DRVINFO)	+= drvinfo.o
>  obj-$(CONFIG_CMD_READF)		+= readf.o
>  obj-$(CONFIG_CMD_MENUTREE)	+= menutree.o
> diff --git a/commands/devunbind.c b/commands/devunbind.c
> new file mode 100644
> index 000000000000..4bebb27e8e68
> --- /dev/null
> +++ b/commands/devunbind.c
> @@ -0,0 +1,74 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// SPDX-FileCopyrightText: ? 2021 Ahmad Fatoum <a.fatoum at pengutronix.de>, Pengutronix
> +
> +#include <command.h>
> +#include <common.h>
> +#include <complete.h>
> +#include <driver.h>
> +#include <getopt.h>
> +
> +static int do_devunbind(int argc, char *argv[])
> +{
> +	bool unregister = false;
> +	struct device_d *dev;
> +	int ret = COMMAND_SUCCESS, i, opt;
> +
> +	while ((opt = getopt(argc, argv, "fl")) > 0) {
> +		switch (opt) {
> +		case 'f':
> +			unregister = true;
> +			break;
> +		case 'l':
> +			list_for_each_entry(dev, &active_device_list, active) {
> +				BUG_ON(!dev->driver);
> +				if (dev->bus->remove)
> +					printf("%pS(%s, %s)\n", dev->bus->remove,
> +					       dev->driver->name, dev_name(dev));
> +			}
> +			return 0;
> +		default:
> +			return COMMAND_ERROR_USAGE;
> +		}
> +	}
> +
> +	if (!argv[optind])
> +		return COMMAND_ERROR_USAGE;
> +
> +	for (i = optind; i < argc; i++) {
> +		dev = get_device_by_name(argv[i]);
> +		if (!dev)
> +			return -ENODEV;
> +
> +		if (unregister)
> +			return unregister_device(dev);

Shouldn't you continue the loop here?

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:57:11 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:57:11 +0100
Subject: [PATCH] include <printk.h>: include <linux/types.h> for size_t
 definition
In-Reply-To: <20220108171437.586532-1-a.fatoum@pengutronix.de>
References: <20220108171437.586532-1-a.fatoum@pengutronix.de>
Message-ID: <20220110085711.GE6003@pengutronix.de>

On Sat, Jan 08, 2022 at 06:14:37PM +0100, Ahmad Fatoum wrote:
> size_t is used without previous definition relying on header include
> order. Fix that up.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  include/printk.h | 2 ++
>  1 file changed, 2 insertions(+)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 00:58:38 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 09:58:38 +0100
Subject: [PATCH] include: <asm/csr.h>: sync with upstream
In-Reply-To: <20220108171445.586681-1-a.fatoum@pengutronix.de>
References: <20220108171445.586681-1-a.fatoum@pengutronix.de>
Message-ID: <20220110085838.GF6003@pengutronix.de>

On Sat, Jan 08, 2022 at 06:14:45PM +0100, Ahmad Fatoum wrote:
> We don't define CONFIG_RISCV_PRIV_1_9, so deleted stuff by the sync is
> unused anyway. No functional change.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  arch/riscv/include/asm/csr.h | 213 ++++++++++++++++++++++++++---------
>  1 file changed, 161 insertions(+), 52 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 10 01:42:14 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Jan 2022 10:42:14 +0100
Subject: barebox extending boot-scripts
In-Reply-To: <trinity-f8991630-17eb-4ae0-9dfa-9a66bc41b02e-1641573741990@3c-app-gmx-bs48>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
 <trinity-7a53a76e-9836-482e-861e-31439f242e2d-1641472899713@3c-app-gmx-bs51>
 <20220107130751.GW6003@pengutronix.de>
 <trinity-f8991630-17eb-4ae0-9dfa-9a66bc41b02e-1641573741990@3c-app-gmx-bs48>
Message-ID: <20220110094214.GG6003@pengutronix.de>

On Fri, Jan 07, 2022 at 05:42:22PM +0100, Frank Wunderlich wrote:
> Hi
> 
> missed the defaultenv_append_directory(defaultenv_rk3568); in board-file...after adding that it seems to work
> 
> > Gesendet: Freitag, 07. Januar 2022 um 14:07 Uhr
> > Von: "Sascha Hauer" <sha at pengutronix.de>
> >
> > Yes. Furthermore you have to add to the board code:
> >
> > 	defaultenv_append_directory(defaultenv_rk3568);
> 
> maybe this is the part i've missed. i thought it were 2 ways...either link via makefile or add to boards code
> 
> > > > > > Boot scripts for publicly available evaluation kits are often not good candidates
> > > > > > for upstreaming, because everybody using the EVKs has different thoughts on how to
> > > > > > boot. The best way would be to use bootloader spec. It's one or more files you
> > > > > > place at a known location that describe where your kernel and device tree are and
> > > > > > what command line arguments to use and barebox can then automatically generate
> > > > > > boot entries from all available bootloader spec files.
> > >
> > > is extlinux (i used in uboot and conf-file is already present) supported here?
> > >
> > > > > > See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
> > > > > > of how to set this up. This is what I'd recommend instead of writing your own
> > > > > > scripts.
> > >
> > > i do not fully understand the bootloader spec in the pdf as config file seems to be
> > >
> > > /mnt/mmc0.4/loader/entries/stm32mp157c-dk2.conf
> > >
> > > and then
> > > boot -d mmc0.4
> > >
> > > is run...so the path (loader/entries) seems to be fixed and all files there will be processed (which order)?
> >
> > Yes. No particular order, I guess it would be the order it is on the
> > filesystem.
> >
> > > how is root appended (/dev/mmcblkXpY|uuid|...) when linux-appendroot is set to true?
> >
> > When root is appended it is assumed to be the same fs that also has the
> > bootloader spec file, so the rootfs also has the entry and the kernel.
> 
> ok, then this is not usable for me, as i have a boot-partition
> (bootloader+kernel+dtb) and separate rootfs-partition
> 
> > > this is for testing multiple kernels with changing filenames (very
> > > dynamic process, e.g. using 1 kernel binary with multiple dtb) and to
> > > avoid adding a bootmenu entry everytime....this is not for end-user :)
> >
> > In that case you could also use bootm directly.
> 
> yes but my approach is to list the available kernels before and ask to
> enter the filename to not everytime look for correct commands ;)
> 
> > > and here scripting is imho the best way...this allows me to add extra
> > > params to cmdline too (like debug level,dumping offsets) without
> > > changing a distroboot config
> >
> > Not sure if you know already, but barebox concatenates all variables in
> > the "global.linux.bootargs." namespace to the kernel command line, so
> > you can easily add or remove a variable to add/remove kernel options
> > without affecting unrelated options.
> 
> i know some options from documentation like this i've used to get a earlycon for tftp
> 
> global linux.bootargs.debug="earlycon=uart8250,mmio32,0xfe660000 earlyprintk"
> 
> > > for fixed kernels i have defined an extlinux.conf for uboot, but i'm
> > > unsure if barebox can use this file too. have not found anything about
> > > extlinux/syslinux in barebox yet.
> >
> > No, not yet.
> 
> ok, i created a bootloader-config like described in the pdf:
> 
> cat /mnt/sd.1/loader/entries/linux-gz.conf
> title Linux GZip
> version 5.16
> options earlycon=uart8250,mmio32,0xfe660000 console=ttyS2,1500000n8
> linux /extlinux/Image_5.16.gz
> devicetree /extlinux/dtb_5.16
> initrd /rootfs.cpio.lz4
> 
> but on starting it is skipped due to devicetree mismatch
> 
> boot -d sd.1
> blspec: ignoring entry with incompatible devicetree "rockchip,rk3568-bpi-r2pro"
> blspec: ignoring entry with incompatible devicetree "rockchip,rk3568-bpi-r2pro"
> Nothing bootable found on 'sd.1'
> Nothing bootable found
> 
> in barebox i use the evb whereas in linux i already have a separate
> dts. Can i override the compatible for the bootloader or do i need to
> add my board (as copy of evb first)?

You can overwrite the compatible using the of_property command. However,
I really recommend to add a separate barebox board for your board.
Sooner or later you'll have to do this anyway and it's the only way to
properly add quirks for your board.

> 
> btw. don't you get my direct messages (regarding vop2 driver for
> rk3568 and the result of my barebox environment-tests)?

Yes, I received them, but probably forgot to answer them because you
didn't ask a question ;)

Regards,
 Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan 10 02:48:31 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 10 Jan 2022 11:48:31 +0100
Subject: [PATCH] misc: acpi-test: retire test driver in favor of WDAT driver
Message-ID: <20220110104831.3149574-1-a.fatoum@pengutronix.de>

With the integration of the ACPI WDAT watchdog driver, we now have an
actually useful user of the ACPI bus in tree, so the test driver
serves no purpose anymore. Drop it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/misc/Kconfig     |  6 ----
 drivers/misc/Makefile    |  1 -
 drivers/misc/acpi-test.c | 61 ----------------------------------------
 3 files changed, 68 deletions(-)
 delete mode 100644 drivers/misc/acpi-test.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 56569145076e..5ab0506cd9fa 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -37,12 +37,6 @@ config UBOOTVAR
 	  While it can be used standalone, it is best when coupled
 	  with corresponding filesystem driver.
 
-config ACPI_TEST
-	bool "ACPI Test driver"
-	depends on ACPI
-	help
-	  This is a simple Test driver to test the ACPI bus.
-
 config STARFIVE_PWRSEQ
 	bool "StarFive power sequencing driver"
 	depends on SOC_STARFIVE
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 05da264a426d..6326e784fc98 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -8,5 +8,4 @@ obj-$(CONFIG_SRAM)		+= sram.o
 obj-$(CONFIG_STATE_DRV)		+= state.o
 obj-$(CONFIG_DEV_MEM)		+= mem.o
 obj-$(CONFIG_UBOOTVAR)		+= ubootvar.o
-obj-$(CONFIG_ACPI_TEST)		+= acpi-test.o
 obj-$(CONFIG_STARFIVE_PWRSEQ)	+= starfive-pwrseq.o
diff --git a/drivers/misc/acpi-test.c b/drivers/misc/acpi-test.c
deleted file mode 100644
index af20370fbc73..000000000000
--- a/drivers/misc/acpi-test.c
+++ /dev/null
@@ -1,61 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2019 Ahmad Fatoum
- */
-
-#include <common.h>
-#include <init.h>
-#include <acpi.h>
-
-static const char *profiles[] = {
-	"Unspecified",
-	"Desktop",
-	"Mobile",
-	"Workstation",
-	"Enterprise Server",
-	"SOHO Server",
-	"Applicance PC",
-	"Performance Server",
-	"Tablet",
-};
-
-static int acpi_test_probe(struct device_d *dev)
-{
-	const char *profile = "reserved";
-	u8 *sdt;
-	u8 profileno;
-
-	dev_dbg(dev, "driver initializing...\n");
-
-	sdt = (u8 __force *)dev_request_mem_region_by_name(dev, "SDT");
-	if (IS_ERR(sdt)) {
-		dev_err(dev, "no SDT resource available: %pe\n", sdt);
-		return PTR_ERR(sdt);
-	}
-
-	dev_dbg(dev, "SDT is at 0x%p\n", sdt);
-
-	profileno = sdt[45];
-
-	if (profileno < ARRAY_SIZE(profiles))
-		profile = profiles[profileno];
-
-	dev_info(dev, "PM profile is for '%s'\n", profile);
-
-	return 0;
-}
-
-static void acpi_test_remove(struct device_d *dev)
-{
-	dev_dbg(dev, "FADT driver removed\n");
-}
-
-static struct acpi_driver acpi_test_driver = {
-	.signature = "FACP",
-	.driver = {
-		.name = "acpi-test",
-		.probe = acpi_test_probe,
-		.remove = acpi_test_remove,
-	}
-};
-device_acpi_driver(acpi_test_driver);
-- 
2.30.2



From antonynpavlov at gmail.com  Mon Jan 10 02:59:46 2022
From: antonynpavlov at gmail.com (Antony Pavlov)
Date: Mon, 10 Jan 2022 13:59:46 +0300
Subject: [PATCH 7/9] RISC-V: don't use x8/s0/fp in assembly
In-Reply-To: <6136d698-30cd-12a7-58e4-a6598ff3a86e@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
 <20220108171524.587144-7-a.fatoum@pengutronix.de>
 <6136d698-30cd-12a7-58e4-a6598ff3a86e@pengutronix.de>
Message-ID: <20220110135946.772f42aea56fedc19c68c2d8@gmail.com>

On Sat, 8 Jan 2022 19:25:03 +0100
Ahmad Fatoum <a.fatoum at pengutronix.de> wrote:

Hi Ahmad!

> Hello Antony,
> 
> On 08.01.22 18:15, Ahmad Fatoum wrote:
> > Free up the register to allow building a configuration with x8/s0 used
> > as the frame pointer.
> > 
> > Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> > ---
> >  arch/riscv/include/asm/debug_ll_litex.h   | 12 +++---
> >  arch/riscv/include/asm/debug_ll_ns16550.h |  8 ++--
> >  arch/riscv/include/asm/riscv_nmon.h       | 50 +++++++++++------------
> 
> I just bumped the s register: s2 -> s3, s1 -> s2, s0 -> s1 to
> clear s0. Is that ok?

I suppose that there is no problem if nmon still works under qemu.


> >  3 files changed, 35 insertions(+), 35 deletions(-)
> > 
> > diff --git a/arch/riscv/include/asm/debug_ll_litex.h b/arch/riscv/include/asm/debug_ll_litex.h
> > index 2fcdd9b0ec3e..295477fc1010 100644
> > --- a/arch/riscv/include/asm/debug_ll_litex.h
> > +++ b/arch/riscv/include/asm/debug_ll_litex.h
> > @@ -90,11 +90,11 @@ static inline void PUTC_LL(char ch)
> >  	li	t0, DEBUG_LL_UART_ADDR
> >  
> >  	/* get line status and check for data present */
> > -	lbu	s0, UART_RXEMPTY(t0)
> > -	bnez    s0, 243f
> > -	li	s0, 1
> > +	lbu	s1, UART_RXEMPTY(t0)
> > +	bnez    s1, 243f
> > +	li	s1, 1
> >  	j	244f
> > -243:	li	s0, 0
> > +243:	li	s1, 0
> >  244:	nop
> >  #endif /* CONFIG_DEBUG_LL */
> >  .endm
> > @@ -109,10 +109,10 @@ static inline void PUTC_LL(char ch)
> >  	debug_ll_tstc
> >  
> >  	/* try again */
> > -	beqz	s0, 204b
> > +	beqz	s1, 204b
> >  
> >  	/* read a character */
> > -	lb	s0, UART_RXTX(t0)
> > +	lb	s1, UART_RXTX(t0)
> >  	li      t1, UART_EV_RX
> >  	sb	t1, UART_EV_PENDING(t0)
> >  
> > diff --git a/arch/riscv/include/asm/debug_ll_ns16550.h b/arch/riscv/include/asm/debug_ll_ns16550.h
> > index e208ef4fb1e1..47f0be328ce8 100644
> > --- a/arch/riscv/include/asm/debug_ll_ns16550.h
> > +++ b/arch/riscv/include/asm/debug_ll_ns16550.h
> > @@ -143,8 +143,8 @@ static inline void debug_ll_ns16550_init(void)
> >  	li      t0, DEBUG_LL_UART_ADDR
> >  
> >  	/* get line status and check for data present */
> > -	UART_REG_L	s0, UART_LSR(DEBUG_LL_UART_SHIFT)(t0)
> > -	andi	s0, s0, UART_LSR_DR
> > +	UART_REG_L	s1, UART_LSR(DEBUG_LL_UART_SHIFT)(t0)
> > +	andi	s1, s1, UART_LSR_DR
> >  
> >  #endif /* CONFIG_DEBUG_LL */
> >  .endm
> > @@ -159,10 +159,10 @@ static inline void debug_ll_ns16550_init(void)
> >  	debug_ll_tstc
> >  
> >  	/* try again */
> > -	beqz	s0, 204b
> > +	beqz	s1, 204b
> >  
> >  	/* read a character */
> > -	UART_REG_L	s0, UART_RBR(DEBUG_LL_UART_SHIFT)(t0)
> > +	UART_REG_L	s1, UART_RBR(DEBUG_LL_UART_SHIFT)(t0)
> >  
> >  #endif /* CONFIG_DEBUG_LL */
> >  .endm
> > diff --git a/arch/riscv/include/asm/riscv_nmon.h b/arch/riscv/include/asm/riscv_nmon.h
> > index 8a44e216d72d..3e349025febc 100644
> > --- a/arch/riscv/include/asm/riscv_nmon.h
> > +++ b/arch/riscv/include/asm/riscv_nmon.h
> > @@ -84,7 +84,7 @@ nmon_main:
> >  	debug_ll_getc
> >  
> >  	li	a0, 'q'
> > -	bne	s0, a0, 3f
> > +	bne	s1, a0, 3f
> >  
> >  	jal	a2, _nmon_outc_a0
> >  
> > @@ -92,13 +92,13 @@ nmon_main:
> >  
> >  3:
> >  	li	a0, 'd'
> > -	beq	s0, a0, nmon_cmd_d
> > +	beq	s1, a0, nmon_cmd_d
> >  
> >  	li	a0, 'w'
> > -	beq	s0, a0, nmon_cmd_w
> > +	beq	s1, a0, nmon_cmd_w
> >  
> >  	li	a0, 'g'
> > -	beq	s0, a0, nmon_cmd_g
> > +	beq	s1, a0, nmon_cmd_g
> >  
> >  	j	nmon_main_help
> >  
> > @@ -112,7 +112,7 @@ nmon_cmd_d:
> >  
> >  	nmon_outs	msg_nl
> >  
> > -	lw	a0, (s0)
> > +	lw	a0, (s1)
> >  	debug_ll_outhexw
> >  
> >  	j	nmon_main
> > @@ -124,13 +124,13 @@ nmon_cmd_w:
> >  	jal	a2, _nmon_outc_a0
> >  
> >  	jal	a2, _nmon_gethexw
> > -	move	s2, s0
> > +	move	s3, s1
> >  
> >  	li	a0, ' '
> >  	jal	a2, _nmon_outc_a0
> >  	jal	a2, _nmon_gethexw
> >  
> > -	sw	s0, 0(s2)
> > +	sw	s1, 0(s3)
> >  	j	nmon_main
> >  
> >  nmon_cmd_g:
> > @@ -140,11 +140,11 @@ nmon_cmd_g:
> >  	jal	a2, _nmon_outc_a0
> >  
> >  	jal	a2, _nmon_gethexw
> > -	move	s2, s0
> > +	move	s3, s1
> >  
> >  	nmon_outs	msg_nl
> >  
> > -	jalr	s2
> > +	jalr	s3
> >  	j	nmon_main
> >  
> >  _nmon_outc_a0:
> > @@ -169,37 +169,37 @@ _nmon_gethexw:
> >  _get_hex_digit:
> >  	debug_ll_getc
> >  
> > -	li	s1, CODE_ESC
> > -	beq	s0, s1, nmon_main
> > +	li	s2, CODE_ESC
> > +	beq	s1, s2, nmon_main
> >  
> > -	li	s1, '0'
> > -	bge	s0, s1, 0f
> > +	li	s2, '0'
> > +	bge	s1, s2, 0f
> >  	j	_get_hex_digit
> >  
> >  0:
> > -	li	s1, '9'
> > -	ble	s0, s1, 9f
> > +	li	s2, '9'
> > +	ble	s1, s2, 9f
> >  
> > -	li	s1, 'f'
> > -	ble	s0, s1, 1f
> > +	li	s2, 'f'
> > +	ble	s1, s2, 1f
> >  	j	_get_hex_digit
> >  
> >  1:
> > -	li	s1, 'a'
> > -	bge	s0, s1, 8f
> > +	li	s2, 'a'
> > +	bge	s1, s2, 8f
> >  
> >  	j	_get_hex_digit
> >  
> > -8: /* s0 \in {'a', 'b' ... 'f'} */
> > -	sub	a3, s0, s1
> > +8: /* s1 \in {'a', 'b' ... 'f'} */
> > +	sub	a3, s1, s2
> >  	addi	a3, a3, 0xa
> >  	j	0f
> >  
> > -9: /* s0 \in {'0', '1' ... '9'} */
> > +9: /* s1 \in {'0', '1' ... '9'} */
> >  	li	a3, '0'
> > -	sub	a3, s0, a3
> > +	sub	a3, s1, a3
> >  
> > -0:	move	a0, s0
> > +0:	move	a0, s1
> >  	debug_ll_outc_a0
> >  
> >  	sll	t2, t2, 4
> > @@ -212,7 +212,7 @@ _get_hex_digit:
> >  	j	_get_hex_digit
> >  
> >  0:
> > -	move	s0, t2
> > +	move	s1, t2
> >  
> >  _nmon_jr_ra_exit:
> >  	jr	a2
> > 
> 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


-- 
Best regards,
? Antony Pavlov


From sam at ravnborg.org  Mon Jan 10 12:52:58 2022
From: sam at ravnborg.org (Sam Ravnborg)
Date: Mon, 10 Jan 2022 21:52:58 +0100
Subject: Q about bootstrap support for at91sam92* boards and proposal for
 retirement
In-Reply-To: <20220110053336.GA3326@pengutronix.de>
References: <Ydsrrj76kk6tmD2X@ravnborg.org> <Yds9TY1wPddN1oNT@ravnborg.org>
 <20220110053336.GA3326@pengutronix.de>
Message-ID: <YdycqscPLMvmGZOH@ravnborg.org>

Hi Oleksij,
> 
> By porting sama5d3 I noticed that bootROM is resetting configuration for
> at least some of ip cores. So, the main question is, do everything needed
> for uart is still pre-configured? For example pllc and clk settings?

I found this in the data sheet that agrees with you:

"
	Before performing the jump to the application in internal SRAM,
	all the PIOs and peripherals used in the boot
	program are set to their reset state.
"

I will throw some hours after this in the weekend to see if I can get
it up and running.

> 
> As soon as UART is working, every thing else will be not really hard to
> do :)
Agree, except that I need find a nice way to add whatever I do to the
current at91 stuff. But that is part of the fun.

	Sam


From jmaselbas at kalray.eu  Mon Jan 10 14:12:50 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 10 Jan 2022 23:12:50 +0100
Subject: [PATCH 0/5] Add support for QOI image format
Message-ID: <20220110221255.5003-1-jmaselbas@kalray.eu>

Ho ho ho,

I had some fun past weeks playing with the QOI image format[1] and I've
added it's support to barebox. I also made the builtin barebox logo image
format selectable, with bmp, png, and qoi...

I am not sure if this be of a great interest to barebox anyway here it is.

[1] https://qoiformat.org/

---

Jules Maselbas (5):
  filetype: Add QOI format image type
  gui: Add qoi image format
  scripts: Add qoiconv to convert png to qoi
  logo: Enable image format selection for the logo
  logo: Add choice for the QOI image format option

 common/filetype.c   |    3 +
 include/filetype.h  |    1 +
 lib/gui/Kconfig     |    5 +
 lib/gui/Makefile    |    1 +
 lib/gui/qoi.c       |   94 +
 lib/gui/qoi.h       |  671 ++++
 lib/logo/Kconfig    |   27 +-
 lib/logo/Makefile   |   55 +-
 lib/logo/logo.c     |   10 +-
 scripts/Kconfig     |    5 +
 scripts/Makefile    |    1 +
 scripts/qoiconv.c   |   91 +
 scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 8705 insertions(+), 15 deletions(-)
 create mode 100644 lib/gui/qoi.c
 create mode 100644 lib/gui/qoi.h
 create mode 100644 scripts/qoiconv.c
 create mode 100644 scripts/stb_image.h

-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 10 14:12:54 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 10 Jan 2022 23:12:54 +0100
Subject: [PATCH 4/5] logo: Enable image format selection for the logo
In-Reply-To: <20220110221255.5003-1-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
Message-ID: <20220110221255.5003-5-jmaselbas@kalray.eu>

Enables the selection of an image format to be used for the built-in
barebox logo. The default image format is set to png, has it was the
only choice before. This also adds bmp as the other option.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 lib/logo/Kconfig  | 20 +++++++++++++++++++-
 lib/logo/Makefile | 43 ++++++++++++++++++++++++++++++-------------
 lib/logo/logo.c   |  8 +++++++-
 3 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/lib/logo/Kconfig b/lib/logo/Kconfig
index 7d55f7fa27..8edfaaeb51 100644
--- a/lib/logo/Kconfig
+++ b/lib/logo/Kconfig
@@ -3,10 +3,28 @@ menuconfig BAREBOX_LOGO
 	help
 	  Say yes here to build the barebox logos. This adds ImageMagick's
 	  convert tool to the build dependencies. The logo can be found under
-	  /logo/barebox-logo-<width>.png in the running barebox.
+	  /logo/barebox-logo-<width>.<ext> in the running barebox.
 
 if BAREBOX_LOGO
 
+choice
+	prompt "Logo image encoding format to be used"
+	default BAREBOX_LOGO_PNG
+
+config BAREBOX_LOGO_PNG
+	bool "png"
+	select PNG
+	help
+	  Encode logo with the PNG image format
+
+config BAREBOX_LOGO_BMP
+	bool "bmp"
+	select BMP
+	help
+	  Encode logo with the BMP image format
+
+endchoice
+
 config BAREBOX_LOGO_64
 	bool "include 64x32 pixel logo"
 
diff --git a/lib/logo/Makefile b/lib/logo/Makefile
index f08beef76b..04c4906838 100644
--- a/lib/logo/Makefile
+++ b/lib/logo/Makefile
@@ -1,17 +1,17 @@
 
-OPTS_barebox-logo-w64.bblogo = -resize 64
+OPTS_barebox-logo-w64 = -resize 64
 bblogo-$(CONFIG_BAREBOX_LOGO_64) += barebox-logo-w64
 
-OPTS_barebox-logo-w240.bblogo = -resize 240
+OPTS_barebox-logo-w240 = -resize 240
 bblogo-$(CONFIG_BAREBOX_LOGO_240) += barebox-logo-w240
 
-OPTS_barebox-logo-w320.bblogo = -resize 320
+OPTS_barebox-logo-w320 = -resize 320
 bblogo-$(CONFIG_BAREBOX_LOGO_320) += barebox-logo-w320
 
-OPTS_barebox-logo-w400.bblogo = -resize 400
+OPTS_barebox-logo-w400 = -resize 400
 bblogo-$(CONFIG_BAREBOX_LOGO_400) += barebox-logo-w400
 
-OPTS_barebox-logo-w640.bblogo = -resize 640
+OPTS_barebox-logo-w640 = -resize 640
 bblogo-$(CONFIG_BAREBOX_LOGO_640) += barebox-logo-w640
 
 obj-y += $(patsubst %,%.bblogo.o,$(bblogo-y))
@@ -38,15 +38,32 @@ cmd_logo_S =							\
 %.bblogo.S: %.bblogo FORCE
 	$(call if_changed,logo_S)
 
+quiet_cmd_logo = LOGO     $@
+      cmd_logo = cp $< $@
+
+ifdef CONFIG_BAREBOX_LOGO_PNG
+extra-y += $(patsubst %,%.png,$(bblogo-y))
+%.bblogo: %.png FORCE
+	$(call if_changed,logo)
+endif
+ifdef CONFIG_BAREBOX_LOGO_BMP
+extra-y += $(patsubst %,%.bmp,$(bblogo-y))
+%.bblogo: %.bmp FORCE
+	$(call if_changed,logo)
+endif
+
 CONVERTOPTS += -background none
 
-quiet_cmd_logo = PNG     $@
-cmd_logo =							\
-(								\
-	convert $(OPTS_$(@F)) $(CONVERTOPTS) $< png:$@; \
-)
+quiet_cmd_bmp = BMP     $@
+      cmd_bmp = convert $(OPTS_$(@F:.bmp=)) $(CONVERTOPTS) $< bmp:$@
 
-%.bblogo: $(srctree)/Documentation/barebox.svg FORCE
-	$(call if_changed,logo)
+%.bmp: $(srctree)/Documentation/barebox.svg FORCE
+	$(call if_changed,bmp)
+
+quiet_cmd_png = PNG     $@
+      cmd_png =	convert $(OPTS_$(@F:.png=)) $(CONVERTOPTS) $< png:$@
+
+%.png: $(srctree)/Documentation/barebox.svg FORCE
+	$(call if_changed,png)
 
-clean-files += *.bblogo *.bblogo.S
+clean-files += *.png *.bmp *.bblogo *.bblogo.S
diff --git a/lib/logo/logo.c b/lib/logo/logo.c
index 8349b060ac..200eb992b3 100644
--- a/lib/logo/logo.c
+++ b/lib/logo/logo.c
@@ -32,8 +32,14 @@ static void load_logo(int width, void *start, void *end)
 {
 	char *filename;
 	size_t size = end - start;
+	char *ext = "";
 
-	filename = basprintf("/logo/barebox-logo-%d.png", width);
+	if (IS_ENABLED(CONFIG_BAREBOX_LOGO_PNG))
+		ext = "png";
+	else if (IS_ENABLED(CONFIG_BAREBOX_LOGO_BMP))
+		ext = "bmp";
+
+	filename = basprintf("/logo/barebox-logo-%d.%s", width, ext);
 	write_file(filename, start, size);
 	free(filename);
 }
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 10 14:12:55 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 10 Jan 2022 23:12:55 +0100
Subject: [PATCH 5/5] logo: Add choice for the QOI image format option
In-Reply-To: <20220110221255.5003-1-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
Message-ID: <20220110221255.5003-6-jmaselbas@kalray.eu>

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 lib/logo/Kconfig  |  7 +++++++
 lib/logo/Makefile | 14 +++++++++++++-
 lib/logo/logo.c   |  2 ++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/lib/logo/Kconfig b/lib/logo/Kconfig
index 8edfaaeb51..a79806f54c 100644
--- a/lib/logo/Kconfig
+++ b/lib/logo/Kconfig
@@ -23,6 +23,13 @@ config BAREBOX_LOGO_BMP
 	help
 	  Encode logo with the BMP image format
 
+config BAREBOX_LOGO_QOI
+	bool "qoi"
+	select QOI
+	select QOICONV
+	help
+	  Encode logo with the QOI image format
+
 endchoice
 
 config BAREBOX_LOGO_64
diff --git a/lib/logo/Makefile b/lib/logo/Makefile
index 04c4906838..e04deb5536 100644
--- a/lib/logo/Makefile
+++ b/lib/logo/Makefile
@@ -51,6 +51,12 @@ extra-y += $(patsubst %,%.bmp,$(bblogo-y))
 %.bblogo: %.bmp FORCE
 	$(call if_changed,logo)
 endif
+ifdef CONFIG_BAREBOX_LOGO_QOI
+extra-y += $(patsubst %,%.png,$(bblogo-y))
+extra-y += $(patsubst %,%.qoi,$(bblogo-y))
+%.bblogo: %.qoi FORCE
+	$(call if_changed,logo)
+endif
 
 CONVERTOPTS += -background none
 
@@ -66,4 +72,10 @@ quiet_cmd_png = PNG     $@
 %.png: $(srctree)/Documentation/barebox.svg FORCE
 	$(call if_changed,png)
 
-clean-files += *.png *.bmp *.bblogo *.bblogo.S
+quiet_cmd_qoi = QOI     $@
+      cmd_qoi =	$(objtree)/scripts/qoiconv $< $@
+
+%.qoi: %.png FORCE
+	$(call if_changed,qoi)
+
+clean-files += *.png *.qoi *.bmp *.bblogo *.bblogo.S
diff --git a/lib/logo/logo.c b/lib/logo/logo.c
index 200eb992b3..a64f489939 100644
--- a/lib/logo/logo.c
+++ b/lib/logo/logo.c
@@ -38,6 +38,8 @@ static void load_logo(int width, void *start, void *end)
 		ext = "png";
 	else if (IS_ENABLED(CONFIG_BAREBOX_LOGO_BMP))
 		ext = "bmp";
+	else if (IS_ENABLED(CONFIG_BAREBOX_LOGO_QOI))
+		ext = "qoi";
 
 	filename = basprintf("/logo/barebox-logo-%d.%s", width, ext);
 	write_file(filename, start, size);
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 10 14:12:51 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 10 Jan 2022 23:12:51 +0100
Subject: [PATCH 1/5] filetype: Add QOI format image type
In-Reply-To: <20220110221255.5003-1-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
Message-ID: <20220110221255.5003-2-jmaselbas@kalray.eu>

QOI image format is a "Quite OK" image format, it's simplicity is it's
strength and could be a good replacement of bmp, maybe even for png.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 common/filetype.c  | 3 +++
 include/filetype.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/common/filetype.c b/common/filetype.c
index 8ffcd6adcd..e5245668e2 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -45,6 +45,7 @@ static const struct filetype_str filetype_str[] = {
 	[filetype_mbr] = { "MBR sector", "mbr" },
 	[filetype_bmp] = { "BMP image", "bmp" },
 	[filetype_png] = { "PNG image", "png" },
+	[filetype_qoi] = { "QOI image", "qoi" },
 	[filetype_ext] = { "EXT filesystem", "ext" },
 	[filetype_gpt] = { "GUID Partition Table", "gpt" },
 	[filetype_ubifs] = { "UBIFS image", "ubifs" },
@@ -300,6 +301,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
 		return filetype_aimage;
 	if (buf64[0] == le64_to_cpu(0x0a1a0a0d474e5089ull))
 		return filetype_png;
+	if (strncmp(buf8, "qoif", 4) == 0)
+		return filetype_qoi;
 	if (is_barebox_mips_head(_buf))
 		return filetype_mips_barebox;
 	if (buf[0] == be32_to_cpu(0x534F4659))
diff --git a/include/filetype.h b/include/filetype.h
index 2640847e1f..8bc179ac08 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -28,6 +28,7 @@ enum filetype {
 	filetype_mbr,
 	filetype_bmp,
 	filetype_png,
+	filetype_qoi,
 	filetype_ext,
 	filetype_gpt,
 	filetype_ubifs,
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 10 14:12:52 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 10 Jan 2022 23:12:52 +0100
Subject: [PATCH 2/5] gui: Add qoi image format
In-Reply-To: <20220110221255.5003-1-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
Message-ID: <20220110221255.5003-3-jmaselbas@kalray.eu>

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 lib/gui/Kconfig  |   5 +
 lib/gui/Makefile |   1 +
 lib/gui/qoi.c    |  94 +++++++
 lib/gui/qoi.h    | 671 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 771 insertions(+)
 create mode 100644 lib/gui/qoi.c
 create mode 100644 lib/gui/qoi.h

diff --git a/lib/gui/Kconfig b/lib/gui/Kconfig
index 2625d9fb2f..f0263c71cc 100644
--- a/lib/gui/Kconfig
+++ b/lib/gui/Kconfig
@@ -16,6 +16,11 @@ config PNG
 	bool "png"
 	select ZLIB
 
+config QOI
+	bool "qoi"
+	help
+	  Support for the Quite OK Image format
+
 if PNG
 
 choice
diff --git a/lib/gui/Makefile b/lib/gui/Makefile
index 31e66225d7..5ed190e9f8 100644
--- a/lib/gui/Makefile
+++ b/lib/gui/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_BMP)	+= bmp.o
 obj-$(CONFIG_IMAGE_RENDERER)	+= image_renderer.o graphic_utils.o
+obj-$(CONFIG_QOI)	+= qoi.o
 obj-$(CONFIG_PNG)	+= png.o
 obj-$(CONFIG_LODEPNG)	+= png_lode.o lodepng.o
 obj-$(CONFIG_PICOPNG)	+= png_pico.o picopng.o
diff --git a/lib/gui/qoi.c b/lib/gui/qoi.c
new file mode 100644
index 0000000000..f6c1bc1b94
--- /dev/null
+++ b/lib/gui/qoi.c
@@ -0,0 +1,94 @@
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fb.h>
+#include <asm/byteorder.h>
+#include <gui/graphic_utils.h>
+#include <init.h>
+#include <gui/image_renderer.h>
+#include <asm/unaligned.h>
+
+#define QOI_NO_STDIO
+#define QOI_IMPLEMENTATION
+#include "qoi.h"
+
+static struct image *qoi_open(char *inbuf, int insize)
+{
+	struct image *img;
+	void *data;
+	qoi_desc qoi;
+
+	img = calloc(1, sizeof(*img));
+	if (!img)
+		return ERR_PTR(-ENOMEM);
+
+	data = qoi_decode(inbuf, insize, &qoi, 0);
+	if (!data) {
+		free(img);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	img->data = data;
+	img->height = qoi.height;
+	img->width = qoi.width;
+	img->bits_per_pixel = qoi.channels * 8;
+
+	pr_debug("qoi: %d x %d  x %d data at 0x%p\n", img->width, img->height,
+		 img->bits_per_pixel, img->data);
+	return img;
+}
+
+static void qoi_close(struct image *img)
+{
+	free(img->data);
+}
+
+static int qoi_renderer(struct screen *sc, struct surface *s, struct image *img)
+{
+	int alpha = img->bits_per_pixel == (4 * 8);
+	int width = s->width;
+	int height = s->height;
+	int startx = s->x;
+	int starty = s->y;
+	void *buf;
+
+	if (s->width < 0)
+		width = img->width;
+	if (s->height < 0)
+		height = img->height;
+
+	if (startx < 0) {
+		startx = (sc->s.width - width) / 2;
+		if (startx < 0)
+			startx = 0;
+	}
+
+	if (starty < 0) {
+		starty = (sc->s.height - height) / 2;
+		if (starty < 0)
+			starty = 0;
+	}
+
+	width = min(width, sc->s.width - startx);
+	height = min(height, sc->s.height - starty);
+
+	buf = gui_screen_render_buffer(sc);
+
+	gu_rgba_blend(sc->info, img, buf, height, width, startx, starty, alpha);
+
+	return img->height;
+}
+
+static struct image_renderer qoi = {
+	.type = filetype_qoi,
+	.open = qoi_open,
+	.close = qoi_close,
+	.renderer = qoi_renderer,
+	.keep_file_data = 1,
+};
+
+static int qoi_init(void)
+{
+	return image_renderer_register(&qoi);
+}
+fs_initcall(qoi_init);
diff --git a/lib/gui/qoi.h b/lib/gui/qoi.h
new file mode 100644
index 0000000000..988f9edcb4
--- /dev/null
+++ b/lib/gui/qoi.h
@@ -0,0 +1,671 @@
+/*
+
+QOI - The "Quite OK Image" format for fast, lossless image compression
+
+Dominic Szablewski - https://phoboslab.org
+
+
+-- LICENSE: The MIT License(MIT)
+
+Copyright(c) 2021 Dominic Szablewski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files(the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions :
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+-- About
+
+QOI encodes and decodes images in a lossless format. Compared to stb_image and
+stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and
+20% better compression.
+
+
+-- Synopsis
+
+// Define `QOI_IMPLEMENTATION` in *one* C/C++ file before including this
+// library to create the implementation.
+
+#define QOI_IMPLEMENTATION
+#include "qoi.h"
+
+// Encode and store an RGBA buffer to the file system. The qoi_desc describes
+// the input pixel data.
+qoi_write("image_new.qoi", rgba_pixels, &(qoi_desc){
+	.width = 1920,
+	.height = 1080,
+	.channels = 4,
+	.colorspace = QOI_SRGB
+});
+
+// Load and decode a QOI image from the file system into a 32bbp RGBA buffer.
+// The qoi_desc struct will be filled with the width, height, number of channels
+// and colorspace read from the file header.
+qoi_desc desc;
+void *rgba_pixels = qoi_read("image.qoi", &desc, 4);
+
+
+
+-- Documentation
+
+This library provides the following functions;
+- qoi_read    -- read and decode a QOI file
+- qoi_decode  -- decode the raw bytes of a QOI image from memory
+- qoi_write   -- encode and write a QOI file
+- qoi_encode  -- encode an rgba buffer into a QOI image in memory
+
+See the function declaration below for the signature and more information.
+
+If you don't want/need the qoi_read and qoi_write functions, you can define
+QOI_NO_STDIO before including this library.
+
+This library uses malloc() and free(). To supply your own malloc implementation
+you can define QOI_MALLOC and QOI_FREE before including this library.
+
+This library uses memset() to zero-initialize the index. To supply your own
+implementation you can define QOI_ZEROARR before including this library.
+
+
+-- Data Format
+
+A QOI file has a 14 byte header, followed by any number of data "chunks" and an
+8-byte end marker.
+
+struct qoi_header_t {
+	char     magic[4];   // magic bytes "qoif"
+	uint32_t width;      // image width in pixels (BE)
+	uint32_t height;     // image height in pixels (BE)
+	uint8_t  channels;   // 3 = RGB, 4 = RGBA
+	uint8_t  colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
+};
+
+Images are encoded row by row, left to right, top to bottom. The decoder and
+encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An
+image is complete when all pixels specified by width * height have been covered.
+
+Pixels are encoded as
+ - a run of the previous pixel
+ - an index into an array of previously seen pixels
+ - a difference to the previous pixel value in r,g,b
+ - full r,g,b or r,g,b,a values
+
+The color channels are assumed to not be premultiplied with the alpha channel
+("un-premultiplied alpha").
+
+A running array[64] (zero-initialized) of previously seen pixel values is
+maintained by the encoder and decoder. Each pixel that is seen by the encoder
+and decoder is put into this array at the position formed by a hash function of
+the color value. In the encoder, if the pixel value at the index matches the
+current pixel, this index position is written to the stream as QOI_OP_INDEX.
+The hash function for the index is:
+
+	index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64
+
+Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The
+bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All
+values encoded in these data bits have the most significant bit on the left.
+
+The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the
+presence of an 8-bit tag first.
+
+The byte stream's end is marked with 7 0x00 bytes followed a single 0x01 byte.
+
+
+The possible chunks are:
+
+
+.- QOI_OP_INDEX ----------.
+|         Byte[0]         |
+|  7  6  5  4  3  2  1  0 |
+|-------+-----------------|
+|  0  0 |     index       |
+`-------------------------`
+2-bit tag b00
+6-bit index into the color index array: 0..63
+
+A valid encoder must not issue 2 or more consecutive QOI_OP_INDEX chunks to the
+same index. QOI_OP_RUN should be used instead.
+
+
+.- QOI_OP_DIFF -----------.
+|         Byte[0]         |
+|  7  6  5  4  3  2  1  0 |
+|-------+-----+-----+-----|
+|  0  1 |  dr |  dg |  db |
+`-------------------------`
+2-bit tag b01
+2-bit   red channel difference from the previous pixel between -2..1
+2-bit green channel difference from the previous pixel between -2..1
+2-bit  blue channel difference from the previous pixel between -2..1
+
+The difference to the current channel values are using a wraparound operation,
+so "1 - 2" will result in 255, while "255 + 1" will result in 0.
+
+Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
+0 (b00). 1 is stored as 3 (b11).
+
+The alpha value remains unchanged from the previous pixel.
+
+
+.- QOI_OP_LUMA -------------------------------------.
+|         Byte[0]         |         Byte[1]         |
+|  7  6  5  4  3  2  1  0 |  7  6  5  4  3  2  1  0 |
+|-------+-----------------+-------------+-----------|
+|  1  0 |  green diff     |   dr - dg   |  db - dg  |
+`---------------------------------------------------`
+2-bit tag b10
+6-bit green channel difference from the previous pixel -32..31
+4-bit   red channel difference minus green channel difference -8..7
+4-bit  blue channel difference minus green channel difference -8..7
+
+The green channel is used to indicate the general direction of change and is
+encoded in 6 bits. The red and blue channels (dr and db) base their diffs off
+of the green channel difference and are encoded in 4 bits. I.e.:
+	dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g)
+	db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g)
+
+The difference to the current channel values are using a wraparound operation,
+so "10 - 13" will result in 253, while "250 + 7" will result in 1.
+
+Values are stored as unsigned integers with a bias of 32 for the green channel
+and a bias of 8 for the red and blue channel.
+
+The alpha value remains unchanged from the previous pixel.
+
+
+.- QOI_OP_RUN ------------.
+|         Byte[0]         |
+|  7  6  5  4  3  2  1  0 |
+|-------+-----------------|
+|  1  1 |       run       |
+`-------------------------`
+2-bit tag b11
+6-bit run-length repeating the previous pixel: 1..62
+
+The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64
+(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and
+QOI_OP_RGBA tags.
+
+
+.- QOI_OP_RGB ------------------------------------------.
+|         Byte[0]         | Byte[1] | Byte[2] | Byte[3] |
+|  7  6  5  4  3  2  1  0 | 7 .. 0  | 7 .. 0  | 7 .. 0  |
+|-------------------------+---------+---------+---------|
+|  1  1  1  1  1  1  1  0 |   red   |  green  |  blue   |
+`-------------------------------------------------------`
+8-bit tag b11111110
+8-bit   red channel value
+8-bit green channel value
+8-bit  blue channel value
+
+The alpha value remains unchanged from the previous pixel.
+
+
+.- QOI_OP_RGBA ---------------------------------------------------.
+|         Byte[0]         | Byte[1] | Byte[2] | Byte[3] | Byte[4] |
+|  7  6  5  4  3  2  1  0 | 7 .. 0  | 7 .. 0  | 7 .. 0  | 7 .. 0  |
+|-------------------------+---------+---------+---------+---------|
+|  1  1  1  1  1  1  1  1 |   red   |  green  |  blue   |  alpha  |
+`-----------------------------------------------------------------`
+8-bit tag b11111111
+8-bit   red channel value
+8-bit green channel value
+8-bit  blue channel value
+8-bit alpha channel value
+
+*/
+
+
+/* -----------------------------------------------------------------------------
+Header - Public functions */
+
+#ifndef QOI_H
+#define QOI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
+It describes either the input format (for qoi_write and qoi_encode), or is
+filled with the description read from the file header (for qoi_read and
+qoi_decode).
+
+The colorspace in this qoi_desc is an enum where
+	0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel
+	1 = all channels are linear
+You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
+informative. It will be saved to the file header, but does not affect
+how chunks are en-/decoded. */
+
+#define QOI_SRGB   0
+#define QOI_LINEAR 1
+
+typedef struct {
+	unsigned int width;
+	unsigned int height;
+	unsigned char channels;
+	unsigned char colorspace;
+} qoi_desc;
+
+#ifndef QOI_NO_STDIO
+
+/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file
+system. The qoi_desc struct must be filled with the image width, height,
+number of channels (3 = RGB, 4 = RGBA) and the colorspace.
+
+The function returns 0 on failure (invalid parameters, or fopen or malloc
+failed) or the number of bytes written on success. */
+
+int qoi_write(const char *filename, const void *data, const qoi_desc *desc);
+
+
+/* Read and decode a QOI image from the file system. If channels is 0, the
+number of channels from the file header is used. If channels is 3 or 4 the
+output format will be forced into this number of channels.
+
+The function either returns NULL on failure (invalid data, or malloc or fopen
+failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
+will be filled with the description from the file header.
+
+The returned pixel data should be free()d after use. */
+
+void *qoi_read(const char *filename, qoi_desc *desc, int channels);
+
+#endif /* QOI_NO_STDIO */
+
+
+/* Encode raw RGB or RGBA pixels into a QOI image in memory.
+
+The function either returns NULL on failure (invalid parameters or malloc
+failed) or a pointer to the encoded data on success. On success the out_len
+is set to the size in bytes of the encoded data.
+
+The returned qoi data should be free()d after use. */
+
+void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len);
+
+
+/* Decode a QOI image from memory.
+
+The function either returns NULL on failure (invalid parameters or malloc
+failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
+is filled with the description from the file header.
+
+The returned pixel data should be free()d after use. */
+
+void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* QOI_H */
+
+
+/* -----------------------------------------------------------------------------
+Implementation */
+
+#ifdef QOI_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef QOI_MALLOC
+	#define QOI_MALLOC(sz) malloc(sz)
+	#define QOI_FREE(p)    free(p)
+#endif
+#ifndef QOI_ZEROARR
+	#define QOI_ZEROARR(a) memset((a),0,sizeof(a))
+#endif
+
+#define QOI_OP_INDEX  0x00 /* 00xxxxxx */
+#define QOI_OP_DIFF   0x40 /* 01xxxxxx */
+#define QOI_OP_LUMA   0x80 /* 10xxxxxx */
+#define QOI_OP_RUN    0xc0 /* 11xxxxxx */
+#define QOI_OP_RGB    0xfe /* 11111110 */
+#define QOI_OP_RGBA   0xff /* 11111111 */
+
+#define QOI_MASK_2    0xc0 /* 11000000 */
+
+#define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11)
+#define QOI_MAGIC \
+	(((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \
+	 ((unsigned int)'i') <<  8 | ((unsigned int)'f'))
+#define QOI_HEADER_SIZE 14
+
+/* 2GB is the max file size that this implementation can safely handle. We guard
+against anything larger than that, assuming the worst case with 5 bytes per
+pixel, rounded down to a nice clean value. 400 million pixels ought to be
+enough for anybody. */
+#define QOI_PIXELS_MAX ((unsigned int)400000000)
+
+typedef union {
+	struct { unsigned char r, g, b, a; } rgba;
+	unsigned int v;
+} qoi_rgba_t;
+
+static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1};
+
+static void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) {
+	bytes[(*p)++] = (0xff000000 & v) >> 24;
+	bytes[(*p)++] = (0x00ff0000 & v) >> 16;
+	bytes[(*p)++] = (0x0000ff00 & v) >> 8;
+	bytes[(*p)++] = (0x000000ff & v);
+}
+
+static unsigned int qoi_read_32(const unsigned char *bytes, int *p) {
+	unsigned int a = bytes[(*p)++];
+	unsigned int b = bytes[(*p)++];
+	unsigned int c = bytes[(*p)++];
+	unsigned int d = bytes[(*p)++];
+	return a << 24 | b << 16 | c << 8 | d;
+}
+
+void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
+	int i, max_size, p, run;
+	int px_len, px_end, px_pos, channels;
+	unsigned char *bytes;
+	const unsigned char *pixels;
+	qoi_rgba_t index[64];
+	qoi_rgba_t px, px_prev;
+
+	if (
+		data == NULL || out_len == NULL || desc == NULL ||
+		desc->width == 0 || desc->height == 0 ||
+		desc->channels < 3 || desc->channels > 4 ||
+		desc->colorspace > 1 ||
+		desc->height >= QOI_PIXELS_MAX / desc->width
+	) {
+		return NULL;
+	}
+
+	max_size =
+		desc->width * desc->height * (desc->channels + 1) +
+		QOI_HEADER_SIZE + sizeof(qoi_padding);
+
+	p = 0;
+	bytes = (unsigned char *) QOI_MALLOC(max_size);
+	if (!bytes) {
+		return NULL;
+	}
+
+	qoi_write_32(bytes, &p, QOI_MAGIC);
+	qoi_write_32(bytes, &p, desc->width);
+	qoi_write_32(bytes, &p, desc->height);
+	bytes[p++] = desc->channels;
+	bytes[p++] = desc->colorspace;
+
+
+	pixels = (const unsigned char *)data;
+
+	QOI_ZEROARR(index);
+
+	run = 0;
+	px_prev.rgba.r = 0;
+	px_prev.rgba.g = 0;
+	px_prev.rgba.b = 0;
+	px_prev.rgba.a = 255;
+	px = px_prev;
+
+	px_len = desc->width * desc->height * desc->channels;
+	px_end = px_len - desc->channels;
+	channels = desc->channels;
+
+	for (px_pos = 0; px_pos < px_len; px_pos += channels) {
+		if (channels == 4) {
+			px = *(qoi_rgba_t *)(pixels + px_pos);
+		}
+		else {
+			px.rgba.r = pixels[px_pos + 0];
+			px.rgba.g = pixels[px_pos + 1];
+			px.rgba.b = pixels[px_pos + 2];
+		}
+
+		if (px.v == px_prev.v) {
+			run++;
+			if (run == 62 || px_pos == px_end) {
+				bytes[p++] = QOI_OP_RUN | (run - 1);
+				run = 0;
+			}
+		}
+		else {
+			int index_pos;
+
+			if (run > 0) {
+				bytes[p++] = QOI_OP_RUN | (run - 1);
+				run = 0;
+			}
+
+			index_pos = QOI_COLOR_HASH(px) % 64;
+
+			if (index[index_pos].v == px.v) {
+				bytes[p++] = QOI_OP_INDEX | index_pos;
+			}
+			else {
+				index[index_pos] = px;
+
+				if (px.rgba.a == px_prev.rgba.a) {
+					signed char vr = px.rgba.r - px_prev.rgba.r;
+					signed char vg = px.rgba.g - px_prev.rgba.g;
+					signed char vb = px.rgba.b - px_prev.rgba.b;
+
+					signed char vg_r = vr - vg;
+					signed char vg_b = vb - vg;
+
+					if (
+						vr > -3 && vr < 2 &&
+						vg > -3 && vg < 2 &&
+						vb > -3 && vb < 2
+					) {
+						bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2);
+					}
+					else if (
+						vg_r >  -9 && vg_r <  8 &&
+						vg   > -33 && vg   < 32 &&
+						vg_b >  -9 && vg_b <  8
+					) {
+						bytes[p++] = QOI_OP_LUMA     | (vg   + 32);
+						bytes[p++] = (vg_r + 8) << 4 | (vg_b +  8);
+					}
+					else {
+						bytes[p++] = QOI_OP_RGB;
+						bytes[p++] = px.rgba.r;
+						bytes[p++] = px.rgba.g;
+						bytes[p++] = px.rgba.b;
+					}
+				}
+				else {
+					bytes[p++] = QOI_OP_RGBA;
+					bytes[p++] = px.rgba.r;
+					bytes[p++] = px.rgba.g;
+					bytes[p++] = px.rgba.b;
+					bytes[p++] = px.rgba.a;
+				}
+			}
+		}
+		px_prev = px;
+	}
+
+	for (i = 0; i < (int)sizeof(qoi_padding); i++) {
+		bytes[p++] = qoi_padding[i];
+	}
+
+	*out_len = p;
+	return bytes;
+}
+
+void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
+	const unsigned char *bytes;
+	unsigned int header_magic;
+	unsigned char *pixels;
+	qoi_rgba_t index[64];
+	qoi_rgba_t px;
+	int px_len, chunks_len, px_pos;
+	int p = 0, run = 0;
+
+	if (
+		data == NULL || desc == NULL ||
+		(channels != 0 && channels != 3 && channels != 4) ||
+		size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding)
+	) {
+		return NULL;
+	}
+
+	bytes = (const unsigned char *)data;
+
+	header_magic = qoi_read_32(bytes, &p);
+	desc->width = qoi_read_32(bytes, &p);
+	desc->height = qoi_read_32(bytes, &p);
+	desc->channels = bytes[p++];
+	desc->colorspace = bytes[p++];
+
+	if (
+		desc->width == 0 || desc->height == 0 ||
+		desc->channels < 3 || desc->channels > 4 ||
+		desc->colorspace > 1 ||
+		header_magic != QOI_MAGIC ||
+		desc->height >= QOI_PIXELS_MAX / desc->width
+	) {
+		return NULL;
+	}
+
+	if (channels == 0) {
+		channels = desc->channels;
+	}
+
+	px_len = desc->width * desc->height * channels;
+	pixels = (unsigned char *) QOI_MALLOC(px_len);
+	if (!pixels) {
+		return NULL;
+	}
+
+	QOI_ZEROARR(index);
+	px.rgba.r = 0;
+	px.rgba.g = 0;
+	px.rgba.b = 0;
+	px.rgba.a = 255;
+
+	chunks_len = size - (int)sizeof(qoi_padding);
+	for (px_pos = 0; px_pos < px_len; px_pos += channels) {
+		if (run > 0) {
+			run--;
+		}
+		else if (p < chunks_len) {
+			int b1 = bytes[p++];
+
+			if (b1 == QOI_OP_RGB) {
+				px.rgba.r = bytes[p++];
+				px.rgba.g = bytes[p++];
+				px.rgba.b = bytes[p++];
+			}
+			else if (b1 == QOI_OP_RGBA) {
+				px.rgba.r = bytes[p++];
+				px.rgba.g = bytes[p++];
+				px.rgba.b = bytes[p++];
+				px.rgba.a = bytes[p++];
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) {
+				px = index[b1];
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) {
+				px.rgba.r += ((b1 >> 4) & 0x03) - 2;
+				px.rgba.g += ((b1 >> 2) & 0x03) - 2;
+				px.rgba.b += ( b1       & 0x03) - 2;
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) {
+				int b2 = bytes[p++];
+				int vg = (b1 & 0x3f) - 32;
+				px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f);
+				px.rgba.g += vg;
+				px.rgba.b += vg - 8 +  (b2       & 0x0f);
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) {
+				run = (b1 & 0x3f);
+			}
+
+			index[QOI_COLOR_HASH(px) % 64] = px;
+		}
+
+		if (channels == 4) {
+			*(qoi_rgba_t*)(pixels + px_pos) = px;
+		}
+		else {
+			pixels[px_pos + 0] = px.rgba.r;
+			pixels[px_pos + 1] = px.rgba.g;
+			pixels[px_pos + 2] = px.rgba.b;
+		}
+	}
+
+	return pixels;
+}
+
+#ifndef QOI_NO_STDIO
+#include <stdio.h>
+
+int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
+	FILE *f = fopen(filename, "wb");
+	int size;
+	void *encoded;
+
+	if (!f) {
+		return 0;
+	}
+
+	encoded = qoi_encode(data, desc, &size);
+	if (!encoded) {
+		fclose(f);
+		return 0;
+	}
+
+	fwrite(encoded, 1, size, f);
+	fclose(f);
+
+	QOI_FREE(encoded);
+	return size;
+}
+
+void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
+	FILE *f = fopen(filename, "rb");
+	int size, bytes_read;
+	void *pixels, *data;
+
+	if (!f) {
+		return NULL;
+	}
+
+	fseek(f, 0, SEEK_END);
+	size = ftell(f);
+	if (size <= 0) {
+		fclose(f);
+		return NULL;
+	}
+	fseek(f, 0, SEEK_SET);
+
+	data = QOI_MALLOC(size);
+	if (!data) {
+		fclose(f);
+		return NULL;
+	}
+
+	bytes_read = fread(data, 1, size, f);
+	fclose(f);
+
+	pixels = qoi_decode(data, bytes_read, desc, channels);
+	QOI_FREE(data);
+	return pixels;
+}
+
+#endif /* QOI_NO_STDIO */
+#endif /* QOI_IMPLEMENTATION */
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 10 14:12:53 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 10 Jan 2022 23:12:53 +0100
Subject: [PATCH 3/5] scripts: Add qoiconv to convert png to qoi
In-Reply-To: <20220110221255.5003-1-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
Message-ID: <20220110221255.5003-4-jmaselbas@kalray.eu>

ImageMagick will eventually support the qoi image format, in the
mean time add a png to qoi conversion program.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 scripts/Kconfig     |    5 +
 scripts/Makefile    |    1 +
 scripts/qoiconv.c   |   91 +
 scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 7853 insertions(+)
 create mode 100644 scripts/qoiconv.c
 create mode 100644 scripts/stb_image.h

diff --git a/scripts/Kconfig b/scripts/Kconfig
index 9b744deba9..747f665e02 100644
--- a/scripts/Kconfig
+++ b/scripts/Kconfig
@@ -110,6 +110,11 @@ config RK_USB_LOADER
 
 	  You need libusb-1.0 to compile this tool.
 
+config QOICONV
+	bool "QOI image format conversion" if COMPILE_HOST_TOOLS
+	help
+	  This enable converting png to qoi images to generate boot logo.
+
 endmenu
 
 menu "Target Tools"
diff --git a/scripts/Makefile b/scripts/Makefile
index dc5fa75f90..cbaf2d55ff 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -8,6 +8,7 @@ hostprogs-always-y					+= fix_size
 hostprogs-always-y					+= bareboxenv
 hostprogs-always-y					+= bareboxcrc32
 hostprogs-always-y					+= kernel-install
+hostprogs-always-$(CONFIG_QOICONV)			+= qoiconv
 hostprogs-always-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS)	+= rsatoc
 HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl`
 HOSTLDLIBS_rsatoc = `pkg-config --libs openssl`
diff --git a/scripts/qoiconv.c b/scripts/qoiconv.c
new file mode 100644
index 0000000000..010c70ead0
--- /dev/null
+++ b/scripts/qoiconv.c
@@ -0,0 +1,91 @@
+/*
+
+Command line tool to convert between png <> qoi format
+
+Requires "stb_image.h" and "stb_image_write.h"
+Compile with: 
+	gcc qoiconv.c -std=c99 -O3 -o qoiconv
+
+Dominic Szablewski - https://phoboslab.org
+
+
+-- LICENSE: The MIT License(MIT)
+
+Copyright(c) 2021 Dominic Szablewski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files(the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions :
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_ONLY_PNG
+#define STBI_NO_LINEAR
+#include "stb_image.h"
+
+#define QOI_IMPLEMENTATION
+#include "../lib/gui/qoi.h"
+
+#define STR_ENDS_WITH(S, E) (strcmp(S + strlen(S) - (sizeof(E)-1), E) == 0)
+
+int main(int argc, char **argv) {
+	if (argc < 3) {
+		puts("Usage: qoiconv <infile> <outfile>");
+		puts("Examples:");
+		puts("  qoiconv input.png output.qoi");
+		puts("  qoiconv input.qoi output.png");
+		exit(1);
+	}
+
+	void *pixels = NULL;
+	int w, h, channels;
+	if (STR_ENDS_WITH(argv[1], ".png")) {
+		if(!stbi_info(argv[1], &w, &h, &channels)) {
+			printf("Couldn't read header %s\n", argv[1]);
+			exit(1);
+		}
+
+		// Force all odd encodings to be RGBA
+		if(channels != 3) {
+			channels = 4;
+		}
+
+		pixels = (void *)stbi_load(argv[1], &w, &h, NULL, channels);
+	}
+	if (pixels == NULL) {
+		printf("Couldn't load/decode %s\n", argv[1]);
+		exit(1);
+	}
+
+	int encoded = 0;
+	if (STR_ENDS_WITH(argv[2], ".qoi")) {
+		encoded = qoi_write(argv[2], pixels, &(qoi_desc){
+			.width = w,
+			.height = h, 
+			.channels = channels,
+			.colorspace = QOI_SRGB
+		});
+	}
+
+	if (!encoded) {
+		printf("Couldn't write/encode %s\n", argv[2]);
+		exit(1);
+	}
+
+	free(pixels);
+	return 0;
+}
diff --git a/scripts/stb_image.h b/scripts/stb_image.h
new file mode 100644
index 0000000000..742fac74f7
--- /dev/null
+++ b/scripts/stb_image.h
@@ -0,0 +1,7756 @@
+/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb
+                                  no warranty implied; use at your own risk
+
+   Do this:
+      #define STB_IMAGE_IMPLEMENTATION
+   before you include this file in *one* C or C++ file to create the implementation.
+
+   // i.e. it should look like this:
+   #include ...
+   #include ...
+   #include ...
+   #define STB_IMAGE_IMPLEMENTATION
+   #include "stb_image.h"
+
+   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+   QUICK NOTES:
+      Primarily of interest to game developers and other people who can
+          avoid problematic images and only need the trivial interface
+
+      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+      PNG 1/2/4/8/16-bit-per-channel
+
+      TGA (not sure what subset, if a subset)
+      BMP non-1bpp, non-RLE
+      PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+      GIF (*comp always reports as 4-channel)
+      HDR (radiance rgbE format)
+      PIC (Softimage PIC)
+      PNM (PPM and PGM binary only)
+
+      Animated GIF still needs a proper API, but here's one way to do it:
+          http://gist.github.com/urraka/685d9a6340b26b830d49
+
+      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+      - decode from arbitrary I/O callbacks
+      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+   Full documentation under "DOCUMENTATION" below.
+
+
+LICENSE
+
+  See end of file for license information.
+
+RECENT REVISION HISTORY:
+
+      2.26  (2020-07-13) many minor fixes
+      2.25  (2020-02-02) fix warnings
+      2.24  (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
+      2.23  (2019-08-11) fix clang static analysis warning
+      2.22  (2019-03-04) gif fixes, fix warnings
+      2.21  (2019-02-25) fix typo in comment
+      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+      2.19  (2018-02-11) fix warning
+      2.18  (2018-01-30) fix warnings
+      2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
+      2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
+      2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
+      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
+      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
+                         RGB-format JPEG; remove white matting in PSD;
+                         allocate large structures on the stack;
+                         correct channel count for PNG & BMP
+      2.10  (2016-01-22) avoid warning introduced in 2.09
+      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
+
+   See end of file for full revision history.
+
+
+ ============================    Contributors    =========================
+
+ Image formats                          Extensions, features
+    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)
+    Nicolas Schulz (hdr, psd)              Martin "SpartanJ" Golini (stbi_info)
+    Jonathan Dummer (tga)                  James "moose2000" Brown (iPhone PNG)
+    Jean-Marc Lienher (gif)                Ben "Disch" Wenger (io callbacks)
+    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)
+    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)
+    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)
+    github:urraka (animated gif)           Junggon Kim (PNM comments)
+    Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA)
+                                           socks-the-fox (16-bit PNG)
+                                           Jeremy Sawicki (handle all ImageNet JPGs)
+ Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP)
+    Fabian "ryg" Giesen                    Anael Seghezzi (is-16-bit query)
+    Arseny Kapoulkine
+    John-Mark Allen
+    Carmelo J Fdez-Aguera
+
+ Bug & warning fixes
+    Marc LeBlanc            David Woo          Guillaume George     Martins Mozeiko
+    Christpher Lloyd        Jerry Jansson      Joseph Thomson       Blazej Dariusz Roszkowski
+    Phil Jordan                                Dave Moore           Roy Eltham
+    Hayaki Saito            Nathan Reed        Won Chun
+    Luke Graham             Johan Duparc       Nick Verigakis       the Horde3D community
+    Thomas Ruf              Ronny Chevalier                         github:rlyeh
+    Janez Zemva             John Bartholomew   Michal Cichon        github:romigrou
+    Jonathan Blow           Ken Hamada         Tero Hanninen        github:svdijk
+                            Laurent Gomila     Cort Stratton        github:snagar
+    Aruelien Pocheville     Sergio Gonzalez    Thibault Reuille     github:Zelex
+    Cass Everitt            Ryamond Barbiero                        github:grim210
+    Paul Du Bois            Engin Manap        Aldo Culquicondor    github:sammyhw
+    Philipp Wiesemann       Dale Weiler        Oriol Ferrer Mesia   github:phprus
+    Josh Tobin                                 Matthew Gregan       github:poppolopoppo
+    Julian Raschke          Gregory Mullen     Christian Floisand   github:darealshinji
+    Baldur Karlsson         Kevin Schmidt      JR Smith             github:Michaelangel007
+                            Brad Weinberger    Matvey Cherevko      [reserved]
+    Luca Sas                Alexander Veselov  Zack Middleton       [reserved]
+    Ryan C. Gordon          [reserved]                              [reserved]
+                     DO NOT ADD YOUR NAME HERE
+
+  To add your name to the credits, pick a random blank space in the middle and fill it.
+  80% of merge conflicts on stb PRs are due to people adding their name at the end
+  of the credits.
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+//    - no 12-bit-per-channel JPEG
+//    - no JPEGs with arithmetic coding
+//    - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+//    int x,y,n;
+//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+//    // ... process data if not NULL ...
+//    // ... x = width, y = height, n = # 8-bit components per pixel ...
+//    // ... replace '0' with '1'..'4' to force that many components per pixel
+//    // ... but 'n' will always be the number that it would have been if you said 0
+//    stbi_image_free(data)
+//
+// Standard parameters:
+//    int *x                 -- outputs image width in pixels
+//    int *y                 -- outputs image height in pixels
+//    int *channels_in_file  -- outputs # of image components in image file
+//    int desired_channels   -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'desired_channels' if desired_channels is non-zero, or
+// *channels_in_file otherwise. If desired_channels is non-zero,
+// *channels_in_file has the number of components that _would_ have been
+// output otherwise. E.g. if you set desired_channels to 4, you will always
+// get RGBA output, but you can check *channels_in_file to see if it's trivially
+// opaque because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+//     N=#comp     components
+//       1           grey
+//       2           grey, alpha
+//       3           red, green, blue
+//       4           red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *channels_in_file will be unchanged. The function
+// stbi_failure_reason() can be queried for an extremely brief, end-user
+// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
+// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// UNICODE:
+//
+//   If compiling for Windows and you wish to use Unicode filenames, compile
+//   with
+//       #define STBI_WINDOWS_UTF8
+//   and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
+//   Windows wchar_t filenames to utf8.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+//    1. easy to use
+//    2. easy to maintain
+//    3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy-to-use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// provide more explicit reasons why performance can't be emphasized.
+//
+//    - Portable ("ease of use")
+//    - Small source code footprint ("easy to maintain")
+//    - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support   (disable by defining STBI_NO_HDR)
+//
+// stb_image supports loading HDR images in general, and currently the Radiance
+// .HDR file format specifically. You can still load any file through the existing
+// interface; if you attempt to load an HDR file, it will be automatically remapped
+// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+//     stbi_hdr_to_ldr_gamma(2.2f);
+//     stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+//    float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+//     stbi_ldr_to_hdr_scale(1.0f);
+//     stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+//     stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+// ===========================================================================
+//
+// ADDITIONAL CONFIGURATION
+//
+//  - You can suppress implementation of any of the decoders to reduce
+//    your code footprint by #defining one or more of the following
+//    symbols before creating the implementation.
+//
+//        STBI_NO_JPEG
+//        STBI_NO_PNG
+//        STBI_NO_BMP
+//        STBI_NO_PSD
+//        STBI_NO_TGA
+//        STBI_NO_GIF
+//        STBI_NO_HDR
+//        STBI_NO_PIC
+//        STBI_NO_PNM   (.ppm and .pgm)
+//
+//  - You can request *only* certain decoders and suppress all other ones
+//    (this will be more forward-compatible, as addition of new decoders
+//    doesn't require you to disable them explicitly):
+//
+//        STBI_ONLY_JPEG
+//        STBI_ONLY_PNG
+//        STBI_ONLY_BMP
+//        STBI_ONLY_PSD
+//        STBI_ONLY_TGA
+//        STBI_ONLY_GIF
+//        STBI_ONLY_HDR
+//        STBI_ONLY_PIC
+//        STBI_ONLY_PNM   (.ppm and .pgm)
+//
+//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+//
+//  - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
+//    than that size (in either width or height) without further processing.
+//    This is to let programs in the wild set an upper bound to prevent
+//    denial-of-service attacks on untrusted data, as one could generate a
+//    valid image of gigantic dimensions and force stb_image to allocate a
+//    huge block of memory and spend disproportionate time decoding it. By
+//    default this is set to (1 << 24), which is 16777216, but that's still
+//    very big.
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+   STBI_default = 0, // only used for desired_channels
+
+   STBI_grey       = 1,
+   STBI_grey_alpha = 2,
+   STBI_rgb        = 3,
+   STBI_rgb_alpha  = 4
+};
+
+#include <stdlib.h>
+typedef unsigned char stbi_uc;
+typedef unsigned short stbi_us;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef STBIDEF
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read
+   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+////////////////////////////////////
+//
+// 8-bits-per-channel interface
+//
+
+STBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+#endif
+
+#ifdef STBI_WINDOWS_UTF8
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
+#endif
+
+////////////////////////////////////
+//
+// 16-bits-per-channel interface
+//
+
+STBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+#endif
+
+////////////////////////////////////
+//
+// float-per-channel interface
+//
+#ifndef STBI_NO_LINEAR
+   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);
+
+   #ifndef STBI_NO_STDIO
+   STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+   #endif
+#endif
+
+#ifndef STBI_NO_HDR
+   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);
+   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_LINEAR
+   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);
+   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_LINEAR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename);
+STBIDEF int      stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// on most compilers (and ALL modern mainstream compilers) this is threadsafe
+STBIDEF const char *stbi_failure_reason  (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void     stbi_image_free      (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+STBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
+STBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp);
+STBIDEF int      stbi_is_16_bit          (char const *filename);
+STBIDEF int      stbi_is_16_bit_from_file(FILE *f);
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// as above, but only applies to images loaded on the thread that calls the function
+// this function is only available if your compiler supports thread-local variables;
+// calling it will fail to link if your compiler doesn't
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+////   end header file   /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+  || defined(STBI_ONLY_ZLIB)
+   #ifndef STBI_ONLY_JPEG
+   #define STBI_NO_JPEG
+   #endif
+   #ifndef STBI_ONLY_PNG
+   #define STBI_NO_PNG
+   #endif
+   #ifndef STBI_ONLY_BMP
+   #define STBI_NO_BMP
+   #endif
+   #ifndef STBI_ONLY_PSD
+   #define STBI_NO_PSD
+   #endif
+   #ifndef STBI_ONLY_TGA
+   #define STBI_NO_TGA
+   #endif
+   #ifndef STBI_ONLY_GIF
+   #define STBI_NO_GIF
+   #endif
+   #ifndef STBI_ONLY_HDR
+   #define STBI_NO_HDR
+   #endif
+   #ifndef STBI_ONLY_PIC
+   #define STBI_NO_PIC
+   #endif
+   #ifndef STBI_ONLY_PNM
+   #define STBI_NO_PNM
+   #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h>  // ldexp, pow
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+#ifdef __cplusplus
+#define STBI_EXTERN extern "C"
+#else
+#define STBI_EXTERN extern
+#endif
+
+
+#ifndef _MSC_VER
+   #ifdef __cplusplus
+   #define stbi_inline inline
+   #else
+   #define stbi_inline
+   #endif
+#else
+   #define stbi_inline __forceinline
+#endif
+
+#ifndef STBI_NO_THREAD_LOCALS
+   #if defined(__cplusplus) &&  __cplusplus >= 201103L
+      #define STBI_THREAD_LOCAL       thread_local
+   #elif defined(__GNUC__) && __GNUC__ < 5
+      #define STBI_THREAD_LOCAL       __thread
+   #elif defined(_MSC_VER)
+      #define STBI_THREAD_LOCAL       __declspec(thread)
+   #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
+      #define STBI_THREAD_LOCAL       _Thread_local
+   #endif
+
+   #ifndef STBI_THREAD_LOCAL
+      #if defined(__GNUC__)
+        #define STBI_THREAD_LOCAL       __thread
+      #endif
+   #endif
+#endif
+
+#ifdef _MSC_VER
+typedef unsigned short stbi__uint16;
+typedef   signed short stbi__int16;
+typedef unsigned int   stbi__uint32;
+typedef   signed int   stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t  stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t  stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v)  (void)(v)
+#else
+#define STBI_NOTUSED(v)  (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+   #define stbi_lrot(x,y)  _lrotl(x,y)
+#else
+   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz)           malloc(sz)
+#define STBI_REALLOC(p,newsz)     realloc(p,newsz)
+#define STBI_FREE(p)              free(p)
+#endif
+
+#ifndef STBI_REALLOC_SIZED
+#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
+#endif
+
+// x86/x64 detection
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define STBI__X86_TARGET
+#endif
+
+#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// which in turn means it gets to use SSE2 everywhere. This is unfortunate,
+// but previous attempts to provide the SSE2 functions with runtime
+// detection caused numerous issues. The way architecture extensions are
+// exposed in GCC/Clang is, sadly, not really suited for one-file libs.
+// New behavior: if compiled with -msse2, we use SSE2 without any
+// detection; if not, we don't use it at all.
+#define STBI_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
+// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+// simultaneously enabling "-mstackrealign".
+//
+// See https://github.com/nothings/stb/issues/81 for more information.
+//
+// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400  // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+   int info[4];
+   __cpuid(info,1);
+   return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+   int res;
+   __asm {
+      mov  eax,1
+      cpuid
+      mov  res,edx
+   }
+   return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
+{
+   int info3 = stbi__cpuid3();
+   return ((info3 >> 26) & 1) != 0;
+}
+#endif
+
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
+{
+   // If we're even attempting to compile this on GCC/Clang, that means
+   // -msse2 is on, which means the compiler is allowed to use SSE2
+   // instructions at will, and so are we.
+   return 1;
+}
+#endif
+
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+// assume GCC or Clang on ARM targets
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+#ifndef STBI_MAX_DIMENSIONS
+#define STBI_MAX_DIMENSIONS (1 << 24)
+#endif
+
+///////////////////////////////////////////////
+//
+//  stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+   stbi__uint32 img_x, img_y;
+   int img_n, img_out_n;
+
+   stbi_io_callbacks io;
+   void *io_user_data;
+
+   int read_from_callbacks;
+   int buflen;
+   stbi_uc buffer_start[128];
+   int callback_already_read;
+
+   stbi_uc *img_buffer, *img_buffer_end;
+   stbi_uc *img_buffer_original, *img_buffer_original_end;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+   s->io.read = NULL;
+   s->read_from_callbacks = 0;
+   s->callback_already_read = 0;
+   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+   s->io = *c;
+   s->io_user_data = user;
+   s->buflen = sizeof(s->buffer_start);
+   s->read_from_callbacks = 1;
+   s->callback_already_read = 0;
+   s->img_buffer = s->img_buffer_original = s->buffer_start;
+   stbi__refill_buffer(s);
+   s->img_buffer_original_end = s->img_buffer_end;
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+   return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+   int ch;
+   fseek((FILE*) user, n, SEEK_CUR);
+   ch = fgetc((FILE*) user);  /* have to read a byte to reset feof()'s flag */
+   if (ch != EOF) {
+      ungetc(ch, (FILE *) user);  /* push byte back onto stream if valid. */
+   }
+}
+
+static int stbi__stdio_eof(void *user)
+{
+   return feof((FILE*) user) || ferror((FILE *) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+   stbi__stdio_read,
+   stbi__stdio_skip,
+   stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+   // conceptually rewind SHOULD rewind to the beginning of the stream,
+   // but we just rewind to the beginning of the initial buffer, because
+   // we only use it after doing 'test', which only ever looks at at most 92 bytes
+   s->img_buffer = s->img_buffer_original;
+   s->img_buffer_end = s->img_buffer_original_end;
+}
+
+enum
+{
+   STBI_ORDER_RGB,
+   STBI_ORDER_BGR
+};
+
+typedef struct
+{
+   int bits_per_channel;
+   int num_channels;
+   int channel_order;
+} stbi__result_info;
+
+#ifndef STBI_NO_JPEG
+static int      stbi__jpeg_test(stbi__context *s);
+static void    *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int      stbi__png_test(stbi__context *s);
+static void    *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+static int      stbi__png_is16(stbi__context *s);
+#endif
+
+#ifndef STBI_NO_BMP
+static int      stbi__bmp_test(stbi__context *s);
+static void    *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int      stbi__tga_test(stbi__context *s);
+static void    *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int      stbi__psd_test(stbi__context *s);
+static void    *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
+static int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+static int      stbi__psd_is16(stbi__context *s);
+#endif
+
+#ifndef STBI_NO_HDR
+static int      stbi__hdr_test(stbi__context *s);
+static float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int      stbi__pic_test(stbi__context *s);
+static void    *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int      stbi__gif_test(stbi__context *s);
+static void    *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static void    *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+static int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int      stbi__pnm_test(stbi__context *s);
+static void    *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+static
+#ifdef STBI_THREAD_LOCAL
+STBI_THREAD_LOCAL
+#endif
+const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+   return stbi__g_failure_reason;
+}
+
+#ifndef STBI_NO_FAILURE_STRINGS
+static int stbi__err(const char *str)
+{
+   stbi__g_failure_reason = str;
+   return 0;
+}
+#endif
+
+static void *stbi__malloc(size_t size)
+{
+    return STBI_MALLOC(size);
+}
+
+// stb_image uses ints pervasively, including for offset calculations.
+// therefore the largest decoded image size we can support with the
+// current code, even on 64-bit targets, is INT_MAX. this is not a
+// significant limitation for the intended use case.
+//
+// we do, however, need to make sure our size calculations don't
+// overflow. hence a few helper functions for size calculations that
+// multiply integers together, making sure that they're non-negative
+// and no overflow occurs.
+
+// return 1 if the sum is valid, 0 on overflow.
+// negative terms are considered invalid.
+static int stbi__addsizes_valid(int a, int b)
+{
+   if (b < 0) return 0;
+   // now 0 <= b <= INT_MAX, hence also
+   // 0 <= INT_MAX - b <= INTMAX.
+   // And "a + b <= INT_MAX" (which might overflow) is the
+   // same as a <= INT_MAX - b (no overflow)
+   return a <= INT_MAX - b;
+}
+
+// returns 1 if the product is valid, 0 on overflow.
+// negative factors are considered invalid.
+static int stbi__mul2sizes_valid(int a, int b)
+{
+   if (a < 0 || b < 0) return 0;
+   if (b == 0) return 1; // mul-by-0 is always safe
+   // portable way to check for no overflows in a*b
+   return a <= INT_MAX/b;
+}
+
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
+// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad2sizes_valid(int a, int b, int add)
+{
+   return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
+}
+#endif
+
+// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad3sizes_valid(int a, int b, int c, int add)
+{
+   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+      stbi__addsizes_valid(a*b*c, add);
+}
+
+// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
+{
+   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+      stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
+}
+#endif
+
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
+// mallocs with size overflow checking
+static void *stbi__malloc_mad2(int a, int b, int add)
+{
+   if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
+   return stbi__malloc(a*b + add);
+}
+#endif
+
+static void *stbi__malloc_mad3(int a, int b, int c, int add)
+{
+   if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
+   return stbi__malloc(a*b*c + add);
+}
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
+{
+   if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
+   return stbi__malloc(a*b*c*d + add);
+}
+#endif
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+   #define stbi__err(x,y)  0
+#elif defined(STBI_FAILURE_USERMSG)
+   #define stbi__err(x,y)  stbi__err(y)
+#else
+   #define stbi__err(x,y)  stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+   STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);
+#endif
+
+static int stbi__vertically_flip_on_load_global = 0;
+
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
+{
+   stbi__vertically_flip_on_load_global = flag_true_if_should_flip;
+}
+
+#ifndef STBI_THREAD_LOCAL
+#define stbi__vertically_flip_on_load  stbi__vertically_flip_on_load_global
+#else
+static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;
+
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)
+{
+   stbi__vertically_flip_on_load_local = flag_true_if_should_flip;
+   stbi__vertically_flip_on_load_set = 1;
+}
+
+#define stbi__vertically_flip_on_load  (stbi__vertically_flip_on_load_set       \
+                                         ? stbi__vertically_flip_on_load_local  \
+                                         : stbi__vertically_flip_on_load_global)
+#endif // STBI_THREAD_LOCAL
+
+static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+   memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
+   ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
+   ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
+   ri->num_channels = 0;
+
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_PNG
+   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
+   #else
+   STBI_NOTUSED(bpc);
+   #endif
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp, ri);
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s)) {
+      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);
+      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+   }
+   #endif
+
+   #ifndef STBI_NO_TGA
+   // test tga last because it's a crappy test!
+   if (stbi__tga_test(s))
+      return stbi__tga_load(s,x,y,comp,req_comp, ri);
+   #endif
+
+   return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
+{
+   int i;
+   int img_len = w * h * channels;
+   stbi_uc *reduced;
+
+   reduced = (stbi_uc *) stbi__malloc(img_len);
+   if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
+
+   for (i = 0; i < img_len; ++i)
+      reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
+
+   STBI_FREE(orig);
+   return reduced;
+}
+
+static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
+{
+   int i;
+   int img_len = w * h * channels;
+   stbi__uint16 *enlarged;
+
+   enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
+   if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+
+   for (i = 0; i < img_len; ++i)
+      enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
+
+   STBI_FREE(orig);
+   return enlarged;
+}
+
+static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
+{
+   int row;
+   size_t bytes_per_row = (size_t)w * bytes_per_pixel;
+   stbi_uc temp[2048];
+   stbi_uc *bytes = (stbi_uc *)image;
+
+   for (row = 0; row < (h>>1); row++) {
+      stbi_uc *row0 = bytes + row*bytes_per_row;
+      stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
+      // swap row0 with row1
+      size_t bytes_left = bytes_per_row;
+      while (bytes_left) {
+         size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
+         memcpy(temp, row0, bytes_copy);
+         memcpy(row0, row1, bytes_copy);
+         memcpy(row1, temp, bytes_copy);
+         row0 += bytes_copy;
+         row1 += bytes_copy;
+         bytes_left -= bytes_copy;
+      }
+   }
+}
+
+#ifndef STBI_NO_GIF
+static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
+{
+   int slice;
+   int slice_size = w * h * bytes_per_pixel;
+
+   stbi_uc *bytes = (stbi_uc *)image;
+   for (slice = 0; slice < z; ++slice) {
+      stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
+      bytes += slice_size;
+   }
+}
+#endif
+
+static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__result_info ri;
+   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
+
+   if (result == NULL)
+      return NULL;
+
+   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
+   if (ri.bits_per_channel != 8) {
+      result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+      ri.bits_per_channel = 8;
+   }
+
+   // @TODO: move stbi__convert_format to here
+
+   if (stbi__vertically_flip_on_load) {
+      int channels = req_comp ? req_comp : *comp;
+      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
+   }
+
+   return (unsigned char *) result;
+}
+
+static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__result_info ri;
+   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
+
+   if (result == NULL)
+      return NULL;
+
+   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
+   if (ri.bits_per_channel != 16) {
+      result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+      ri.bits_per_channel = 16;
+   }
+
+   // @TODO: move stbi__convert_format16 to here
+   // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
+
+   if (stbi__vertically_flip_on_load) {
+      int channels = req_comp ? req_comp : *comp;
+      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
+   }
+
+   return (stbi__uint16 *) result;
+}
+
+#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)
+static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
+{
+   if (stbi__vertically_flip_on_load && result != NULL) {
+      int channels = req_comp ? req_comp : *comp;
+      stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
+   }
+}
+#endif
+
+#ifndef STBI_NO_STDIO
+
+#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
+STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
+STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
+#endif
+
+#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
+{
+	return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
+}
+#endif
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+   FILE *f;
+#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
+   wchar_t wMode[64];
+   wchar_t wFilename[1024];
+	if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
+      return 0;
+
+	if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
+      return 0;
+
+#if _MSC_VER >= 1400
+	if (0 != _wfopen_s(&f, wFilename, wMode))
+		f = 0;
+#else
+   f = _wfopen(wFilename, wMode);
+#endif
+
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
+   if (0 != fopen_s(&f, filename, mode))
+      f=0;
+#else
+   f = fopen(filename, mode);
+#endif
+   return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   unsigned char *result;
+   if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+   result = stbi_load_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *result;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+   if (result) {
+      // need to 'unget' all the characters in the IO buffer
+      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+   }
+   return result;
+}
+
+STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__uint16 *result;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
+   if (result) {
+      // need to 'unget' all the characters in the IO buffer
+      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+   }
+   return result;
+}
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   stbi__uint16 *result;
+   if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file");
+   result = stbi_load_from_file_16(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
+   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+   unsigned char *result;
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+
+   result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
+   if (stbi__vertically_flip_on_load) {
+      stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
+   }
+
+   return result;
+}
+#endif
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *data;
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s)) {
+      stbi__result_info ri;
+      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);
+      if (hdr_data)
+         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
+      return hdr_data;
+   }
+   #endif
+   data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
+   if (data)
+      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+   return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   float *result;
+   FILE *f = stbi__fopen(filename, "rb");
+   if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+   result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_file(&s,f);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(buffer);
+   STBI_NOTUSED(len);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   int result=0;
+   if (f) {
+      result = stbi_is_hdr_from_file(f);
+      fclose(f);
+   }
+   return result;
+}
+
+STBIDEF int stbi_is_hdr_from_file(FILE *f)
+{
+   #ifndef STBI_NO_HDR
+   long pos = ftell(f);
+   int res;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   res = stbi__hdr_test(&s);
+   fseek(f, pos, SEEK_SET);
+   return res;
+   #else
+   STBI_NOTUSED(f);
+   return 0;
+   #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(clbk);
+   STBI_NOTUSED(user);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_LINEAR
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+
+STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+   STBI__SCAN_load=0,
+   STBI__SCAN_type,
+   STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+   s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);
+   if (n == 0) {
+      // at end of file, treat same as if from memory, but need to handle case
+      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+      s->read_from_callbacks = 0;
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start+1;
+      *s->img_buffer = 0;
+   } else {
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start + n;
+   }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+   if (s->read_from_callbacks) {
+      stbi__refill_buffer(s);
+      return *s->img_buffer++;
+   }
+   return 0;
+}
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+   if (s->io.read) {
+      if (!(s->io.eof)(s->io_user_data)) return 0;
+      // if feof() is true, check if buffer = end
+      // special case: we've only got the special 0 character at the end
+      if (s->read_from_callbacks == 0) return 1;
+   }
+
+   return s->img_buffer >= s->img_buffer_end;
+}
+#endif
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)
+// nothing
+#else
+static void stbi__skip(stbi__context *s, int n)
+{
+   if (n == 0) return;  // already there!
+   if (n < 0) {
+      s->img_buffer = s->img_buffer_end;
+      return;
+   }
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         s->img_buffer = s->img_buffer_end;
+         (s->io.skip)(s->io_user_data, n - blen);
+         return;
+      }
+   }
+   s->img_buffer += n;
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)
+// nothing
+#else
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         int res, count;
+
+         memcpy(buffer, s->img_buffer, blen);
+
+         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+         res = (count == (n-blen));
+         s->img_buffer = s->img_buffer_end;
+         return res;
+      }
+   }
+
+   if (s->img_buffer+n <= s->img_buffer_end) {
+      memcpy(buffer, s->img_buffer, n);
+      s->img_buffer += n;
+      return 1;
+   } else
+      return 0;
+}
+#endif
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
+static int stbi__get16be(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return (z << 8) + stbi__get8(s);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16be(s);
+   return (z << 16) + stbi__get16be(s);
+}
+#endif
+
+#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
+// nothing
+#else
+static int stbi__get16le(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return z + (stbi__get8(s) << 8);
+}
+#endif
+
+#ifndef STBI_NO_BMP
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16le(s);
+   return z + (stbi__get16le(s) << 16);
+}
+#endif
+
+#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+//////////////////////////////////////////////////////////////////////////////
+//
+//  generic converter from built-in img_n to req_comp
+//    individual types do this automatically as much as possible (e.g. jpeg
+//    does all cases internally since it needs to colorspace convert anyway,
+//    and it never has alpha, so very few cases ). png can automatically
+//    interleave an alpha=255 channel, but falls back to this for other cases
+//
+//  assume data buffer is malloced, so malloc a new one and free that one
+//  only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+   int i,j;
+   unsigned char *good;
+
+   if (req_comp == img_n) return data;
+   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+   good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
+   if (good == NULL) {
+      STBI_FREE(data);
+      return stbi__errpuc("outofmem", "Out of memory");
+   }
+
+   for (j=0; j < (int) y; ++j) {
+      unsigned char *src  = data + j * x * img_n   ;
+      unsigned char *dest = good + j * x * req_comp;
+
+      #define STBI__COMBO(a,b)  ((a)*8+(b))
+      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+      // convert source image with img_n components to one with req_comp components;
+      // avoid switch per pixel, so use switch per scanline and massive macros
+      switch (STBI__COMBO(img_n, req_comp)) {
+         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255;                                     } break;
+         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;
+         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255;                     } break;
+         STBI__CASE(2,1) { dest[0]=src[0];                                                  } break;
+         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;
+         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                  } break;
+         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255;        } break;
+         STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255;    } break;
+         STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                    } break;
+         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion");
+      }
+      #undef STBI__CASE
+   }
+
+   STBI_FREE(data);
+   return good;
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
+static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
+{
+   return (stbi__uint16) (((r*77) + (g*150) +  (29*b)) >> 8);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
+static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+   int i,j;
+   stbi__uint16 *good;
+
+   if (req_comp == img_n) return data;
+   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+   good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
+   if (good == NULL) {
+      STBI_FREE(data);
+      return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+   }
+
+   for (j=0; j < (int) y; ++j) {
+      stbi__uint16 *src  = data + j * x * img_n   ;
+      stbi__uint16 *dest = good + j * x * req_comp;
+
+      #define STBI__COMBO(a,b)  ((a)*8+(b))
+      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+      // convert source image with img_n components to one with req_comp components;
+      // avoid switch per pixel, so use switch per scanline and massive macros
+      switch (STBI__COMBO(img_n, req_comp)) {
+         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff;                                     } break;
+         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;
+         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff;                     } break;
+         STBI__CASE(2,1) { dest[0]=src[0];                                                     } break;
+         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;
+         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                     } break;
+         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff;        } break;
+         STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;
+         STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                       } break;
+         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion");
+      }
+      #undef STBI__CASE
+   }
+
+   STBI_FREE(data);
+   return good;
+}
+#endif
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+   int i,k,n;
+   float *output;
+   if (!data) return NULL;
+   output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
+   if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+      }
+   }
+   if (n < comp) {
+      for (i=0; i < x*y; ++i) {
+         output[i*comp + n] = data[i*comp + n]/255.0f;
+      }
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x)   ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)
+{
+   int i,k,n;
+   stbi_uc *output;
+   if (!data) return NULL;
+   output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);
+   if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+      if (k < comp) {
+         float z = data[i*comp+k] * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  "baseline" JPEG/JFIF decoder
+//
+//    simple implementation
+//      - doesn't support delayed output of y-dimension
+//      - simple interface (only one output format: 8-bit interleaved RGB)
+//      - doesn't try to recover corrupt jpegs
+//      - doesn't allow partial loading, loading multiple at once
+//      - still fast on x86 (copying globals into locals doesn't help x86)
+//      - allocates lots of intermediate memory (full size of all components)
+//        - non-interleaved case requires this anyway
+//        - allows good upsampling (see next)
+//    high-quality
+//      - upsampled channels are bilinearly interpolated, even across blocks
+//      - quality integer IDCT derived from IJG's 'slow'
+//    performance
+//      - fast huffman; reasonable integer IDCT
+//      - some SIMD kernels for common paths on targets with SSE2/NEON
+//      - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+   stbi_uc  fast[1 << FAST_BITS];
+   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+   stbi__uint16 code[256];
+   stbi_uc  values[256];
+   stbi_uc  size[257];
+   unsigned int maxcode[18];
+   int    delta[17];   // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+   stbi__context *s;
+   stbi__huffman huff_dc[4];
+   stbi__huffman huff_ac[4];
+   stbi__uint16 dequant[4][64];
+   stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+   int img_h_max, img_v_max;
+   int img_mcu_x, img_mcu_y;
+   int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+   struct
+   {
+      int id;
+      int h,v;
+      int tq;
+      int hd,ha;
+      int dc_pred;
+
+      int x,y,w2,h2;
+      stbi_uc *data;
+      void *raw_data, *raw_coeff;
+      stbi_uc *linebuf;
+      short   *coeff;   // progressive only
+      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks
+   } img_comp[4];
+
+   stbi__uint32   code_buffer; // jpeg entropy-coded buffer
+   int            code_bits;   // number of valid bits
+   unsigned char  marker;      // marker seen while filling entropy buffer
+   int            nomore;      // flag if we saw a marker so must stop
+
+   int            progressive;
+   int            spec_start;
+   int            spec_end;
+   int            succ_high;
+   int            succ_low;
+   int            eob_run;
+   int            jfif;
+   int            app14_color_transform; // Adobe APP14 tag
+   int            rgb;
+
+   int scan_n, order[4];
+   int restart_interval, todo;
+
+// kernels
+   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+   int i,j,k=0;
+   unsigned int code;
+   // build size list for each symbol (from JPEG spec)
+   for (i=0; i < 16; ++i)
+      for (j=0; j < count[i]; ++j)
+         h->size[k++] = (stbi_uc) (i+1);
+   h->size[k] = 0;
+
+   // compute actual symbols (from jpeg spec)
+   code = 0;
+   k = 0;
+   for(j=1; j <= 16; ++j) {
+      // compute delta to add to code to compute symbol id
+      h->delta[j] = k - code;
+      if (h->size[k] == j) {
+         while (h->size[k] == j)
+            h->code[k++] = (stbi__uint16) (code++);
+         if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+      }
+      // compute largest code + 1 for this size, preshifted as needed later
+      h->maxcode[j] = code << (16-j);
+      code <<= 1;
+   }
+   h->maxcode[j] = 0xffffffff;
+
+   // build non-spec acceleration table; 255 is flag for not-accelerated
+   memset(h->fast, 255, 1 << FAST_BITS);
+   for (i=0; i < k; ++i) {
+      int s = h->size[i];
+      if (s <= FAST_BITS) {
+         int c = h->code[i] << (FAST_BITS-s);
+         int m = 1 << (FAST_BITS-s);
+         for (j=0; j < m; ++j) {
+            h->fast[c+j] = (stbi_uc) i;
+         }
+      }
+   }
+   return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+   int i;
+   for (i=0; i < (1 << FAST_BITS); ++i) {
+      stbi_uc fast = h->fast[i];
+      fast_ac[i] = 0;
+      if (fast < 255) {
+         int rs = h->values[fast];
+         int run = (rs >> 4) & 15;
+         int magbits = rs & 15;
+         int len = h->size[fast];
+
+         if (magbits && len + magbits <= FAST_BITS) {
+            // magnitude code followed by receive_extend code
+            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+            int m = 1 << (magbits - 1);
+            if (k < m) k += (~0U << magbits) + 1;
+            // if the result is small enough, we can fit it in fast_ac table
+            if (k >= -128 && k <= 127)
+               fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
+         }
+      }
+   }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+   do {
+      unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
+      if (b == 0xff) {
+         int c = stbi__get8(j->s);
+         while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
+         if (c != 0) {
+            j->marker = (unsigned char) c;
+            j->nomore = 1;
+            return;
+         }
+      }
+      j->code_buffer |= b << (24 - j->code_bits);
+      j->code_bits += 8;
+   } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+   unsigned int temp;
+   int c,k;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   // look at the top FAST_BITS and determine what symbol ID it is,
+   // if the code is <= FAST_BITS
+   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+   k = h->fast[c];
+   if (k < 255) {
+      int s = h->size[k];
+      if (s > j->code_bits)
+         return -1;
+      j->code_buffer <<= s;
+      j->code_bits -= s;
+      return h->values[k];
+   }
+
+   // naive test is to shift the code_buffer down so k bits are
+   // valid, then test against maxcode. To speed this up, we've
+   // preshifted maxcode left so that it has (16-k) 0s at the
+   // end; in other words, regardless of the number of bits, it
+   // wants to be compared against something shifted to have 16;
+   // that way we don't need to shift inside the loop.
+   temp = j->code_buffer >> 16;
+   for (k=FAST_BITS+1 ; ; ++k)
+      if (temp < h->maxcode[k])
+         break;
+   if (k == 17) {
+      // error! code not found
+      j->code_bits -= 16;
+      return -1;
+   }
+
+   if (k > j->code_bits)
+      return -1;
+
+   // convert the huffman code to the symbol id
+   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+   // convert the id to a symbol
+   j->code_bits -= k;
+   j->code_buffer <<= k;
+   return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   int sgn;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+
+   sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+   k = stbi_lrot(j->code_buffer, n);
+   if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0;
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k + (stbi__jbias[n] & ~sgn);
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+   k = stbi_lrot(j->code_buffer, n);
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+   unsigned int k;
+   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+   k = j->code_buffer;
+   j->code_buffer <<= 1;
+   --j->code_bits;
+   return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static const stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+    0,  1,  8, 16,  9,  2,  3, 10,
+   17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34,
+   27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36,
+   29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46,
+   53, 60, 61, 54, 47, 55, 62, 63,
+   // let corrupt input sample past end
+   63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)
+{
+   int diff,dc,k;
+   int t;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+   t = stbi__jpeg_huff_decode(j, hdc);
+   if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+
+   // 0 all the ac values now so we can do it 32-bits at a time
+   memset(data,0,64*sizeof(data[0]));
+
+   diff = t ? stbi__extend_receive(j, t) : 0;
+   dc = j->img_comp[b].dc_pred + diff;
+   j->img_comp[b].dc_pred = dc;
+   data[0] = (short) (dc * dequant[0]);
+
+   // decode AC components, see JPEG spec
+   k = 1;
+   do {
+      unsigned int zig;
+      int c,r,s;
+      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+      r = fac[c];
+      if (r) { // fast-AC path
+         k += (r >> 4) & 15; // run
+         s = r & 15; // combined length
+         j->code_buffer <<= s;
+         j->code_bits -= s;
+         // decode into unzigzag'd location
+         zig = stbi__jpeg_dezigzag[k++];
+         data[zig] = (short) ((r >> 8) * dequant[zig]);
+      } else {
+         int rs = stbi__jpeg_huff_decode(j, hac);
+         if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+         s = rs & 15;
+         r = rs >> 4;
+         if (s == 0) {
+            if (rs != 0xf0) break; // end block
+            k += 16;
+         } else {
+            k += r;
+            // decode into unzigzag'd location
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+         }
+      }
+   } while (k < 64);
+   return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+   int diff,dc;
+   int t;
+   if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   if (j->succ_high == 0) {
+      // first scan for DC coefficient, must be first
+      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+      t = stbi__jpeg_huff_decode(j, hdc);
+      if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+      diff = t ? stbi__extend_receive(j, t) : 0;
+
+      dc = j->img_comp[b].dc_pred + diff;
+      j->img_comp[b].dc_pred = dc;
+      data[0] = (short) (dc << j->succ_low);
+   } else {
+      // refinement scan for DC coefficient
+      if (stbi__jpeg_get_bit(j))
+         data[0] += (short) (1 << j->succ_low);
+   }
+   return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+   int k;
+   if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->succ_high == 0) {
+      int shift = j->succ_low;
+
+      if (j->eob_run) {
+         --j->eob_run;
+         return 1;
+      }
+
+      k = j->spec_start;
+      do {
+         unsigned int zig;
+         int c,r,s;
+         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+         r = fac[c];
+         if (r) { // fast-AC path
+            k += (r >> 4) & 15; // run
+            s = r & 15; // combined length
+            j->code_buffer <<= s;
+            j->code_bits -= s;
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) ((r >> 8) << shift);
+         } else {
+            int rs = stbi__jpeg_huff_decode(j, hac);
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r);
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  --j->eob_run;
+                  break;
+               }
+               k += 16;
+            } else {
+               k += r;
+               zig = stbi__jpeg_dezigzag[k++];
+               data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+            }
+         }
+      } while (k <= j->spec_end);
+   } else {
+      // refinement scan for these AC coefficients
+
+      short bit = (short) (1 << j->succ_low);
+
+      if (j->eob_run) {
+         --j->eob_run;
+         for (k = j->spec_start; k <= j->spec_end; ++k) {
+            short *p = &data[stbi__jpeg_dezigzag[k]];
+            if (*p != 0)
+               if (stbi__jpeg_get_bit(j))
+                  if ((*p & bit)==0) {
+                     if (*p > 0)
+                        *p += bit;
+                     else
+                        *p -= bit;
+                  }
+         }
+      } else {
+         k = j->spec_start;
+         do {
+            int r,s;
+            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r) - 1;
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  r = 64; // force end of block
+               } else {
+                  // r=15 s=0 should write 16 0s, so we just do
+                  // a run of 15 0s and then write s (which is 0),
+                  // so we don't have to do anything special here
+               }
+            } else {
+               if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+               // sign bit
+               if (stbi__jpeg_get_bit(j))
+                  s = bit;
+               else
+                  s = -bit;
+            }
+
+            // advance by r
+            while (k <= j->spec_end) {
+               short *p = &data[stbi__jpeg_dezigzag[k++]];
+               if (*p != 0) {
+                  if (stbi__jpeg_get_bit(j))
+                     if ((*p & bit)==0) {
+                        if (*p > 0)
+                           *p += bit;
+                        else
+                           *p -= bit;
+                     }
+               } else {
+                  if (r == 0) {
+                     *p = (short) s;
+                     break;
+                  }
+                  --r;
+               }
+            }
+         } while (k <= j->spec_end);
+      }
+   }
+   return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+   // trick to use a single test to catch both cases
+   if ((unsigned int) x > 255) {
+      if (x < 0) return 0;
+      if (x > 255) return 255;
+   }
+   return (stbi_uc) x;
+}
+
+#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x)  ((x) * 4096)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+   p2 = s2;                                    \
+   p3 = s6;                                    \
+   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \
+   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \
+   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \
+   p2 = s0;                                    \
+   p3 = s4;                                    \
+   t0 = stbi__fsh(p2+p3);                      \
+   t1 = stbi__fsh(p2-p3);                      \
+   x0 = t0+t3;                                 \
+   x3 = t0-t3;                                 \
+   x1 = t1+t2;                                 \
+   x2 = t1-t2;                                 \
+   t0 = s7;                                    \
+   t1 = s5;                                    \
+   t2 = s3;                                    \
+   t3 = s1;                                    \
+   p3 = t0+t2;                                 \
+   p4 = t1+t3;                                 \
+   p1 = t0+t3;                                 \
+   p2 = t1+t2;                                 \
+   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \
+   t0 = t0*stbi__f2f( 0.298631336f);           \
+   t1 = t1*stbi__f2f( 2.053119869f);           \
+   t2 = t2*stbi__f2f( 3.072711026f);           \
+   t3 = t3*stbi__f2f( 1.501321110f);           \
+   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \
+   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \
+   p3 = p3*stbi__f2f(-1.961570560f);           \
+   p4 = p4*stbi__f2f(-0.390180644f);           \
+   t3 += p1+p4;                                \
+   t2 += p2+p3;                                \
+   t1 += p2+p4;                                \
+   t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+   int i,val[64],*v=val;
+   stbi_uc *o;
+   short *d = data;
+
+   // columns
+   for (i=0; i < 8; ++i,++d, ++v) {
+      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+           && d[40]==0 && d[48]==0 && d[56]==0) {
+         //    no shortcut                 0     seconds
+         //    (1|2|3|4|5|6|7)==0          0     seconds
+         //    all separate               -0.047 seconds
+         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds
+         int dcterm = d[0]*4;
+         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+      } else {
+         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+         // constants scaled things up by 1<<12; let's bring them back
+         // down, but keep 2 extra bits of precision
+         x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+         v[ 0] = (x0+t3) >> 10;
+         v[56] = (x0-t3) >> 10;
+         v[ 8] = (x1+t2) >> 10;
+         v[48] = (x1-t2) >> 10;
+         v[16] = (x2+t1) >> 10;
+         v[40] = (x2-t1) >> 10;
+         v[24] = (x3+t0) >> 10;
+         v[32] = (x3-t0) >> 10;
+      }
+   }
+
+   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+      // no fast case since the first 1D IDCT spread components out
+      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+      // constants scaled things up by 1<<12, plus we had 1<<2 from first
+      // loop, plus horizontal and vertical each scale by sqrt(8) so together
+      // we've got an extra 1<<3, so 1<<17 total we need to remove.
+      // so we want to round that, which means adding 0.5 * 1<<17,
+      // aka 65536. Also, we'll end up with -128 to 127 that we want
+      // to encode as 0..255 by adding 128, so we'll add that before the shift
+      x0 += 65536 + (128<<17);
+      x1 += 65536 + (128<<17);
+      x2 += 65536 + (128<<17);
+      x3 += 65536 + (128<<17);
+      // tried computing the shifts into temps, or'ing the temps to see
+      // if any were out of range, but that was slower
+      o[0] = stbi__clamp((x0+t3) >> 17);
+      o[7] = stbi__clamp((x0-t3) >> 17);
+      o[1] = stbi__clamp((x1+t2) >> 17);
+      o[6] = stbi__clamp((x1-t2) >> 17);
+      o[2] = stbi__clamp((x2+t1) >> 17);
+      o[5] = stbi__clamp((x2-t1) >> 17);
+      o[3] = stbi__clamp((x3+t0) >> 17);
+      o[4] = stbi__clamp((x3-t0) >> 17);
+   }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   // This is constructed to match our regular (generic) integer IDCT exactly.
+   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+   __m128i tmp;
+
+   // dot product constant: even elems=x, odd elems=y
+   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
+   // out(1) = c1[even]*x + c1[odd]*y
+   #define dct_rot(out0,out1, x,y,c0,c1) \
+      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+   // out = in << 12  (in 16-bit, out 32-bit)
+   #define dct_widen(out, in) \
+      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+   // wide add
+   #define dct_wadd(out, a, b) \
+      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+   // wide sub
+   #define dct_wsub(out, a, b) \
+      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+   // butterfly a/b, add bias, then shift by "s" and pack
+   #define dct_bfly32o(out0, out1, a,b,bias,s) \
+      { \
+         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+         dct_wadd(sum, abiased, b); \
+         dct_wsub(dif, abiased, b); \
+         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+      }
+
+   // 8-bit interleave step (for transposes)
+   #define dct_interleave8(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi8(a, b); \
+      b = _mm_unpackhi_epi8(tmp, b)
+
+   // 16-bit interleave step (for transposes)
+   #define dct_interleave16(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi16(a, b); \
+      b = _mm_unpackhi_epi16(tmp, b)
+
+   #define dct_pass(bias,shift) \
+      { \
+         /* even part */ \
+         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+         __m128i sum04 = _mm_add_epi16(row0, row4); \
+         __m128i dif04 = _mm_sub_epi16(row0, row4); \
+         dct_widen(t0e, sum04); \
+         dct_widen(t1e, dif04); \
+         dct_wadd(x0, t0e, t3e); \
+         dct_wsub(x3, t0e, t3e); \
+         dct_wadd(x1, t1e, t2e); \
+         dct_wsub(x2, t1e, t2e); \
+         /* odd part */ \
+         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+         __m128i sum17 = _mm_add_epi16(row1, row7); \
+         __m128i sum35 = _mm_add_epi16(row3, row5); \
+         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+         dct_wadd(x4, y0o, y4o); \
+         dct_wadd(x5, y1o, y5o); \
+         dct_wadd(x6, y2o, y5o); \
+         dct_wadd(x7, y3o, y4o); \
+         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+      }
+
+   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
+   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
+   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
+   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
+   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
+   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
+   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
+   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
+
+   // rounding biases in column/row passes, see stbi__idct_block for explanation.
+   __m128i bias_0 = _mm_set1_epi32(512);
+   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+   // load
+   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+   row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+   // column pass
+   dct_pass(bias_0, 10);
+
+   {
+      // 16bit 8x8 transpose pass 1
+      dct_interleave16(row0, row4);
+      dct_interleave16(row1, row5);
+      dct_interleave16(row2, row6);
+      dct_interleave16(row3, row7);
+
+      // transpose pass 2
+      dct_interleave16(row0, row2);
+      dct_interleave16(row1, row3);
+      dct_interleave16(row4, row6);
+      dct_interleave16(row5, row7);
+
+      // transpose pass 3
+      dct_interleave16(row0, row1);
+      dct_interleave16(row2, row3);
+      dct_interleave16(row4, row5);
+      dct_interleave16(row6, row7);
+   }
+
+   // row pass
+   dct_pass(bias_1, 17);
+
+   {
+      // pack
+      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
+      __m128i p1 = _mm_packus_epi16(row2, row3);
+      __m128i p2 = _mm_packus_epi16(row4, row5);
+      __m128i p3 = _mm_packus_epi16(row6, row7);
+
+      // 8bit 8x8 transpose pass 1
+      dct_interleave8(p0, p2); // a0e0a1e1...
+      dct_interleave8(p1, p3); // c0g0c1g1...
+
+      // transpose pass 2
+      dct_interleave8(p0, p1); // a0c0e0g0...
+      dct_interleave8(p2, p3); // b0d0f0h0...
+
+      // transpose pass 3
+      dct_interleave8(p0, p2); // a0b0c0d0...
+      dct_interleave8(p1, p3); // a4b4c4d4...
+
+      // store
+      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+   }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif // STBI_SSE2
+
+#ifdef STBI_NEON
+
+// NEON integer IDCT. should produce bit-identical
+// results to the generic C version.
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
+   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
+   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
+   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
+   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
+   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
+   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
+   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
+   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
+   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
+   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
+   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+// wide add
+#define dct_wadd(out, a, b) \
+   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+// wide sub
+#define dct_wsub(out, a, b) \
+   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+// butterfly a/b, then shift using "shiftop" by "s" and pack
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+   { \
+      dct_wadd(sum, a, b); \
+      dct_wsub(dif, a, b); \
+      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+   }
+
+#define dct_pass(shiftop, shift) \
+   { \
+      /* even part */ \
+      int16x8_t sum26 = vaddq_s16(row2, row6); \
+      dct_long_mul(p1e, sum26, rot0_0); \
+      dct_long_mac(t2e, p1e, row6, rot0_1); \
+      dct_long_mac(t3e, p1e, row2, rot0_2); \
+      int16x8_t sum04 = vaddq_s16(row0, row4); \
+      int16x8_t dif04 = vsubq_s16(row0, row4); \
+      dct_widen(t0e, sum04); \
+      dct_widen(t1e, dif04); \
+      dct_wadd(x0, t0e, t3e); \
+      dct_wsub(x3, t0e, t3e); \
+      dct_wadd(x1, t1e, t2e); \
+      dct_wsub(x2, t1e, t2e); \
+      /* odd part */ \
+      int16x8_t sum15 = vaddq_s16(row1, row5); \
+      int16x8_t sum17 = vaddq_s16(row1, row7); \
+      int16x8_t sum35 = vaddq_s16(row3, row5); \
+      int16x8_t sum37 = vaddq_s16(row3, row7); \
+      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+      dct_long_mul(p5o, sumodd, rot1_0); \
+      dct_long_mac(p1o, p5o, sum17, rot1_1); \
+      dct_long_mac(p2o, p5o, sum35, rot1_2); \
+      dct_long_mul(p3o, sum37, rot2_0); \
+      dct_long_mul(p4o, sum15, rot2_1); \
+      dct_wadd(sump13o, p1o, p3o); \
+      dct_wadd(sump24o, p2o, p4o); \
+      dct_wadd(sump23o, p2o, p3o); \
+      dct_wadd(sump14o, p1o, p4o); \
+      dct_long_mac(x4, sump13o, row7, rot3_0); \
+      dct_long_mac(x5, sump24o, row5, rot3_1); \
+      dct_long_mac(x6, sump23o, row3, rot3_2); \
+      dct_long_mac(x7, sump14o, row1, rot3_3); \
+      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+   }
+
+   // load
+   row0 = vld1q_s16(data + 0*8);
+   row1 = vld1q_s16(data + 1*8);
+   row2 = vld1q_s16(data + 2*8);
+   row3 = vld1q_s16(data + 3*8);
+   row4 = vld1q_s16(data + 4*8);
+   row5 = vld1q_s16(data + 5*8);
+   row6 = vld1q_s16(data + 6*8);
+   row7 = vld1q_s16(data + 7*8);
+
+   // add DC bias
+   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+   // column pass
+   dct_pass(vrshrn_n_s32, 10);
+
+   // 16bit 8x8 transpose
+   {
+// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+// whether compilers actually get this is another story, sadly.
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+      // pass 1
+      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
+      dct_trn16(row2, row3);
+      dct_trn16(row4, row5);
+      dct_trn16(row6, row7);
+
+      // pass 2
+      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
+      dct_trn32(row1, row3);
+      dct_trn32(row4, row6);
+      dct_trn32(row5, row7);
+
+      // pass 3
+      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
+      dct_trn64(row1, row5);
+      dct_trn64(row2, row6);
+      dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+   }
+
+   // row pass
+   // vrshrn_n_s32 only supports shifts up to 16, we need
+   // 17. so do a non-rounding shift of 16 first then follow
+   // up with a rounding shift by 1.
+   dct_pass(vshrn_n_s32, 16);
+
+   {
+      // pack and round
+      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+      // again, these can translate into one instruction, but often don't.
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+      // sadly can't use interleaved stores here since we only write
+      // 8 bytes to each scan line!
+
+      // 8x8 8-bit transpose pass 1
+      dct_trn8_8(p0, p1);
+      dct_trn8_8(p2, p3);
+      dct_trn8_8(p4, p5);
+      dct_trn8_8(p6, p7);
+
+      // pass 2
+      dct_trn8_16(p0, p2);
+      dct_trn8_16(p1, p3);
+      dct_trn8_16(p4, p6);
+      dct_trn8_16(p5, p7);
+
+      // pass 3
+      dct_trn8_32(p0, p4);
+      dct_trn8_32(p1, p5);
+      dct_trn8_32(p2, p6);
+      dct_trn8_32(p3, p7);
+
+      // store
+      vst1_u8(out, p0); out += out_stride;
+      vst1_u8(out, p1); out += out_stride;
+      vst1_u8(out, p2); out += out_stride;
+      vst1_u8(out, p3); out += out_stride;
+      vst1_u8(out, p4); out += out_stride;
+      vst1_u8(out, p5); out += out_stride;
+      vst1_u8(out, p6); out += out_stride;
+      vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+   }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif // STBI_NEON
+
+#define STBI__MARKER_none  0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static stbi_uc stbi__get_marker(stbi__jpeg *j)
+{
+   stbi_uc x;
+   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
+   x = stbi__get8(j->s);
+   if (x != 0xff) return STBI__MARKER_none;
+   while (x == 0xff)
+      x = stbi__get8(j->s); // consume repeated 0xff fill bytes
+   return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, stbi__jpeg_reset the entropy decoder and
+// the dc prediction
+static void stbi__jpeg_reset(stbi__jpeg *j)
+{
+   j->code_bits = 0;
+   j->code_buffer = 0;
+   j->nomore = 0;
+   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;
+   j->marker = STBI__MARKER_none;
+   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+   j->eob_run = 0;
+   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+   // since we don't even allow 1<<30 pixels
+}
+
+static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
+{
+   stbi__jpeg_reset(z);
+   if (!z->progressive) {
+      if (z->scan_n == 1) {
+         int i,j;
+         STBI_SIMD_ALIGN(short, data[64]);
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               int ha = z->img_comp[n].ha;
+               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  // if it's NOT a restart, then just bail, so we get corrupt data
+                  // rather than no data
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         STBI_SIMD_ALIGN(short, data[64]);
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x)*8;
+                        int y2 = (j*z->img_comp[n].v + y)*8;
+                        int ha = z->img_comp[n].ha;
+                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   } else {
+      if (z->scan_n == 1) {
+         int i,j;
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               if (z->spec_start == 0) {
+                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                     return 0;
+               } else {
+                  int ha = z->img_comp[n].ha;
+                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+                     return 0;
+               }
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x);
+                        int y2 = (j*z->img_comp[n].v + y);
+                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                           return 0;
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   }
+}
+
+static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)
+{
+   int i;
+   for (i=0; i < 64; ++i)
+      data[i] *= dequant[i];
+}
+
+static void stbi__jpeg_finish(stbi__jpeg *z)
+{
+   if (z->progressive) {
+      // dequantize and idct the data
+      int i,j,n;
+      for (n=0; n < z->s->img_n; ++n) {
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+            }
+         }
+      }
+   }
+}
+
+static int stbi__process_marker(stbi__jpeg *z, int m)
+{
+   int L;
+   switch (m) {
+      case STBI__MARKER_none: // no marker found
+         return stbi__err("expected marker","Corrupt JPEG");
+
+      case 0xDD: // DRI - specify restart interval
+         if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
+         z->restart_interval = stbi__get16be(z->s);
+         return 1;
+
+      case 0xDB: // DQT - define quantization table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            int q = stbi__get8(z->s);
+            int p = q >> 4, sixteen = (p != 0);
+            int t = q & 15,i;
+            if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG");
+            if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
+
+            for (i=0; i < 64; ++i)
+               z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));
+            L -= (sixteen ? 129 : 65);
+         }
+         return L==0;
+
+      case 0xC4: // DHT - define huffman table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            stbi_uc *v;
+            int sizes[16],i,n=0;
+            int q = stbi__get8(z->s);
+            int tc = q >> 4;
+            int th = q & 15;
+            if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
+            for (i=0; i < 16; ++i) {
+               sizes[i] = stbi__get8(z->s);
+               n += sizes[i];
+            }
+            L -= 17;
+            if (tc == 0) {
+               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
+               v = z->huff_dc[th].values;
+            } else {
+               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
+               v = z->huff_ac[th].values;
+            }
+            for (i=0; i < n; ++i)
+               v[i] = stbi__get8(z->s);
+            if (tc != 0)
+               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+            L -= n;
+         }
+         return L==0;
+   }
+
+   // check for comment block or APP blocks
+   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+      L = stbi__get16be(z->s);
+      if (L < 2) {
+         if (m == 0xFE)
+            return stbi__err("bad COM len","Corrupt JPEG");
+         else
+            return stbi__err("bad APP len","Corrupt JPEG");
+      }
+      L -= 2;
+
+      if (m == 0xE0 && L >= 5) { // JFIF APP0 segment
+         static const unsigned char tag[5] = {'J','F','I','F','\0'};
+         int ok = 1;
+         int i;
+         for (i=0; i < 5; ++i)
+            if (stbi__get8(z->s) != tag[i])
+               ok = 0;
+         L -= 5;
+         if (ok)
+            z->jfif = 1;
+      } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment
+         static const unsigned char tag[6] = {'A','d','o','b','e','\0'};
+         int ok = 1;
+         int i;
+         for (i=0; i < 6; ++i)
+            if (stbi__get8(z->s) != tag[i])
+               ok = 0;
+         L -= 6;
+         if (ok) {
+            stbi__get8(z->s); // version
+            stbi__get16be(z->s); // flags0
+            stbi__get16be(z->s); // flags1
+            z->app14_color_transform = stbi__get8(z->s); // color transform
+            L -= 6;
+         }
+      }
+
+      stbi__skip(z->s, L);
+      return 1;
+   }
+
+   return stbi__err("unknown marker","Corrupt JPEG");
+}
+
+// after we see SOS
+static int stbi__process_scan_header(stbi__jpeg *z)
+{
+   int i;
+   int Ls = stbi__get16be(z->s);
+   z->scan_n = stbi__get8(z->s);
+   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
+   if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
+   for (i=0; i < z->scan_n; ++i) {
+      int id = stbi__get8(z->s), which;
+      int q = stbi__get8(z->s);
+      for (which = 0; which < z->s->img_n; ++which)
+         if (z->img_comp[which].id == id)
+            break;
+      if (which == z->s->img_n) return 0; // no match
+      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
+      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
+      z->order[i] = which;
+   }
+
+   {
+      int aa;
+      z->spec_start = stbi__get8(z->s);
+      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0
+      aa = stbi__get8(z->s);
+      z->succ_high = (aa >> 4);
+      z->succ_low  = (aa & 15);
+      if (z->progressive) {
+         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
+            return stbi__err("bad SOS", "Corrupt JPEG");
+      } else {
+         if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         z->spec_end = 63;
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)
+{
+   int i;
+   for (i=0; i < ncomp; ++i) {
+      if (z->img_comp[i].raw_data) {
+         STBI_FREE(z->img_comp[i].raw_data);
+         z->img_comp[i].raw_data = NULL;
+         z->img_comp[i].data = NULL;
+      }
+      if (z->img_comp[i].raw_coeff) {
+         STBI_FREE(z->img_comp[i].raw_coeff);
+         z->img_comp[i].raw_coeff = 0;
+         z->img_comp[i].coeff = 0;
+      }
+      if (z->img_comp[i].linebuf) {
+         STBI_FREE(z->img_comp[i].linebuf);
+         z->img_comp[i].linebuf = NULL;
+      }
+   }
+   return why;
+}
+
+static int stbi__process_frame_header(stbi__jpeg *z, int scan)
+{
+   stbi__context *s = z->s;
+   int Lf,p,i,q, h_max=1,v_max=1,c;
+   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
+   p  = stbi__get8(s);            if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
+   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+   c = stbi__get8(s);
+   if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
+   s->img_n = c;
+   for (i=0; i < c; ++i) {
+      z->img_comp[i].data = NULL;
+      z->img_comp[i].linebuf = NULL;
+   }
+
+   if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
+
+   z->rgb = 0;
+   for (i=0; i < s->img_n; ++i) {
+      static const unsigned char rgb[3] = { 'R', 'G', 'B' };
+      z->img_comp[i].id = stbi__get8(s);
+      if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
+         ++z->rgb;
+      q = stbi__get8(s);
+      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
+      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
+      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
+   }
+
+   if (scan != STBI__SCAN_load) return 1;
+
+   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode");
+
+   for (i=0; i < s->img_n; ++i) {
+      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+   }
+
+   // compute interleaved mcu info
+   z->img_h_max = h_max;
+   z->img_v_max = v_max;
+   z->img_mcu_w = h_max * 8;
+   z->img_mcu_h = v_max * 8;
+   // these sizes can't be more than 17 bits
+   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+   for (i=0; i < s->img_n; ++i) {
+      // number of effective pixels (e.g. for non-interleaved MCU)
+      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+      // to simplify generation, we'll allocate enough memory to decode
+      // the bogus oversized data from using interleaved MCUs and their
+      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+      // discard the extra data until colorspace conversion
+      //
+      // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)
+      // so these muls can't overflow with 32-bit ints (which we require)
+      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+      z->img_comp[i].coeff = 0;
+      z->img_comp[i].raw_coeff = 0;
+      z->img_comp[i].linebuf = NULL;
+      z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);
+      if (z->img_comp[i].raw_data == NULL)
+         return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+      // align blocks for idct using mmx/sse
+      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+      if (z->progressive) {
+         // w2, h2 are multiples of 8 (see above)
+         z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;
+         z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;
+         z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);
+         if (z->img_comp[i].raw_coeff == NULL)
+            return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+      }
+   }
+
+   return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define stbi__DNL(x)         ((x) == 0xdc)
+#define stbi__SOI(x)         ((x) == 0xd8)
+#define stbi__EOI(x)         ((x) == 0xd9)
+#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+#define stbi__SOS(x)         ((x) == 0xda)
+
+#define stbi__SOF_progressive(x)   ((x) == 0xc2)
+
+static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
+{
+   int m;
+   z->jfif = 0;
+   z->app14_color_transform = -1; // valid values are 0,1,2
+   z->marker = STBI__MARKER_none; // initialize cached marker to empty
+   m = stbi__get_marker(z);
+   if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
+   if (scan == STBI__SCAN_type) return 1;
+   m = stbi__get_marker(z);
+   while (!stbi__SOF(m)) {
+      if (!stbi__process_marker(z,m)) return 0;
+      m = stbi__get_marker(z);
+      while (m == STBI__MARKER_none) {
+         // some files have extra padding after their blocks, so ok, we'll scan
+         if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
+         m = stbi__get_marker(z);
+      }
+   }
+   z->progressive = stbi__SOF_progressive(m);
+   if (!stbi__process_frame_header(z, scan)) return 0;
+   return 1;
+}
+
+// decode image to YCbCr format
+static int stbi__decode_jpeg_image(stbi__jpeg *j)
+{
+   int m;
+   for (m = 0; m < 4; m++) {
+      j->img_comp[m].raw_data = NULL;
+      j->img_comp[m].raw_coeff = NULL;
+   }
+   j->restart_interval = 0;
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
+   m = stbi__get_marker(j);
+   while (!stbi__EOI(m)) {
+      if (stbi__SOS(m)) {
+         if (!stbi__process_scan_header(j)) return 0;
+         if (!stbi__parse_entropy_coded_data(j)) return 0;
+         if (j->marker == STBI__MARKER_none ) {
+            // handle 0s at the end of image data from IP Kamera 9060
+            while (!stbi__at_eof(j->s)) {
+               int x = stbi__get8(j->s);
+               if (x == 255) {
+                  j->marker = stbi__get8(j->s);
+                  break;
+               }
+            }
+            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
+         }
+      } else if (stbi__DNL(m)) {
+         int Ld = stbi__get16be(j->s);
+         stbi__uint32 NL = stbi__get16be(j->s);
+         if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
+         if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
+      } else {
+         if (!stbi__process_marker(j, m)) return 0;
+      }
+      m = stbi__get_marker(j);
+   }
+   if (j->progressive)
+      stbi__jpeg_finish(j);
+   return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
+                                    int w, int hs);
+
+#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
+
+static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   STBI_NOTUSED(out);
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(w);
+   STBI_NOTUSED(hs);
+   return in_near;
+}
+
+static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples vertically for every one in input
+   int i;
+   STBI_NOTUSED(hs);
+   for (i=0; i < w; ++i)
+      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
+   return out;
+}
+
+static stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples horizontally for every one in input
+   int i;
+   stbi_uc *input = in_near;
+
+   if (w == 1) {
+      // if only one sample, can't do any interpolation
+      out[0] = out[1] = input[0];
+      return out;
+   }
+
+   out[0] = input[0];
+   out[1] = stbi__div4(input[0]*3 + input[1] + 2);
+   for (i=1; i < w-1; ++i) {
+      int n = 3*input[i]+2;
+      out[i*2+0] = stbi__div4(n+input[i-1]);
+      out[i*2+1] = stbi__div4(n+input[i+1]);
+   }
+   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
+   out[i*2+1] = input[w-1];
+
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
+
+static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i,t0,t1;
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   out[0] = stbi__div4(t1+2);
+   for (i=1; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i=0,t0,t1;
+
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   // process groups of 8 pixels for as long as we can.
+   // note we can't handle the last pixel in a row in this loop
+   // because we need to handle the filter boundary conditions.
+   for (; i < ((w-1) & ~7); i += 8) {
+#if defined(STBI_SSE2)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      __m128i zero  = _mm_setzero_si128();
+      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
+      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
+      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+      __m128i diff  = _mm_sub_epi16(farw, nearw);
+      __m128i nears = _mm_slli_epi16(nearw, 2);
+      __m128i curr  = _mm_add_epi16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      __m128i prv0 = _mm_slli_si128(curr, 2);
+      __m128i nxt0 = _mm_srli_si128(curr, 2);
+      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      __m128i bias  = _mm_set1_epi16(8);
+      __m128i curs = _mm_slli_epi16(curr, 2);
+      __m128i prvd = _mm_sub_epi16(prev, curr);
+      __m128i nxtd = _mm_sub_epi16(next, curr);
+      __m128i curb = _mm_add_epi16(curs, bias);
+      __m128i even = _mm_add_epi16(prvd, curb);
+      __m128i odd  = _mm_add_epi16(nxtd, curb);
+
+      // interleave even and odd pixels, then undo scaling.
+      __m128i int0 = _mm_unpacklo_epi16(even, odd);
+      __m128i int1 = _mm_unpackhi_epi16(even, odd);
+      __m128i de0  = _mm_srli_epi16(int0, 4);
+      __m128i de1  = _mm_srli_epi16(int1, 4);
+
+      // pack and write output
+      __m128i outv = _mm_packus_epi16(de0, de1);
+      _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(STBI_NEON)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      uint8x8_t farb  = vld1_u8(in_far + i);
+      uint8x8_t nearb = vld1_u8(in_near + i);
+      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+      int16x8_t curr  = vaddq_s16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      int16x8_t prv0 = vextq_s16(curr, curr, 7);
+      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      int16x8_t curs = vshlq_n_s16(curr, 2);
+      int16x8_t prvd = vsubq_s16(prev, curr);
+      int16x8_t nxtd = vsubq_s16(next, curr);
+      int16x8_t even = vaddq_s16(curs, prvd);
+      int16x8_t odd  = vaddq_s16(curs, nxtd);
+
+      // undo scaling and round, then store with even/odd phases interleaved
+      uint8x8x2_t o;
+      o.val[0] = vqrshrun_n_s16(even, 4);
+      o.val[1] = vqrshrun_n_s16(odd,  4);
+      vst2_u8(out + i*2, o);
+#endif
+
+      // "previous" value for next iter
+      t1 = 3*in_near[i+7] + in_far[i+7];
+   }
+
+   t0 = t1;
+   t1 = 3*in_near[i] + in_far[i];
+   out[i*2] = stbi__div16(3*t1 + t0 + 8);
+
+   for (++i; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+#endif
+
+static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // resample with nearest-neighbor
+   int i,j;
+   STBI_NOTUSED(in_far);
+   for (i=0; i < w; ++i)
+      for (j=0; j < hs; ++j)
+         out[i*hs+j] = in_near[i];
+   return out;
+}
+
+// this is a reduced-precision calculation of YCbCr-to-RGB introduced
+// to make sure the code produces the same results in both SIMD and scalar
+#define stbi__float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+   int i;
+   for (i=0; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed +  cr* stbi__float2fixed(1.40200f);
+      g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                                     +   cb* stbi__float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
+{
+   int i = 0;
+
+#ifdef STBI_SSE2
+   // step == 3 is pretty ugly on the final interleave, and i'm not convinced
+   // it's useful in practice (you wouldn't use it for textures, for example).
+   // so just accelerate step == 4 case.
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      __m128i signflip  = _mm_set1_epi8(-0x80);
+      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
+      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
+      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
+      __m128i xw = _mm_set1_epi16(255); // alpha channel
+
+      for (; i+7 < count; i += 8) {
+         // load
+         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
+         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
+
+         // unpack to short (and left-shift cr, cb by 8)
+         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
+         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+         // color transform
+         __m128i yws = _mm_srli_epi16(yw, 4);
+         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+         __m128i rws = _mm_add_epi16(cr0, yws);
+         __m128i gwt = _mm_add_epi16(cb0, yws);
+         __m128i bws = _mm_add_epi16(yws, cb1);
+         __m128i gws = _mm_add_epi16(gwt, cr1);
+
+         // descale
+         __m128i rw = _mm_srai_epi16(rws, 4);
+         __m128i bw = _mm_srai_epi16(bws, 4);
+         __m128i gw = _mm_srai_epi16(gws, 4);
+
+         // back to byte, set up for transpose
+         __m128i brb = _mm_packus_epi16(rw, bw);
+         __m128i gxb = _mm_packus_epi16(gw, xw);
+
+         // transpose to interleave channels
+         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+         __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+         // store
+         _mm_storeu_si128((__m128i *) (out + 0), o0);
+         _mm_storeu_si128((__m128i *) (out + 16), o1);
+         out += 32;
+      }
+   }
+#endif
+
+#ifdef STBI_NEON
+   // in this version, step=3 support would be easy to add. but is there demand?
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      uint8x8_t signflip = vdup_n_u8(0x80);
+      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
+      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));
+
+      for (; i+7 < count; i += 8) {
+         // load
+         uint8x8_t y_bytes  = vld1_u8(y + i);
+         uint8x8_t cr_bytes = vld1_u8(pcr + i);
+         uint8x8_t cb_bytes = vld1_u8(pcb + i);
+         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+         // expand to s16
+         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+         int16x8_t crw = vshll_n_s8(cr_biased, 7);
+         int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+         // color transform
+         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+         int16x8_t rws = vaddq_s16(yws, cr0);
+         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+         int16x8_t bws = vaddq_s16(yws, cb1);
+
+         // undo scaling, round, convert to byte
+         uint8x8x4_t o;
+         o.val[0] = vqrshrun_n_s16(rws, 4);
+         o.val[1] = vqrshrun_n_s16(gws, 4);
+         o.val[2] = vqrshrun_n_s16(bws, 4);
+         o.val[3] = vdup_n_u8(255);
+
+         // store, interleaving r/g/b/a
+         vst4_u8(out, o);
+         out += 8*4;
+      }
+   }
+#endif
+
+   for (; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed + cr* stbi__float2fixed(1.40200f);
+      g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                                   +   cb* stbi__float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#endif
+
+// set up the kernels
+static void stbi__setup_jpeg(stbi__jpeg *j)
+{
+   j->idct_block_kernel = stbi__idct_block;
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
+
+#ifdef STBI_SSE2
+   if (stbi__sse2_available()) {
+      j->idct_block_kernel = stbi__idct_simd;
+      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+   }
+#endif
+
+#ifdef STBI_NEON
+   j->idct_block_kernel = stbi__idct_simd;
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+#endif
+}
+
+// clean up the temporary component buffers
+static void stbi__cleanup_jpeg(stbi__jpeg *j)
+{
+   stbi__free_jpeg_components(j, j->s->img_n, 0);
+}
+
+typedef struct
+{
+   resample_row_func resample;
+   stbi_uc *line0,*line1;
+   int hs,vs;   // expansion factor in each axis
+   int w_lores; // horizontal pixels pre-expansion
+   int ystep;   // how far through vertical expansion we are
+   int ypos;    // which pre-expansion row we're on
+} stbi__resample;
+
+// fast 0..255 * 0..255 => 0..255 rounded multiplication
+static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)
+{
+   unsigned int t = x*y + 128;
+   return (stbi_uc) ((t + (t >>8)) >> 8);
+}
+
+static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+   int n, decode_n, is_rgb;
+   z->s->img_n = 0; // make stbi__cleanup_jpeg safe
+
+   // validate req_comp
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+
+   // load a jpeg image from whichever source, but leave in YCbCr format
+   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
+
+   // determine actual number of components to generate
+   n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;
+
+   is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));
+
+   if (z->s->img_n == 3 && n < 3 && !is_rgb)
+      decode_n = 1;
+   else
+      decode_n = z->s->img_n;
+
+   // resample and color-convert
+   {
+      int k;
+      unsigned int i,j;
+      stbi_uc *output;
+      stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };
+
+      stbi__resample res_comp[4];
+
+      for (k=0; k < decode_n; ++k) {
+         stbi__resample *r = &res_comp[k];
+
+         // allocate line buffer big enough for upsampling off the edges
+         // with upsample factor of 4
+         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
+         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+         r->hs      = z->img_h_max / z->img_comp[k].h;
+         r->vs      = z->img_v_max / z->img_comp[k].v;
+         r->ystep   = r->vs >> 1;
+         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+         r->ypos    = 0;
+         r->line0   = r->line1 = z->img_comp[k].data;
+
+         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
+         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
+         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
+         else                               r->resample = stbi__resample_row_generic;
+      }
+
+      // can't error after this so, this is safe
+      output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);
+      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+      // now go ahead and resample
+      for (j=0; j < z->s->img_y; ++j) {
+         stbi_uc *out = output + n * z->s->img_x * j;
+         for (k=0; k < decode_n; ++k) {
+            stbi__resample *r = &res_comp[k];
+            int y_bot = r->ystep >= (r->vs >> 1);
+            coutput[k] = r->resample(z->img_comp[k].linebuf,
+                                     y_bot ? r->line1 : r->line0,
+                                     y_bot ? r->line0 : r->line1,
+                                     r->w_lores, r->hs);
+            if (++r->ystep >= r->vs) {
+               r->ystep = 0;
+               r->line0 = r->line1;
+               if (++r->ypos < z->img_comp[k].y)
+                  r->line1 += z->img_comp[k].w2;
+            }
+         }
+         if (n >= 3) {
+            stbi_uc *y = coutput[0];
+            if (z->s->img_n == 3) {
+               if (is_rgb) {
+                  for (i=0; i < z->s->img_x; ++i) {
+                     out[0] = y[i];
+                     out[1] = coutput[1][i];
+                     out[2] = coutput[2][i];
+                     out[3] = 255;
+                     out += n;
+                  }
+               } else {
+                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+               }
+            } else if (z->s->img_n == 4) {
+               if (z->app14_color_transform == 0) { // CMYK
+                  for (i=0; i < z->s->img_x; ++i) {
+                     stbi_uc m = coutput[3][i];
+                     out[0] = stbi__blinn_8x8(coutput[0][i], m);
+                     out[1] = stbi__blinn_8x8(coutput[1][i], m);
+                     out[2] = stbi__blinn_8x8(coutput[2][i], m);
+                     out[3] = 255;
+                     out += n;
+                  }
+               } else if (z->app14_color_transform == 2) { // YCCK
+                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+                  for (i=0; i < z->s->img_x; ++i) {
+                     stbi_uc m = coutput[3][i];
+                     out[0] = stbi__blinn_8x8(255 - out[0], m);
+                     out[1] = stbi__blinn_8x8(255 - out[1], m);
+                     out[2] = stbi__blinn_8x8(255 - out[2], m);
+                     out += n;
+                  }
+               } else { // YCbCr + alpha?  Ignore the fourth channel for now
+                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+               }
+            } else
+               for (i=0; i < z->s->img_x; ++i) {
+                  out[0] = out[1] = out[2] = y[i];
+                  out[3] = 255; // not used if n==3
+                  out += n;
+               }
+         } else {
+            if (is_rgb) {
+               if (n == 1)
+                  for (i=0; i < z->s->img_x; ++i)
+                     *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+               else {
+                  for (i=0; i < z->s->img_x; ++i, out += 2) {
+                     out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+                     out[1] = 255;
+                  }
+               }
+            } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
+               for (i=0; i < z->s->img_x; ++i) {
+                  stbi_uc m = coutput[3][i];
+                  stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);
+                  stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);
+                  stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);
+                  out[0] = stbi__compute_y(r, g, b);
+                  out[1] = 255;
+                  out += n;
+               }
+            } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {
+               for (i=0; i < z->s->img_x; ++i) {
+                  out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);
+                  out[1] = 255;
+                  out += n;
+               }
+            } else {
+               stbi_uc *y = coutput[0];
+               if (n == 1)
+                  for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+               else
+                  for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }
+            }
+         }
+      }
+      stbi__cleanup_jpeg(z);
+      *out_x = z->s->img_x;
+      *out_y = z->s->img_y;
+      if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output
+      return output;
+   }
+}
+
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   unsigned char* result;
+   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
+   STBI_NOTUSED(ri);
+   j->s = s;
+   stbi__setup_jpeg(j);
+   result = load_jpeg_image(j, x,y,comp,req_comp);
+   STBI_FREE(j);
+   return result;
+}
+
+static int stbi__jpeg_test(stbi__context *s)
+{
+   int r;
+   stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
+   j->s = s;
+   stbi__setup_jpeg(j);
+   r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
+   stbi__rewind(s);
+   STBI_FREE(j);
+   return r;
+}
+
+static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
+{
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
+      stbi__rewind( j->s );
+      return 0;
+   }
+   if (x) *x = j->s->img_x;
+   if (y) *y = j->s->img_y;
+   if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;
+   return 1;
+}
+
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int result;
+   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
+   j->s = s;
+   result = stbi__jpeg_info_raw(j, x, y, comp);
+   STBI_FREE(j);
+   return result;
+}
+#endif
+
+// public domain zlib decode    v0.2  Sean Barrett 2006-11-18
+//    simple implementation
+//      - all input must be provided in an upfront buffer
+//      - all output is written to a single output buffer (can malloc/realloc)
+//    performance
+//      - fast huffman
+
+#ifndef STBI_NO_ZLIB
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables
+#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+   stbi__uint16 fast[1 << STBI__ZFAST_BITS];
+   stbi__uint16 firstcode[16];
+   int maxcode[17];
+   stbi__uint16 firstsymbol[16];
+   stbi_uc  size[288];
+   stbi__uint16 value[288];
+} stbi__zhuffman;
+
+stbi_inline static int stbi__bitreverse16(int n)
+{
+  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);
+  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);
+  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);
+  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);
+  return n;
+}
+
+stbi_inline static int stbi__bit_reverse(int v, int bits)
+{
+   STBI_ASSERT(bits <= 16);
+   // to bit reverse n bits, reverse 16 and shift
+   // e.g. 11 bits, bit reverse and shift away 5
+   return stbi__bitreverse16(v) >> (16-bits);
+}
+
+static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)
+{
+   int i,k=0;
+   int code, next_code[16], sizes[17];
+
+   // DEFLATE spec for generating codes
+   memset(sizes, 0, sizeof(sizes));
+   memset(z->fast, 0, sizeof(z->fast));
+   for (i=0; i < num; ++i)
+      ++sizes[sizelist[i]];
+   sizes[0] = 0;
+   for (i=1; i < 16; ++i)
+      if (sizes[i] > (1 << i))
+         return stbi__err("bad sizes", "Corrupt PNG");
+   code = 0;
+   for (i=1; i < 16; ++i) {
+      next_code[i] = code;
+      z->firstcode[i] = (stbi__uint16) code;
+      z->firstsymbol[i] = (stbi__uint16) k;
+      code = (code + sizes[i]);
+      if (sizes[i])
+         if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
+      z->maxcode[i] = code << (16-i); // preshift for inner loop
+      code <<= 1;
+      k += sizes[i];
+   }
+   z->maxcode[16] = 0x10000; // sentinel
+   for (i=0; i < num; ++i) {
+      int s = sizelist[i];
+      if (s) {
+         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
+         z->size [c] = (stbi_uc     ) s;
+         z->value[c] = (stbi__uint16) i;
+         if (s <= STBI__ZFAST_BITS) {
+            int j = stbi__bit_reverse(next_code[s],s);
+            while (j < (1 << STBI__ZFAST_BITS)) {
+               z->fast[j] = fastv;
+               j += (1 << s);
+            }
+         }
+         ++next_code[s];
+      }
+   }
+   return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+//    because PNG allows splitting the zlib stream arbitrarily,
+//    and it's annoying structurally to have PNG call ZLIB call PNG,
+//    we require PNG read all the IDATs and combine them into a single
+//    memory buffer
+
+typedef struct
+{
+   stbi_uc *zbuffer, *zbuffer_end;
+   int num_bits;
+   stbi__uint32 code_buffer;
+
+   char *zout;
+   char *zout_start;
+   char *zout_end;
+   int   z_expandable;
+
+   stbi__zhuffman z_length, z_distance;
+} stbi__zbuf;
+
+stbi_inline static int stbi__zeof(stbi__zbuf *z)
+{
+   return (z->zbuffer >= z->zbuffer_end);
+}
+
+stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+{
+   return stbi__zeof(z) ? 0 : *z->zbuffer++;
+}
+
+static void stbi__fill_bits(stbi__zbuf *z)
+{
+   do {
+      if (z->code_buffer >= (1U << z->num_bits)) {
+        z->zbuffer = z->zbuffer_end;  /* treat this as EOF so we fail. */
+        return;
+      }
+      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
+      z->num_bits += 8;
+   } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+{
+   unsigned int k;
+   if (z->num_bits < n) stbi__fill_bits(z);
+   k = z->code_buffer & ((1 << n) - 1);
+   z->code_buffer >>= n;
+   z->num_bits -= n;
+   return k;
+}
+
+static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s,k;
+   // not resolved by fast table, so compute it the slow way
+   // use jpeg approach, which requires MSbits at top
+   k = stbi__bit_reverse(a->code_buffer, 16);
+   for (s=STBI__ZFAST_BITS+1; ; ++s)
+      if (k < z->maxcode[s])
+         break;
+   if (s >= 16) return -1; // invalid code!
+   // code size is s, so:
+   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+   if ((long unsigned int) b >= sizeof (z->size)) return -1; // some data was corrupt somewhere!
+   if (z->size[b] != s) return -1;  // was originally an assert, but report failure instead.
+   a->code_buffer >>= s;
+   a->num_bits -= s;
+   return z->value[b];
+}
+
+stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s;
+   if (a->num_bits < 16) {
+      if (stbi__zeof(a)) {
+         return -1;   /* report error for unexpected end of data. */
+      }
+      stbi__fill_bits(a);
+   }
+   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
+   if (b) {
+      s = b >> 9;
+      a->code_buffer >>= s;
+      a->num_bits -= s;
+      return b & 511;
+   }
+   return stbi__zhuffman_decode_slowpath(a, z);
+}
+
+static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes
+{
+   char *q;
+   unsigned int cur, limit, old_limit;
+   z->zout = zout;
+   if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+   cur   = (unsigned int) (z->zout - z->zout_start);
+   limit = old_limit = (unsigned) (z->zout_end - z->zout_start);
+   if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory");
+   while (cur + n > limit) {
+      if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory");
+      limit *= 2;
+   }
+   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
+   STBI_NOTUSED(old_limit);
+   if (q == NULL) return stbi__err("outofmem", "Out of memory");
+   z->zout_start = q;
+   z->zout       = q + cur;
+   z->zout_end   = q + limit;
+   return 1;
+}
+
+static const int stbi__zlength_base[31] = {
+   3,4,5,6,7,8,9,10,11,13,
+   15,17,19,23,27,31,35,43,51,59,
+   67,83,99,115,131,163,195,227,258,0,0 };
+
+static const int stbi__zlength_extra[31]=
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static const int stbi__zdist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int stbi__parse_huffman_block(stbi__zbuf *a)
+{
+   char *zout = a->zout;
+   for(;;) {
+      int z = stbi__zhuffman_decode(a, &a->z_length);
+      if (z < 256) {
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
+         if (zout >= a->zout_end) {
+            if (!stbi__zexpand(a, zout, 1)) return 0;
+            zout = a->zout;
+         }
+         *zout++ = (char) z;
+      } else {
+         stbi_uc *p;
+         int len,dist;
+         if (z == 256) {
+            a->zout = zout;
+            return 1;
+         }
+         z -= 257;
+         len = stbi__zlength_base[z];
+         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
+         z = stbi__zhuffman_decode(a, &a->z_distance);
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
+         dist = stbi__zdist_base[z];
+         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
+         if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+         if (zout + len > a->zout_end) {
+            if (!stbi__zexpand(a, zout, len)) return 0;
+            zout = a->zout;
+         }
+         p = (stbi_uc *) (zout - dist);
+         if (dist == 1) { // run of one byte; common in images.
+            stbi_uc v = *p;
+            if (len) { do *zout++ = v; while (--len); }
+         } else {
+            if (len) { do *zout++ = *p++; while (--len); }
+         }
+      }
+   }
+}
+
+static int stbi__compute_huffman_codes(stbi__zbuf *a)
+{
+   static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+   stbi__zhuffman z_codelength;
+   stbi_uc lencodes[286+32+137];//padding for maximum single op
+   stbi_uc codelength_sizes[19];
+   int i,n;
+
+   int hlit  = stbi__zreceive(a,5) + 257;
+   int hdist = stbi__zreceive(a,5) + 1;
+   int hclen = stbi__zreceive(a,4) + 4;
+   int ntot  = hlit + hdist;
+
+   memset(codelength_sizes, 0, sizeof(codelength_sizes));
+   for (i=0; i < hclen; ++i) {
+      int s = stbi__zreceive(a,3);
+      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+   }
+   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+   n = 0;
+   while (n < ntot) {
+      int c = stbi__zhuffman_decode(a, &z_codelength);
+      if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
+      if (c < 16)
+         lencodes[n++] = (stbi_uc) c;
+      else {
+         stbi_uc fill = 0;
+         if (c == 16) {
+            c = stbi__zreceive(a,2)+3;
+            if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
+            fill = lencodes[n-1];
+         } else if (c == 17) {
+            c = stbi__zreceive(a,3)+3;
+         } else if (c == 18) {
+            c = stbi__zreceive(a,7)+11;
+         } else {
+            return stbi__err("bad codelengths", "Corrupt PNG");
+         }
+         if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
+         memset(lencodes+n, fill, c);
+         n += c;
+      }
+   }
+   if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
+   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+   return 1;
+}
+
+static int stbi__parse_uncompressed_block(stbi__zbuf *a)
+{
+   stbi_uc header[4];
+   int len,nlen,k;
+   if (a->num_bits & 7)
+      stbi__zreceive(a, a->num_bits & 7); // discard
+   // drain the bit-packed data into header
+   k = 0;
+   while (a->num_bits > 0) {
+      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
+      a->code_buffer >>= 8;
+      a->num_bits -= 8;
+   }
+   if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG");
+   // now fill header the normal way
+   while (k < 4)
+      header[k++] = stbi__zget8(a);
+   len  = header[1] * 256 + header[0];
+   nlen = header[3] * 256 + header[2];
+   if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
+   if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+   if (a->zout + len > a->zout_end)
+      if (!stbi__zexpand(a, a->zout, len)) return 0;
+   memcpy(a->zout, a->zbuffer, len);
+   a->zbuffer += len;
+   a->zout += len;
+   return 1;
+}
+
+static int stbi__parse_zlib_header(stbi__zbuf *a)
+{
+   int cmf   = stbi__zget8(a);
+   int cm    = cmf & 15;
+   /* int cinfo = cmf >> 4; */
+   int flg   = stbi__zget8(a);
+   if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+   if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+   if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+   if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
+   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+   return 1;
+}
+
+static const stbi_uc stbi__zdefault_length[288] =
+{
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8
+};
+static const stbi_uc stbi__zdefault_distance[32] =
+{
+   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
+};
+/*
+Init algorithm:
+{
+   int i;   // use <= to match clearly with spec
+   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;
+   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;
+   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;
+   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;
+
+   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;
+}
+*/
+
+static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+{
+   int final, type;
+   if (parse_header)
+      if (!stbi__parse_zlib_header(a)) return 0;
+   a->num_bits = 0;
+   a->code_buffer = 0;
+   do {
+      final = stbi__zreceive(a,1);
+      type = stbi__zreceive(a,2);
+      if (type == 0) {
+         if (!stbi__parse_uncompressed_block(a)) return 0;
+      } else if (type == 3) {
+         return 0;
+      } else {
+         if (type == 1) {
+            // use fixed code lengths
+            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , 288)) return 0;
+            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;
+         } else {
+            if (!stbi__compute_huffman_codes(a)) return 0;
+         }
+         if (!stbi__parse_huffman_block(a)) return 0;
+      }
+   } while (!final);
+   return 1;
+}
+
+static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+   a->zout_start = obuf;
+   a->zout       = obuf;
+   a->zout_end   = obuf + olen;
+   a->z_expandable = exp;
+
+   return stbi__parse_zlib(a, parse_header);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(16384);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer+len;
+   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+#endif
+
+// public domain "baseline" PNG decoder   v0.10  Sean Barrett 2006-11-18
+//    simple implementation
+//      - only 8-bit samples
+//      - no CRC checking
+//      - allocates lots of intermediate memory
+//        - avoids problem of streaming data between subsystems
+//        - avoids explicit window management
+//    performance
+//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+#ifndef STBI_NO_PNG
+typedef struct
+{
+   stbi__uint32 length;
+   stbi__uint32 type;
+} stbi__pngchunk;
+
+static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+{
+   stbi__pngchunk c;
+   c.length = stbi__get32be(s);
+   c.type   = stbi__get32be(s);
+   return c;
+}
+
+static int stbi__check_png_header(stbi__context *s)
+{
+   static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+   int i;
+   for (i=0; i < 8; ++i)
+      if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+   return 1;
+}
+
+typedef struct
+{
+   stbi__context *s;
+   stbi_uc *idata, *expanded, *out;
+   int depth;
+} stbi__png;
+
+
+enum {
+   STBI__F_none=0,
+   STBI__F_sub=1,
+   STBI__F_up=2,
+   STBI__F_avg=3,
+   STBI__F_paeth=4,
+   // synthetic filters used for first scanline to avoid needing a dummy row of 0s
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static stbi_uc first_row_filter[5] =
+{
+   STBI__F_none,
+   STBI__F_sub,
+   STBI__F_none,
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static int stbi__paeth(int a, int b, int c)
+{
+   int p = a + b - c;
+   int pa = abs(p-a);
+   int pb = abs(p-b);
+   int pc = abs(p-c);
+   if (pa <= pb && pa <= pc) return a;
+   if (pb <= pc) return b;
+   return c;
+}
+
+static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+
+// create the png data from post-deflated data
+static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+{
+   int bytes = (depth == 16? 2 : 1);
+   stbi__context *s = a->s;
+   stbi__uint32 i,j,stride = x*out_n*bytes;
+   stbi__uint32 img_len, img_width_bytes;
+   int k;
+   int img_n = s->img_n; // copy it into a local for later
+
+   int output_bytes = out_n*bytes;
+   int filter_bytes = img_n*bytes;
+   int width = x;
+
+   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
+   a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
+   if (!a->out) return stbi__err("outofmem", "Out of memory");
+
+   if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
+   img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+   img_len = (img_width_bytes + 1) * y;
+
+   // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
+   // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
+   // so just check for raw_len < img_len always.
+   if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+
+   for (j=0; j < y; ++j) {
+      stbi_uc *cur = a->out + stride*j;
+      stbi_uc *prior;
+      int filter = *raw++;
+
+      if (filter > 4)
+         return stbi__err("invalid filter","Corrupt PNG");
+
+      if (depth < 8) {
+         if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
+         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
+         filter_bytes = 1;
+         width = img_width_bytes;
+      }
+      prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
+
+      // if first row, use special filter that doesn't sample previous row
+      if (j == 0) filter = first_row_filter[filter];
+
+      // handle first byte explicitly
+      for (k=0; k < filter_bytes; ++k) {
+         switch (filter) {
+            case STBI__F_none       : cur[k] = raw[k]; break;
+            case STBI__F_sub        : cur[k] = raw[k]; break;
+            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
+            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
+            case STBI__F_avg_first  : cur[k] = raw[k]; break;
+            case STBI__F_paeth_first: cur[k] = raw[k]; break;
+         }
+      }
+
+      if (depth == 8) {
+         if (img_n != out_n)
+            cur[img_n] = 255; // first pixel
+         raw += img_n;
+         cur += out_n;
+         prior += out_n;
+      } else if (depth == 16) {
+         if (img_n != out_n) {
+            cur[filter_bytes]   = 255; // first pixel top byte
+            cur[filter_bytes+1] = 255; // first pixel bottom byte
+         }
+         raw += filter_bytes;
+         cur += output_bytes;
+         prior += output_bytes;
+      } else {
+         raw += 1;
+         cur += 1;
+         prior += 1;
+      }
+
+      // this is a little gross, so that we don't switch per-pixel or per-component
+      if (depth < 8 || img_n == out_n) {
+         int nk = (width - 1)*filter_bytes;
+         #define STBI__CASE(f) \
+             case f:     \
+                for (k=0; k < nk; ++k)
+         switch (filter) {
+            // "none" filter turns into a memcpy here; make that explicit.
+            case STBI__F_none:         memcpy(cur, raw, nk); break;
+            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
+            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
+            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
+            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
+            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
+         }
+         #undef STBI__CASE
+         raw += nk;
+      } else {
+         STBI_ASSERT(img_n+1 == out_n);
+         #define STBI__CASE(f) \
+             case f:     \
+                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
+                   for (k=0; k < filter_bytes; ++k)
+         switch (filter) {
+            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;
+            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
+            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
+            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
+            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
+            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
+         }
+         #undef STBI__CASE
+
+         // the loop above sets the high byte of the pixels' alpha, but for
+         // 16 bit png files we also need the low byte set. we'll do that here.
+         if (depth == 16) {
+            cur = a->out + stride*j; // start at the beginning of the row again
+            for (i=0; i < x; ++i,cur+=output_bytes) {
+               cur[filter_bytes+1] = 255;
+            }
+         }
+      }
+   }
+
+   // we make a separate pass to expand bits to pixels; for performance,
+   // this could run two scanlines behind the above code, so it won't
+   // intefere with filtering but will still be in the cache.
+   if (depth < 8) {
+      for (j=0; j < y; ++j) {
+         stbi_uc *cur = a->out + stride*j;
+         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;
+         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
+         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
+         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+
+         // note that the final byte might overshoot and write more data than desired.
+         // we can allocate enough data that this never writes out of memory, but it
+         // could also overwrite the next scanline. can it overwrite non-empty data
+         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
+         // so we need to explicitly clamp the final ones
+
+         if (depth == 4) {
+            for (k=x*img_n; k >= 2; k-=2, ++in) {
+               *cur++ = scale * ((*in >> 4)       );
+               *cur++ = scale * ((*in     ) & 0x0f);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 4)       );
+         } else if (depth == 2) {
+            for (k=x*img_n; k >= 4; k-=4, ++in) {
+               *cur++ = scale * ((*in >> 6)       );
+               *cur++ = scale * ((*in >> 4) & 0x03);
+               *cur++ = scale * ((*in >> 2) & 0x03);
+               *cur++ = scale * ((*in     ) & 0x03);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 6)       );
+            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
+            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
+         } else if (depth == 1) {
+            for (k=x*img_n; k >= 8; k-=8, ++in) {
+               *cur++ = scale * ((*in >> 7)       );
+               *cur++ = scale * ((*in >> 6) & 0x01);
+               *cur++ = scale * ((*in >> 5) & 0x01);
+               *cur++ = scale * ((*in >> 4) & 0x01);
+               *cur++ = scale * ((*in >> 3) & 0x01);
+               *cur++ = scale * ((*in >> 2) & 0x01);
+               *cur++ = scale * ((*in >> 1) & 0x01);
+               *cur++ = scale * ((*in     ) & 0x01);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 7)       );
+            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
+            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
+            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
+            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
+            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
+            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
+         }
+         if (img_n != out_n) {
+            int q;
+            // insert alpha = 255
+            cur = a->out + stride*j;
+            if (img_n == 1) {
+               for (q=x-1; q >= 0; --q) {
+                  cur[q*2+1] = 255;
+                  cur[q*2+0] = cur[q];
+               }
+            } else {
+               STBI_ASSERT(img_n == 3);
+               for (q=x-1; q >= 0; --q) {
+                  cur[q*4+3] = 255;
+                  cur[q*4+2] = cur[q*3+2];
+                  cur[q*4+1] = cur[q*3+1];
+                  cur[q*4+0] = cur[q*3+0];
+               }
+            }
+         }
+      }
+   } else if (depth == 16) {
+      // force the image data from big-endian to platform-native.
+      // this is done in a separate pass due to the decoding relying
+      // on the data being untouched, but could probably be done
+      // per-line during decode if care is taken.
+      stbi_uc *cur = a->out;
+      stbi__uint16 *cur16 = (stbi__uint16*)cur;
+
+      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
+         *cur16 = (cur[0] << 8) | cur[1];
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+{
+   int bytes = (depth == 16 ? 2 : 1);
+   int out_bytes = out_n * bytes;
+   stbi_uc *final;
+   int p;
+   if (!interlaced)
+      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+
+   // de-interlacing
+   final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
+   for (p=0; p < 7; ++p) {
+      int xorig[] = { 0,4,0,2,0,1,0 };
+      int yorig[] = { 0,0,4,0,2,0,1 };
+      int xspc[]  = { 8,8,4,4,2,2,1 };
+      int yspc[]  = { 8,8,8,4,4,2,2 };
+      int i,j,x,y;
+      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+      if (x && y) {
+         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+            STBI_FREE(final);
+            return 0;
+         }
+         for (j=0; j < y; ++j) {
+            for (i=0; i < x; ++i) {
+               int out_y = j*yspc[p]+yorig[p];
+               int out_x = i*xspc[p]+xorig[p];
+               memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
+                      a->out + (j*x+i)*out_bytes, out_bytes);
+            }
+         }
+         STBI_FREE(a->out);
+         image_data += img_len;
+         image_data_len -= img_len;
+      }
+   }
+   a->out = final;
+
+   return 1;
+}
+
+static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 255 as the alpha value in the output
+   STBI_ASSERT(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i=0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 255);
+         p += 2;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi__uint16 *p = (stbi__uint16*) z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 65535 as the alpha value in the output
+   STBI_ASSERT(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i = 0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 65535);
+         p += 2;
+      }
+   } else {
+      for (i = 0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+{
+   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+   stbi_uc *p, *temp_out, *orig = a->out;
+
+   p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
+   if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+   // between here and free(out) below, exitting would leak
+   temp_out = p;
+
+   if (pal_img_n == 3) {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p += 3;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p[3] = palette[n+3];
+         p += 4;
+      }
+   }
+   STBI_FREE(a->out);
+   a->out = temp_out;
+
+   STBI_NOTUSED(len);
+
+   return 1;
+}
+
+static int stbi__unpremultiply_on_load = 0;
+static int stbi__de_iphone_flag = 0;
+
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+   stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+   stbi__de_iphone_flag = flag_true_if_should_convert;
+}
+
+static void stbi__de_iphone(stbi__png *z)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   if (s->img_out_n == 3) {  // convert bgr to rgb
+      for (i=0; i < pixel_count; ++i) {
+         stbi_uc t = p[0];
+         p[0] = p[2];
+         p[2] = t;
+         p += 3;
+      }
+   } else {
+      STBI_ASSERT(s->img_out_n == 4);
+      if (stbi__unpremultiply_on_load) {
+         // convert bgr to rgb and unpremultiply
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc a = p[3];
+            stbi_uc t = p[0];
+            if (a) {
+               stbi_uc half = a / 2;
+               p[0] = (p[2] * 255 + half) / a;
+               p[1] = (p[1] * 255 + half) / a;
+               p[2] = ( t   * 255 + half) / a;
+            } else {
+               p[0] = p[2];
+               p[2] = t;
+            }
+            p += 4;
+         }
+      } else {
+         // convert bgr to rgb
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc t = p[0];
+            p[0] = p[2];
+            p[2] = t;
+            p += 4;
+         }
+      }
+   }
+}
+
+#define STBI__PNG_TYPE(a,b,c,d)  (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
+
+static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
+{
+   stbi_uc palette[1024], pal_img_n=0;
+   stbi_uc has_trans=0, tc[3]={0};
+   stbi__uint16 tc16[3];
+   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+   int first=1,k,interlace=0, color=0, is_iphone=0;
+   stbi__context *s = z->s;
+
+   z->expanded = NULL;
+   z->idata = NULL;
+   z->out = NULL;
+
+   if (!stbi__check_png_header(s)) return 0;
+
+   if (scan == STBI__SCAN_type) return 1;
+
+   for (;;) {
+      stbi__pngchunk c = stbi__get_chunk_header(s);
+      switch (c.type) {
+         case STBI__PNG_TYPE('C','g','B','I'):
+            is_iphone = 1;
+            stbi__skip(s, c.length);
+            break;
+         case STBI__PNG_TYPE('I','H','D','R'): {
+            int comp,filter;
+            if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+            first = 0;
+            if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
+            s->img_x = stbi__get32be(s);
+            s->img_y = stbi__get32be(s);
+            if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+            if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
+            color = stbi__get8(s);  if (color > 6)         return stbi__err("bad ctype","Corrupt PNG");
+            if (color == 3 && z->depth == 16)                  return stbi__err("bad ctype","Corrupt PNG");
+            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
+            comp  = stbi__get8(s);  if (comp) return stbi__err("bad comp method","Corrupt PNG");
+            filter= stbi__get8(s);  if (filter) return stbi__err("bad filter method","Corrupt PNG");
+            interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
+            if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+            if (!pal_img_n) {
+               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+               if (scan == STBI__SCAN_header) return 1;
+            } else {
+               // if paletted, then pal_n is our final components, and
+               // img_n is # components to decompress/filter.
+               s->img_n = 1;
+               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+               // if SCAN_header, have to scan to see if we have a tRNS
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('P','L','T','E'):  {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+            pal_len = c.length / 3;
+            if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+            for (i=0; i < pal_len; ++i) {
+               palette[i*4+0] = stbi__get8(s);
+               palette[i*4+1] = stbi__get8(s);
+               palette[i*4+2] = stbi__get8(s);
+               palette[i*4+3] = 255;
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('t','R','N','S'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+            if (pal_img_n) {
+               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
+               if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
+               if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+               pal_img_n = 4;
+               for (i=0; i < c.length; ++i)
+                  palette[i*4+3] = stbi__get8(s);
+            } else {
+               if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
+               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+               has_trans = 1;
+               if (z->depth == 16) {
+                  for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
+               } else {
+                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
+               }
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','D','A','T'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
+            if ((int)(ioff + c.length) < (int)ioff) return 0;
+            if (ioff + c.length > idata_limit) {
+               stbi__uint32 idata_limit_old = idata_limit;
+               stbi_uc *p;
+               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+               while (ioff + c.length > idata_limit)
+                  idata_limit *= 2;
+               STBI_NOTUSED(idata_limit_old);
+               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+               z->idata = p;
+            }
+            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+            ioff += c.length;
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','E','N','D'): {
+            stbi__uint32 raw_len, bpl;
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (scan != STBI__SCAN_load) return 1;
+            if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+            // initial guess for decoded data size to avoid unnecessary reallocs
+            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component
+            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
+            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+            if (z->expanded == NULL) return 0; // zlib should set error
+            STBI_FREE(z->idata); z->idata = NULL;
+            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+               s->img_out_n = s->img_n+1;
+            else
+               s->img_out_n = s->img_n;
+            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
+            if (has_trans) {
+               if (z->depth == 16) {
+                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
+               } else {
+                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+               }
+            }
+            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
+               stbi__de_iphone(z);
+            if (pal_img_n) {
+               // pal_img_n == 3 or 4
+               s->img_n = pal_img_n; // record the actual colors we had
+               s->img_out_n = pal_img_n;
+               if (req_comp >= 3) s->img_out_n = req_comp;
+               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+                  return 0;
+            } else if (has_trans) {
+               // non-paletted image with tRNS -> source image has (constant) alpha
+               ++s->img_n;
+            }
+            STBI_FREE(z->expanded); z->expanded = NULL;
+            // end of PNG chunk, read and skip CRC
+            stbi__get32be(s);
+            return 1;
+         }
+
+         default:
+            // if critical, fail
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if ((c.type & (1 << 29)) == 0) {
+               #ifndef STBI_NO_FAILURE_STRINGS
+               // not threadsafe
+               static char invalid_chunk[] = "XXXX PNG chunk not known";
+               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
+               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
+               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);
+               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);
+               #endif
+               return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
+            }
+            stbi__skip(s, c.length);
+            break;
+      }
+      // end of PNG chunk, read and skip CRC
+      stbi__get32be(s);
+   }
+}
+
+static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
+{
+   void *result=NULL;
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+      if (p->depth <= 8)
+         ri->bits_per_channel = 8;
+      else if (p->depth == 16)
+         ri->bits_per_channel = 16;
+      else
+         return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth");
+      result = p->out;
+      p->out = NULL;
+      if (req_comp && req_comp != p->s->img_out_n) {
+         if (ri->bits_per_channel == 8)
+            result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+         else
+            result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+         p->s->img_out_n = req_comp;
+         if (result == NULL) return result;
+      }
+      *x = p->s->img_x;
+      *y = p->s->img_y;
+      if (n) *n = p->s->img_n;
+   }
+   STBI_FREE(p->out);      p->out      = NULL;
+   STBI_FREE(p->expanded); p->expanded = NULL;
+   STBI_FREE(p->idata);    p->idata    = NULL;
+
+   return result;
+}
+
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__do_png(&p, x,y,comp,req_comp, ri);
+}
+
+static int stbi__png_test(stbi__context *s)
+{
+   int r;
+   r = stbi__check_png_header(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
+{
+   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
+      stbi__rewind( p->s );
+      return 0;
+   }
+   if (x) *x = p->s->img_x;
+   if (y) *y = p->s->img_y;
+   if (comp) *comp = p->s->img_n;
+   return 1;
+}
+
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__png_info_raw(&p, x, y, comp);
+}
+
+static int stbi__png_is16(stbi__context *s)
+{
+   stbi__png p;
+   p.s = s;
+   if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
+	   return 0;
+   if (p.depth != 16) {
+      stbi__rewind(p.s);
+      return 0;
+   }
+   return 1;
+}
+#endif
+
+// Microsoft/Windows BMP image
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test_raw(stbi__context *s)
+{
+   int r;
+   int sz;
+   if (stbi__get8(s) != 'B') return 0;
+   if (stbi__get8(s) != 'M') return 0;
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   stbi__get32le(s); // discard data offset
+   sz = stbi__get32le(s);
+   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
+   return r;
+}
+
+static int stbi__bmp_test(stbi__context *s)
+{
+   int r = stbi__bmp_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int stbi__high_bit(unsigned int z)
+{
+   int n=0;
+   if (z == 0) return -1;
+   if (z >= 0x10000) { n += 16; z >>= 16; }
+   if (z >= 0x00100) { n +=  8; z >>=  8; }
+   if (z >= 0x00010) { n +=  4; z >>=  4; }
+   if (z >= 0x00004) { n +=  2; z >>=  2; }
+   if (z >= 0x00002) { n +=  1;/* >>=  1;*/ }
+   return n;
+}
+
+static int stbi__bitcount(unsigned int a)
+{
+   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2
+   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4
+   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+   a = (a + (a >> 8)); // max 16 per 8 bits
+   a = (a + (a >> 16)); // max 32 per 8 bits
+   return a & 0xff;
+}
+
+// extract an arbitrarily-aligned N-bit value (N=bits)
+// from v, and then make it 8-bits long and fractionally
+// extend it to full full range.
+static int stbi__shiftsigned(unsigned int v, int shift, int bits)
+{
+   static unsigned int mul_table[9] = {
+      0,
+      0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
+      0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
+   };
+   static unsigned int shift_table[9] = {
+      0, 0,0,1,0,2,4,6,0,
+   };
+   if (shift < 0)
+      v <<= -shift;
+   else
+      v >>= shift;
+   STBI_ASSERT(v < 256);
+   v >>= (8-bits);
+   STBI_ASSERT(bits >= 0 && bits <= 8);
+   return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
+}
+
+typedef struct
+{
+   int bpp, offset, hsz;
+   unsigned int mr,mg,mb,ma, all_a;
+   int extra_read;
+} stbi__bmp_data;
+
+static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
+{
+   int hsz;
+   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   info->offset = stbi__get32le(s);
+   info->hsz = hsz = stbi__get32le(s);
+   info->mr = info->mg = info->mb = info->ma = 0;
+   info->extra_read = 14;
+
+   if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP");
+
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
+   if (hsz == 12) {
+      s->img_x = stbi__get16le(s);
+      s->img_y = stbi__get16le(s);
+   } else {
+      s->img_x = stbi__get32le(s);
+      s->img_y = stbi__get32le(s);
+   }
+   if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
+   info->bpp = stbi__get16le(s);
+   if (hsz != 12) {
+      int compress = stbi__get32le(s);
+      if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+      stbi__get32le(s); // discard sizeof
+      stbi__get32le(s); // discard hres
+      stbi__get32le(s); // discard vres
+      stbi__get32le(s); // discard colorsused
+      stbi__get32le(s); // discard max important
+      if (hsz == 40 || hsz == 56) {
+         if (hsz == 56) {
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+         }
+         if (info->bpp == 16 || info->bpp == 32) {
+            if (compress == 0) {
+               if (info->bpp == 32) {
+                  info->mr = 0xffu << 16;
+                  info->mg = 0xffu <<  8;
+                  info->mb = 0xffu <<  0;
+                  info->ma = 0xffu << 24;
+                  info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+               } else {
+                  info->mr = 31u << 10;
+                  info->mg = 31u <<  5;
+                  info->mb = 31u <<  0;
+               }
+            } else if (compress == 3) {
+               info->mr = stbi__get32le(s);
+               info->mg = stbi__get32le(s);
+               info->mb = stbi__get32le(s);
+               info->extra_read += 12;
+               // not documented, but generated by photoshop and handled by mspaint
+               if (info->mr == info->mg && info->mg == info->mb) {
+                  // ?!?!?
+                  return stbi__errpuc("bad BMP", "bad BMP");
+               }
+            } else
+               return stbi__errpuc("bad BMP", "bad BMP");
+         }
+      } else {
+         int i;
+         if (hsz != 108 && hsz != 124)
+            return stbi__errpuc("bad BMP", "bad BMP");
+         info->mr = stbi__get32le(s);
+         info->mg = stbi__get32le(s);
+         info->mb = stbi__get32le(s);
+         info->ma = stbi__get32le(s);
+         stbi__get32le(s); // discard color space
+         for (i=0; i < 12; ++i)
+            stbi__get32le(s); // discard color space parameters
+         if (hsz == 124) {
+            stbi__get32le(s); // discard rendering intent
+            stbi__get32le(s); // discard offset of profile data
+            stbi__get32le(s); // discard size of profile data
+            stbi__get32le(s); // discard reserved
+         }
+      }
+   }
+   return (void *) 1;
+}
+
+
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *out;
+   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
+   stbi_uc pal[256][4];
+   int psize=0,i,j,width;
+   int flip_vertically, pad, target;
+   stbi__bmp_data info;
+   STBI_NOTUSED(ri);
+
+   info.all_a = 255;
+   if (stbi__bmp_parse_header(s, &info) == NULL)
+      return NULL; // error code already set
+
+   flip_vertically = ((int) s->img_y) > 0;
+   s->img_y = abs((int) s->img_y);
+
+   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   mr = info.mr;
+   mg = info.mg;
+   mb = info.mb;
+   ma = info.ma;
+   all_a = info.all_a;
+
+   if (info.hsz == 12) {
+      if (info.bpp < 24)
+         psize = (info.offset - info.extra_read - 24) / 3;
+   } else {
+      if (info.bpp < 16)
+         psize = (info.offset - info.extra_read - info.hsz) >> 2;
+   }
+   if (psize == 0) {
+      STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original));
+      if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) {
+        return stbi__errpuc("bad offset", "Corrupt BMP");
+      }
+   }
+
+   if (info.bpp == 24 && ma == 0xff000000)
+      s->img_n = 3;
+   else
+      s->img_n = ma ? 4 : 3;
+   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+      target = req_comp;
+   else
+      target = s->img_n; // if they want monochrome, we'll post-convert
+
+   // sanity-check size
+   if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))
+      return stbi__errpuc("too large", "Corrupt BMP");
+
+   out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   if (info.bpp < 16) {
+      int z=0;
+      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
+      for (i=0; i < psize; ++i) {
+         pal[i][2] = stbi__get8(s);
+         pal[i][1] = stbi__get8(s);
+         pal[i][0] = stbi__get8(s);
+         if (info.hsz != 12) stbi__get8(s);
+         pal[i][3] = 255;
+      }
+      stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+      if (info.bpp == 1) width = (s->img_x + 7) >> 3;
+      else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+      else if (info.bpp == 8) width = s->img_x;
+      else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
+      pad = (-width)&3;
+      if (info.bpp == 1) {
+         for (j=0; j < (int) s->img_y; ++j) {
+            int bit_offset = 7, v = stbi__get8(s);
+            for (i=0; i < (int) s->img_x; ++i) {
+               int color = (v>>bit_offset)&0x1;
+               out[z++] = pal[color][0];
+               out[z++] = pal[color][1];
+               out[z++] = pal[color][2];
+               if (target == 4) out[z++] = 255;
+               if (i+1 == (int) s->img_x) break;
+               if((--bit_offset) < 0) {
+                  bit_offset = 7;
+                  v = stbi__get8(s);
+               }
+            }
+            stbi__skip(s, pad);
+         }
+      } else {
+         for (j=0; j < (int) s->img_y; ++j) {
+            for (i=0; i < (int) s->img_x; i += 2) {
+               int v=stbi__get8(s),v2=0;
+               if (info.bpp == 4) {
+                  v2 = v & 15;
+                  v >>= 4;
+               }
+               out[z++] = pal[v][0];
+               out[z++] = pal[v][1];
+               out[z++] = pal[v][2];
+               if (target == 4) out[z++] = 255;
+               if (i+1 == (int) s->img_x) break;
+               v = (info.bpp == 8) ? stbi__get8(s) : v2;
+               out[z++] = pal[v][0];
+               out[z++] = pal[v][1];
+               out[z++] = pal[v][2];
+               if (target == 4) out[z++] = 255;
+            }
+            stbi__skip(s, pad);
+         }
+      }
+   } else {
+      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+      int z = 0;
+      int easy=0;
+      stbi__skip(s, info.offset - info.extra_read - info.hsz);
+      if (info.bpp == 24) width = 3 * s->img_x;
+      else if (info.bpp == 16) width = 2*s->img_x;
+      else /* bpp = 32 and pad = 0 */ width=0;
+      pad = (-width) & 3;
+      if (info.bpp == 24) {
+         easy = 1;
+      } else if (info.bpp == 32) {
+         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+            easy = 2;
+      }
+      if (!easy) {
+         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+         // right shift amt to put high bit in position #7
+         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
+         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
+         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
+         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+         if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+      }
+      for (j=0; j < (int) s->img_y; ++j) {
+         if (easy) {
+            for (i=0; i < (int) s->img_x; ++i) {
+               unsigned char a;
+               out[z+2] = stbi__get8(s);
+               out[z+1] = stbi__get8(s);
+               out[z+0] = stbi__get8(s);
+               z += 3;
+               a = (easy == 2 ? stbi__get8(s) : 255);
+               all_a |= a;
+               if (target == 4) out[z++] = a;
+            }
+         } else {
+            int bpp = info.bpp;
+            for (i=0; i < (int) s->img_x; ++i) {
+               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
+               unsigned int a;
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
+               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
+               all_a |= a;
+               if (target == 4) out[z++] = STBI__BYTECAST(a);
+            }
+         }
+         stbi__skip(s, pad);
+      }
+   }
+
+   // if alpha channel is all 0s, replace with all 255s
+   if (target == 4 && all_a == 0)
+      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)
+         out[i] = 255;
+
+   if (flip_vertically) {
+      stbi_uc t;
+      for (j=0; j < (int) s->img_y>>1; ++j) {
+         stbi_uc *p1 = out +      j     *s->img_x*target;
+         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+         for (i=0; i < (int) s->img_x*target; ++i) {
+            t = p1[i]; p1[i] = p2[i]; p2[i] = t;
+         }
+      }
+   }
+
+   if (req_comp && req_comp != target) {
+      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   *x = s->img_x;
+   *y = s->img_y;
+   if (comp) *comp = s->img_n;
+   return out;
+}
+#endif
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+#ifndef STBI_NO_TGA
+// returns STBI_rgb or whatever, 0 on error
+static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
+{
+   // only RGB or RGBA (incl. 16bit) or grey allowed
+   if (is_rgb16) *is_rgb16 = 0;
+   switch(bits_per_pixel) {
+      case 8:  return STBI_grey;
+      case 16: if(is_grey) return STBI_grey_alpha;
+               // fallthrough
+      case 15: if(is_rgb16) *is_rgb16 = 1;
+               return STBI_rgb;
+      case 24: // fallthrough
+      case 32: return bits_per_pixel/8;
+      default: return 0;
+   }
+}
+
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
+{
+    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
+    int sz, tga_colormap_type;
+    stbi__get8(s);                   // discard Offset
+    tga_colormap_type = stbi__get8(s); // colormap type
+    if( tga_colormap_type > 1 ) {
+        stbi__rewind(s);
+        return 0;      // only RGB or indexed allowed
+    }
+    tga_image_type = stbi__get8(s); // image type
+    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
+        if (tga_image_type != 1 && tga_image_type != 9) {
+            stbi__rewind(s);
+            return 0;
+        }
+        stbi__skip(s,4);       // skip index of first colormap entry and number of entries
+        sz = stbi__get8(s);    //   check bits per palette color entry
+        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
+            stbi__rewind(s);
+            return 0;
+        }
+        stbi__skip(s,4);       // skip image x and y origin
+        tga_colormap_bpp = sz;
+    } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
+        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
+            stbi__rewind(s);
+            return 0; // only RGB or grey allowed, +/- RLE
+        }
+        stbi__skip(s,9); // skip colormap specification and image x/y origin
+        tga_colormap_bpp = 0;
+    }
+    tga_w = stbi__get16le(s);
+    if( tga_w < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test width
+    }
+    tga_h = stbi__get16le(s);
+    if( tga_h < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test height
+    }
+    tga_bits_per_pixel = stbi__get8(s); // bits per pixel
+    stbi__get8(s); // ignore alpha bits
+    if (tga_colormap_bpp != 0) {
+        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
+            // when using a colormap, tga_bits_per_pixel is the size of the indexes
+            // I don't think anything but 8 or 16bit indexes makes sense
+            stbi__rewind(s);
+            return 0;
+        }
+        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
+    } else {
+        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
+    }
+    if(!tga_comp) {
+      stbi__rewind(s);
+      return 0;
+    }
+    if (x) *x = tga_w;
+    if (y) *y = tga_h;
+    if (comp) *comp = tga_comp;
+    return 1;                   // seems to have passed everything
+}
+
+static int stbi__tga_test(stbi__context *s)
+{
+   int res = 0;
+   int sz, tga_color_type;
+   stbi__get8(s);      //   discard Offset
+   tga_color_type = stbi__get8(s);   //   color type
+   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed
+   sz = stbi__get8(s);   //   image type
+   if ( tga_color_type == 1 ) { // colormapped (paletted) image
+      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
+      stbi__skip(s,4);       // skip index of first colormap entry and number of entries
+      sz = stbi__get8(s);    //   check bits per palette color entry
+      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+      stbi__skip(s,4);       // skip image x and y origin
+   } else { // "normal" image w/o colormap
+      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
+      stbi__skip(s,9); // skip colormap specification and image x/y origin
+   }
+   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width
+   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height
+   sz = stbi__get8(s);   //   bits per pixel
+   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
+   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+
+   res = 1; // if we got this far, everything's good and we can return 1 instead of 0
+
+errorEnd:
+   stbi__rewind(s);
+   return res;
+}
+
+// read 16bit value and convert to 24bit RGB
+static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
+{
+   stbi__uint16 px = (stbi__uint16)stbi__get16le(s);
+   stbi__uint16 fiveBitMask = 31;
+   // we have 3 channels with 5bits each
+   int r = (px >> 10) & fiveBitMask;
+   int g = (px >> 5) & fiveBitMask;
+   int b = px & fiveBitMask;
+   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
+   out[0] = (stbi_uc)((r * 255)/31);
+   out[1] = (stbi_uc)((g * 255)/31);
+   out[2] = (stbi_uc)((b * 255)/31);
+
+   // some people claim that the most significant bit might be used for alpha
+   // (possibly if an alpha-bit is set in the "image descriptor byte")
+   // but that only made 16bit test images completely translucent..
+   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.
+}
+
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   //   read in the TGA header stuff
+   int tga_offset = stbi__get8(s);
+   int tga_indexed = stbi__get8(s);
+   int tga_image_type = stbi__get8(s);
+   int tga_is_RLE = 0;
+   int tga_palette_start = stbi__get16le(s);
+   int tga_palette_len = stbi__get16le(s);
+   int tga_palette_bits = stbi__get8(s);
+   int tga_x_origin = stbi__get16le(s);
+   int tga_y_origin = stbi__get16le(s);
+   int tga_width = stbi__get16le(s);
+   int tga_height = stbi__get16le(s);
+   int tga_bits_per_pixel = stbi__get8(s);
+   int tga_comp, tga_rgb16=0;
+   int tga_inverted = stbi__get8(s);
+   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
+   //   image data
+   unsigned char *tga_data;
+   unsigned char *tga_palette = NULL;
+   int i, j;
+   unsigned char raw_data[4] = {0};
+   int RLE_count = 0;
+   int RLE_repeating = 0;
+   int read_next_pixel = 1;
+   STBI_NOTUSED(ri);
+   STBI_NOTUSED(tga_x_origin); // @TODO
+   STBI_NOTUSED(tga_y_origin); // @TODO
+
+   if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   //   do a tiny bit of precessing
+   if ( tga_image_type >= 8 )
+   {
+      tga_image_type -= 8;
+      tga_is_RLE = 1;
+   }
+   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+   //   If I'm paletted, then I'll use the number of bits from the palette
+   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
+   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
+
+   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
+      return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
+
+   //   tga info
+   *x = tga_width;
+   *y = tga_height;
+   if (comp) *comp = tga_comp;
+
+   if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))
+      return stbi__errpuc("too large", "Corrupt TGA");
+
+   tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
+   if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
+
+   // skip to the data's starting position (offset usually = 0)
+   stbi__skip(s, tga_offset );
+
+   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
+      for (i=0; i < tga_height; ++i) {
+         int row = tga_inverted ? tga_height -i - 1 : i;
+         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
+         stbi__getn(s, tga_row, tga_width * tga_comp);
+      }
+   } else  {
+      //   do I need to load a palette?
+      if ( tga_indexed)
+      {
+         if (tga_palette_len == 0) {  /* you have to have at least one entry! */
+            STBI_FREE(tga_data);
+            return stbi__errpuc("bad palette", "Corrupt TGA");
+         }
+
+         //   any data to skip? (offset usually = 0)
+         stbi__skip(s, tga_palette_start );
+         //   load the palette
+         tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);
+         if (!tga_palette) {
+            STBI_FREE(tga_data);
+            return stbi__errpuc("outofmem", "Out of memory");
+         }
+         if (tga_rgb16) {
+            stbi_uc *pal_entry = tga_palette;
+            STBI_ASSERT(tga_comp == STBI_rgb);
+            for (i=0; i < tga_palette_len; ++i) {
+               stbi__tga_read_rgb16(s, pal_entry);
+               pal_entry += tga_comp;
+            }
+         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
+               STBI_FREE(tga_data);
+               STBI_FREE(tga_palette);
+               return stbi__errpuc("bad palette", "Corrupt TGA");
+         }
+      }
+      //   load the data
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
+         if ( tga_is_RLE )
+         {
+            if ( RLE_count == 0 )
+            {
+               //   yep, get the next byte as a RLE command
+               int RLE_cmd = stbi__get8(s);
+               RLE_count = 1 + (RLE_cmd & 127);
+               RLE_repeating = RLE_cmd >> 7;
+               read_next_pixel = 1;
+            } else if ( !RLE_repeating )
+            {
+               read_next_pixel = 1;
+            }
+         } else
+         {
+            read_next_pixel = 1;
+         }
+         //   OK, if I need to read a pixel, do it now
+         if ( read_next_pixel )
+         {
+            //   load however much data we did have
+            if ( tga_indexed )
+            {
+               // read in index, then perform the lookup
+               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
+               if ( pal_idx >= tga_palette_len ) {
+                  // invalid index
+                  pal_idx = 0;
+               }
+               pal_idx *= tga_comp;
+               for (j = 0; j < tga_comp; ++j) {
+                  raw_data[j] = tga_palette[pal_idx+j];
+               }
+            } else if(tga_rgb16) {
+               STBI_ASSERT(tga_comp == STBI_rgb);
+               stbi__tga_read_rgb16(s, raw_data);
+            } else {
+               //   read in the data raw
+               for (j = 0; j < tga_comp; ++j) {
+                  raw_data[j] = stbi__get8(s);
+               }
+            }
+            //   clear the reading flag for the next pixel
+            read_next_pixel = 0;
+         } // end of reading a pixel
+
+         // copy data
+         for (j = 0; j < tga_comp; ++j)
+           tga_data[i*tga_comp+j] = raw_data[j];
+
+         //   in case we're in RLE mode, keep counting down
+         --RLE_count;
+      }
+      //   do I need to invert the image?
+      if ( tga_inverted )
+      {
+         for (j = 0; j*2 < tga_height; ++j)
+         {
+            int index1 = j * tga_width * tga_comp;
+            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+            for (i = tga_width * tga_comp; i > 0; --i)
+            {
+               unsigned char temp = tga_data[index1];
+               tga_data[index1] = tga_data[index2];
+               tga_data[index2] = temp;
+               ++index1;
+               ++index2;
+            }
+         }
+      }
+      //   clear my palette, if I had one
+      if ( tga_palette != NULL )
+      {
+         STBI_FREE( tga_palette );
+      }
+   }
+
+   // swap RGB - if the source data was RGB16, it already is in the right order
+   if (tga_comp >= 3 && !tga_rgb16)
+   {
+      unsigned char* tga_pixel = tga_data;
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         unsigned char temp = tga_pixel[0];
+         tga_pixel[0] = tga_pixel[2];
+         tga_pixel[2] = temp;
+         tga_pixel += tga_comp;
+      }
+   }
+
+   // convert to target component count
+   if (req_comp && req_comp != tga_comp)
+      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
+   //   the things I do to get rid of an error message, and yet keep
+   //   Microsoft's C compilers happy... [8^(
+   tga_palette_start = tga_palette_len = tga_palette_bits =
+         tga_x_origin = tga_y_origin = 0;
+   STBI_NOTUSED(tga_palette_start);
+   //   OK, done
+   return tga_data;
+}
+#endif
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s)
+{
+   int r = (stbi__get32be(s) == 0x38425053);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)
+{
+   int count, nleft, len;
+
+   count = 0;
+   while ((nleft = pixelCount - count) > 0) {
+      len = stbi__get8(s);
+      if (len == 128) {
+         // No-op.
+      } else if (len < 128) {
+         // Copy next len+1 bytes literally.
+         len++;
+         if (len > nleft) return 0; // corrupt data
+         count += len;
+         while (len) {
+            *p = stbi__get8(s);
+            p += 4;
+            len--;
+         }
+      } else if (len > 128) {
+         stbi_uc   val;
+         // Next -len+1 bytes in the dest are replicated from next source byte.
+         // (Interpret len as a negative 8-bit int.)
+         len = 257 - len;
+         if (len > nleft) return 0; // corrupt data
+         val = stbi__get8(s);
+         count += len;
+         while (len) {
+            *p = val;
+            p += 4;
+            len--;
+         }
+      }
+   }
+
+   return 1;
+}
+
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+   int pixelCount;
+   int channelCount, compression;
+   int channel, i;
+   int bitdepth;
+   int w,h;
+   stbi_uc *out;
+   STBI_NOTUSED(ri);
+
+   // Check identifier
+   if (stbi__get32be(s) != 0x38425053)   // "8BPS"
+      return stbi__errpuc("not PSD", "Corrupt PSD image");
+
+   // Check file type version.
+   if (stbi__get16be(s) != 1)
+      return stbi__errpuc("wrong version", "Unsupported version of PSD image");
+
+   // Skip 6 reserved bytes.
+   stbi__skip(s, 6 );
+
+   // Read the number of channels (R, G, B, A, etc).
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16)
+      return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+   // Read the rows and columns of the image.
+   h = stbi__get32be(s);
+   w = stbi__get32be(s);
+
+   if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   // Make sure the depth is 8 bits.
+   bitdepth = stbi__get16be(s);
+   if (bitdepth != 8 && bitdepth != 16)
+      return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit");
+
+   // Make sure the color mode is RGB.
+   // Valid options are:
+   //   0: Bitmap
+   //   1: Grayscale
+   //   2: Indexed color
+   //   3: RGB color
+   //   4: CMYK color
+   //   7: Multichannel
+   //   8: Duotone
+   //   9: Lab color
+   if (stbi__get16be(s) != 3)
+      return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
+
+   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
+   stbi__skip(s,stbi__get32be(s) );
+
+   // Skip the image resources.  (resolution, pen tool paths, etc)
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Skip the reserved data.
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Find out if the data is compressed.
+   // Known values:
+   //   0: no compression
+   //   1: RLE compressed
+   compression = stbi__get16be(s);
+   if (compression > 1)
+      return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+
+   // Check size
+   if (!stbi__mad3sizes_valid(4, w, h, 0))
+      return stbi__errpuc("too large", "Corrupt PSD");
+
+   // Create the destination image.
+
+   if (!compression && bitdepth == 16 && bpc == 16) {
+      out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);
+      ri->bits_per_channel = 16;
+   } else
+      out = (stbi_uc *) stbi__malloc(4 * w*h);
+
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   pixelCount = w*h;
+
+   // Initialize the data to zero.
+   //memset( out, 0, pixelCount * 4 );
+
+   // Finally, the image data.
+   if (compression) {
+      // RLE as used by .PSD and .TIFF
+      // Loop until you get the number of unpacked bytes you are expecting:
+      //     Read the next source byte into n.
+      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+      //     Else if n is 128, noop.
+      // Endloop
+
+      // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,
+      // which we're going to just skip.
+      stbi__skip(s, h * channelCount * 2 );
+
+      // Read the RLE data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         stbi_uc *p;
+
+         p = out+channel;
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            for (i = 0; i < pixelCount; i++, p += 4)
+               *p = (channel == 3 ? 255 : 0);
+         } else {
+            // Read the RLE data.
+            if (!stbi__psd_decode_rle(s, p, pixelCount)) {
+               STBI_FREE(out);
+               return stbi__errpuc("corrupt", "bad RLE data");
+            }
+         }
+      }
+
+   } else {
+      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
+      // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.
+
+      // Read the data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            if (bitdepth == 16 && bpc == 16) {
+               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+               stbi__uint16 val = channel == 3 ? 65535 : 0;
+               for (i = 0; i < pixelCount; i++, q += 4)
+                  *q = val;
+            } else {
+               stbi_uc *p = out+channel;
+               stbi_uc val = channel == 3 ? 255 : 0;
+               for (i = 0; i < pixelCount; i++, p += 4)
+                  *p = val;
+            }
+         } else {
+            if (ri->bits_per_channel == 16) {    // output bpc
+               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+               for (i = 0; i < pixelCount; i++, q += 4)
+                  *q = (stbi__uint16) stbi__get16be(s);
+            } else {
+               stbi_uc *p = out+channel;
+               if (bitdepth == 16) {  // input bpc
+                  for (i = 0; i < pixelCount; i++, p += 4)
+                     *p = (stbi_uc) (stbi__get16be(s) >> 8);
+               } else {
+                  for (i = 0; i < pixelCount; i++, p += 4)
+                     *p = stbi__get8(s);
+               }
+            }
+         }
+      }
+   }
+
+   // remove weird white matte from PSD
+   if (channelCount >= 4) {
+      if (ri->bits_per_channel == 16) {
+         for (i=0; i < w*h; ++i) {
+            stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;
+            if (pixel[3] != 0 && pixel[3] != 65535) {
+               float a = pixel[3] / 65535.0f;
+               float ra = 1.0f / a;
+               float inv_a = 65535.0f * (1 - ra);
+               pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);
+               pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);
+               pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);
+            }
+         }
+      } else {
+         for (i=0; i < w*h; ++i) {
+            unsigned char *pixel = out + 4*i;
+            if (pixel[3] != 0 && pixel[3] != 255) {
+               float a = pixel[3] / 255.0f;
+               float ra = 1.0f / a;
+               float inv_a = 255.0f * (1 - ra);
+               pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
+               pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
+               pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+            }
+         }
+      }
+   }
+
+   // convert to desired output format
+   if (req_comp && req_comp != 4) {
+      if (ri->bits_per_channel == 16)
+         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);
+      else
+         out = stbi__convert_format(out, 4, req_comp, w, h);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   if (comp) *comp = 4;
+   *y = h;
+   *x = w;
+
+   return out;
+}
+#endif
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_is4(stbi__context *s,const char *str)
+{
+   int i;
+   for (i=0; i<4; ++i)
+      if (stbi__get8(s) != (stbi_uc)str[i])
+         return 0;
+
+   return 1;
+}
+
+static int stbi__pic_test_core(stbi__context *s)
+{
+   int i;
+
+   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
+      return 0;
+
+   for(i=0;i<84;++i)
+      stbi__get8(s);
+
+   if (!stbi__pic_is4(s,"PICT"))
+      return 0;
+
+   return 1;
+}
+
+typedef struct
+{
+   stbi_uc size,type,channel;
+} stbi__pic_packet;
+
+static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
+{
+   int mask=0x80, i;
+
+   for (i=0; i<4; ++i, mask>>=1) {
+      if (channel & mask) {
+         if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
+         dest[i]=stbi__get8(s);
+      }
+   }
+
+   return dest;
+}
+
+static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+   int mask=0x80,i;
+
+   for (i=0;i<4; ++i, mask>>=1)
+      if (channel&mask)
+         dest[i]=src[i];
+}
+
+static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
+{
+   int act_comp=0,num_packets=0,y,chained;
+   stbi__pic_packet packets[10];
+
+   // this will (should...) cater for even some bizarre stuff like having data
+    // for the same channel in multiple packets.
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return stbi__errpuc("bad format","too many packets");
+
+      packet = &packets[num_packets++];
+
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s))          return stbi__errpuc("bad file","file too short (reading packets)");
+      if (packet->size != 8)  return stbi__errpuc("bad format","packet isn't 8bpp");
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+   for(y=0; y<height; ++y) {
+      int packet_idx;
+
+      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+         stbi__pic_packet *packet = &packets[packet_idx];
+         stbi_uc *dest = result+y*width*4;
+
+         switch (packet->type) {
+            default:
+               return stbi__errpuc("bad format","packet has bad compression type");
+
+            case 0: {//uncompressed
+               int x;
+
+               for(x=0;x<width;++x, dest+=4)
+                  if (!stbi__readval(s,packet->channel,dest))
+                     return 0;
+               break;
+            }
+
+            case 1://Pure RLE
+               {
+                  int left=width, i;
+
+                  while (left>0) {
+                     stbi_uc count,value[4];
+
+                     count=stbi__get8(s);
+                     if (stbi__at_eof(s))   return stbi__errpuc("bad file","file too short (pure read count)");
+
+                     if (count > left)
+                        count = (stbi_uc) left;
+
+                     if (!stbi__readval(s,packet->channel,value))  return 0;
+
+                     for(i=0; i<count; ++i,dest+=4)
+                        stbi__copyval(packet->channel,dest,value);
+                     left -= count;
+                  }
+               }
+               break;
+
+            case 2: {//Mixed RLE
+               int left=width;
+               while (left>0) {
+                  int count = stbi__get8(s), i;
+                  if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (mixed read count)");
+
+                  if (count >= 128) { // Repeated
+                     stbi_uc value[4];
+
+                     if (count==128)
+                        count = stbi__get16be(s);
+                     else
+                        count -= 127;
+                     if (count > left)
+                        return stbi__errpuc("bad file","scanline overrun");
+
+                     if (!stbi__readval(s,packet->channel,value))
+                        return 0;
+
+                     for(i=0;i<count;++i, dest += 4)
+                        stbi__copyval(packet->channel,dest,value);
+                  } else { // Raw
+                     ++count;
+                     if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+                     for(i=0;i<count;++i, dest+=4)
+                        if (!stbi__readval(s,packet->channel,dest))
+                           return 0;
+                  }
+                  left-=count;
+               }
+               break;
+            }
+         }
+      }
+   }
+
+   return result;
+}
+
+static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *result;
+   int i, x,y, internal_comp;
+   STBI_NOTUSED(ri);
+
+   if (!comp) comp = &internal_comp;
+
+   for (i=0; i<92; ++i)
+      stbi__get8(s);
+
+   x = stbi__get16be(s);
+   y = stbi__get16be(s);
+
+   if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (pic header)");
+   if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
+
+   stbi__get32be(s); //skip `ratio'
+   stbi__get16be(s); //skip `fields'
+   stbi__get16be(s); //skip `pad'
+
+   // intermediate buffer is RGBA
+   result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
+   memset(result, 0xff, x*y*4);
+
+   if (!stbi__pic_load_core(s,x,y,comp, result)) {
+      STBI_FREE(result);
+      result=0;
+   }
+   *px = x;
+   *py = y;
+   if (req_comp == 0) req_comp = *comp;
+   result=stbi__convert_format(result,4,req_comp,x,y);
+
+   return result;
+}
+
+static int stbi__pic_test(stbi__context *s)
+{
+   int r = stbi__pic_test_core(s);
+   stbi__rewind(s);
+   return r;
+}
+#endif
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+
+#ifndef STBI_NO_GIF
+typedef struct
+{
+   stbi__int16 prefix;
+   stbi_uc first;
+   stbi_uc suffix;
+} stbi__gif_lzw;
+
+typedef struct
+{
+   int w,h;
+   stbi_uc *out;                 // output buffer (always 4 components)
+   stbi_uc *background;          // The current "background" as far as a gif is concerned
+   stbi_uc *history;
+   int flags, bgindex, ratio, transparent, eflags;
+   stbi_uc  pal[256][4];
+   stbi_uc lpal[256][4];
+   stbi__gif_lzw codes[8192];
+   stbi_uc *color_table;
+   int parse, step;
+   int lflags;
+   int start_x, start_y;
+   int max_x, max_y;
+   int cur_x, cur_y;
+   int line_size;
+   int delay;
+} stbi__gif;
+
+static int stbi__gif_test_raw(stbi__context *s)
+{
+   int sz;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
+   sz = stbi__get8(s);
+   if (sz != '9' && sz != '7') return 0;
+   if (stbi__get8(s) != 'a') return 0;
+   return 1;
+}
+
+static int stbi__gif_test(stbi__context *s)
+{
+   int r = stbi__gif_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
+{
+   int i;
+   for (i=0; i < num_entries; ++i) {
+      pal[i][2] = stbi__get8(s);
+      pal[i][1] = stbi__get8(s);
+      pal[i][0] = stbi__get8(s);
+      pal[i][3] = transp == i ? 0 : 255;
+   }
+}
+
+static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
+{
+   stbi_uc version;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
+      return stbi__err("not GIF", "Corrupt GIF");
+
+   version = stbi__get8(s);
+   if (version != '7' && version != '9')    return stbi__err("not GIF", "Corrupt GIF");
+   if (stbi__get8(s) != 'a')                return stbi__err("not GIF", "Corrupt GIF");
+
+   stbi__g_failure_reason = "";
+   g->w = stbi__get16le(s);
+   g->h = stbi__get16le(s);
+   g->flags = stbi__get8(s);
+   g->bgindex = stbi__get8(s);
+   g->ratio = stbi__get8(s);
+   g->transparent = -1;
+
+   if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+   if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+
+   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments
+
+   if (is_info) return 1;
+
+   if (g->flags & 0x80)
+      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+   return 1;
+}
+
+static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+   if (!stbi__gif_header(s, g, comp, 1)) {
+      STBI_FREE(g);
+      stbi__rewind( s );
+      return 0;
+   }
+   if (x) *x = g->w;
+   if (y) *y = g->h;
+   STBI_FREE(g);
+   return 1;
+}
+
+static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
+{
+   stbi_uc *p, *c;
+   int idx;
+
+   // recurse to decode the prefixes, since the linked-list is backwards,
+   // and working backwards through an interleaved image would be nasty
+   if (g->codes[code].prefix >= 0)
+      stbi__out_gif_code(g, g->codes[code].prefix);
+
+   if (g->cur_y >= g->max_y) return;
+
+   idx = g->cur_x + g->cur_y;
+   p = &g->out[idx];
+   g->history[idx / 4] = 1;
+
+   c = &g->color_table[g->codes[code].suffix * 4];
+   if (c[3] > 128) { // don't render transparent pixels;
+      p[0] = c[2];
+      p[1] = c[1];
+      p[2] = c[0];
+      p[3] = c[3];
+   }
+   g->cur_x += 4;
+
+   if (g->cur_x >= g->max_x) {
+      g->cur_x = g->start_x;
+      g->cur_y += g->step;
+
+      while (g->cur_y >= g->max_y && g->parse > 0) {
+         g->step = (1 << g->parse) * g->line_size;
+         g->cur_y = g->start_y + (g->step >> 1);
+         --g->parse;
+      }
+   }
+}
+
+static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
+{
+   stbi_uc lzw_cs;
+   stbi__int32 len, init_code;
+   stbi__uint32 first;
+   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+   stbi__gif_lzw *p;
+
+   lzw_cs = stbi__get8(s);
+   if (lzw_cs > 12) return NULL;
+   clear = 1 << lzw_cs;
+   first = 1;
+   codesize = lzw_cs + 1;
+   codemask = (1 << codesize) - 1;
+   bits = 0;
+   valid_bits = 0;
+   for (init_code = 0; init_code < clear; init_code++) {
+      g->codes[init_code].prefix = -1;
+      g->codes[init_code].first = (stbi_uc) init_code;
+      g->codes[init_code].suffix = (stbi_uc) init_code;
+   }
+
+   // support no starting clear code
+   avail = clear+2;
+   oldcode = -1;
+
+   len = 0;
+   for(;;) {
+      if (valid_bits < codesize) {
+         if (len == 0) {
+            len = stbi__get8(s); // start new block
+            if (len == 0)
+               return g->out;
+         }
+         --len;
+         bits |= (stbi__int32) stbi__get8(s) << valid_bits;
+         valid_bits += 8;
+      } else {
+         stbi__int32 code = bits & codemask;
+         bits >>= codesize;
+         valid_bits -= codesize;
+         // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+         if (code == clear) {  // clear code
+            codesize = lzw_cs + 1;
+            codemask = (1 << codesize) - 1;
+            avail = clear + 2;
+            oldcode = -1;
+            first = 0;
+         } else if (code == clear + 1) { // end of stream code
+            stbi__skip(s, len);
+            while ((len = stbi__get8(s)) > 0)
+               stbi__skip(s,len);
+            return g->out;
+         } else if (code <= avail) {
+            if (first) {
+               return stbi__errpuc("no clear code", "Corrupt GIF");
+            }
+
+            if (oldcode >= 0) {
+               p = &g->codes[avail++];
+               if (avail > 8192) {
+                  return stbi__errpuc("too many codes", "Corrupt GIF");
+               }
+
+               p->prefix = (stbi__int16) oldcode;
+               p->first = g->codes[oldcode].first;
+               p->suffix = (code == avail) ? p->first : g->codes[code].first;
+            } else if (code == avail)
+               return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+
+            stbi__out_gif_code(g, (stbi__uint16) code);
+
+            if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+               codesize++;
+               codemask = (1 << codesize) - 1;
+            }
+
+            oldcode = code;
+         } else {
+            return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+         }
+      }
+   }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+// two back is the image from two frames ago, used for a very specific disposal format
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
+{
+   int dispose;
+   int first_frame;
+   int pi;
+   int pcount;
+   STBI_NOTUSED(req_comp);
+
+   // on first frame, any non-written pixels get the background colour (non-transparent)
+   first_frame = 0;
+   if (g->out == 0) {
+      if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
+      if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))
+         return stbi__errpuc("too large", "GIF image is too large");
+      pcount = g->w * g->h;
+      g->out = (stbi_uc *) stbi__malloc(4 * pcount);
+      g->background = (stbi_uc *) stbi__malloc(4 * pcount);
+      g->history = (stbi_uc *) stbi__malloc(pcount);
+      if (!g->out || !g->background || !g->history)
+         return stbi__errpuc("outofmem", "Out of memory");
+
+      // image is treated as "transparent" at the start - ie, nothing overwrites the current background;
+      // background colour is only used for pixels that are not rendered first frame, after that "background"
+      // color refers to the color that was there the previous frame.
+      memset(g->out, 0x00, 4 * pcount);
+      memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)
+      memset(g->history, 0x00, pcount);        // pixels that were affected previous frame
+      first_frame = 1;
+   } else {
+      // second frame - how do we dispose of the previous one?
+      dispose = (g->eflags & 0x1C) >> 2;
+      pcount = g->w * g->h;
+
+      if ((dispose == 3) && (two_back == 0)) {
+         dispose = 2; // if I don't have an image to revert back to, default to the old background
+      }
+
+      if (dispose == 3) { // use previous graphic
+         for (pi = 0; pi < pcount; ++pi) {
+            if (g->history[pi]) {
+               memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
+            }
+         }
+      } else if (dispose == 2) {
+         // restore what was changed last frame to background before that frame;
+         for (pi = 0; pi < pcount; ++pi) {
+            if (g->history[pi]) {
+               memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
+            }
+         }
+      } else {
+         // This is a non-disposal case eithe way, so just
+         // leave the pixels as is, and they will become the new background
+         // 1: do not dispose
+         // 0:  not specified.
+      }
+
+      // background is what out is after the undoing of the previou frame;
+      memcpy( g->background, g->out, 4 * g->w * g->h );
+   }
+
+   // clear my history;
+   memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame
+
+   for (;;) {
+      int tag = stbi__get8(s);
+      switch (tag) {
+         case 0x2C: /* Image Descriptor */
+         {
+            stbi__int32 x, y, w, h;
+            stbi_uc *o;
+
+            x = stbi__get16le(s);
+            y = stbi__get16le(s);
+            w = stbi__get16le(s);
+            h = stbi__get16le(s);
+            if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+               return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
+
+            g->line_size = g->w * 4;
+            g->start_x = x * 4;
+            g->start_y = y * g->line_size;
+            g->max_x   = g->start_x + w * 4;
+            g->max_y   = g->start_y + h * g->line_size;
+            g->cur_x   = g->start_x;
+            g->cur_y   = g->start_y;
+
+            // if the width of the specified rectangle is 0, that means
+            // we may not see *any* pixels or the image is malformed;
+            // to make sure this is caught, move the current y down to
+            // max_y (which is what out_gif_code checks).
+            if (w == 0)
+               g->cur_y = g->max_y;
+
+            g->lflags = stbi__get8(s);
+
+            if (g->lflags & 0x40) {
+               g->step = 8 * g->line_size; // first interlaced spacing
+               g->parse = 3;
+            } else {
+               g->step = g->line_size;
+               g->parse = 0;
+            }
+
+            if (g->lflags & 0x80) {
+               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+               g->color_table = (stbi_uc *) g->lpal;
+            } else if (g->flags & 0x80) {
+               g->color_table = (stbi_uc *) g->pal;
+            } else
+               return stbi__errpuc("missing color table", "Corrupt GIF");
+
+            o = stbi__process_gif_raster(s, g);
+            if (!o) return NULL;
+
+            // if this was the first frame,
+            pcount = g->w * g->h;
+            if (first_frame && (g->bgindex > 0)) {
+               // if first frame, any pixel not drawn to gets the background color
+               for (pi = 0; pi < pcount; ++pi) {
+                  if (g->history[pi] == 0) {
+                     g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
+                     memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
+                  }
+               }
+            }
+
+            return o;
+         }
+
+         case 0x21: // Comment Extension.
+         {
+            int len;
+            int ext = stbi__get8(s);
+            if (ext == 0xF9) { // Graphic Control Extension.
+               len = stbi__get8(s);
+               if (len == 4) {
+                  g->eflags = stbi__get8(s);
+                  g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
+
+                  // unset old transparent
+                  if (g->transparent >= 0) {
+                     g->pal[g->transparent][3] = 255;
+                  }
+                  if (g->eflags & 0x01) {
+                     g->transparent = stbi__get8(s);
+                     if (g->transparent >= 0) {
+                        g->pal[g->transparent][3] = 0;
+                     }
+                  } else {
+                     // don't need transparent
+                     stbi__skip(s, 1);
+                     g->transparent = -1;
+                  }
+               } else {
+                  stbi__skip(s, len);
+                  break;
+               }
+            }
+            while ((len = stbi__get8(s)) != 0) {
+               stbi__skip(s, len);
+            }
+            break;
+         }
+
+         case 0x3B: // gif stream termination code
+            return (stbi_uc *) s; // using '1' causes warning on some compilers
+
+         default:
+            return stbi__errpuc("unknown code", "Corrupt GIF");
+      }
+   }
+}
+
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+   if (stbi__gif_test(s)) {
+      int layers = 0;
+      stbi_uc *u = 0;
+      stbi_uc *out = 0;
+      stbi_uc *two_back = 0;
+      stbi__gif g;
+      int stride;
+      memset(&g, 0, sizeof(g));
+      if (delays) {
+         *delays = 0;
+      }
+
+      do {
+         u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
+         if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
+
+         if (u) {
+            *x = g.w;
+            *y = g.h;
+            ++layers;
+            stride = g.w * g.h * 4;
+
+            if (out) {
+               void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, 0, layers * stride );
+               if (NULL == tmp) {
+                  STBI_FREE(g.out);
+                  STBI_FREE(g.history);
+                  STBI_FREE(g.background);
+                  return stbi__errpuc("outofmem", "Out of memory");
+               }
+               else {
+                   out = (stbi_uc*) tmp;
+               }
+
+               if (delays) {
+                  *delays = (int*) STBI_REALLOC_SIZED( *delays, 0, sizeof(int) * layers );
+               }
+            } else {
+               out = (stbi_uc*)stbi__malloc( layers * stride );
+               if (delays) {
+                  *delays = (int*) stbi__malloc( layers * sizeof(int) );
+               }
+            }
+            memcpy( out + ((layers - 1) * stride), u, stride );
+            if (layers >= 2) {
+               two_back = out - 2 * stride;
+            }
+
+            if (delays) {
+               (*delays)[layers - 1U] = g.delay;
+            }
+         }
+      } while (u != 0);
+
+      // free temp buffer;
+      STBI_FREE(g.out);
+      STBI_FREE(g.history);
+      STBI_FREE(g.background);
+
+      // do the final conversion after loading everything;
+      if (req_comp && req_comp != 4)
+         out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
+
+      *z = layers;
+      return out;
+   } else {
+      return stbi__errpuc("not GIF", "Image was not as a gif type.");
+   }
+}
+
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *u = 0;
+   stbi__gif g;
+   memset(&g, 0, sizeof(g));
+   STBI_NOTUSED(ri);
+
+   u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
+   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
+   if (u) {
+      *x = g.w;
+      *y = g.h;
+
+      // moved conversion to after successful load so that the same
+      // can be done for multiple frames.
+      if (req_comp && req_comp != 4)
+         u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
+   } else if (g.out) {
+      // if there was an error and we allocated an image buffer, free it!
+      STBI_FREE(g.out);
+   }
+
+   // free buffers needed for multiple frame loading;
+   STBI_FREE(g.history);
+   STBI_FREE(g.background);
+
+   return u;
+}
+
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   return stbi__gif_info_raw(s,x,y,comp);
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test_core(stbi__context *s, const char *signature)
+{
+   int i;
+   for (i=0; signature[i]; ++i)
+      if (stbi__get8(s) != signature[i])
+          return 0;
+   stbi__rewind(s);
+   return 1;
+}
+
+static int stbi__hdr_test(stbi__context* s)
+{
+   int r = stbi__hdr_test_core(s, "#?RADIANCE\n");
+   stbi__rewind(s);
+   if(!r) {
+       r = stbi__hdr_test_core(s, "#?RGBE\n");
+       stbi__rewind(s);
+   }
+   return r;
+}
+
+#define STBI__HDR_BUFLEN  1024
+static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
+{
+   int len=0;
+   char c = '\0';
+
+   c = (char) stbi__get8(z);
+
+   while (!stbi__at_eof(z) && c != '\n') {
+      buffer[len++] = c;
+      if (len == STBI__HDR_BUFLEN-1) {
+         // flush to end of line
+         while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
+            ;
+         break;
+      }
+      c = (char) stbi__get8(z);
+   }
+
+   buffer[len] = 0;
+   return buffer;
+}
+
+static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+   if ( input[3] != 0 ) {
+      float f1;
+      // Exponent
+      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+      if (req_comp <= 2)
+         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+      else {
+         output[0] = input[0] * f1;
+         output[1] = input[1] * f1;
+         output[2] = input[2] * f1;
+      }
+      if (req_comp == 2) output[1] = 1;
+      if (req_comp == 4) output[3] = 1;
+   } else {
+      switch (req_comp) {
+         case 4: output[3] = 1; /* fallthrough */
+         case 3: output[0] = output[1] = output[2] = 0;
+                 break;
+         case 2: output[1] = 1; /* fallthrough */
+         case 1: output[0] = 0;
+                 break;
+      }
+   }
+}
+
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+   int width, height;
+   stbi_uc *scanline;
+   float *hdr_data;
+   int len;
+   unsigned char count, value;
+   int i, j, k, c1,c2, z;
+   const char *headerToken;
+   STBI_NOTUSED(ri);
+
+   // Check identifier
+   headerToken = stbi__hdr_gettoken(s,buffer);
+   if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0)
+      return stbi__errpf("not HDR", "Corrupt HDR image");
+
+   // Parse header
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid)    return stbi__errpf("unsupported format", "Unsupported HDR format");
+
+   // Parse width and height
+   // can't use sscanf() if we're not using stdio!
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   height = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   width = (int) strtol(token, NULL, 10);
+
+   if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+   if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+
+   *x = width;
+   *y = height;
+
+   if (comp) *comp = 3;
+   if (req_comp == 0) req_comp = 3;
+
+   if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))
+      return stbi__errpf("too large", "HDR image is too large");
+
+   // Read data
+   hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
+   if (!hdr_data)
+      return stbi__errpf("outofmem", "Out of memory");
+
+   // Load image data
+   // image data is stored as some number of sca
+   if ( width < 8 || width >= 32768) {
+      // Read flat data
+      for (j=0; j < height; ++j) {
+         for (i=0; i < width; ++i) {
+            stbi_uc rgbe[4];
+           main_decode_loop:
+            stbi__getn(s, rgbe, 4);
+            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+         }
+      }
+   } else {
+      // Read RLE-encoded data
+      scanline = NULL;
+
+      for (j = 0; j < height; ++j) {
+         c1 = stbi__get8(s);
+         c2 = stbi__get8(s);
+         len = stbi__get8(s);
+         if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+            // not run-length encoded, so we have to actually use THIS data as a decoded
+            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+            stbi_uc rgbe[4];
+            rgbe[0] = (stbi_uc) c1;
+            rgbe[1] = (stbi_uc) c2;
+            rgbe[2] = (stbi_uc) len;
+            rgbe[3] = (stbi_uc) stbi__get8(s);
+            stbi__hdr_convert(hdr_data, rgbe, req_comp);
+            i = 1;
+            j = 0;
+            STBI_FREE(scanline);
+            goto main_decode_loop; // yes, this makes no sense
+         }
+         len <<= 8;
+         len |= stbi__get8(s);
+         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
+         if (scanline == NULL) {
+            scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
+            if (!scanline) {
+               STBI_FREE(hdr_data);
+               return stbi__errpf("outofmem", "Out of memory");
+            }
+         }
+
+         for (k = 0; k < 4; ++k) {
+            int nleft;
+            i = 0;
+            while ((nleft = width - i) > 0) {
+               count = stbi__get8(s);
+               if (count > 128) {
+                  // Run
+                  value = stbi__get8(s);
+                  count -= 128;
+                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = value;
+               } else {
+                  // Dump
+                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = stbi__get8(s);
+               }
+            }
+         }
+         for (i=0; i < width; ++i)
+            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+      }
+      if (scanline)
+         STBI_FREE(scanline);
+   }
+
+   return hdr_data;
+}
+
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+   int dummy;
+
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+
+   if (stbi__hdr_test(s) == 0) {
+       stbi__rewind( s );
+       return 0;
+   }
+
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *y = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *x = (int) strtol(token, NULL, 10);
+   *comp = 3;
+   return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   void *p;
+   stbi__bmp_data info;
+
+   info.all_a = 255;
+   p = stbi__bmp_parse_header(s, &info);
+   stbi__rewind( s );
+   if (p == NULL)
+      return 0;
+   if (x) *x = s->img_x;
+   if (y) *y = s->img_y;
+   if (comp) {
+      if (info.bpp == 24 && info.ma == 0xff000000)
+         *comp = 3;
+      else
+         *comp = info.ma ? 4 : 3;
+   }
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int channelCount, dummy, depth;
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+   if (stbi__get32be(s) != 0x38425053) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 1) {
+       stbi__rewind( s );
+       return 0;
+   }
+   stbi__skip(s, 6);
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *y = stbi__get32be(s);
+   *x = stbi__get32be(s);
+   depth = stbi__get16be(s);
+   if (depth != 8 && depth != 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 3) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *comp = 4;
+   return 1;
+}
+
+static int stbi__psd_is16(stbi__context *s)
+{
+   int channelCount, depth;
+   if (stbi__get32be(s) != 0x38425053) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 1) {
+       stbi__rewind( s );
+       return 0;
+   }
+   stbi__skip(s, 6);
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   (void) stbi__get32be(s);
+   (void) stbi__get32be(s);
+   depth = stbi__get16be(s);
+   if (depth != 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int act_comp=0,num_packets=0,chained,dummy;
+   stbi__pic_packet packets[10];
+
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+
+   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
+      stbi__rewind(s);
+      return 0;
+   }
+
+   stbi__skip(s, 88);
+
+   *x = stbi__get16be(s);
+   *y = stbi__get16be(s);
+   if (stbi__at_eof(s)) {
+      stbi__rewind( s);
+      return 0;
+   }
+   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+      stbi__rewind( s );
+      return 0;
+   }
+
+   stbi__skip(s, 8);
+
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return 0;
+
+      packet = &packets[num_packets++];
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s)) {
+          stbi__rewind( s );
+          return 0;
+      }
+      if (packet->size != 8) {
+          stbi__rewind( s );
+          return 0;
+      }
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3);
+
+   return 1;
+}
+#endif
+
+// *************************************************************************************************
+// Portable Gray Map and Portable Pixel Map loader
+// by Ken Miller
+//
+// PGM: http://netpbm.sourceforge.net/doc/pgm.html
+// PPM: http://netpbm.sourceforge.net/doc/ppm.html
+//
+// Known limitations:
+//    Does not support comments in the header section
+//    Does not support ASCII image data (formats P2 and P3)
+//    Does not support 16-bit-per-channel
+
+#ifndef STBI_NO_PNM
+
+static int      stbi__pnm_test(stbi__context *s)
+{
+   char p, t;
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind( s );
+       return 0;
+   }
+   return 1;
+}
+
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *out;
+   STBI_NOTUSED(ri);
+
+   if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
+      return 0;
+
+   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   *x = s->img_x;
+   *y = s->img_y;
+   if (comp) *comp = s->img_n;
+
+   if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
+      return stbi__errpuc("too large", "PNM too large");
+
+   out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
+
+   if (req_comp && req_comp != s->img_n) {
+      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+   return out;
+}
+
+static int      stbi__pnm_isspace(char c)
+{
+   return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
+}
+
+static void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)
+{
+   for (;;) {
+      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
+         *c = (char) stbi__get8(s);
+
+      if (stbi__at_eof(s) || *c != '#')
+         break;
+
+      while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
+         *c = (char) stbi__get8(s);
+   }
+}
+
+static int      stbi__pnm_isdigit(char c)
+{
+   return c >= '0' && c <= '9';
+}
+
+static int      stbi__pnm_getinteger(stbi__context *s, char *c)
+{
+   int value = 0;
+
+   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
+      value = value*10 + (*c - '0');
+      *c = (char) stbi__get8(s);
+   }
+
+   return value;
+}
+
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int maxv, dummy;
+   char c, p, t;
+
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+
+   stbi__rewind(s);
+
+   // Get identifier
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind(s);
+       return 0;
+   }
+
+   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm
+
+   c = (char) stbi__get8(s);
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *x = stbi__pnm_getinteger(s, &c); // read width
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *y = stbi__pnm_getinteger(s, &c); // read height
+   stbi__pnm_skip_whitespace(s, &c);
+
+   maxv = stbi__pnm_getinteger(s, &c);  // read max value
+
+   if (maxv > 255)
+      return stbi__err("max value > 255", "PPM image not 8-bit");
+   else
+      return 1;
+}
+#endif
+
+static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
+{
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_info(s, x, y, comp)) return 1;
+   #endif
+
+   #ifndef STBI_NO_PNG
+   if (stbi__png_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_info(s, x, y, comp))  return 1;
+   #endif
+
+   // test tga last because it's a crappy test!
+   #ifndef STBI_NO_TGA
+   if (stbi__tga_info(s, x, y, comp))
+       return 1;
+   #endif
+   return stbi__err("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static int stbi__is_16_main(stbi__context *s)
+{
+   #ifndef STBI_NO_PNG
+   if (stbi__png_is16(s))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_is16(s))  return 1;
+   #endif
+
+   return 0;
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+    FILE *f = stbi__fopen(filename, "rb");
+    int result;
+    if (!f) return stbi__err("can't fopen", "Unable to open file");
+    result = stbi_info_from_file(f, x, y, comp);
+    fclose(f);
+    return result;
+}
+
+STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+   int r;
+   stbi__context s;
+   long pos = ftell(f);
+   stbi__start_file(&s, f);
+   r = stbi__info_main(&s,x,y,comp);
+   fseek(f,pos,SEEK_SET);
+   return r;
+}
+
+STBIDEF int stbi_is_16_bit(char const *filename)
+{
+    FILE *f = stbi__fopen(filename, "rb");
+    int result;
+    if (!f) return stbi__err("can't fopen", "Unable to open file");
+    result = stbi_is_16_bit_from_file(f);
+    fclose(f);
+    return result;
+}
+
+STBIDEF int stbi_is_16_bit_from_file(FILE *f)
+{
+   int r;
+   stbi__context s;
+   long pos = ftell(f);
+   stbi__start_file(&s, f);
+   r = stbi__is_16_main(&s);
+   fseek(f,pos,SEEK_SET);
+   return r;
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__is_16_main(&s);
+}
+
+STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+   return stbi__is_16_main(&s);
+}
+
+#endif // STB_IMAGE_IMPLEMENTATION
+
+/*
+   revision history:
+      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+      2.19  (2018-02-11) fix warning
+      2.18  (2018-01-30) fix warnings
+      2.17  (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
+                         1-bit BMP
+                         *_is_16_bit api
+                         avoid warnings
+      2.16  (2017-07-23) all functions have 16-bit variants;
+                         STBI_NO_STDIO works again;
+                         compilation fixes;
+                         fix rounding in unpremultiply;
+                         optimize vertical flip;
+                         disable raw_len validation;
+                         documentation fixes
+      2.15  (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
+                         warning fixes; disable run-time SSE detection on gcc;
+                         uniform handling of optional "return" values;
+                         thread-safe initialization of zlib tables
+      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+      2.13  (2016-11-29) add 16-bit API, only supported for PNG right now
+      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+      2.11  (2016-04-02) allocate large structures on the stack
+                         remove white matting for transparent PSD
+                         fix reported channel count for PNG & BMP
+                         re-enable SSE2 in non-gcc 64-bit
+                         support RGB-formatted JPEG
+                         read 16-bit PNGs (only as 8-bit)
+      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
+      2.09  (2016-01-16) allow comments in PNM files
+                         16-bit-per-pixel TGA (not bit-per-component)
+                         info() for TGA could break due to .hdr handling
+                         info() for BMP to shares code instead of sloppy parse
+                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc
+                         code cleanup
+      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+      2.07  (2015-09-13) fix compiler warnings
+                         partial animated GIF support
+                         limited 16-bpc PSD support
+                         #ifdef unused functions
+                         bug with < 92 byte PIC,PNM,HDR,TGA
+      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value
+      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning
+      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+      2.03  (2015-04-12) extra corruption checking (mmozeiko)
+                         stbi_set_flip_vertically_on_load (nguillemot)
+                         fix NEON support; fix mingw support
+      2.02  (2015-01-19) fix incorrect assert, fix warning
+      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
+      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
+                         progressive JPEG (stb)
+                         PGM/PPM support (Ken Miller)
+                         STBI_MALLOC,STBI_REALLOC,STBI_FREE
+                         GIF bugfix -- seemingly never worked
+                         STBI_NO_*, STBI_ONLY_*
+      1.48  (2014-12-14) fix incorrectly-named assert()
+      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
+                         optimize PNG (ryg)
+                         fix bug in interlaced PNG with user-specified channel count (stb)
+      1.46  (2014-08-26)
+              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
+      1.45  (2014-08-16)
+              fix MSVC-ARM internal compiler error by wrapping malloc
+      1.44  (2014-08-07)
+              various warning fixes from Ronny Chevalier
+      1.43  (2014-07-15)
+              fix MSVC-only compiler problem in code changed in 1.42
+      1.42  (2014-07-09)
+              don't define _CRT_SECURE_NO_WARNINGS (affects user code)
+              fixes to stbi__cleanup_jpeg path
+              added STBI_ASSERT to avoid requiring assert.h
+      1.41  (2014-06-25)
+              fix search&replace from 1.36 that messed up comments/error messages
+      1.40  (2014-06-22)
+              fix gcc struct-initialization warning
+      1.39  (2014-06-15)
+              fix to TGA optimization when req_comp != number of components in TGA;
+              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
+              add support for BMP version 5 (more ignored fields)
+      1.38  (2014-06-06)
+              suppress MSVC warnings on integer casts truncating values
+              fix accidental rename of 'skip' field of I/O
+      1.37  (2014-06-04)
+              remove duplicate typedef
+      1.36  (2014-06-03)
+              convert to header file single-file library
+              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
+      1.35  (2014-05-27)
+              various warnings
+              fix broken STBI_SIMD path
+              fix bug where stbi_load_from_file no longer left file pointer in correct place
+              fix broken non-easy path for 32-bit BMP (possibly never used)
+              TGA optimization by Arseny Kapoulkine
+      1.34  (unknown)
+              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
+      1.33  (2011-07-14)
+              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+      1.32  (2011-07-13)
+              support for "info" function for all supported filetypes (SpartanJ)
+      1.31  (2011-06-20)
+              a few more leak fixes, bug in PNG handling (SpartanJ)
+      1.30  (2011-06-11)
+              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+              removed deprecated format-specific test/load functions
+              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+              fix inefficiency in decoding 32-bit BMP (David Woo)
+      1.29  (2010-08-16)
+              various warning fixes from Aurelien Pocheville
+      1.28  (2010-08-01)
+              fix bug in GIF palette transparency (SpartanJ)
+      1.27  (2010-08-01)
+              cast-to-stbi_uc to fix warnings
+      1.26  (2010-07-24)
+              fix bug in file buffering for PNG reported by SpartanJ
+      1.25  (2010-07-17)
+              refix trans_data warning (Won Chun)
+      1.24  (2010-07-12)
+              perf improvements reading from files on platforms with lock-heavy fgetc()
+              minor perf improvements for jpeg
+              deprecated type-specific functions so we'll get feedback if they're needed
+              attempt to fix trans_data warning (Won Chun)
+      1.23    fixed bug in iPhone support
+      1.22  (2010-07-10)
+              removed image *writing* support
+              stbi_info support from Jetro Lauha
+              GIF support from Jean-Marc Lienher
+              iPhone PNG-extensions from James Brown
+              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
+      1.21    fix use of 'stbi_uc' in header (reported by jon blow)
+      1.20    added support for Softimage PIC, by Tom Seddon
+      1.19    bug in interlaced PNG corruption check (found by ryg)
+      1.18  (2008-08-02)
+              fix a threading bug (local mutable static)
+      1.17    support interlaced PNG
+      1.16    major bugfix - stbi__convert_format converted one too many pixels
+      1.15    initialize some fields for thread safety
+      1.14    fix threadsafe conversion bug
+              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+      1.13    threadsafe
+      1.12    const qualifiers in the API
+      1.11    Support installable IDCT, colorspace conversion routines
+      1.10    Fixes for 64-bit (don't use "unsigned long")
+              optimized upsampling by Fabian "ryg" Giesen
+      1.09    Fix format-conversion for PSD code (bad global variables!)
+      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+      1.07    attempt to fix C++ warning/errors again
+      1.06    attempt to fix C++ warning/errors again
+      1.05    fix TGA loading to return correct *comp and use good luminance calc
+      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free
+      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+      1.02    support for (subset of) HDR files, float interface for preferred access to them
+      1.01    fix bug: possible bug in handling right-side up bmps... not sure
+              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
+      1.00    interface to zlib that skips zlib header
+      0.99    correct handling of alpha in palette
+      0.98    TGA loader by lonesock; dynamically add loaders (untested)
+      0.97    jpeg errors on too large a file; also catch another malloc failure
+      0.96    fix detection of invalid v value - particleman at mollyrocket forum
+      0.95    during header scan, seek to markers in case of padding
+      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+      0.93    handle jpegtran output; verbose errors
+      0.92    read 4,8,16,24,32-bit BMP files of several formats
+      0.91    output 24-bit Windows 3.0 BMP files
+      0.90    fix a few more warnings; bump version number to approach 1.0
+      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd
+      0.60    fix compiling as c++
+      0.59    fix warnings: merge Dave Moore's -Wall fixes
+      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian
+      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+      0.56    fix bug: zlib uncompressed mode len vs. nlen
+      0.55    fix bug: restart_interval not initialized to 0
+      0.54    allow NULL for 'int *comp'
+      0.53    fix bug in png 3->4; speedup png decoding
+      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+      0.51    obey req_comp requests, 1-component jpegs return as 1-component,
+              on 'test' only check type, not whether we support this variant
+      0.50  (2006-11-19)
+              first released version
+*/
+
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
-- 
2.17.1





From a.fatoum at pengutronix.de  Mon Jan 10 23:57:59 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Tue, 11 Jan 2022 08:57:59 +0100
Subject: Q about bootstrap support for at91sam92* boards and proposal for
 retirement
In-Reply-To: <Ydsrrj76kk6tmD2X@ravnborg.org>
References: <Ydsrrj76kk6tmD2X@ravnborg.org>
Message-ID: <d8f67d11-e18d-0bb5-ec76-b8bbfce75add@pengutronix.de>

Hello Sam,

On 09.01.22 19:38, Sam Ravnborg wrote:
> Hi all.
> 
> This little detour started because Ahmad pointed out I had made
> a stupid mistake in pwm-atmel.
> So I decided I wanted to give it a spin to verify if it actually works
> now.
> 
> The first challenge I encountered was that said driver had bit-rotted
> as it used the old pwm framework - so I updated it from the Linux
> kernel.

Ouch. How did I miss this :/

> I have the code locally - but this time I will not have it posted before
> it is tested.
> 
> Then I cloned the latest at91bootstrap - but they no longer support old
> at91sam92xx CPUs.
> So it was time to enable bootstrap support for at91sam9263.
> 
> In the past I had something working, but alas no luck this time.
> 
> Can anyone (Ahmad?) help me a little how to get the bootstrap
> functionality working on the at91sam9263?
> 
> I do not expect patches, but I hope for something that can point me in
> the right way to do it.
> 
> I have skov-arm9cpu boards (plenty - as they are mostly retired by SKOV)
> and one at91sam9263ek where I can test.

The skov-arm9cpu looks like it already runs first stage without at91bootstrap?
So the issue is only with at91sam9263ek?

> We see very little interest in at91sam92* boards and we could decide
> to retire all the boards that are not updated to multi-image.

As long as it works, I guess most people don't see a reason make interest
publicly known.

> This could simplify things - and if there is interest the missing boards
> can be brought back to life provided they are updated to multi image.
> Any comments on this?

I have only worked on SAMA5D3 and SAMA5D2. Of course, I'd like to see
board code in AT91 replaced with DT-enabled/multi-image-compatible code,
but I don't think it will happen. I don't think the maintenance burden
is high, so I'd just leave it as is. If it bitrots and people complain,
we can nudge them into the right direction.

> I am happy to type the patches - and verify that the boards I have works.

Great. Looking forward to more boards in at91_multi_defconfig.

Cheers,
Ahmad

> 
> 	Sam
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Tue Jan 11 00:08:15 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Tue, 11 Jan 2022 09:08:15 +0100
Subject: Q about bootstrap support for at91sam92* boards and proposal for
 retirement
In-Reply-To: <Yds9TY1wPddN1oNT@ravnborg.org>
References: <Ydsrrj76kk6tmD2X@ravnborg.org> <Yds9TY1wPddN1oNT@ravnborg.org>
Message-ID: <69226f39-3ab2-cac0-5307-96eb4e9d356e@pengutronix.de>

Hi Sam,

On 09.01.22 20:53, Sam Ravnborg wrote:
> Hi, 
>>
>> Can anyone (Ahmad?) help me a little how to get the bootstrap
>> functionality working on the at91sam9263?
> 
> To answer the obvious questions - what have I done so far.
> 
> - I have an at91bootstrap generated BOOT.BIN that works.
>   This ruins out a lot of possible issues with the SD card
>   as the board boots from the SD card with the at91bootstrap based
>   BOOT.BIN.

So the arm9cpu boots XIP from NAND, but the 9263ek boots from SD?
Did I get that right?

> - The toolchain used is generated from buildroot, and I do not have any
>   proof that it works as I have not had any successes.
>   So far I have assumed that it works.
> 
> - The configuration used is pasted below.
> 
> - The board I use is the skov-arm9cpu which I know works as it boots
>   barebox with the at91bootstrap BOOT.BIN
> 
> - I have only a limited set of patches - pasted below.
> 
> - Latest barebox from the master branch
> 
> - I have tried to power cycle and reset of the board - no change
> 
> - There is a ">RomBOOT" prompt - but nothing else
> 
> 	Sam
> 
> 
> diff --git a/arch/arm/boards/skov-arm9cpu/lowlevel.c b/arch/arm/boards/skov-arm9cpu/lowlevel.c
> index d335953a7..8d5c0b025 100644
> --- a/arch/arm/boards/skov-arm9cpu/lowlevel.c
> +++ b/arch/arm/boards/skov-arm9cpu/lowlevel.c
> @@ -3,14 +3,20 @@
>  
>  #include <linux/sizes.h>
>  
> +#include <debug_ll.h>
> +
>  #include <asm/barebox-arm.h>
>  
>  #include <mach/at91sam926x_board_init.h>
>  #include <mach/at91sam9263_matrix.h>
> +#include <mach/at91_dbgu.h>
> +#include <mach/iomux.h>
>  
>  #define MASTER_PLL_MUL		171
>  #define MASTER_PLL_DIV		14
>  
> +#define MASTER_CLOCK            (200000000/2)
> +
>  static void __bare_init skovarm9cpu_board_config(struct at91sam926x_board_cfg *cfg)
>  {
>  	/* Disable Watchdog */
> @@ -96,6 +102,18 @@ static void __bare_init skovarm9cpu_board_config(struct at91sam926x_board_cfg *c
>  		AT91_RSTC_RSTTYP_WATCHDOG;
>  }
>  
> +static void dbgu_init(void)
> +{
> +	void __iomem *pio = IOMEM(AT91SAM9263_BASE_PIOC);
> +	// Setup DBGU uart
> +	at91_mux_pio3_pin(pio, pin_to_mask(AT91_PIN_PC30), AT91_MUX_PERIPH_A, GPIO_PULL_UP); // DRXD
> +	at91_mux_pio3_pin(pio, pin_to_mask(AT91_PIN_PC31), AT91_MUX_PERIPH_A, 0); // DTXD
> +
> +	at91_dbgu_setup_ll(IOMEM(AT91_BASE_DBGU1), MASTER_CLOCK, 115200);
> +	pbl_set_putc(at91_dbgu_putc, IOMEM(AT91_BASE_DBGU1));

That's not safe to call here. pbl_set_putc accesses global variables, but there has
been no relocation yet.

> +	putc_ll('#');
> +}
> +
>  static void __bare_init skov_arm9cpu_init(void *fdt)
>  {
>  	struct at91sam926x_board_cfg cfg;
> @@ -108,6 +126,8 @@ static void __bare_init skov_arm9cpu_init(void *fdt)
>  	skovarm9cpu_board_config(&cfg);
>  	at91sam9263_board_init(&cfg);
>  
> +	dbgu_init();
> +

If you have a functional skov arm9cpu configuration. Could you figure out the bare
minimum of clock setup you need for DEBUG_LL to work and move that further up?

Once you get get to the barebox_arm_entry, you'll want to call into the PBL
xload from MMC stuff instead, like Oleksij did for the SAMA5D3.

Cheers,
Ahmad

>  	barebox_arm_entry(AT91_CHIPSELECT_1, at91_get_sdram_size(cfg.sdramc),
>  			  fdt);
>  }
> 
> #
> # Automatically generated file; DO NOT EDIT.
> # Barebox/arm 2021.12.0 Configuration
> #
> CONFIG_ARM=y
> CONFIG_HAVE_MACH_ARM_HEAD=y
> CONFIG_ARM_USE_COMPRESSED_DTB=y
> CONFIG_TEXT_BASE=0x0
> 
> #
> # System Type
> #
> CONFIG_ARCH_AT91=y
> # CONFIG_ARCH_BCM283X is not set
> # CONFIG_ARCH_CLPS711X is not set
> # CONFIG_ARCH_DAVINCI is not set
> # CONFIG_ARCH_DIGIC is not set
> # CONFIG_ARCH_EP93XX is not set
> # CONFIG_ARCH_IMX is not set
> # CONFIG_ARCH_LAYERSCAPE is not set
> # CONFIG_ARCH_MVEBU is not set
> # CONFIG_ARCH_MXS is not set
> # CONFIG_ARCH_NOMADIK is not set
> # CONFIG_ARCH_OMAP is not set
> # CONFIG_ARCH_PXA is not set
> # CONFIG_ARCH_ROCKCHIP is not set
> # CONFIG_ARCH_SOCFPGA is not set
> # CONFIG_ARCH_S3C24xx is not set
> # CONFIG_ARCH_S5PCxx is not set
> # CONFIG_ARCH_S3C64xx is not set
> # CONFIG_ARCH_STM32MP is not set
> # CONFIG_ARCH_VERSATILE is not set
> # CONFIG_ARCH_VEXPRESS is not set
> # CONFIG_ARCH_TEGRA is not set
> # CONFIG_ARCH_UEMD is not set
> # CONFIG_ARCH_ZYNQ is not set
> # CONFIG_ARCH_ZYNQMP is not set
> # CONFIG_ARCH_ARM64_VIRT is not set
> 
> #
> # Processor Type
> #
> CONFIG_CPU_32=y
> CONFIG_CPU_ARM926T=y
> CONFIG_CPU_32v5=y
> 
> #
> # processor features
> #
> # CONFIG_BOOT_ENDIANNESS_SWITCH is not set
> CONFIG_HAVE_AT91_UTMI=y
> CONFIG_HAVE_AT91_USB_CLK=y
> CONFIG_COMMON_CLK_AT91=y
> CONFIG_HAVE_AT91_SMD=y
> CONFIG_HAVE_AT91_BOOTSTRAP=y
> CONFIG_AT91SAM926X_BOARD_INIT=y
> CONFIG_AT91SAM9_SMC=y
> CONFIG_HAVE_AT91SAM9_RST=y
> CONFIG_SOC_AT91SAM9=y
> CONFIG_ARCH_TEXT_BASE=0x23f00000
> CONFIG_HAVE_AT91_LOAD_BAREBOX_SRAM=y
> 
> #
> # Atmel AT91 System-on-Chip
> #
> CONFIG_SOC_AT91SAM9263=y
> CONFIG_AT91_MULTI_BOARDS=y
> CONFIG_MACH_SKOV_ARM9CPU=y
> # CONFIG_MACH_AT91SAM9263EK is not set
> # CONFIG_MACH_AT91SAM9X5EK is not set
> # CONFIG_MACH_MICROCHIP_KSZ9477_EVB is not set
> # CONFIG_MACH_SAMA5D3_XPLAINED is not set
> # CONFIG_MACH_SAMA5D27_SOM1 is not set
> # CONFIG_MACH_SAMA5D27_GIANTBOARD is not set
> 
> #
> # AT91 Board Options
> #
> CONFIG_AT91_BOOTSTRAP=y
> # CONFIG_AT91_LOAD_BAREBOX_SRAM is not set
> CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x40000
> # CONFIG_BOARD_ARM_GENERIC_DT is not set
> # CONFIG_AEABI is not set
> # end of System Type
> 
> #
> # ARM specific settings
> #
> # CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS is not set
> CONFIG_ARM_EXCEPTIONS=y
> # CONFIG_ARM_SEMIHOSTING is not set
> # end of ARM specific settings
> 
> CONFIG_GREGORIAN_CALENDER=y
> CONFIG_HAS_KALLSYMS=y
> CONFIG_HAS_MODULES=y
> CONFIG_HAS_CACHE=y
> CONFIG_HAS_DMA=y
> CONFIG_HAS_ARCH_SJLJ=y
> CONFIG_GENERIC_GPIO=y
> CONFIG_BLOCK=y
> CONFIG_BLOCK_WRITE=y
> CONFIG_USE_COMPRESSED_DTB=y
> CONFIG_FILETYPE=y
> 
> #
> # General Settings
> #
> CONFIG_LOCALVERSION=""
> CONFIG_LOCALVERSION_AUTO=y
> CONFIG_BANNER=y
> CONFIG_MEMINFO=y
> # CONFIG_ENVIRONMENT_VARIABLES is not set
> # CONFIG_GLOBALVAR is not set
> 
> #
> # memory layout
> #
> CONFIG_HAVE_PBL_IMAGE=y
> CONFIG_HAVE_PBL_MULTI_IMAGES=y
> CONFIG_HAVE_IMAGE_COMPRESSION=y
> CONFIG_PBL_IMAGE=y
> CONFIG_PBL_MULTI_IMAGES=y
> CONFIG_PBL_RELOCATABLE=y
> CONFIG_IMAGE_COMPRESSION=y
> # CONFIG_IMAGE_COMPRESSION_LZ4 is not set
> CONFIG_IMAGE_COMPRESSION_LZO=y
> # CONFIG_IMAGE_COMPRESSION_GZIP is not set
> # CONFIG_IMAGE_COMPRESSION_XZKERN is not set
> # CONFIG_IMAGE_COMPRESSION_NONE is not set
> # CONFIG_MMU is not set
> CONFIG_BAREBOX_MAX_PBL_SIZE=0xffffffff
> CONFIG_BAREBOX_MAX_BARE_INIT_SIZE=0xffffffff
> CONFIG_STACK_SIZE=0x8000
> CONFIG_MALLOC_SIZE=0x400000
> # end of memory layout
> 
> # CONFIG_EXPERIMENTAL is not set
> # CONFIG_MALLOC_DLMALLOC is not set
> CONFIG_MALLOC_TLSF=y
> # CONFIG_MALLOC_DUMMY is not set
> CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
> # CONFIG_KALLSYMS is not set
> CONFIG_RELOCATABLE=y
> # CONFIG_PANIC_HANG is not set
> CONFIG_PROMPT="barebox:"
> CONFIG_BAUDRATE=115200
> CONFIG_SIMPLE_READLINE=y
> CONFIG_CBSIZE=1024
> # CONFIG_SHELL_HUSH is not set
> # CONFIG_SHELL_SIMPLE is not set
> CONFIG_SHELL_NONE=y
> # CONFIG_GLOB is not set
> # CONFIG_PASSWORD is not set
> CONFIG_ERRNO_MESSAGES=y
> CONFIG_TIMESTAMP=y
> # CONFIG_BOOTM is not set
> # CONFIG_BAREBOX_UPDATE is not set
> # CONFIG_IMD is not set
> # CONFIG_CONSOLE_FULL is not set
> CONFIG_CONSOLE_SIMPLE=y
> # CONFIG_CONSOLE_NONE is not set
> # CONFIG_CONSOLE_ALLOW_COLOR is not set
> # CONFIG_CONSOLE_DISABLE_INPUT is not set
> CONFIG_PBL_CONSOLE=y
> CONFIG_PARTITION=y
> CONFIG_PARTITION_DISK=y
> CONFIG_PARTITION_DISK_DOS=y
> # CONFIG_PARTITION_DISK_EFI is not set
> # CONFIG_ENV_HANDLING is not set
> # CONFIG_DEFAULT_ENVIRONMENT is not set
> # CONFIG_DEFAULT_COMPRESSION_GZIP is not set
> # CONFIG_DEFAULT_COMPRESSION_LZO is not set
> CONFIG_DEFAULT_COMPRESSION_NONE=y
> CONFIG_HAS_SCHED=y
> CONFIG_POLLER=y
> # CONFIG_BTHREAD is not set
> # CONFIG_STATE is not set
> # CONFIG_BOOTCHOOSER is not set
> CONFIG_EXTERNAL_DTS_FRAGMENTS=""
> 
> #
> # OP-TEE loading
> #
> # CONFIG_PBL_OPTEE is not set
> # end of OP-TEE loading
> # end of General Settings
> 
> #
> # Debugging
> #
> CONFIG_COMPILE_LOGLEVEL=6
> CONFIG_DEFAULT_LOGLEVEL=7
> CONFIG_DEBUG_LL=y
> CONFIG_DEBUG_AT91_UART=y
> CONFIG_DEBUG_AT91_UART_BASE=0xffffee00
> # CONFIG_DEBUG_INITCALLS is not set
> # CONFIG_DEBUG_PROBES is not set
> # CONFIG_PBL_BREAK is not set
> # CONFIG_PRINTF_FULL is not set
> # CONFIG_UBSAN is not set
> CONFIG_HAVE_ARCH_KASAN=y
> CONFIG_CC_HAS_KASAN_GENERIC=y
> # CONFIG_KASAN is not set
> # CONFIG_COMPILE_TEST is not set
> # end of Debugging
> 
> #
> # EFI (Extensible Firmware Interface) Support
> #
> # end of EFI (Extensible Firmware Interface) Support
> 
> CONFIG_HAS_DEBUG_LL=y
> # CONFIG_NET is not set
> 
> #
> # Drivers
> #
> CONFIG_OFTREE=y
> CONFIG_OFTREE_MEM_GENERIC=y
> CONFIG_DTC=y
> CONFIG_OFDEVICE=y
> CONFIG_OF_GPIO=y
> # CONFIG_OF_OVERLAY is not set
> # CONFIG_AIODEV is not set
> 
> #
> # serial drivers
> #
> # CONFIG_DRIVER_SERIAL_ARM_DCC is not set
> # CONFIG_DRIVER_SERIAL_NS16550 is not set
> CONFIG_DRIVER_SERIAL_ATMEL=y
> # CONFIG_DRIVER_SERIAL_CADENCE is not set
> # CONFIG_SERIAL_SIFIVE is not set
> # end of serial drivers
> 
> CONFIG_HAS_MACB=y
> 
> #
> # SPI drivers
> #
> # CONFIG_SPI is not set
> # end of SPI drivers
> 
> # CONFIG_I2C is not set
> # CONFIG_MTD is not set
> CONFIG_DISK=y
> CONFIG_DISK_WRITE=y
> 
> #
> # drive types
> #
> # CONFIG_DISK_ATA is not set
> # CONFIG_DISK_AHCI is not set
> 
> #
> # interface types
> #
> # CONFIG_DISK_INTF_PLATFORM_IDE is not set
> # CONFIG_USB_HOST is not set
> # CONFIG_USB_GADGET is not set
> # CONFIG_USB_MUSB is not set
> CONFIG_VIDEO=y
> # CONFIG_FRAMEBUFFER_CONSOLE is not set
> CONFIG_DRIVER_VIDEO_ATMEL=y
> # CONFIG_DRIVER_VIDEO_ATMEL_HLCD is not set
> # CONFIG_DRIVER_VIDEO_BOCHS_ISA is not set
> # CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT is not set
> # CONFIG_DRIVER_VIDEO_SIMPLEFB is not set
> # CONFIG_DRIVER_VIDEO_EDID is not set
> CONFIG_DRIVER_VIDEO_BACKLIGHT=y
> 
> #
> # Video encoder chips
> #
> # CONFIG_DRIVER_VIDEO_SIMPLE_PANEL is not set
> # CONFIG_SOUND is not set
> CONFIG_MCI=y
> 
> #
> # --- Feature list ---
> #
> # CONFIG_MCI_STARTUP is not set
> CONFIG_MCI_WRITE=y
> CONFIG_MCI_MMC_BOOT_PARTITIONS=y
> # CONFIG_MCI_MMC_GPP_PARTITIONS is not set
> 
> #
> # --- MCI host drivers ---
> #
> # CONFIG_MCI_DW is not set
> # CONFIG_MCI_ROCKCHIP_DWCMSHC is not set
> CONFIG_MCI_ATMEL=y
> # CONFIG_MCI_ATMEL_SDHCI is not set
> # CONFIG_MCI_ARASAN is not set
> CONFIG_HAVE_CLK=y
> CONFIG_CLKDEV_LOOKUP=y
> CONFIG_COMMON_CLK=y
> CONFIG_COMMON_CLK_OF_PROVIDER=y
> 
> #
> # Clocksource
> #
> CONFIG_CLOCKSOURCE_DUMMY_RATE=1000
> CONFIG_CLOCKSOURCE_ATMEL_PIT=y
> # CONFIG_CLOCKSOURCE_DW_APB_TIMER is not set
> # end of Clocksource
> 
> #
> # Multifunction device drivers
> #
> CONFIG_MFD_SYSCON=y
> # CONFIG_MFD_ATMEL_FLEXCOM is not set
> # end of Multifunction device drivers
> 
> #
> # Misc devices
> #
> # CONFIG_JTAG is not set
> CONFIG_SRAM=y
> # CONFIG_DEV_MEM is not set
> # CONFIG_UBOOTVAR is not set
> # end of Misc devices
> 
> CONFIG_LED=y
> CONFIG_LED_GPIO=y
> CONFIG_LED_GPIO_OF=y
> # CONFIG_LED_GPIO_RGB is not set
> # CONFIG_LED_GPIO_BICOLOR is not set
> CONFIG_LED_TRIGGERS=y
> 
> #
> # EEPROM support
> #
> # end of EEPROM support
> 
> #
> # Input device support
> #
> CONFIG_INPUT=y
> CONFIG_KEYBOARD_GPIO=y
> # CONFIG_INPUT_SPECIALKEYS is not set
> # end of Input device support
> 
> # CONFIG_WATCHDOG is not set
> # CONFIG_PWM is not set
> # CONFIG_HWRNG is not set
> 
> #
> # DMA support
> #
> # end of DMA support
> 
> CONFIG_GPIOLIB=y
> 
> #
> # GPIO
> #
> # CONFIG_GPIO_74XX_MMIO is not set
> # CONFIG_GPIO_GENERIC_PLATFORM is not set
> # CONFIG_GPIO_DESIGNWARE is not set
> # CONFIG_GPIO_SIFIVE is not set
> # end of GPIO
> 
> # CONFIG_W1 is not set
> 
> #
> # Pin controllers
> #
> CONFIG_PINCTRL=y
> CONFIG_PINCTRL_AT91=y
> # CONFIG_PINCTRL_AT91PIO4 is not set
> # CONFIG_PINCTRL_SINGLE is not set
> # end of Pin controllers
> 
> # CONFIG_NVMEM is not set
> 
> #
> # Bus devices
> #
> # end of Bus devices
> 
> # CONFIG_REGULATOR is not set
> 
> #
> # Remoteproc drivers
> #
> # CONFIG_REMOTEPROC is not set
> # end of Remoteproc drivers
> 
> # CONFIG_RESET_CONTROLLER is not set
> # CONFIG_RTC_CLASS is not set
> 
> #
> # Firmware Drivers
> #
> # end of Firmware Drivers
> 
> #
> # FPGA Configuration Support
> #
> # CONFIG_FPGA is not set
> # end of FPGA Configuration Support
> 
> # CONFIG_GENERIC_PHY is not set
> # CONFIG_CRYPTO_HW is not set
> 
> #
> # Memory controller drivers
> #
> # end of Memory controller drivers
> 
> #
> # i.MX SoC drivers
> #
> # end of i.MX SoC drivers
> 
> #
> # NVME Support
> #
> # end of NVME Support
> 
> # CONFIG_SYSCON_REBOOT_MODE is not set
> # CONFIG_POWER_RESET_SYSCON is not set
> # CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
> # CONFIG_POWER_RESET_GPIO is not set
> # CONFIG_POWER_RESET_GPIO_RESTART is not set
> # CONFIG_VIRTIO_MENU is not set
> # end of Drivers
> 
> #
> # Filesystem support
> #
> CONFIG_FS=y
> CONFIG_FS_LEGACY=y
> 
> #
> # Some selected filesystems still use the legacy FS API.
> #
> 
> #
> # Consider updating them.
> #
> # CONFIG_FS_CRAMFS is not set
> # CONFIG_FS_EXT4 is not set
> # CONFIG_FS_RAMFS is not set
> # CONFIG_FS_DEVFS is not set
> CONFIG_FS_FAT=y
> CONFIG_FS_FAT_WRITE=y
> CONFIG_FS_FAT_LFN=y
> # CONFIG_FS_BPKFS is not set
> # CONFIG_FS_UIMAGEFS is not set
> # CONFIG_FS_PSTORE is not set
> # CONFIG_FS_SQUASHFS is not set
> 
> #
> # ZLIB support disabled
> #
> 
> #
> # LZ4 support disabled
> #
> 
> #
> # LZO support disabled
> #
> 
> #
> # XZ support disabled
> #
> 
> #
> # ZSTD support disabled
> #
> # end of Filesystem support
> 
> #
> # Library routines
> #
> CONFIG_UNCOMPRESS=y
> CONFIG_ZLIB=y
> # CONFIG_BZLIB is not set
> # CONFIG_LZ4_DECOMPRESS is not set
> # CONFIG_ZSTD_DECOMPRESS is not set
> # CONFIG_XZ_DECOMPRESS is not set
> # CONFIG_BASE64 is not set
> CONFIG_LZO_DECOMPRESS=y
> # CONFIG_ALLOW_PRNG_FALLBACK is not set
> # CONFIG_CRC_CCITT is not set
> # CONFIG_CRC8 is not set
> 
> #
> # Library gui routines
> #
> # end of Library gui routines
> 
> # CONFIG_BAREBOX_LOGO is not set
> CONFIG_BOOTSTRAP=y
> CONFIG_BOOTSTRAP_DEVFS=y
> CONFIG_BOOTSTRAP_DISK=y
> # CONFIG_NLS is not set
> # CONFIG_BLOBGEN is not set
> CONFIG_ARCH_HAS_DATA_ABORT_MASK=y
> # end of Library routines
> 
> #
> # Crypto support
> #
> # CONFIG_DIGEST is not set
> # CONFIG_CRYPTO_KEYSTORE is not set
> # end of Crypto support
> 
> #
> # Firmware files
> #
> CONFIG_EXTRA_FIRMWARE_DIR="firmware"
> # end of Firmware files
> 
> #
> # Host Tools
> #
> # CONFIG_COMPILE_HOST_TOOLS is not set
> # end of Host Tools
> 
> #
> # Target Tools
> #
> # CONFIG_KERNEL_INSTALL_TARGET is not set
> # CONFIG_BAREBOXENV_TARGET is not set
> # CONFIG_BAREBOXCRC32_TARGET is not set
> # CONFIG_MVEBU_KWBOOT_TARGET is not set
> # end of Target Tools
> 
> # CONFIG_TEST is not set
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sam at ravnborg.org  Tue Jan 11 14:12:39 2022
From: sam at ravnborg.org (Sam Ravnborg)
Date: Tue, 11 Jan 2022 23:12:39 +0100
Subject: Q about bootstrap support for at91sam92* boards and proposal for
 retirement
In-Reply-To: <d8f67d11-e18d-0bb5-ec76-b8bbfce75add@pengutronix.de>
References: <Ydsrrj76kk6tmD2X@ravnborg.org>
 <d8f67d11-e18d-0bb5-ec76-b8bbfce75add@pengutronix.de>
Message-ID: <Yd4A12htShfcvl6+@ravnborg.org>

Hi Ahmad,

> > I have the code locally - but this time I will not have it posted before
> > it is tested.
> > 
> > Then I cloned the latest at91bootstrap - but they no longer support old
> > at91sam92xx CPUs.
> > So it was time to enable bootstrap support for at91sam9263.
> > 
> > In the past I had something working, but alas no luck this time.
> > 
> > Can anyone (Ahmad?) help me a little how to get the bootstrap
> > functionality working on the at91sam9263?
> > 
> > I do not expect patches, but I hope for something that can point me in
> > the right way to do it.
> > 
> > I have skov-arm9cpu boards (plenty - as they are mostly retired by SKOV)
> > and one at91sam9263ek where I can test.
> 
> The skov-arm9cpu looks like it already runs first stage without at91bootstrap?
> So the issue is only with at91sam9263ek?

For the moment my focus is on the skov-arm9cpu - and here bootstrap is
not (yet) functional. But I think with all the good feedback from you
and Oleksij I should manage. Thanks for the replies!

> > We see very little interest in at91sam92* boards and we could decide
> > to retire all the boards that are not updated to multi-image.
> 
> As long as it works, I guess most people don't see a reason make interest
> publicly known.
> 
> > This could simplify things - and if there is interest the missing boards
> > can be brought back to life provided they are updated to multi image.
> > Any comments on this?
> 
> I have only worked on SAMA5D3 and SAMA5D2. Of course, I'd like to see
> board code in AT91 replaced with DT-enabled/multi-image-compatible code,
> but I don't think it will happen. I don't think the maintenance burden
> is high, so I'd just leave it as is. If it bitrots and people complain,
> we can nudge them into the right direction.

OK, you are right that if it just works no reason to touch it.
I will do the patches alongside the current codebase then.

	Sam


From sha at pengutronix.de  Wed Jan 12 02:23:04 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Jan 2022 11:23:04 +0100
Subject: [PATCH 1/9] RISC-V: virt: activate all consoles
In-Reply-To: <20220108171524.587144-1-a.fatoum@pengutronix.de>
References: <20220108171524.587144-1-a.fatoum@pengutronix.de>
Message-ID: <20220112102304.GC26619@pengutronix.de>

On Sat, Jan 08, 2022 at 06:15:16PM +0100, Ahmad Fatoum wrote:
> While CONSOLE_ACTIVATE_NONE + stdout-path is usually the way to go, main
> console on this platform can be virtio console, which can't be
> referenced as is in DT, so just enable all consoles.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  arch/riscv/configs/virt32_defconfig | 1 +
>  arch/riscv/configs/virt64_defconfig | 1 +
>  2 files changed, 2 insertions(+)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Wed Jan 12 02:29:40 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Jan 2022 11:29:40 +0100
Subject: [PATCH 1/2] fs: implement pushd/popd chdir wrappers
In-Reply-To: <20220108171555.588426-1-a.fatoum@pengutronix.de>
References: <20220108171555.588426-1-a.fatoum@pengutronix.de>
Message-ID: <20220112102940.GD26619@pengutronix.de>

On Sat, Jan 08, 2022 at 06:15:54PM +0100, Ahmad Fatoum wrote:
> We don't have dirfd's, so running operations relative to the current
> working directory always involves some allocation/freeing boilerplate.
> 
> Add pushd/popd helpers to move the boilerplate out of the callsites.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  fs/fs.c          | 30 ++++++++++++++++++++++++++++++
>  include/unistd.h |  2 ++
>  2 files changed, 32 insertions(+)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Thu Jan 13 08:04:13 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 13 Jan 2022 17:04:13 +0100
Subject: [PATCH v2 2/3] driver: have CONFIG_DEBUG_PROBES report device unbind
 as well
In-Reply-To: <20220113160414.3943151-1-a.fatoum@pengutronix.de>
References: <20220113160414.3943151-1-a.fatoum@pengutronix.de>
Message-ID: <20220113160414.3943151-2-a.fatoum@pengutronix.de>

This aligns it with DEBUG_INITCALLS, which also traces exitcalls.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2: no change
---
 common/Kconfig        | 10 ++++++++--
 drivers/base/driver.c |  4 ++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/common/Kconfig b/common/Kconfig
index 482faea933a6..060e21d9fedf 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1524,9 +1524,15 @@ config DEBUG_INITCALLS
 	  If enabled this will print initcall traces.
 
 config DEBUG_PROBES
-	bool "Trace driver probes"
+	bool "Trace driver probes/removes"
 	help
-	  If enabled this will print driver probe traces.
+	  If enabled this will log driver probe and remove traces. If DEBUG_LL is enabled,
+	  probes will be printed even before registering consoles. If it's disabled, they
+	  will be collected in the log and written out once a console is active.
+
+	  Removes are written to the log and will be printed as long as consoles exist.
+	  Most consoles do not implement a remove callback to remain operable until
+	  the very end. Consoles using DMA, however, must be removed.
 
 config PBL_BREAK
 	bool "Execute software break on pbl start"
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index dd965eb165ee..bb07e96dcaf4 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -502,11 +502,15 @@ EXPORT_SYMBOL_GPL(dev_set_name);
 static void devices_shutdown(void)
 {
 	struct device_d *dev;
+	int depth = 0;
 
 	list_for_each_entry(dev, &active, active) {
 		if (dev->bus->remove) {
+			depth++;
+			pr_report_probe("%*sremove-> %s\n", depth * 4, "", dev_name(dev));
 			dev->bus->remove(dev);
 			dev->driver = NULL;
+			depth--;
 		}
 	}
 }
-- 
2.30.2



From a.fatoum at pengutronix.de  Thu Jan 13 08:04:14 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 13 Jan 2022 17:04:14 +0100
Subject: [PATCH v2 3/3] commands: add new devunbind debugging command
In-Reply-To: <20220113160414.3943151-1-a.fatoum@pengutronix.de>
References: <20220113160414.3943151-1-a.fatoum@pengutronix.de>
Message-ID: <20220113160414.3943151-3-a.fatoum@pengutronix.de>

Memory corruption around device removal may go unnoticed, because
barebox is shutting down anyway and doing no new allocations.

Add a new devunbind command that should help with debugging such issues
by allowing selective unbinding and removal of devices.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - updated Kconfig discription with -l option
  - fixed too early exit after unregistering first device (Sascha)
  - report skipping of missing device
---
 commands/Kconfig      | 12 +++++++
 commands/Makefile     |  1 +
 commands/devunbind.c  | 79 +++++++++++++++++++++++++++++++++++++++++++
 drivers/base/driver.c |  7 ++--
 include/driver.h      |  4 +++
 5 files changed, 100 insertions(+), 3 deletions(-)
 create mode 100644 commands/devunbind.c

diff --git a/commands/Kconfig b/commands/Kconfig
index 5506d1b8f07c..ba8ca5cdebce 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -75,6 +75,18 @@ config CMD_DEVINFO
 	  If called with a device path being the argument, devinfo shows more
 	  default information about this device and its parameters.
 
+config CMD_DEVUNBIND
+	tristate
+	prompt "devunbind"
+	help
+	  Debugging aid to unbind device(s) from driver at runtime
+
+	  devunbind [-fl] DEVICES..
+
+	  Options:
+		-f   unbind driver and force removal of device and children
+		-l   list remove callbacks in shutdown order
+
 config CMD_DMESG
 	tristate
 	prompt "dmesg"
diff --git a/commands/Makefile b/commands/Makefile
index c1a060da5204..db78d0b877f6 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_CMD_MIITOOL)	+= miitool.o
 obj-$(CONFIG_CMD_DETECT)	+= detect.o
 obj-$(CONFIG_CMD_BOOT)		+= boot.o
 obj-$(CONFIG_CMD_DEVINFO)	+= devinfo.o
+obj-$(CONFIG_CMD_DEVUNBIND)	+= devunbind.o
 obj-$(CONFIG_CMD_DRVINFO)	+= drvinfo.o
 obj-$(CONFIG_CMD_READF)		+= readf.o
 obj-$(CONFIG_CMD_MENUTREE)	+= menutree.o
diff --git a/commands/devunbind.c b/commands/devunbind.c
new file mode 100644
index 000000000000..3f9cd7b849c8
--- /dev/null
+++ b/commands/devunbind.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: ? 2021 Ahmad Fatoum <a.fatoum at pengutronix.de>, Pengutronix
+
+#include <command.h>
+#include <common.h>
+#include <complete.h>
+#include <driver.h>
+#include <getopt.h>
+
+static int do_devunbind(int argc, char *argv[])
+{
+	bool unregister = false;
+	struct device_d *dev;
+	int ret = COMMAND_SUCCESS, i, opt;
+
+	while ((opt = getopt(argc, argv, "fl")) > 0) {
+		switch (opt) {
+		case 'f':
+			unregister = true;
+			break;
+		case 'l':
+			list_for_each_entry(dev, &active_device_list, active) {
+				BUG_ON(!dev->driver);
+				if (dev->bus->remove)
+					printf("%pS(%s, %s)\n", dev->bus->remove,
+					       dev->driver->name, dev_name(dev));
+			}
+			return 0;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	if (!argv[optind])
+		return COMMAND_ERROR_USAGE;
+
+	for (i = optind; i < argc; i++) {
+		dev = get_device_by_name(argv[i]);
+		if (!dev) {
+			printf("skipping missing %s\n", argv[i]);
+			ret = -ENODEV;
+			continue;
+		}
+
+		if (unregister) {
+			unregister_device(dev);
+			continue;
+		}
+
+		if (!dev->driver || !dev->bus->remove) {
+			printf("skipping unbound %s\n", argv[i]);
+			ret = COMMAND_ERROR;
+			continue;
+		}
+
+		dev->bus->remove(dev);
+		dev->driver = NULL;
+		list_del(&dev->active);
+	}
+
+	return ret;
+}
+
+BAREBOX_CMD_HELP_START(devunbind)
+BAREBOX_CMD_HELP_TEXT("Debugging aid to unbind device from driver at runtime")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-f",  "unbind driver and force removal of device and children")
+BAREBOX_CMD_HELP_OPT ("-l",  "list remove callbacks in shutdown order")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(devunbind)
+	.cmd		= do_devunbind,
+	BAREBOX_CMD_DESC("unbind device(s) from driver")
+	BAREBOX_CMD_OPTS("[-fl] DEVICES..")
+	BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+	BAREBOX_CMD_HELP(cmd_devunbind_help)
+	BAREBOX_CMD_COMPLETE(device_complete)
+BAREBOX_CMD_END
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index bb07e96dcaf4..f54f4d0b3746 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -41,7 +41,8 @@ EXPORT_SYMBOL(device_list);
 LIST_HEAD(driver_list);
 EXPORT_SYMBOL(driver_list);
 
-static LIST_HEAD(active);
+LIST_HEAD(active_device_list);
+EXPORT_SYMBOL(active_device_list);
 static LIST_HEAD(deferred);
 
 struct device_d *get_device_by_name(const char *name)
@@ -91,7 +92,7 @@ int device_probe(struct device_d *dev)
 	pinctrl_select_state_default(dev);
 	of_clk_set_defaults(dev->device_node, false);
 
-	list_add(&dev->active, &active);
+	list_add(&dev->active, &active_device_list);
 
 	ret = dev->bus->probe(dev);
 	if (ret == 0)
@@ -504,7 +505,7 @@ static void devices_shutdown(void)
 	struct device_d *dev;
 	int depth = 0;
 
-	list_for_each_entry(dev, &active, active) {
+	list_for_each_entry(dev, &active_device_list, active) {
 		if (dev->bus->remove) {
 			depth++;
 			pr_report_probe("%*sremove-> %s\n", depth * 4, "", dev_name(dev));
diff --git a/include/driver.h b/include/driver.h
index 4f6d40e17c14..1215a2d57ab3 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -328,6 +328,10 @@ extern struct list_head device_list;
  */
 extern struct list_head driver_list;
 
+/* linear list over all active devices
+ */
+extern struct list_head active_device_list;
+
 /* Iterate over all devices
  */
 #define for_each_device(dev) list_for_each_entry(dev, &device_list, list)
-- 
2.30.2



From a.fatoum at pengutronix.de  Thu Jan 13 08:04:20 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 13 Jan 2022 17:04:20 +0100
Subject: [PATCH 3/3] commands: add new devunbind debugging command
In-Reply-To: <20220110085634.GD6003@pengutronix.de>
References: <20220108171426.586330-1-a.fatoum@pengutronix.de>
 <20220108171426.586330-3-a.fatoum@pengutronix.de>
 <20220110085634.GD6003@pengutronix.de>
Message-ID: <0ea7d9ed-0aa9-1fab-6e39-eb07f4833c99@pengutronix.de>

On 10.01.22 09:56, Sascha Hauer wrote:
> On Sat, Jan 08, 2022 at 06:14:26PM +0100, Ahmad Fatoum wrote:
>> Memory corruption around device removal may go unnoticed, because
>> barebox is shutting down anyway and doing no new allocations.
>>
>> Add a new devunbind command that should help with debugging such issues
>> by allowing selective unbinding and removal of devices.
>>
>> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
>> ---
>>  commands/Kconfig      | 12 +++++++
>>  commands/Makefile     |  1 +
>>  commands/devunbind.c  | 74 +++++++++++++++++++++++++++++++++++++++++++
>>  drivers/base/driver.c |  7 ++--
>>  include/driver.h      |  4 +++
>>  5 files changed, 95 insertions(+), 3 deletions(-)
>>  create mode 100644 commands/devunbind.c
>>
>> diff --git a/commands/Kconfig b/commands/Kconfig
>> index e2c36949347e..9abd97271952 100644
>> --- a/commands/Kconfig
>> +++ b/commands/Kconfig
>> @@ -68,6 +68,18 @@ config CMD_DEVINFO
>>  	  If called with a device path being the argument, devinfo shows more
>>  	  default information about this device and its parameters.
>>  
>> +config CMD_DEVUNBIND
>> +	tristate
>> +	default y
>> +	prompt "devunbind"
>> +	help
>> +	  Debugging aid to unbind device from driver at runtime
>> +
>> +	  devunbind [-f] DEVICE
>> +
>> +	  Options:
>> +	    -f   unbind driver and force removal of device and children
>> +
>>  config CMD_DMESG
>>  	tristate
>>  	prompt "dmesg"
>> diff --git a/commands/Makefile b/commands/Makefile
>> index 0b7c1563b534..875826743ffe 100644
>> --- a/commands/Makefile
>> +++ b/commands/Makefile
>> @@ -107,6 +107,7 @@ obj-$(CONFIG_CMD_MIITOOL)	+= miitool.o
>>  obj-$(CONFIG_CMD_DETECT)	+= detect.o
>>  obj-$(CONFIG_CMD_BOOT)		+= boot.o
>>  obj-$(CONFIG_CMD_DEVINFO)	+= devinfo.o
>> +obj-$(CONFIG_CMD_DEVUNBIND)	+= devunbind.o
>>  obj-$(CONFIG_CMD_DRVINFO)	+= drvinfo.o
>>  obj-$(CONFIG_CMD_READF)		+= readf.o
>>  obj-$(CONFIG_CMD_MENUTREE)	+= menutree.o
>> diff --git a/commands/devunbind.c b/commands/devunbind.c
>> new file mode 100644
>> index 000000000000..4bebb27e8e68
>> --- /dev/null
>> +++ b/commands/devunbind.c
>> @@ -0,0 +1,74 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +// SPDX-FileCopyrightText: ? 2021 Ahmad Fatoum <a.fatoum at pengutronix.de>, Pengutronix
>> +
>> +#include <command.h>
>> +#include <common.h>
>> +#include <complete.h>
>> +#include <driver.h>
>> +#include <getopt.h>
>> +
>> +static int do_devunbind(int argc, char *argv[])
>> +{
>> +	bool unregister = false;
>> +	struct device_d *dev;
>> +	int ret = COMMAND_SUCCESS, i, opt;
>> +
>> +	while ((opt = getopt(argc, argv, "fl")) > 0) {
>> +		switch (opt) {
>> +		case 'f':
>> +			unregister = true;
>> +			break;
>> +		case 'l':
>> +			list_for_each_entry(dev, &active_device_list, active) {
>> +				BUG_ON(!dev->driver);
>> +				if (dev->bus->remove)
>> +					printf("%pS(%s, %s)\n", dev->bus->remove,
>> +					       dev->driver->name, dev_name(dev));
>> +			}
>> +			return 0;
>> +		default:
>> +			return COMMAND_ERROR_USAGE;
>> +		}
>> +	}
>> +
>> +	if (!argv[optind])
>> +		return COMMAND_ERROR_USAGE;
>> +
>> +	for (i = optind; i < argc; i++) {
>> +		dev = get_device_by_name(argv[i]);
>> +		if (!dev)
>> +			return -ENODEV;
>> +
>> +		if (unregister)
>> +			return unregister_device(dev);
> 
> Shouldn't you continue the loop here?

Yes. Fixed in v2.

> 
> Sascha
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Thu Jan 13 08:04:12 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 13 Jan 2022 17:04:12 +0100
Subject: [PATCH v2 1/3] tlsf: dump stack on assertion failure
Message-ID: <20220113160414.3943151-1-a.fatoum@pengutronix.de>

We only support AddressSanitizer on ARM, ARM64 and sandbox. For other
platforms TLSF assertions may detect some nconsistency, like some double
frees. Make the reports more useful by dumping stack in that case.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2: no change
---
 include/tlsf.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/tlsf.h b/include/tlsf.h
index 7015de0eb525..161176d5ac84 100644
--- a/include/tlsf.h
+++ b/include/tlsf.h
@@ -42,9 +42,12 @@
 extern "C" {
 #endif
 
+#include <printk.h>
+
 #define tlsf_assert(expr) do {                              \
         if (unlikely(!(expr))) {                            \
                 printf(#expr "%s %d\n", __FILE__, __LINE__); \
+                dump_stack();                               \
         }                                                   \
 } while (0)
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Thu Jan 13 21:05:56 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 06:05:56 +0100
Subject: [PATCH] i2c: add Rockchip i2c controller support
In-Reply-To: <20220105112031.GT6003@pengutronix.de>
References: <20220103120015.1727051-1-a.fatoum@pengutronix.de>
 <20220105112031.GT6003@pengutronix.de>
Message-ID: <fc427ed1-df5a-caee-2c0b-5b0d799470f4@pengutronix.de>

On 05.01.22 12:20, Sascha Hauer wrote:
> On Mon, Jan 03, 2022 at 01:00:15PM +0100, Ahmad Fatoum wrote:
>> For addressing the PMIC on Rockchip platforms, add an i2c controller
>> driver. Tested with rk3399 and rk808.
>>
>> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
>> ---
>>  drivers/i2c/busses/Kconfig        |   8 +
>>  drivers/i2c/busses/Makefile       |   1 +
>>  drivers/i2c/busses/i2c-rockchip.c | 472 ++++++++++++++++++++++++++++++
>>  3 files changed, 481 insertions(+)
>>  create mode 100644 drivers/i2c/busses/i2c-rockchip.c
>>
>> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
>> index c1e76a04096e..a551df537a69 100644
>> --- a/drivers/i2c/busses/Kconfig
>> +++ b/drivers/i2c/busses/Kconfig
>> @@ -62,4 +62,12 @@ config I2C_STM32
>>  	depends on HAVE_CLK
>>  	depends on ARCH_STM32MP || COMPILE_TEST
>>  
>> +config I2C_RK3X
>> +	tristate "Rockchip RK3xxx I2C adapter"
>> +	depends on HAVE_CLK
>> +	depends on ARCH_ROCKCHIP || COMPILE_TEST
>> +	help
>> +	  Say Y here to include support for the I2C adapter in Rockchip RK3xxx
>> +	  SoCs.
>> +
>>  endmenu
>> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
>> index 34a12fcbea96..d6273f3d8679 100644
>> --- a/drivers/i2c/busses/Makefile
>> +++ b/drivers/i2c/busses/Makefile
>> @@ -9,3 +9,4 @@ obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
>>  obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
>>  obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o
>>  obj-$(CONFIG_I2C_STM32)		+= i2c-stm32.o
>> +obj-$(CONFIG_I2C_RK3X)		+= i2c-rockchip.o
>> diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
>> new file mode 100644
>> index 000000000000..ba7397b19967
>> --- /dev/null
>> +++ b/drivers/i2c/busses/i2c-rockchip.c
>> @@ -0,0 +1,472 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * (C) Copyright 2015 Google, Inc
>> + *
>> + * (C) Copyright 2008-2014 Rockchip Electronics
>> + * Peter, Software Engineering, <superpeter.cai at gmail.com>.
>> + */
>> +
>> +#include <common.h>
>> +#include <i2c/i2c.h>
>> +#include <linux/iopoll.h>
>> +#include <errno.h>
>> +#include <linux/err.h>
>> +#include <driver.h>
>> +#include <io.h>
>> +#include <linux/clk.h>
>> +#include <mfd/syscon.h>
>> +#include <regmap.h>
>> +#include <linux/sizes.h>
>> +
>> +struct i2c_regs {
>> +	u32 con;
>> +	u32 clkdiv;
>> +	u32 mrxaddr;
>> +	u32 mrxraddr;
>> +	u32 mtxcnt;
>> +	u32 mrxcnt;
>> +	u32 ien;
>> +	u32 ipd;
>> +	u32 fcnt;
>> +	u32 reserved0[0x37];
>> +	u32 txdata[8];
>> +	u32 reserved1[0x38];
>> +	u32 rxdata[8];
>> +};
>> +
>> +/* Control register */
>> +#define I2C_CON_EN		(1 << 0)
>> +#define I2C_CON_MOD(mod)	((mod) << 1)
>> +#define I2C_MODE_TX		0x00
>> +#define I2C_MODE_TRX		0x01
>> +#define I2C_MODE_RX		0x02
>> +#define I2C_MODE_RRX		0x03
>> +#define I2C_CON_MASK		(3 << 1)
>> +
>> +#define I2C_CON_START		(1 << 3)
>> +#define I2C_CON_STOP		(1 << 4)
>> +#define I2C_CON_LASTACK		(1 << 5)
>> +#define I2C_CON_ACTACK		(1 << 6)
>> +
>> +/* Clock dividor register */
> 
> s/dividor/divider/

Fixed.

> 
>> +#define I2C_CLKDIV_VAL(divl, divh) \
>> +	(((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))
>> +
>> +/* the slave address accessed  for master rx mode */
>> +#define I2C_MRXADDR_SET(vld, addr)	(((vld) << 24) | (addr))
>> +
>> +/* the slave register address accessed  for master rx mode */
>> +#define I2C_MRXRADDR_SET(vld, raddr)	(((vld) << 24) | (raddr))
>> +
>> +/* interrupt enable register */
>> +#define I2C_BTFIEN		(1 << 0)
>> +#define I2C_BRFIEN		(1 << 1)
>> +#define I2C_MBTFIEN		(1 << 2)
>> +#define I2C_MBRFIEN		(1 << 3)
>> +#define I2C_STARTIEN		(1 << 4)
>> +#define I2C_STOPIEN		(1 << 5)
>> +#define I2C_NAKRCVIEN		(1 << 6)
>> +
>> +/* interrupt pending register */
>> +#define I2C_BTFIPD              (1 << 0)
>> +#define I2C_BRFIPD              (1 << 1)
>> +#define I2C_MBTFIPD             (1 << 2)
>> +#define I2C_MBRFIPD             (1 << 3)
>> +#define I2C_STARTIPD            (1 << 4)
>> +#define I2C_STOPIPD             (1 << 5)
>> +#define I2C_NAKRCVIPD           (1 << 6)
>> +#define I2C_IPD_ALL_CLEAN       0x7f
>> +
>> +/* i2c timerout */
> 
> s/timerout/timeout/
> 
>> +#define I2C_TIMEOUT		(100 * MSECOND)
>> +#define I2C_RETRY_COUNT		3
> 
> unused
> 
>> +
>> +/* rk i2c fifo max transfer bytes */
>> +#define RK_I2C_FIFO_SIZE	32
>> +
>> +struct rk_i2c {
>> +	struct i2c_adapter	adapter;
>> +	struct clk *clk;
>> +	struct i2c_regs *regs;
>> +	unsigned int speed;
>> +};
>> +
>> +static inline struct rk_i2c *to_rk_i2c(struct i2c_adapter *adapter)
>> +{
>> +	return container_of(adapter, struct rk_i2c, adapter);
>> +}
>> +
>> +static inline void rk_i2c_get_div(int div, int *divh, int *divl)
>> +{
>> +	*divl = div / 2;
>> +	if (div % 2 == 0)
>> +		*divh = div / 2;
> 
> Why special case this? DIV_ROUND_UP(div, 2) should work for even numbers
> as well.

You're right. Fixed.

> 
>> +	else
>> +		*divh = DIV_ROUND_UP(div, 2);
>> +}
>> +
>> +/*
>> + * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
>> + * SCL = PCLK / SCLK Divisor
>> + * i2c_rate = PCLK
>> + */
>> +static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
>> +{
>> +	struct device_d *dev = i2c->adapter.dev.parent;
>> +	uint32_t i2c_rate;
>> +	int div, divl, divh;
>> +
>> +	/* First get i2c rate from pclk */
>> +	i2c_rate = clk_get_rate(i2c->clk);
>> +
>> +	div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
>> +	divh = 0;
>> +	divl = 0;
>> +	if (div >= 0)
>> +		rk_i2c_get_div(div, &divh, &divl);
>> +	writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
>> +
>> +	dev_dbg(dev, "rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
>> +		scl_rate);
>> +	dev_dbg(dev, "set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
>> +	dev_dbg(dev, "set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
>> +}
>> +
>> +static void rk_i2c_show_regs(struct rk_i2c *i2c)
>> +{
>> +	struct device_d *dev = &i2c->adapter.dev;
>> +	struct i2c_regs *regs = i2c->regs;
>> +	int i;
>> +
>> +	dev_dbg(dev, "i2c_con: 0x%08x\n", readl(&regs->con));
>> +	dev_dbg(dev, "i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
>> +	dev_dbg(dev, "i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
>> +	dev_dbg(dev, "i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
>> +	dev_dbg(dev, "i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
>> +	dev_dbg(dev, "i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
>> +	dev_dbg(dev, "i2c_ien: 0x%08x\n", readl(&regs->ien));
>> +	dev_dbg(dev, "i2c_ipd: 0x%08x\n", readl(&regs->ipd));
>> +	dev_dbg(dev, "i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
>> +
>> +	for (i = 0; i < 8; i++)
>> +		dev_dbg(dev, "i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
>> +	for (i = 0; i < 8; i++)
>> +		dev_dbg(dev, "i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
>> +}
>> +
>> +static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
>> +{
>> +	struct device_d *dev = &i2c->adapter.dev;
>> +	struct i2c_regs *regs = i2c->regs;
>> +	u64 start;
>> +
>> +	dev_dbg(dev, "I2c Send Start bit.\n");
>> +	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
>> +
>> +	writel(I2C_CON_EN | I2C_CON_START, &regs->con);
>> +	writel(I2C_STARTIEN, &regs->ien);
>> +
>> +	for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
>> +		if (readl(&regs->ipd) & I2C_STARTIPD) {
>> +			writel(I2C_STARTIPD, &regs->ipd);
>> +			return 0;
>> +		}
>> +		udelay(1);
> 
> Unnecessary udelay()

All removed.

> 
>> +	}
>> +
>> +	dev_dbg(dev, "I2C Send Start Bit Timeout\n");
>> +	rk_i2c_show_regs(i2c);
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
>> +{
>> +	struct device_d *dev = &i2c->adapter.dev;
>> +	struct i2c_regs *regs = i2c->regs;
>> +	u64 start;
>> +
>> +	dev_dbg(dev, "I2c Send Stop bit.\n");
>> +	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
>> +
>> +	writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
>> +	writel(I2C_CON_STOP, &regs->ien);
>> +
>> +	for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
>> +		if (readl(&regs->ipd) & I2C_STOPIPD) {
>> +			writel(I2C_STOPIPD, &regs->ipd);
>> +			return 0;
>> +		}
>> +		udelay(1);
> 
> ditto
> 
>> +	}
>> +
>> +	dev_dbg(dev, "I2C Send Start Bit Timeout\n");
>> +	rk_i2c_show_regs(i2c);
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static inline void rk_i2c_disable(struct rk_i2c *i2c)
>> +{
>> +	writel(0, &i2c->regs->con);
>> +}
>> +
>> +static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
>> +		       uchar *buf, uint b_len)
>> +{
>> +	struct device_d *dev = &i2c->adapter.dev;
>> +	struct i2c_regs *regs = i2c->regs;
>> +	uchar *pbuf = buf;
>> +	uint bytes_remain_len = b_len;
>> +	uint bytes_xferred = 0;
>> +	uint words_xferred = 0;
>> +	u64 start;
>> +	uint con = 0;
>> +	uint rxdata;
>> +	uint i, j;
>> +	int err;
>> +	bool snd_chunk = false;
>> +
>> +	dev_dbg(dev, "rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
>> +	      chip, reg, r_len, b_len);
>> +
>> +	err = rk_i2c_send_start_bit(i2c);
>> +	if (err)
>> +		return err;
>> +
>> +	writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
>> +	if (r_len == 0) {
>> +		writel(0, &regs->mrxraddr);
>> +	} else if (r_len < 4) {
>> +		writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
>> +	} else {
>> +		dev_dbg(dev, "I2C Read: addr len %d not supported\n", r_len);
>> +		return -EIO;
>> +	}
>> +
>> +	while (bytes_remain_len) {
>> +		if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
>> +			con = I2C_CON_EN;
>> +			bytes_xferred = 32;
> 
> bytes_xferred = RK_I2C_FIFO_SIZE

Done.

> 
>> +		} else {
>> +			/*
>> +			 * The hw can read up to 32 bytes at a time. If we need
>> +			 * more than one chunk, send an ACK after the last byte.
>> +			 */
>> +			con = I2C_CON_EN | I2C_CON_LASTACK;
>> +			bytes_xferred = bytes_remain_len;
>> +		}
>> +		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
>> +
>> +		/*
>> +		 * make sure we are in plain RX mode if we read a second chunk
>> +		 */
>> +		if (snd_chunk)
>> +			con |= I2C_CON_MOD(I2C_MODE_RX);
>> +		else
>> +			con |= I2C_CON_MOD(I2C_MODE_TRX);
>> +
>> +		writel(con, &regs->con);
>> +		writel(bytes_xferred, &regs->mrxcnt);
>> +		writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
>> +
>> +		err = -ETIMEDOUT;
>> +		for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
>> +			if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
>> +				writel(I2C_NAKRCVIPD, &regs->ipd);
>> +				err = -EREMOTEIO;
> 
> Does it make sense to stay in the loop here?

In Linux, depends on whether ignore NAK is configured, but in our
case, we should exit.

> 
>> +			}
>> +			if (readl(&regs->ipd) & I2C_MBRFIPD) {
>> +				writel(I2C_MBRFIPD, &regs->ipd);
>> +				err = 0;
>> +				break;
>> +			}
>> +			udelay(1);
> 
> Unnecessary udelay().
> 
>> +		}
>> +
>> +		if (err) {
>> +			dev_dbg(dev, "I2C Read Data Timeout\n");
>> +			rk_i2c_show_regs(i2c);
>> +			goto i2c_exit;
>> +		}
> 
> It's easier to follow when you just exit the loop with
> 
> 	if (is_timeout()) {
> 		err = -ETIMEDOUT;
> 		goto i2c_exit;
> 	}

I just changed all instances to use readl_poll_timeout instead

> 
>> +
>> +		for (i = 0; i < words_xferred; i++) {
>> +			rxdata = readl(&regs->rxdata[i]);
>> +			dev_dbg(dev, "I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
>> +			for (j = 0; j < 4; j++) {
>> +				if ((i * 4 + j) == bytes_xferred)
>> +					break;
>> +				*pbuf++ = (rxdata >> (j * 8)) & 0xff;
>> +			}
>> +		}
>> +
>> +		bytes_remain_len -= bytes_xferred;
>> +		snd_chunk = true;
>> +		dev_dbg(dev, "I2C Read bytes_remain_len %d\n", bytes_remain_len);
>> +	}
>> +
>> +i2c_exit:
>> +	rk_i2c_disable(i2c);
>> +
>> +	return err;
>> +}
>> +
>> +static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
>> +			uchar *buf, uint b_len)
>> +{
>> +	struct device_d *dev = &i2c->adapter.dev;
>> +	struct i2c_regs *regs = i2c->regs;
>> +	int err;
>> +	uchar *pbuf = buf;
>> +	uint bytes_remain_len = b_len + r_len + 1;
>> +	uint bytes_xferred = 0;
>> +	uint words_xferred = 0;
>> +	u64 start;
>> +	uint txdata;
>> +	uint i, j;
>> +
>> +	dev_dbg(dev, "rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
>> +	      chip, reg, r_len, b_len);
>> +	err = rk_i2c_send_start_bit(i2c);
>> +	if (err)
>> +		return err;
>> +
>> +	while (bytes_remain_len) {
>> +		if (bytes_remain_len > RK_I2C_FIFO_SIZE)
>> +			bytes_xferred = RK_I2C_FIFO_SIZE;
>> +		else
>> +			bytes_xferred = bytes_remain_len;
>> +		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
>> +
>> +		for (i = 0; i < words_xferred; i++) {
>> +			txdata = 0;
>> +			for (j = 0; j < 4; j++) {
>> +				if ((i * 4 + j) == bytes_xferred)
>> +					break;
>> +
>> +				if (i == 0 && j == 0 && pbuf == buf) {
>> +					txdata |= (chip << 1);
>> +				} else if (i == 0 && j <= r_len && pbuf == buf) {
>> +					txdata |= (reg &
>> +						(0xff << ((j - 1) * 8))) << 8;
>> +				} else {
>> +					txdata |= (*pbuf++)<<(j * 8);
>> +				}
>> +			}
>> +			writel(txdata, &regs->txdata[i]);
>> +			dev_dbg(dev, "I2c Write TXDATA[%d] = 0x%08x\n", i, txdata);
>> +		}
>> +
>> +		writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
>> +		writel(bytes_xferred, &regs->mtxcnt);
>> +		writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
>> +
>> +		err = -ETIMEDOUT;
>> +		for (start = get_time_ns(); !is_timeout(start, I2C_TIMEOUT);) {
>> +			if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
>> +				writel(I2C_NAKRCVIPD, &regs->ipd);
>> +				err = -EREMOTEIO;
>> +			}
> 
> Same as above, need to stay in the loop here?
> 
>> +			if (readl(&regs->ipd) & I2C_MBTFIPD) {
>> +				writel(I2C_MBTFIPD, &regs->ipd);
>> +				err = 0;
>> +				break;
>> +			}
>> +			udelay(1);
> 
> Drop the udelay()
> 
>> +		}
>> +
>> +		if (err) {
>> +			dev_dbg(dev, "I2C Write Data Timeout\n");
>> +			rk_i2c_show_regs(i2c);
>> +			goto i2c_exit;
>> +		}
> 
> Test for timeout in the loop.

There is already a timeout test in the for loop condition (which is replaced
by readl_poll_timeout in v2). The while loop around it doesn't need a dedicated
timeout IMO, because you are guaranteed progress. Either you manage to send
bytes, so you decrement bytes_remain_len or you error out and early exit.

> 
>> +
>> +		bytes_remain_len -= bytes_xferred;
>> +		dev_dbg(dev, "I2C Write bytes_remain_len %d\n", bytes_remain_len);
>> +	}
>> +
>> +i2c_exit:
>> +	rk_i2c_disable(i2c);
>> +
>> +	return err;
>> +}
>> +
>> +static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
>> +			     int nmsgs)
>> +{
>> +	struct rk_i2c *i2c = to_rk_i2c(adapter);
>> +	struct device_d *dev = &adapter->dev;
>> +	int ret;
>> +
>> +	dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
>> +	for (; nmsgs > 0; nmsgs--, msg++) {
>> +		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
>> +		if (msg->flags & I2C_M_RD) {
>> +			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
>> +					  msg->len);
>> +		} else {
>> +			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
>> +					   msg->len);
>> +		}
>> +		if (ret) {
>> +			dev_dbg(dev, "i2c_write: error sending\n");
>> +			return -EREMOTEIO;
> 
> Print the error code? Forward the error?

Will print.

> 
>> +		}
>> +	}
>> +
>> +	rk_i2c_send_stop_bit(i2c);
>> +	rk_i2c_disable(i2c);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rk_i2c_probe(struct device_d *dev)
>> +{
>> +	struct device_node *np = dev->device_node;
>> +	struct resource *iores;
>> +	struct rk_i2c *i2c;
>> +	unsigned bitrate;
>> +
>> +	iores = dev_request_mem_resource(dev, 0);
>> +	if (IS_ERR(iores))
>> +		return PTR_ERR(iores);
>> +
>> +	i2c = kzalloc(sizeof(struct rk_i2c), GFP_KERNEL);
>> +	if (!i2c)
>> +		return -ENOMEM;
>> +
>> +	dev->priv = i2c;
>> +	i2c->regs = IOMEM(iores->start);
>> +
>> +	/* Only one clock to use for bus clock and peripheral clock */
>> +	i2c->clk = clk_get(dev, NULL);
>> +	if (IS_ERR(i2c->clk))
>> +		return dev_err_probe(dev, PTR_ERR(i2c->clk), "Can't get bus clk\n");
>> +
>> +	/* Setup i2c_fsl driver structure */
> 
> copy/paste, it's not i2c_fsl

Dropped.

Thanks for the review!

> 
>> +	i2c->adapter.master_xfer = rockchip_i2c_xfer;
>> +	i2c->adapter.nr = dev->id;
>> +	i2c->adapter.dev.parent = dev;
>> +	i2c->adapter.dev.device_node = np;
>> +
>> +	/* Set up clock divider */
>> +	bitrate = 100000;
>> +	of_property_read_u32(np, "clock-frequency", &bitrate);
>> +
>> +	rk_i2c_set_clk(i2c, bitrate);
>> +
>> +	return i2c_add_numbered_adapter(&i2c->adapter);
>> +}
>> +
>> +static const struct of_device_id rk_i2c_match[] = {
>> +	{ .compatible = "rockchip,rv1108-i2c" },
>> +	{ .compatible = "rockchip,rk3228-i2c" },
>> +	{ .compatible = "rockchip,rk3288-i2c" },
>> +	{ .compatible = "rockchip,rk3399-i2c" },
>> +	{},
>> +};
>> +
>> +static struct driver_d rk_i2c_driver = {
>> +	.name  = "rk3x-i2c",
>> +	.of_compatible = rk_i2c_match,
>> +	.probe   = rk_i2c_probe,
>> +};
>> +coredevice_platform_driver(rk_i2c_driver);
>> -- 
>> 2.30.2
>>
>>
>> _______________________________________________
>> barebox mailing list
>> barebox at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/barebox
>>
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Thu Jan 13 21:24:00 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 06:24:00 +0100
Subject: [PATCH 2/3] net: designware: rockchip: remove unnecessary clock
 pclk_xpcs
In-Reply-To: <20211111140316.1646962-3-michael.riesch@wolfvision.net>
References: <20211111140316.1646962-1-michael.riesch@wolfvision.net>
 <20211111140316.1646962-3-michael.riesch@wolfvision.net>
Message-ID: <603ef8b9-0103-5b53-b9bb-3db329961b04@pengutronix.de>

Hello Sascha,

On 11.11.21 15:03, Michael Riesch wrote:
> The pclk_xpcs clock is not used in the mainline Linux driver and
> only rarely specified in the mainline dts files. Drop it in order
> to avoid errors when the mainline dts files are used.
> 
> Signed-off-by: Michael Riesch <michael.riesch at wolfvision.net>

Can you cherry-pick this one patch? I have code depending on it.

> ---
>  drivers/net/designware_rockchip.c | 2 --
>  1 file changed, 2 deletions(-)
> 
> diff --git a/drivers/net/designware_rockchip.c b/drivers/net/designware_rockchip.c
> index e4f74f646..7acbd723b 100644
> --- a/drivers/net/designware_rockchip.c
> +++ b/drivers/net/designware_rockchip.c
> @@ -44,7 +44,6 @@ enum {
>  	CLK_MAC_PCLK,
>  	CLK_MAC_SPEED,
>  	CLK_PTP_REF,
> -	CLK_XPCS_PCLK,
>  };
>  
>  static const struct clk_bulk_data rk_gmac_clks[] = {
> @@ -56,7 +55,6 @@ static const struct clk_bulk_data rk_gmac_clks[] = {
>  	[CLK_MAC_PCLK]    = { .id = "pclk_mac" },
>  	[CLK_MAC_SPEED]   = { .id = "clk_mac_speed" },
>  	[CLK_PTP_REF]     = { .id = "ptp_ref" },
> -	[CLK_XPCS_PCLK]   = { .id = "pclk_xpcs" },
>  };
>  
>  static inline struct eqos_rk_gmac *to_rk_gmac(struct eqos *eqos)
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From ahmad at a3f.at  Thu Jan 13 22:59:43 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 07:59:43 +0100
Subject: [PATCH] pinctrl: stm32: replace magic values with defines for
 STM32_PINMODE
Message-ID: <20220114065943.698337-1-ahmad@a3f.at>

Makes the code easier to follow and allows using the new macros in PBL
code for early pinmuxing of e.g. the debug UART.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 drivers/pinctrl/pinctrl-stm32.c | 6 +++---
 include/soc/stm32/gpio.h        | 4 ++++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-stm32.c b/drivers/pinctrl/pinctrl-stm32.c
index 9b5b04b6d6a8..ceaa4254c4d0 100644
--- a/drivers/pinctrl/pinctrl-stm32.c
+++ b/drivers/pinctrl/pinctrl-stm32.c
@@ -63,11 +63,11 @@ static inline u32 stm32_gpio_get_mode(u32 function)
 {
 	switch (function) {
 	case STM32_PIN_GPIO:
-		return 0;
+		return STM32_PINMODE_GPIO;
 	case STM32_PIN_AF(0) ... STM32_PIN_AF(15):
-		return 2;
+		return STM32_PINMODE_AF;
 	case STM32_PIN_ANALOG:
-		return 3;
+		return STM32_PINMODE_ANALOG;
 	}
 
 	return 0;
diff --git a/include/soc/stm32/gpio.h b/include/soc/stm32/gpio.h
index 13b492a6937c..448fb19e2ef8 100644
--- a/include/soc/stm32/gpio.h
+++ b/include/soc/stm32/gpio.h
@@ -25,6 +25,10 @@
 #define STM32_PIN_AF(x)		((x) + 1)
 #define STM32_PIN_ANALOG	(STM32_PIN_AF(15) + 1)
 
+#define STM32_PINMODE_GPIO	0
+#define STM32_PINMODE_AF	2
+#define STM32_PINMODE_ANALOG	3
+
 #define STM32_GPIO_PINS_PER_BANK	16
 
 enum stm32_pin_bias { STM32_PIN_NO_BIAS, STM32_PIN_PULL_UP, STM32_PIN_PULL_DOWN };
-- 
2.33.0



From ahmad at a3f.at  Thu Jan 13 22:59:52 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 07:59:52 +0100
Subject: [PATCH 1/2] clk: change clk_get_num_parents into
 clk_hw_get_num_parents
Message-ID: <20220114065953.698483-1-ahmad@a3f.at>

There is no clk_get_num_parents in Linux, but clk_hw_get_num_parents.
Our only users uses it with a clk_hw, so adjust the function
accordingly.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 drivers/clk/at91/clk-generated.c | 2 +-
 include/linux/clk.h              | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
index 628ff407d91e..e639fb3a1a65 100644
--- a/drivers/clk/at91/clk-generated.c
+++ b/drivers/clk/at91/clk-generated.c
@@ -92,7 +92,7 @@ static int clk_generated_set_parent(struct clk_hw *hw, u8 index)
 {
 	struct clk_generated *gck = to_clk_generated(hw);
 
-	if (index >= clk_get_num_parents(clk_hw_to_clk(hw)))
+	if (index >= clk_hw_get_num_parents(hw))
 		return -EINVAL;
 
 	gck->parent_id = index;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 6565429a9b9f..481c28871258 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -721,9 +721,9 @@ int of_clk_add_provider(struct device_node *np,
 						   void *data),
 			void *data);
 
-static inline unsigned int clk_get_num_parents(const struct clk *hw)
+static inline unsigned int clk_hw_get_num_parents(const struct clk_hw *hw)
 {
-	return hw->num_parents;
+	return hw->clk.num_parents;
 }
 
 #else
-- 
2.33.0



From ahmad at a3f.at  Thu Jan 13 22:59:53 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 07:59:53 +0100
Subject: [PATCH 2/2] clk: propagate error pointers in clk_hw_to_clk and
 clk_to_clk_hw
In-Reply-To: <20220114065953.698483-1-ahmad@a3f.at>
References: <20220114065953.698483-1-ahmad@a3f.at>
Message-ID: <20220114065953.698483-2-ahmad@a3f.at>

This will make porting helpers easier, because it's harder to miss
error checking.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 include/linux/clk.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/clk.h b/include/linux/clk.h
index 481c28871258..ffc1ac8489b0 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -432,12 +432,12 @@ struct clk_hw {
 
 static inline struct clk *clk_hw_to_clk(struct clk_hw *hw)
 {
-	return &hw->clk;
+	return IS_ERR(hw) ? ERR_CAST(hw) : &hw->clk;
 }
 
 static inline struct clk_hw *clk_to_clk_hw(struct clk *clk)
 {
-	return container_of(clk, struct clk_hw, clk);
+	return IS_ERR(clk) ? ERR_CAST(clk) : container_of(clk, struct clk_hw, clk);
 }
 
 struct clk_div_table {
-- 
2.33.0



From sha at pengutronix.de  Thu Jan 13 23:53:01 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 08:53:01 +0100
Subject: [PATCH v2 1/3] tlsf: dump stack on assertion failure
In-Reply-To: <20220113160414.3943151-1-a.fatoum@pengutronix.de>
References: <20220113160414.3943151-1-a.fatoum@pengutronix.de>
Message-ID: <20220114075301.GN26619@pengutronix.de>

On Thu, Jan 13, 2022 at 05:04:12PM +0100, Ahmad Fatoum wrote:
> We only support AddressSanitizer on ARM, ARM64 and sandbox. For other
> platforms TLSF assertions may detect some nconsistency, like some double
> frees. Make the reports more useful by dumping stack in that case.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> v1 -> v2: no change
> ---
>  include/tlsf.h | 3 +++
>  1 file changed, 3 insertions(+)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Fri Jan 14 00:16:54 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 09:16:54 +0100
Subject: [PATCH 2/3] net: designware: rockchip: remove unnecessary clock
 pclk_xpcs
In-Reply-To: <603ef8b9-0103-5b53-b9bb-3db329961b04@pengutronix.de>
References: <20211111140316.1646962-1-michael.riesch@wolfvision.net>
 <20211111140316.1646962-3-michael.riesch@wolfvision.net>
 <603ef8b9-0103-5b53-b9bb-3db329961b04@pengutronix.de>
Message-ID: <20220114081654.GP26619@pengutronix.de>

On Fri, Jan 14, 2022 at 06:24:00AM +0100, Ahmad Fatoum wrote:
> Hello Sascha,
> 
> On 11.11.21 15:03, Michael Riesch wrote:
> > The pclk_xpcs clock is not used in the mainline Linux driver and
> > only rarely specified in the mainline dts files. Drop it in order
> > to avoid errors when the mainline dts files are used.
> > 
> > Signed-off-by: Michael Riesch <michael.riesch at wolfvision.net>
> 
> Can you cherry-pick this one patch? I have code depending on it.

Did that.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From o.rempel at pengutronix.de  Fri Jan 14 00:21:41 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 14 Jan 2022 09:21:41 +0100
Subject: [PATCH v1 2/2] ARM: rpi: set uart0-pl0110 clk to 48MHz
In-Reply-To: <20220114082141.302151-1-o.rempel@pengutronix.de>
References: <20220114082141.302151-1-o.rempel@pengutronix.de>
Message-ID: <20220114082141.302151-2-o.rempel@pengutronix.de>

At least on RPi2 this clock is 48MHz. This issue was not visible,
becouse amba-pl011 driver was not reseting UART controller after
changing baudrate. So, clk settings was not updated for some time.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 6c5df6fd69..2684bd5ed7 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -374,7 +374,7 @@ static int rpi_console_clock_init(void)
 	clk = clk_fixed("apb_pclk", 0);
 	clk_register_clkdev(clk, "apb_pclk", NULL);
 
-	clk = clk_fixed("uart0-pl0110", 3 * 1000 * 1000);
+	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
 	clk_register_clkdev(clk, NULL, "uart0-pl0110");
 	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
 	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
-- 
2.30.2



From o.rempel at pengutronix.de  Fri Jan 14 00:21:40 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 14 Jan 2022 09:21:40 +0100
Subject: [PATCH v1 1/2] serial: amba-pl011: reset controller on
 pl011_setbaudrate()
Message-ID: <20220114082141.302151-1-o.rempel@pengutronix.de>

Reset UART controller on baudrate update. Otherwise, at least on some
systems (for example RPi2), new baudrate setting will not be updated
and system will continue to use previous settings.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 drivers/serial/amba-pl011.c | 41 ++++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 3baadd54e7..345c58e274 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -54,6 +54,23 @@ to_amba_uart_port(struct console_device *uart)
 	return container_of(uart, struct amba_uart_port, uart);
 }
 
+static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr)
+{
+	struct vendor_data	*vendor = uart->vendor;
+
+	writew(lcr, uart->base + vendor->lcrh_rx);
+	if (vendor->lcrh_tx != vendor->lcrh_rx) {
+		int i;
+		/*
+		 * Wait 10 PCLKs before writing LCRH_TX register,
+		 * to get this delay write read only register 10 times
+		 */
+		for (i = 0; i < 10; ++i)
+			writew(0xff, uart->base + UART011_MIS);
+		writew(lcr, uart->base +  vendor->lcrh_tx);
+	}
+}
+
 static int pl011_setbaudrate(struct console_device *cdev, int baudrate)
 {
 	struct amba_uart_port *uart = to_amba_uart_port(cdev);
@@ -61,6 +78,7 @@ static int pl011_setbaudrate(struct console_device *cdev, int baudrate)
 	unsigned int divider;
 	unsigned int remainder;
 	unsigned int fraction;
+	uint32_t cr;
 
 	/*
 	 ** Set baud rate
@@ -74,9 +92,15 @@ static int pl011_setbaudrate(struct console_device *cdev, int baudrate)
 	temp = (8 * remainder) / baudrate;
 	fraction = (temp >> 1) + (temp & 1);
 
+	cr = readl(uart->base + UART011_CR);
+	writel(0x0, uart->base + UART011_CR);
+
 	writel(divider, uart->base + UART011_IBRD);
 	writel(fraction, uart->base + UART011_FBRD);
 
+	pl011_rlcr(uart, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN);
+	writel(cr, uart->base + UART011_CR);
+
 	return 0;
 }
 
@@ -118,23 +142,6 @@ static int pl011_tstc(struct console_device *cdev)
 	return !(readl(uart->base + UART01x_FR) & UART01x_FR_RXFE);
 }
 
-static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr)
-{
-	struct vendor_data	*vendor = uart->vendor;
-
-	writew(lcr, uart->base + vendor->lcrh_rx);
-	if (vendor->lcrh_tx != vendor->lcrh_rx) {
-		int i;
-		/*
-		 * Wait 10 PCLKs before writing LCRH_TX register,
-		 * to get this delay write read only register 10 times
-		 */
-		for (i = 0; i < 10; ++i)
-			writew(0xff, uart->base + UART011_MIS);
-		writew(lcr, uart->base +  vendor->lcrh_tx);
-	}
-}
-
 static int pl011_init_port(struct console_device *cdev)
 {
 	struct amba_uart_port *uart = to_amba_uart_port(cdev);
-- 
2.30.2



From sha at pengutronix.de  Fri Jan 14 00:24:46 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 09:24:46 +0100
Subject: [PATCH] pinctrl: stm32: replace magic values with defines for
 STM32_PINMODE
In-Reply-To: <20220114065943.698337-1-ahmad@a3f.at>
References: <20220114065943.698337-1-ahmad@a3f.at>
Message-ID: <20220114082446.GQ26619@pengutronix.de>

On Fri, Jan 14, 2022 at 07:59:43AM +0100, Ahmad Fatoum wrote:
> Makes the code easier to follow and allows using the new macros in PBL
> code for early pinmuxing of e.g. the debug UART.
> 
> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
> ---
>  drivers/pinctrl/pinctrl-stm32.c | 6 +++---
>  include/soc/stm32/gpio.h        | 4 ++++
>  2 files changed, 7 insertions(+), 3 deletions(-)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 00:26:01 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 09:26:01 +0100
Subject: [PATCH 1/2] clk: change clk_get_num_parents into
 clk_hw_get_num_parents
In-Reply-To: <20220114065953.698483-1-ahmad@a3f.at>
References: <20220114065953.698483-1-ahmad@a3f.at>
Message-ID: <20220114082601.GR26619@pengutronix.de>

On Fri, Jan 14, 2022 at 07:59:52AM +0100, Ahmad Fatoum wrote:
> There is no clk_get_num_parents in Linux, but clk_hw_get_num_parents.
> Our only users uses it with a clk_hw, so adjust the function
> accordingly.
> 
> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
> ---
>  drivers/clk/at91/clk-generated.c | 2 +-
>  include/linux/clk.h              | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From michael.riesch at wolfvision.net  Fri Jan 14 00:25:56 2022
From: michael.riesch at wolfvision.net (Michael Riesch)
Date: Fri, 14 Jan 2022 09:25:56 +0100
Subject: [RFC PATCH] bootsource: add helper to set instance by name
In-Reply-To: <20211117142448.2091017-1-michael.riesch@wolfvision.net>
References: <3fb6debc-4891-c366-94df-0d7c0b80685c@wolfvision.net>
 <20211117142448.2091017-1-michael.riesch@wolfvision.net>
Message-ID: <0a914276-723d-69fa-cee3-42b517435d6f@wolfvision.net>

Hi Sascha and Ahmad,

On 11/17/21 15:24, Michael Riesch wrote:
> Instance numbers should be related to device tree aliases, which may be
> board-specific. In order to establish a board-independent link between
> the boot source and the actual alias, introduce a helper that sets the
> instance by the OF name.

Gentle ping here. A rough indication whether or not this is the correct
path would be great.

Since patch 2/3 has just been cherry-picked, I could prepare a v2 of the
remaining two patches as next step.

Best regards,
Michael

> 
> Signed-off-by: Michael Riesch <michael.riesch at wolfvision.net>
> ---
>  common/bootsource.c  | 74 ++++++++++++++++++++++++++++----------------
>  include/bootsource.h |  1 +
>  2 files changed, 48 insertions(+), 27 deletions(-)
> 
> diff --git a/common/bootsource.c b/common/bootsource.c
> index 1f8d053a8..1b45956a5 100644
> --- a/common/bootsource.c
> +++ b/common/bootsource.c
> @@ -9,6 +9,7 @@
>  #include <environment.h>
>  #include <magicvar.h>
>  #include <init.h>
> +#include <of.h>
>  
>  static const char *bootsource_str[] = {
>  	[BOOTSOURCE_UNKNOWN] = "unknown",
> @@ -33,31 +34,8 @@ static enum bootsource bootsource = BOOTSOURCE_UNKNOWN;
>  static int bootsource_instance = BOOTSOURCE_INSTANCE_UNKNOWN;
>  const char *bootsource_alias_name = NULL;
>  
> -/**
> - * bootsource_get_alias_name() - Get the name of the bootsource alias
> - *
> - * This function will return newly allocated string containing name of
> - * the alias that is expected to point to DTB node corresponding to
> - * detected bootsource
> - *
> - * NOTE: Caller is expected to free() the string allocated by this
> - * function
> - */
> -char *bootsource_get_alias_name(void)
> +static const char *bootsource_get_of_stem(void)
>  {
> -	const char *stem;
> -
> -	/*
> -	 * If alias name was overridden via
> -	 * bootsource_set_alias_name() return that value without
> -	 * asking any questions.
> -	 *
> -	 * Note that we have to strdup() the result to make it
> -	 * free-able.
> -	 */
> -	if (bootsource_alias_name)
> -		return strdup(bootsource_alias_name);
> -
>  	switch (bootsource) {
>  		/*
>  		 * For I2C and SPI EEPROMs we set the stem to be 'i2c'
> @@ -69,22 +47,50 @@ char *bootsource_get_alias_name(void)
>  		 * controller
>  		 */
>  	case BOOTSOURCE_I2C_EEPROM:
> -		stem = bootsource_str[BOOTSOURCE_I2C];
> +		return bootsource_str[BOOTSOURCE_I2C];
>  		break;
>  	case BOOTSOURCE_SPI_EEPROM:
>  	case BOOTSOURCE_SPI_NOR:
> -		stem = bootsource_str[BOOTSOURCE_SPI];
> +		return bootsource_str[BOOTSOURCE_SPI];
>  		break;
>  	case BOOTSOURCE_SERIAL:	/* FALLTHROUGH */
>  	case BOOTSOURCE_I2C:	/* FALLTHROUGH */
>  	case BOOTSOURCE_MMC:	/* FALLTHROUGH */
>  	case BOOTSOURCE_SPI:	/* FALLTHROUGH */
>  	case BOOTSOURCE_CAN:
> -		stem = bootsource_str[bootsource];
> +		return bootsource_str[bootsource];
>  		break;
>  	default:
>  		return NULL;
>  	}
> +}
> +
> +/**
> + * bootsource_get_alias_name() - Get the name of the bootsource alias
> + *
> + * This function will return newly allocated string containing name of
> + * the alias that is expected to point to DTB node corresponding to
> + * detected bootsource
> + *
> + * NOTE: Caller is expected to free() the string allocated by this
> + * function
> + */
> +char *bootsource_get_alias_name(void)
> +{
> +	const char *stem;
> +
> +	/*
> +	 * If alias name was overridden via
> +	 * bootsource_set_alias_name() return that value without
> +	 * asking any questions.
> +	 *
> +	 * Note that we have to strdup() the result to make it
> +	 * free-able.
> +	 */
> +	if (bootsource_alias_name)
> +		return strdup(bootsource_alias_name);
> +
> +	stem = bootsource_get_of_stem();
>  
>  	/*
>  	 * We expect SoC specific bootsource detection code to properly
> @@ -125,6 +131,20 @@ void bootsource_set_instance(int instance)
>  	setenv("bootsource_instance", buf);
>  }
>  
> +void bootsource_set_instance_by_of_name(const char *name)
> +{
> +	int instance = BOOTSOURCE_UNKNOWN;
> +	struct device_node *node;
> +
> +	node = of_find_node_by_name(of_get_root_node(), name);
> +	if (node) {
> +		instance = of_alias_get_id(node, bootsource_get_of_stem());
> +		if (instance < 0)
> +			instance = BOOTSOURCE_UNKNOWN;
> +	}
> +	bootsource_set_instance(instance);
> +}
> +
>  enum bootsource bootsource_get(void)
>  {
>  	return bootsource;
> diff --git a/include/bootsource.h b/include/bootsource.h
> index 646b0e91c..4dcb969ac 100644
> --- a/include/bootsource.h
> +++ b/include/bootsource.h
> @@ -28,6 +28,7 @@ enum bootsource bootsource_get(void);
>  int bootsource_get_instance(void);
>  void bootsource_set(enum bootsource src);
>  void bootsource_set_instance(int instance);
> +void bootsource_set_instance_by_of_name(const char *name);
>  void bootsource_set_alias_name(const char *name);
>  char *bootsource_get_alias_name(void);
>  


From sha at pengutronix.de  Fri Jan 14 00:30:18 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 09:30:18 +0100
Subject: [PATCH v1 2/2] ARM: rpi: set uart0-pl0110 clk to 48MHz
In-Reply-To: <20220114082141.302151-2-o.rempel@pengutronix.de>
References: <20220114082141.302151-1-o.rempel@pengutronix.de>
 <20220114082141.302151-2-o.rempel@pengutronix.de>
Message-ID: <20220114083018.GS26619@pengutronix.de>

On Fri, Jan 14, 2022 at 09:21:41AM +0100, Oleksij Rempel wrote:
> At least on RPi2 this clock is 48MHz. This issue was not visible,
> becouse amba-pl011 driver was not reseting UART controller after
> changing baudrate. So, clk settings was not updated for some time.

We have an rpi3 and rpi4 in our lab. Could you give this a test on these
boards?

Sascha

> 
> Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
> ---
>  arch/arm/boards/raspberry-pi/rpi-common.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
> index 6c5df6fd69..2684bd5ed7 100644
> --- a/arch/arm/boards/raspberry-pi/rpi-common.c
> +++ b/arch/arm/boards/raspberry-pi/rpi-common.c
> @@ -374,7 +374,7 @@ static int rpi_console_clock_init(void)
>  	clk = clk_fixed("apb_pclk", 0);
>  	clk_register_clkdev(clk, "apb_pclk", NULL);
>  
> -	clk = clk_fixed("uart0-pl0110", 3 * 1000 * 1000);
> +	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
>  	clk_register_clkdev(clk, NULL, "uart0-pl0110");
>  	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
>  	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
> -- 
> 2.30.2
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From ahmad at a3f.at  Fri Jan 14 00:38:23 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:38:23 +0100
Subject: [PATCH 1/3] ARM: rockchip: add new ARCH_ROCKCHIP_{V7,V8} symbols
Message-ID: <20220114083825.726347-1-ahmad@a3f.at>

In preparation for adding rk3399 support, which is another SoC with
ARMv8 CPUs, add new ARCH_ROCKCHIP_{V7,V8} symbols for the common
functionality.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 arch/arm/mach-rockchip/Kconfig  | 18 ++++++++++++------
 arch/arm/mach-rockchip/Makefile |  5 +++--
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 2e855714f7da..596de663f9e3 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -12,24 +12,30 @@ config RK_TIMER
 	hex
 	default 1
 
-config ARCH_RK3188
+config ARCH_ROCKCHIP_V7
 	bool
 	select CPU_V7
 	select ARM_SMP_TWD
 	select ARCH_HAS_L2X0
 
+config ARCH_RK3188
+	bool
+	select ARCH_ROCKCHIP_V7
+
 config ARCH_RK3288
 	bool
-	select CPU_V7
-	select ARM_SMP_TWD
-	select ARCH_HAS_L2X0
+	select ARCH_ROCKCHIP_V7
 	select CLOCKSOURCE_ROCKCHIP
 
-config ARCH_RK3568
+config ARCH_ROCKCHIP_V8
 	bool
 	select CPU_V8
-	select ARM_ATF
 	select SYS_SUPPORTS_64BIT_KERNEL
+	select ARM_ATF
+
+config ARCH_RK3568
+	bool
+	select ARCH_ROCKCHIP_V8
 
 comment "select Rockchip boards:"
 
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 72bf77c1e124..474b8629d13f 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -1,9 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 obj-y += rockchip.o
-pbl-$(CONFIG_ARCH_RK3568) += atf.o
+pbl-$(CONFIG_ARCH_ROCKCHIP_V8) += atf.o
 obj-$(CONFIG_ARCH_RK3188) += rk3188.o
 obj-$(CONFIG_ARCH_RK3288) += rk3288.o
+obj-pbl-$(CONFIG_ARCH_RK3399) += rk3399.o
 obj-pbl-$(CONFIG_ARCH_RK3568) += rk3568.o
-obj-$(CONFIG_ARCH_RK3568) += bootm.o
+obj-$(CONFIG_ARCH_ROCKCHIP_V8) += bootm.o
 obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o
-- 
2.33.0



From ahmad at a3f.at  Fri Jan 14 00:38:24 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:38:24 +0100
Subject: [PATCH 2/3] ARM64: rockchip: add config symbol for ARMv8-based rk3399
 SoC
In-Reply-To: <20220114083825.726347-1-ahmad@a3f.at>
References: <20220114083825.726347-1-ahmad@a3f.at>
Message-ID: <20220114083825.726347-2-ahmad@a3f.at>

As preperation for adding support for the RK3399-based Radxa Rock Pi
N10, define the ARCH_RK3399 config symbol and associated boilerplate.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 arch/arm/mach-rockchip/Kconfig                 | 18 +++++++++++++++++-
 arch/arm/mach-rockchip/atf.c                   |  4 ++++
 arch/arm/mach-rockchip/include/mach/atf.h      |  6 ++++++
 arch/arm/mach-rockchip/include/mach/debug_ll.h |  6 ++++++
 .../mach-rockchip/include/mach/rk3399-regs.h   | 16 ++++++++++++++++
 common/Kconfig                                 | 10 +++++++++-
 firmware/Makefile                              |  2 ++
 7 files changed, 60 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-rockchip/include/mach/rk3399-regs.h

diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 596de663f9e3..98ef35769ffd 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -6,7 +6,7 @@ menu "Rockchip Features"
 config ARCH_TEXT_BASE
 	hex
 	default 0x68000000 if ARCH_RK3188
-	default 0x0 if ARCH_RK3288
+	default 0x0
 
 config RK_TIMER
 	hex
@@ -32,6 +32,15 @@ config ARCH_ROCKCHIP_V8
 	select CPU_V8
 	select SYS_SUPPORTS_64BIT_KERNEL
 	select ARM_ATF
+	select RELOCATABLE
+
+config ARCH_RK3399
+	bool
+	select ARCH_ROCKCHIP_V8
+
+config ARCH_RK3399PRO
+	bool
+	select ARCH_RK3399
 
 config ARCH_RK3568
 	bool
@@ -66,6 +75,13 @@ config MACH_PINE64_QUARTZ64
 
 comment "select board features:"
 
+config ARCH_RK3399_OPTEE
+	bool "Build rk3399 OP-TEE binary into barebox"
+	depends on ARCH_RK3399
+	help
+	  With this option enabled the RK3399 OP-TEE binary is compiled
+	  into barebox and started along with the BL31 trusted firmware.
+
 config ARCH_RK3568_OPTEE
 	bool "Build rk3568 OP-TEE binary into barebox"
 	depends on ARCH_RK3568
diff --git a/arch/arm/mach-rockchip/atf.c b/arch/arm/mach-rockchip/atf.c
index de22784489b5..0512ff99f456 100644
--- a/arch/arm/mach-rockchip/atf.c
+++ b/arch/arm/mach-rockchip/atf.c
@@ -60,6 +60,10 @@ static unsigned long load_elf64_image_phdr(const void *elf)
 		   SOC##_BAREBOX_LOAD_ADDRESS, (uintptr_t)fdt);                 \
 } while (0)                                                                     \
 
+void rk3399_atf_load_bl31(void *fdt)
+{
+	rockchip_atf_load_bl31(RK3399, rk3399_bl31_bin, rk3399_op_tee_bin, fdt);
+}
 
 void rk3568_atf_load_bl31(void *fdt)
 {
diff --git a/arch/arm/mach-rockchip/include/mach/atf.h b/arch/arm/mach-rockchip/include/mach/atf.h
index ab328cc8d20a..d1bae5a7714f 100644
--- a/arch/arm/mach-rockchip/include/mach/atf.h
+++ b/arch/arm/mach-rockchip/include/mach/atf.h
@@ -4,17 +4,23 @@
 #define __MACH_ATF_H
 
 /* First usable DRAM address. Lower mem is used for ATF and OP-TEE */
+#define RK3399_DRAM_BOTTOM		0xa00000
 #define RK3568_DRAM_BOTTOM		0xa00000
 
 /* OP-TEE expects to be loaded here */
+#define RK3399_OPTEE_LOAD_ADDRESS	0x200000
 #define RK3568_OPTEE_LOAD_ADDRESS	0x200000
 
 /*
  * board lowlevel code should relocate barebox here. This is where
  * OP-TEE jumps to after initialization.
  */
+#define RK3399_BAREBOX_LOAD_ADDRESS	(RK3399_DRAM_BOTTOM + 1024*1024)
 #define RK3568_BAREBOX_LOAD_ADDRESS	(RK3568_DRAM_BOTTOM + 1024*1024)
 
+#ifndef __ASSEMBLY__
+void rk3399_atf_load_bl31(void *fdt);
 void rk3568_atf_load_bl31(void *fdt);
+#endif
 
 #endif /* __MACH_ATF_H */
diff --git a/arch/arm/mach-rockchip/include/mach/debug_ll.h b/arch/arm/mach-rockchip/include/mach/debug_ll.h
index 73fc5b5db2ff..42e35188a20a 100644
--- a/arch/arm/mach-rockchip/include/mach/debug_ll.h
+++ b/arch/arm/mach-rockchip/include/mach/debug_ll.h
@@ -8,6 +8,7 @@
 #include <mach/rk3188-regs.h>
 #include <mach/rk3288-regs.h>
 #include <mach/rk3568-regs.h>
+#include <mach/rk3399-regs.h>
 
 #ifdef CONFIG_DEBUG_LL
 
@@ -29,6 +30,11 @@
 
 #define UART_CLOCK		24000000
 #define RK_DEBUG_SOC		RK3568
+
+#elif defined CONFIG_DEBUG_ROCKCHIP_RK3399_UART
+
+#define UART_CLOCK		24000000
+#define RK_DEBUG_SOC		RK3399
 #define serial_out(a, v)	writel(v, a)
 #define serial_in(a)		readl(a)
 
diff --git a/arch/arm/mach-rockchip/include/mach/rk3399-regs.h b/arch/arm/mach-rockchip/include/mach/rk3399-regs.h
new file mode 100644
index 000000000000..57033b651085
--- /dev/null
+++ b/arch/arm/mach-rockchip/include/mach/rk3399-regs.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __MACH_RK3399_REGS_H
+#define __MACH_RK3399_REGS_H
+
+/* UART */
+#define RK3399_UART0_BASE	0xff180000
+#define RK3399_UART1_BASE	0xff190000
+#define RK3399_UART2_BASE	0xff1a0000
+#define RK3399_UART3_BASE	0xff1b0000
+#define RK3399_UART4_BASE	0xff370000
+
+#define RK3399_IRAM_BASE	0xff8c0000
+#define RK3399_STIMER_BASE	0xff8680a0
+
+#endif
diff --git a/common/Kconfig b/common/Kconfig
index 482faea933a6..1843a81b3d97 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1358,6 +1358,13 @@ config DEBUG_ROCKCHIP_RK3568_UART
 	  Say Y here if you want kernel low-level debugging support
 	  on RK3568.
 
+config DEBUG_ROCKCHIP_RK3399_UART
+	bool "RK3399 Debug UART"
+	depends on ARCH_RK3399
+	help
+	  Say Y here if you want kernel low-level debugging support
+	  on RK3399.
+
 config DEBUG_SOCFPGA_UART0
 	bool "Use SOCFPGA UART0 for low-level debug"
 	depends on ARCH_SOCFPGA
@@ -1474,7 +1481,8 @@ config DEBUG_OMAP_UART_PORT
 config DEBUG_ROCKCHIP_UART_PORT
 	int "RK3xxx UART debug port" if DEBUG_ROCKCHIP_RK3188_UART || \
 				DEBUG_ROCKCHIP_RK3288_UART || \
-				DEBUG_ROCKCHIP_RK3568_UART
+				DEBUG_ROCKCHIP_RK3568_UART || \
+				DEBUG_ROCKCHIP_RK3399_UART
 	default 2
 	depends on ARCH_ROCKCHIP
 	help
diff --git a/firmware/Makefile b/firmware/Makefile
index 8873f5178d33..87bd033f6e5c 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -18,6 +18,8 @@ firmware-$(CONFIG_FIRMWARE_IMX8MP_ATF) += imx8mp-bl31.bin
 firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx8mq-bl31.bin
 firmware-$(CONFIG_ARCH_RK3568) += rk3568-bl31.bin
 firmware-$(CONFIG_ARCH_RK3568_OPTEE) += rk3568-op-tee.bin
+firmware-$(CONFIG_ARCH_RK3399) += rk3399-bl31.bin
+firmware-$(CONFIG_ARCH_RK3399_OPTEE) += rk3399-op-tee.bin
 firmware-$(CONFIG_DRIVER_NET_FSL_FMAN) += fsl_fman_ucode_ls1046_r1.0_106_4_18.bin
 
 firmware-$(CONFIG_ARCH_LAYERSCAPE_PPA) += ppa-ls1046a.bin
-- 
2.33.0



From ahmad at a3f.at  Fri Jan 14 00:38:25 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:38:25 +0100
Subject: [PATCH 3/3] clk: rockchip: extend for rk3399 support
In-Reply-To: <20220114083825.726347-1-ahmad@a3f.at>
References: <20220114083825.726347-1-ahmad@a3f.at>
Message-ID: <20220114083825.726347-3-ahmad@a3f.at>

This is a very straight-forward port of Linux' clock driver for the
SoC facilitated with the very convenient changes done to synchronize
barebox clock framework with Linux'.

It adds support for clock tree, restart handler and a reset controller.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 arch/arm/mach-rockchip/Kconfig    |    1 +
 drivers/clk/rockchip/Makefile     |    1 +
 drivers/clk/rockchip/clk-rk3399.c | 1653 +++++++++++++++++++++++++++++
 3 files changed, 1655 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-rk3399.c

diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 98ef35769ffd..3c6b3dd9b531 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -37,6 +37,7 @@ config ARCH_ROCKCHIP_V8
 config ARCH_RK3399
 	bool
 	select ARCH_ROCKCHIP_V8
+	select ARCH_HAS_RESET_CONTROLLER
 
 config ARCH_RK3399PRO
 	bool
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index a2461d16c10d..7adbaf266f0b 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -3,4 +3,5 @@ obj-y += clk-cpu.o clk-pll.o clk.o clk-muxgrf.o clk-mmc-phase.o clk-inverter.o
 obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
 obj-$(CONFIG_ARCH_RK3188) += clk-rk3188.o
 obj-$(CONFIG_ARCH_RK3288) += clk-rk3288.o
+obj-$(CONFIG_ARCH_RK3399) += clk-rk3399.o
 obj-$(CONFIG_ARCH_RK3568) += clk-rk3568.o
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
new file mode 100644
index 000000000000..399d6006c668
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -0,0 +1,1653 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing at rock-chips.com>
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <of.h>
+#include <of_address.h>
+#include <linux/barebox-wrapper.h>
+#include <init.h>
+#include <linux/spinlock.h>
+#include <of_device.h>
+#include <dt-bindings/clock/rk3399-cru.h>
+#include "clk.h"
+
+enum rk3399_plls {
+	lpll, bpll, dpll, cpll, gpll, npll, vpll,
+};
+
+enum rk3399_pmu_plls {
+	ppll,
+};
+
+static struct rockchip_pll_rate_table rk3399_pll_rates[] = {
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+	RK3036_PLL_RATE(2208000000, 1, 92, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2184000000, 1, 91, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2160000000, 1, 90, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2136000000, 1, 89, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2112000000, 1, 88, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2088000000, 1, 87, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2064000000, 1, 86, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2040000000, 1, 85, 1, 1, 1, 0),
+	RK3036_PLL_RATE(2016000000, 1, 84, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1992000000, 1, 83, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1968000000, 1, 82, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1944000000, 1, 81, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1920000000, 1, 80, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1872000000, 1, 78, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1848000000, 1, 77, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1824000000, 1, 76, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1776000000, 1, 74, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1752000000, 1, 73, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1728000000, 1, 72, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1680000000, 1, 70, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1600000000, 3, 200, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+	RK3036_PLL_RATE(1000000000, 1, 125, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 800000000, 1, 100, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 676000000, 3, 169, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 594000000, 1, 99, 4, 1, 1, 0),
+	RK3036_PLL_RATE( 533250000, 8, 711, 4, 1, 1, 0),
+	RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 297000000, 1, 99, 4, 2, 1, 0),
+	RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+	RK3036_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0),
+	RK3036_PLL_RATE( 106500000, 1, 71, 4, 4, 1, 0),
+	RK3036_PLL_RATE(  96000000, 1, 64, 4, 4, 1, 0),
+	RK3036_PLL_RATE(  74250000, 2, 99, 4, 4, 1, 0),
+	RK3036_PLL_RATE(  65000000, 1, 65, 6, 4, 1, 0),
+	RK3036_PLL_RATE(  54000000, 1, 54, 6, 4, 1, 0),
+	RK3036_PLL_RATE(  27000000, 1, 27, 6, 4, 1, 0),
+	{ /* sentinel */ },
+};
+
+/* CRU parents */
+PNAME(mux_pll_p)				= { "xin24m", "xin32k" };
+
+PNAME(mux_armclkl_p)				= { "clk_core_l_lpll_src",
+						    "clk_core_l_bpll_src",
+						    "clk_core_l_dpll_src",
+						    "clk_core_l_gpll_src" };
+PNAME(mux_armclkb_p)				= { "clk_core_b_lpll_src",
+						    "clk_core_b_bpll_src",
+						    "clk_core_b_dpll_src",
+						    "clk_core_b_gpll_src" };
+PNAME(mux_ddrclk_p)				= { "clk_ddrc_lpll_src",
+						    "clk_ddrc_bpll_src",
+						    "clk_ddrc_dpll_src",
+						    "clk_ddrc_gpll_src" };
+PNAME(mux_aclk_cci_p)				= { "cpll_aclk_cci_src",
+						    "gpll_aclk_cci_src",
+						    "npll_aclk_cci_src",
+						    "vpll_aclk_cci_src" };
+PNAME(mux_cci_trace_p)				= { "cpll_cci_trace",
+						    "gpll_cci_trace" };
+PNAME(mux_cs_p)					= { "cpll_cs", "gpll_cs",
+						    "npll_cs"};
+PNAME(mux_aclk_perihp_p)			= { "cpll_aclk_perihp_src",
+						    "gpll_aclk_perihp_src" };
+
+PNAME(mux_pll_src_cpll_gpll_p)			= { "cpll", "gpll" };
+PNAME(mux_pll_src_cpll_gpll_npll_p)		= { "cpll", "gpll", "npll" };
+PNAME(mux_pll_src_cpll_gpll_ppll_p)		= { "cpll", "gpll", "ppll" };
+PNAME(mux_pll_src_cpll_gpll_upll_p)		= { "cpll", "gpll", "upll" };
+PNAME(mux_pll_src_npll_cpll_gpll_p)		= { "npll", "cpll", "gpll" };
+PNAME(mux_pll_src_cpll_gpll_npll_ppll_p)	= { "cpll", "gpll", "npll",
+						    "ppll" };
+PNAME(mux_pll_src_cpll_gpll_npll_24m_p)		= { "cpll", "gpll", "npll",
+						    "xin24m" };
+PNAME(mux_pll_src_cpll_gpll_npll_usbphy480m_p)	= { "cpll", "gpll", "npll",
+						    "clk_usbphy_480m" };
+PNAME(mux_pll_src_ppll_cpll_gpll_npll_p)	= { "ppll", "cpll", "gpll",
+						    "npll", "upll" };
+PNAME(mux_pll_src_cpll_gpll_npll_upll_24m_p)	= { "cpll", "gpll", "npll",
+						    "upll", "xin24m" };
+PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll",
+						    "ppll", "upll", "xin24m" };
+
+PNAME(mux_pll_src_vpll_cpll_gpll_p)		= { "vpll", "cpll", "gpll" };
+PNAME(mux_pll_src_vpll_cpll_gpll_npll_p)	= { "vpll", "cpll", "gpll",
+						    "npll" };
+PNAME(mux_pll_src_vpll_cpll_gpll_24m_p)		= { "vpll", "cpll", "gpll",
+						    "xin24m" };
+
+PNAME(mux_dclk_vop0_p)			= { "dclk_vop0_div",
+					    "dclk_vop0_frac" };
+PNAME(mux_dclk_vop1_p)			= { "dclk_vop1_div",
+					    "dclk_vop1_frac" };
+
+PNAME(mux_clk_cif_p)			= { "clk_cifout_src", "xin24m" };
+
+PNAME(mux_pll_src_24m_usbphy480m_p)	= { "xin24m", "clk_usbphy_480m" };
+PNAME(mux_pll_src_24m_pciephy_p)	= { "xin24m", "clk_pciephy_ref100m" };
+PNAME(mux_pll_src_24m_32k_cpll_gpll_p)	= { "xin24m", "xin32k",
+					    "cpll", "gpll" };
+PNAME(mux_pciecore_cru_phy_p)		= { "clk_pcie_core_cru",
+					    "clk_pcie_core_phy" };
+
+PNAME(mux_aclk_emmc_p)			= { "cpll_aclk_emmc_src",
+					    "gpll_aclk_emmc_src" };
+
+PNAME(mux_aclk_perilp0_p)		= { "cpll_aclk_perilp0_src",
+					    "gpll_aclk_perilp0_src" };
+
+PNAME(mux_fclk_cm0s_p)			= { "cpll_fclk_cm0s_src",
+					    "gpll_fclk_cm0s_src" };
+
+PNAME(mux_hclk_perilp1_p)		= { "cpll_hclk_perilp1_src",
+					    "gpll_hclk_perilp1_src" };
+
+PNAME(mux_clk_testout1_p)		= { "clk_testout1_pll_src", "xin24m" };
+PNAME(mux_clk_testout2_p)		= { "clk_testout2_pll_src", "xin24m" };
+
+PNAME(mux_usbphy_480m_p)		= { "clk_usbphy0_480m_src",
+					    "clk_usbphy1_480m_src" };
+PNAME(mux_aclk_gmac_p)			= { "cpll_aclk_gmac_src",
+					    "gpll_aclk_gmac_src" };
+PNAME(mux_rmii_p)			= { "clk_gmac", "clkin_gmac" };
+PNAME(mux_spdif_p)			= { "clk_spdif_div", "clk_spdif_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2s0_p)			= { "clk_i2s0_div", "clk_i2s0_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2s1_p)			= { "clk_i2s1_div", "clk_i2s1_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2s2_p)			= { "clk_i2s2_div", "clk_i2s2_frac",
+					    "clkin_i2s", "xin12m" };
+PNAME(mux_i2sch_p)			= { "clk_i2s0", "clk_i2s1",
+					    "clk_i2s2" };
+PNAME(mux_i2sout_p)			= { "clk_i2sout_src", "xin12m" };
+
+PNAME(mux_uart0_p)	= { "clk_uart0_div", "clk_uart0_frac", "xin24m" };
+PNAME(mux_uart1_p)	= { "clk_uart1_div", "clk_uart1_frac", "xin24m" };
+PNAME(mux_uart2_p)	= { "clk_uart2_div", "clk_uart2_frac", "xin24m" };
+PNAME(mux_uart3_p)	= { "clk_uart3_div", "clk_uart3_frac", "xin24m" };
+
+/* PMU CRU parents */
+PNAME(mux_ppll_24m_p)		= { "ppll", "xin24m" };
+PNAME(mux_24m_ppll_p)		= { "xin24m", "ppll" };
+PNAME(mux_fclk_cm0s_pmu_ppll_p)	= { "fclk_cm0s_pmu_ppll_src", "xin24m" };
+PNAME(mux_wifi_pmu_p)		= { "clk_wifi_div", "clk_wifi_frac" };
+PNAME(mux_uart4_pmu_p)		= { "clk_uart4_div", "clk_uart4_frac",
+				    "xin24m" };
+PNAME(mux_clk_testout2_2io_p)	= { "clk_testout2", "clk_32k_suspend_pmu" };
+
+static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = {
+	[lpll] = PLL(pll_rk3399, PLL_APLLL, "lpll", mux_pll_p, 0, RK3399_PLL_CON(0),
+		     RK3399_PLL_CON(3), 8, 31, 0, rk3399_pll_rates),
+	[bpll] = PLL(pll_rk3399, PLL_APLLB, "bpll", mux_pll_p, 0, RK3399_PLL_CON(8),
+		     RK3399_PLL_CON(11), 8, 31, 0, rk3399_pll_rates),
+	[dpll] = PLL(pll_rk3399, PLL_DPLL, "dpll", mux_pll_p, 0, RK3399_PLL_CON(16),
+		     RK3399_PLL_CON(19), 8, 31, 0, NULL),
+	[cpll] = PLL(pll_rk3399, PLL_CPLL, "cpll", mux_pll_p, 0, RK3399_PLL_CON(24),
+		     RK3399_PLL_CON(27), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+	[gpll] = PLL(pll_rk3399, PLL_GPLL, "gpll", mux_pll_p, 0, RK3399_PLL_CON(32),
+		     RK3399_PLL_CON(35), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+	[npll] = PLL(pll_rk3399, PLL_NPLL, "npll",  mux_pll_p, 0, RK3399_PLL_CON(40),
+		     RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+	[vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll",  mux_pll_p, 0, RK3399_PLL_CON(48),
+		     RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+};
+
+static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = {
+	[ppll] = PLL(pll_rk3399, PLL_PPLL, "ppll",  mux_pll_p, 0, RK3399_PMU_PLL_CON(0),
+		     RK3399_PMU_PLL_CON(3), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
+
+static struct rockchip_clk_branch rk3399_spdif_fracmux __initdata =
+	MUX(0, "clk_spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(32), 13, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_i2s0_fracmux __initdata =
+	MUX(0, "clk_i2s0_mux", mux_i2s0_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(28), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_i2s1_fracmux __initdata =
+	MUX(0, "clk_i2s1_mux", mux_i2s1_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(29), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_i2s2_fracmux __initdata =
+	MUX(0, "clk_i2s2_mux", mux_i2s2_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(30), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart0_fracmux __initdata =
+	MUX(SCLK_UART0, "clk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(33), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart1_fracmux __initdata =
+	MUX(SCLK_UART1, "clk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(34), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart2_fracmux __initdata =
+	MUX(SCLK_UART2, "clk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(35), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart3_fracmux __initdata =
+	MUX(SCLK_UART3, "clk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(36), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata =
+	MUX(SCLK_UART4_PMU, "clk_uart4_pmu", mux_uart4_pmu_p, CLK_SET_RATE_PARENT,
+			RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata =
+	MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(49), 11, 1, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata =
+	MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(50), 11, 1, MFLAGS);
+
+static struct rockchip_clk_branch rk3399_pmuclk_wifi_fracmux __initdata =
+	MUX(SCLK_WIFI_PMU, "clk_wifi_pmu", mux_wifi_pmu_p, CLK_SET_RATE_PARENT,
+			RK3399_PMU_CLKSEL_CON(1), 14, 1, MFLAGS);
+
+static const struct rockchip_cpuclk_reg_data rk3399_cpuclkl_data = {
+	.core_reg[0] = RK3399_CLKSEL_CON(0),
+	.div_core_shift[0] = 0,
+	.div_core_mask[0] = 0x1f,
+	.num_cores = 1,
+	.mux_core_alt = 3,
+	.mux_core_main = 0,
+	.mux_core_shift = 6,
+	.mux_core_mask = 0x3,
+};
+
+static const struct rockchip_cpuclk_reg_data rk3399_cpuclkb_data = {
+	.core_reg[0] = RK3399_CLKSEL_CON(2),
+	.div_core_shift[0] = 0,
+	.div_core_mask[0] = 0x1f,
+	.num_cores = 1,
+	.mux_core_alt = 3,
+	.mux_core_main = 1,
+	.mux_core_shift = 6,
+	.mux_core_mask = 0x3,
+};
+
+#define RK3399_DIV_ACLKM_MASK		0x1f
+#define RK3399_DIV_ACLKM_SHIFT		8
+#define RK3399_DIV_ATCLK_MASK		0x1f
+#define RK3399_DIV_ATCLK_SHIFT		0
+#define RK3399_DIV_PCLK_DBG_MASK	0x1f
+#define RK3399_DIV_PCLK_DBG_SHIFT	8
+
+#define RK3399_CLKSEL0(_offs, _aclkm)					\
+	{								\
+		.reg = RK3399_CLKSEL_CON(0 + _offs),			\
+		.val = HIWORD_UPDATE(_aclkm, RK3399_DIV_ACLKM_MASK,	\
+				RK3399_DIV_ACLKM_SHIFT),		\
+	}
+#define RK3399_CLKSEL1(_offs, _atclk, _pdbg)				\
+	{								\
+		.reg = RK3399_CLKSEL_CON(1 + _offs),			\
+		.val = HIWORD_UPDATE(_atclk, RK3399_DIV_ATCLK_MASK,	\
+				RK3399_DIV_ATCLK_SHIFT) |		\
+		       HIWORD_UPDATE(_pdbg, RK3399_DIV_PCLK_DBG_MASK,	\
+				RK3399_DIV_PCLK_DBG_SHIFT),		\
+	}
+
+/* cluster_l: aclkm in clksel0, rest in clksel1 */
+#define RK3399_CPUCLKL_RATE(_prate, _aclkm, _atclk, _pdbg)		\
+	{								\
+		.prate = _prate##U,					\
+		.divs = {						\
+			RK3399_CLKSEL0(0, _aclkm),			\
+			RK3399_CLKSEL1(0, _atclk, _pdbg),		\
+		},							\
+	}
+
+/* cluster_b: aclkm in clksel2, rest in clksel3 */
+#define RK3399_CPUCLKB_RATE(_prate, _aclkm, _atclk, _pdbg)		\
+	{								\
+		.prate = _prate##U,					\
+		.divs = {						\
+			RK3399_CLKSEL0(2, _aclkm),			\
+			RK3399_CLKSEL1(2, _atclk, _pdbg),		\
+		},							\
+	}
+
+static struct rockchip_cpuclk_rate_table rk3399_cpuclkl_rates[] __initdata = {
+	RK3399_CPUCLKL_RATE(1800000000, 1, 8, 8),
+	RK3399_CPUCLKL_RATE(1704000000, 1, 8, 8),
+	RK3399_CPUCLKL_RATE(1608000000, 1, 7, 7),
+	RK3399_CPUCLKL_RATE(1512000000, 1, 7, 7),
+	RK3399_CPUCLKL_RATE(1488000000, 1, 6, 6),
+	RK3399_CPUCLKL_RATE(1416000000, 1, 6, 6),
+	RK3399_CPUCLKL_RATE(1200000000, 1, 5, 5),
+	RK3399_CPUCLKL_RATE(1008000000, 1, 5, 5),
+	RK3399_CPUCLKL_RATE( 816000000, 1, 4, 4),
+	RK3399_CPUCLKL_RATE( 696000000, 1, 3, 3),
+	RK3399_CPUCLKL_RATE( 600000000, 1, 3, 3),
+	RK3399_CPUCLKL_RATE( 408000000, 1, 2, 2),
+	RK3399_CPUCLKL_RATE( 312000000, 1, 1, 1),
+	RK3399_CPUCLKL_RATE( 216000000, 1, 1, 1),
+	RK3399_CPUCLKL_RATE(  96000000, 1, 1, 1),
+};
+
+static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = {
+	RK3399_CPUCLKB_RATE(2208000000, 1, 11, 11),
+	RK3399_CPUCLKB_RATE(2184000000, 1, 11, 11),
+	RK3399_CPUCLKB_RATE(2088000000, 1, 10, 10),
+	RK3399_CPUCLKB_RATE(2040000000, 1, 10, 10),
+	RK3399_CPUCLKB_RATE(2016000000, 1, 9, 9),
+	RK3399_CPUCLKB_RATE(1992000000, 1, 9, 9),
+	RK3399_CPUCLKB_RATE(1896000000, 1, 9, 9),
+	RK3399_CPUCLKB_RATE(1800000000, 1, 8, 8),
+	RK3399_CPUCLKB_RATE(1704000000, 1, 8, 8),
+	RK3399_CPUCLKB_RATE(1608000000, 1, 7, 7),
+	RK3399_CPUCLKB_RATE(1512000000, 1, 7, 7),
+	RK3399_CPUCLKB_RATE(1488000000, 1, 6, 6),
+	RK3399_CPUCLKB_RATE(1416000000, 1, 6, 6),
+	RK3399_CPUCLKB_RATE(1200000000, 1, 5, 5),
+	RK3399_CPUCLKB_RATE(1008000000, 1, 5, 5),
+	RK3399_CPUCLKB_RATE( 816000000, 1, 4, 4),
+	RK3399_CPUCLKB_RATE( 696000000, 1, 3, 3),
+	RK3399_CPUCLKB_RATE( 600000000, 1, 3, 3),
+	RK3399_CPUCLKB_RATE( 408000000, 1, 2, 2),
+	RK3399_CPUCLKB_RATE( 312000000, 1, 1, 1),
+	RK3399_CPUCLKB_RATE( 216000000, 1, 1, 1),
+	RK3399_CPUCLKB_RATE(  96000000, 1, 1, 1),
+};
+
+static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
+	/*
+	 * CRU Clock-Architecture
+	 */
+
+	/* usbphy */
+	GATE(SCLK_USB2PHY0_REF, "clk_usb2phy0_ref", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 5, GFLAGS),
+	GATE(SCLK_USB2PHY1_REF, "clk_usb2phy1_ref", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 6, GFLAGS),
+
+	GATE(0, "clk_usbphy0_480m_src", "clk_usbphy0_480m", 0,
+			RK3399_CLKGATE_CON(13), 12, GFLAGS),
+	GATE(0, "clk_usbphy1_480m_src", "clk_usbphy1_480m", 0,
+			RK3399_CLKGATE_CON(13), 12, GFLAGS),
+	MUX(0, "clk_usbphy_480m", mux_usbphy_480m_p, 0,
+			RK3399_CLKSEL_CON(14), 6, 1, MFLAGS),
+
+	MUX(0, "upll", mux_pll_src_24m_usbphy480m_p, 0,
+			RK3399_CLKSEL_CON(14), 15, 1, MFLAGS),
+
+	COMPOSITE_NODIV(SCLK_HSICPHY, "clk_hsicphy", mux_pll_src_cpll_gpll_npll_usbphy480m_p, 0,
+			RK3399_CLKSEL_CON(19), 0, 2, MFLAGS,
+			RK3399_CLKGATE_CON(6), 4, GFLAGS),
+
+	COMPOSITE(ACLK_USB3, "aclk_usb3", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 0, GFLAGS),
+	GATE(ACLK_USB3_NOC, "aclk_usb3_noc", "aclk_usb3", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(30), 0, GFLAGS),
+	GATE(ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 1, GFLAGS),
+	GATE(ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 2, GFLAGS),
+	GATE(ACLK_USB3_RKSOC_AXI_PERF, "aclk_usb3_rksoc_axi_perf", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 3, GFLAGS),
+	GATE(ACLK_USB3_GRF, "aclk_usb3_grf", "aclk_usb3", 0,
+			RK3399_CLKGATE_CON(30), 4, GFLAGS),
+
+	GATE(SCLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", 0,
+			RK3399_CLKGATE_CON(12), 1, GFLAGS),
+	GATE(SCLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", 0,
+			RK3399_CLKGATE_CON(12), 2, GFLAGS),
+
+	COMPOSITE(SCLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(40), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(12), 3, GFLAGS),
+
+	COMPOSITE(SCLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(41), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(12), 4, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY0_TCPDPHY_REF, "clk_uphy0_tcpdphy_ref", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(64), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 4, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY0_TCPDCORE, "clk_uphy0_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(64), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 5, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY1_TCPDPHY_REF, "clk_uphy1_tcpdphy_ref", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(65), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 6, GFLAGS),
+
+	COMPOSITE(SCLK_UPHY1_TCPDCORE, "clk_uphy1_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(65), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 7, GFLAGS),
+
+	/* little core */
+	GATE(0, "clk_core_l_lpll_src", "lpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 0, GFLAGS),
+	GATE(0, "clk_core_l_bpll_src", "bpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 1, GFLAGS),
+	GATE(0, "clk_core_l_dpll_src", "dpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 2, GFLAGS),
+	GATE(0, "clk_core_l_gpll_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(0), 3, GFLAGS),
+
+	COMPOSITE_NOMUX(0, "aclkm_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(0), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(0), 4, GFLAGS),
+	COMPOSITE_NOMUX(0, "atclk_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(0), 5, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_COREDBG_L, "pclk_dbg_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(1), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(0), 6, GFLAGS),
+
+	GATE(ACLK_CORE_ADB400_CORE_L_2_CCI500, "aclk_core_adb400_core_l_2_cci500", "aclkm_core_l", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 12, GFLAGS),
+	GATE(ACLK_PERF_CORE_L, "aclk_perf_core_l", "aclkm_core_l", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 13, GFLAGS),
+
+	GATE(0, "clk_dbg_pd_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 9, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_core_adb400_gic_2_core_l", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 10, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_core_adb400_core_l_2_gic", "armclkl", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 11, GFLAGS),
+	GATE(SCLK_PVTM_CORE_L, "clk_pvtm_core_l", "xin24m", 0,
+			RK3399_CLKGATE_CON(0), 7, GFLAGS),
+
+	/* big core */
+	GATE(0, "clk_core_b_lpll_src", "lpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 0, GFLAGS),
+	GATE(0, "clk_core_b_bpll_src", "bpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 1, GFLAGS),
+	GATE(0, "clk_core_b_dpll_src", "dpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 2, GFLAGS),
+	GATE(0, "clk_core_b_gpll_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(1), 3, GFLAGS),
+
+	COMPOSITE_NOMUX(0, "aclkm_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(2), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(1), 4, GFLAGS),
+	COMPOSITE_NOMUX(0, "atclk_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(3), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(1), 5, GFLAGS),
+	COMPOSITE_NOMUX(0, "pclk_dbg_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(3), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK3399_CLKGATE_CON(1), 6, GFLAGS),
+
+	GATE(ACLK_CORE_ADB400_CORE_B_2_CCI500, "aclk_core_adb400_core_b_2_cci500", "aclkm_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 5, GFLAGS),
+	GATE(ACLK_PERF_CORE_B, "aclk_perf_core_b", "aclkm_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 6, GFLAGS),
+
+	GATE(0, "clk_dbg_pd_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 1, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_core_adb400_gic_2_core_b", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 3, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_core_adb400_core_b_2_gic", "armclkb", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 4, GFLAGS),
+
+	DIV(PCLK_COREDBG_B, "pclken_dbg_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(3), 13, 2, DFLAGS | CLK_DIVIDER_READ_ONLY),
+
+	GATE(0, "pclk_dbg_cxcs_pd_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(14), 2, GFLAGS),
+
+	GATE(SCLK_PVTM_CORE_B, "clk_pvtm_core_b", "xin24m", 0,
+			RK3399_CLKGATE_CON(1), 7, GFLAGS),
+
+	/* gmac */
+	GATE(0, "cpll_aclk_gmac_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 9, GFLAGS),
+	GATE(0, "gpll_aclk_gmac_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 8, GFLAGS),
+	COMPOSITE(0, "aclk_gmac_pre", mux_aclk_gmac_p, 0,
+			RK3399_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(6), 10, GFLAGS),
+
+	GATE(ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", 0,
+			RK3399_CLKGATE_CON(32), 0, GFLAGS),
+	GATE(ACLK_GMAC_NOC, "aclk_gmac_noc", "aclk_gmac_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 1, GFLAGS),
+	GATE(ACLK_PERF_GMAC, "aclk_perf_gmac", "aclk_gmac_pre", 0,
+			RK3399_CLKGATE_CON(32), 4, GFLAGS),
+
+	COMPOSITE_NOMUX(0, "pclk_gmac_pre", "aclk_gmac_pre", 0,
+			RK3399_CLKSEL_CON(19), 8, 3, DFLAGS,
+			RK3399_CLKGATE_CON(6), 11, GFLAGS),
+	GATE(PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", 0,
+			RK3399_CLKGATE_CON(32), 2, GFLAGS),
+	GATE(PCLK_GMAC_NOC, "pclk_gmac_noc", "pclk_gmac_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 3, GFLAGS),
+
+	COMPOSITE(SCLK_MAC, "clk_gmac", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(5), 5, GFLAGS),
+
+	MUX(SCLK_RMII_SRC, "clk_rmii_src", mux_rmii_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(19), 4, 1, MFLAGS),
+	GATE(SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 6, GFLAGS),
+	GATE(SCLK_MACREF, "clk_mac_ref", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 7, GFLAGS),
+	GATE(SCLK_MAC_RX, "clk_rmii_rx", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 8, GFLAGS),
+	GATE(SCLK_MAC_TX, "clk_rmii_tx", "clk_rmii_src", 0,
+			RK3399_CLKGATE_CON(5), 9, GFLAGS),
+
+	/* spdif */
+	COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 13, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", 0,
+			RK3399_CLKSEL_CON(99), 0,
+			RK3399_CLKGATE_CON(8), 14, GFLAGS,
+			&rk3399_spdif_fracmux),
+	GATE(SCLK_SPDIF_8CH, "clk_spdif", "clk_spdif_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 15, GFLAGS),
+
+	COMPOSITE(SCLK_SPDIF_REC_DPTX, "clk_spdif_rec_dptx", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(32), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 6, GFLAGS),
+	/* i2s */
+	COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(28), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 3, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", 0,
+			RK3399_CLKSEL_CON(96), 0,
+			RK3399_CLKGATE_CON(8), 4, GFLAGS,
+			&rk3399_i2s0_fracmux),
+	GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 5, GFLAGS),
+
+	COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(29), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 6, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", 0,
+			RK3399_CLKSEL_CON(97), 0,
+			RK3399_CLKGATE_CON(8), 7, GFLAGS,
+			&rk3399_i2s1_fracmux),
+	GATE(SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 8, GFLAGS),
+
+	COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(30), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(8), 9, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", 0,
+			RK3399_CLKSEL_CON(98), 0,
+			RK3399_CLKGATE_CON(8), 10, GFLAGS,
+			&rk3399_i2s2_fracmux),
+	GATE(SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT,
+			RK3399_CLKGATE_CON(8), 11, GFLAGS),
+
+	MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(31), 0, 2, MFLAGS),
+	COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(31), 2, 1, MFLAGS,
+			RK3399_CLKGATE_CON(8), 12, GFLAGS),
+
+	/* uart */
+	MUX(0, "clk_uart0_src", mux_pll_src_cpll_gpll_upll_p, 0,
+			RK3399_CLKSEL_CON(33), 12, 2, MFLAGS),
+	COMPOSITE_NOMUX(0, "clk_uart0_div", "clk_uart0_src", 0,
+			RK3399_CLKSEL_CON(33), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 0, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", 0,
+			RK3399_CLKSEL_CON(100), 0,
+			RK3399_CLKGATE_CON(9), 1, GFLAGS,
+			&rk3399_uart0_fracmux),
+
+	MUX(0, "clk_uart_src", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(33), 15, 1, MFLAGS),
+	COMPOSITE_NOMUX(0, "clk_uart1_div", "clk_uart_src", 0,
+			RK3399_CLKSEL_CON(34), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 2, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", 0,
+			RK3399_CLKSEL_CON(101), 0,
+			RK3399_CLKGATE_CON(9), 3, GFLAGS,
+			&rk3399_uart1_fracmux),
+
+	COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0,
+			RK3399_CLKSEL_CON(35), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 4, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", 0,
+			RK3399_CLKSEL_CON(102), 0,
+			RK3399_CLKGATE_CON(9), 5, GFLAGS,
+			&rk3399_uart2_fracmux),
+
+	COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0,
+			RK3399_CLKSEL_CON(36), 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 6, GFLAGS),
+	COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", 0,
+			RK3399_CLKSEL_CON(103), 0,
+			RK3399_CLKGATE_CON(9), 7, GFLAGS,
+			&rk3399_uart3_fracmux),
+
+	COMPOSITE(PCLK_DDR, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(3), 4, GFLAGS),
+
+	GATE(PCLK_CENTER_MAIN_NOC, "pclk_center_main_noc", "pclk_ddr", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(18), 10, GFLAGS),
+	GATE(PCLK_DDR_MON, "pclk_ddr_mon", "pclk_ddr", 0,
+			RK3399_CLKGATE_CON(18), 12, GFLAGS),
+	GATE(PCLK_CIC, "pclk_cic", "pclk_ddr", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(18), 15, GFLAGS),
+	GATE(PCLK_DDR_SGRF, "pclk_ddr_sgrf", "pclk_ddr", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(19), 2, GFLAGS),
+
+	GATE(SCLK_PVTM_DDR, "clk_pvtm_ddr", "xin24m", 0,
+			RK3399_CLKGATE_CON(4), 11, GFLAGS),
+	GATE(SCLK_DFIMON0_TIMER, "clk_dfimon0_timer", "xin24m", 0,
+			RK3399_CLKGATE_CON(3), 5, GFLAGS),
+	GATE(SCLK_DFIMON1_TIMER, "clk_dfimon1_timer", "xin24m", 0,
+			RK3399_CLKGATE_CON(3), 6, GFLAGS),
+
+	/* cci */
+	GATE(0, "cpll_aclk_cci_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 0, GFLAGS),
+	GATE(0, "gpll_aclk_cci_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 1, GFLAGS),
+	GATE(0, "npll_aclk_cci_src", "npll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 2, GFLAGS),
+	GATE(0, "vpll_aclk_cci_src", "vpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 3, GFLAGS),
+
+	COMPOSITE(0, "aclk_cci_pre", mux_aclk_cci_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(2), 4, GFLAGS),
+
+	GATE(ACLK_ADB400M_PD_CORE_L, "aclk_adb400m_pd_core_l", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 0, GFLAGS),
+	GATE(ACLK_ADB400M_PD_CORE_B, "aclk_adb400m_pd_core_b", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 1, GFLAGS),
+	GATE(ACLK_CCI, "aclk_cci", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 2, GFLAGS),
+	GATE(ACLK_CCI_NOC0, "aclk_cci_noc0", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 3, GFLAGS),
+	GATE(ACLK_CCI_NOC1, "aclk_cci_noc1", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 4, GFLAGS),
+	GATE(ACLK_CCI_GRF, "aclk_cci_grf", "aclk_cci_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 7, GFLAGS),
+
+	GATE(0, "cpll_cci_trace", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 5, GFLAGS),
+	GATE(0, "gpll_cci_trace", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 6, GFLAGS),
+	COMPOSITE(SCLK_CCI_TRACE, "clk_cci_trace", mux_cci_trace_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(5), 15, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(2), 7, GFLAGS),
+
+	GATE(0, "cpll_cs", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 8, GFLAGS),
+	GATE(0, "gpll_cs", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 9, GFLAGS),
+	GATE(0, "npll_cs", "npll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(2), 10, GFLAGS),
+	COMPOSITE_NOGATE(0, "clk_cs", mux_cs_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS),
+	GATE(0, "clk_dbg_cxcs", "clk_cs", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 5, GFLAGS),
+	GATE(0, "clk_dbg_noc", "clk_cs", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(15), 6, GFLAGS),
+
+	/* vcodec */
+	COMPOSITE(0, "aclk_vcodec_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(7), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 0, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vcodec_pre", "aclk_vcodec_pre", 0,
+			RK3399_CLKSEL_CON(7), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 1, GFLAGS),
+	GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0,
+			RK3399_CLKGATE_CON(17), 2, GFLAGS),
+	GATE(0, "hclk_vcodec_noc", "hclk_vcodec_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 3, GFLAGS),
+
+	GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0,
+			RK3399_CLKGATE_CON(17), 0, GFLAGS),
+	GATE(0, "aclk_vcodec_noc", "aclk_vcodec_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 1, GFLAGS),
+
+	/* vdu */
+	COMPOSITE(SCLK_VDU_CORE, "clk_vdu_core", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(9), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 4, GFLAGS),
+	COMPOSITE(SCLK_VDU_CA, "clk_vdu_ca", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(9), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 5, GFLAGS),
+
+	COMPOSITE(0, "aclk_vdu_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(8), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 2, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vdu_pre", "aclk_vdu_pre", 0,
+			RK3399_CLKSEL_CON(8), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 3, GFLAGS),
+	GATE(HCLK_VDU, "hclk_vdu", "hclk_vdu_pre", 0,
+			RK3399_CLKGATE_CON(17), 10, GFLAGS),
+	GATE(HCLK_VDU_NOC, "hclk_vdu_noc", "hclk_vdu_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 11, GFLAGS),
+
+	GATE(ACLK_VDU, "aclk_vdu", "aclk_vdu_pre", 0,
+			RK3399_CLKGATE_CON(17), 8, GFLAGS),
+	GATE(ACLK_VDU_NOC, "aclk_vdu_noc", "aclk_vdu_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(17), 9, GFLAGS),
+
+	/* iep */
+	COMPOSITE(0, "aclk_iep_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(10), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 6, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_iep_pre", "aclk_iep_pre", 0,
+			RK3399_CLKSEL_CON(10), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 7, GFLAGS),
+	GATE(HCLK_IEP, "hclk_iep", "hclk_iep_pre", 0,
+			RK3399_CLKGATE_CON(16), 2, GFLAGS),
+	GATE(HCLK_IEP_NOC, "hclk_iep_noc", "hclk_iep_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 3, GFLAGS),
+
+	GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0,
+			RK3399_CLKGATE_CON(16), 0, GFLAGS),
+	GATE(ACLK_IEP_NOC, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 1, GFLAGS),
+
+	/* rga */
+	COMPOSITE(SCLK_RGA_CORE, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 10, GFLAGS),
+
+	COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0,
+			RK3399_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 8, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_rga_pre", "aclk_rga_pre", 0,
+			RK3399_CLKSEL_CON(11), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(4), 9, GFLAGS),
+	GATE(HCLK_RGA, "hclk_rga", "hclk_rga_pre", 0,
+			RK3399_CLKGATE_CON(16), 10, GFLAGS),
+	GATE(HCLK_RGA_NOC, "hclk_rga_noc", "hclk_rga_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 11, GFLAGS),
+
+	GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0,
+			RK3399_CLKGATE_CON(16), 8, GFLAGS),
+	GATE(ACLK_RGA_NOC, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(16), 9, GFLAGS),
+
+	/* center */
+	COMPOSITE(0, "aclk_center", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(3), 7, GFLAGS),
+	GATE(ACLK_CENTER_MAIN_NOC, "aclk_center_main_noc", "aclk_center", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(19), 0, GFLAGS),
+	GATE(ACLK_CENTER_PERI_NOC, "aclk_center_peri_noc", "aclk_center", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(19), 1, GFLAGS),
+
+	/* gpu */
+	COMPOSITE(0, "aclk_gpu_pre", mux_pll_src_ppll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(13), 5, 3, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 0, GFLAGS),
+	GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0,
+			RK3399_CLKGATE_CON(30), 8, GFLAGS),
+	GATE(ACLK_PERF_GPU, "aclk_perf_gpu", "aclk_gpu_pre", 0,
+			RK3399_CLKGATE_CON(30), 10, GFLAGS),
+	GATE(ACLK_GPU_GRF, "aclk_gpu_grf", "aclk_gpu_pre", 0,
+			RK3399_CLKGATE_CON(30), 11, GFLAGS),
+	GATE(SCLK_PVTM_GPU, "aclk_pvtm_gpu", "xin24m", 0,
+			RK3399_CLKGATE_CON(13), 1, GFLAGS),
+
+	/* perihp */
+	GATE(0, "cpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(5), 1, GFLAGS),
+	GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(5), 0, GFLAGS),
+	COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(5), 2, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_PERIHP, "hclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(14), 8, 2, DFLAGS,
+			RK3399_CLKGATE_CON(5), 3, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERIHP, "pclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(14), 12, 2, DFLAGS,
+			RK3399_CLKGATE_CON(5), 4, GFLAGS),
+
+	GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 2, GFLAGS),
+	GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 10, GFLAGS),
+	GATE(0, "aclk_perihp_noc", "aclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 12, GFLAGS),
+
+	GATE(HCLK_HOST0, "hclk_host0", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 5, GFLAGS),
+	GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 6, GFLAGS),
+	GATE(HCLK_HOST1, "hclk_host1", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 7, GFLAGS),
+	GATE(HCLK_HOST1_ARB, "hclk_host1_arb", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 8, GFLAGS),
+	GATE(HCLK_HSIC, "hclk_hsic", "hclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 9, GFLAGS),
+	GATE(0, "hclk_perihp_noc", "hclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 13, GFLAGS),
+	GATE(0, "hclk_ahb1tom", "hclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 15, GFLAGS),
+
+	GATE(PCLK_PERIHP_GRF, "pclk_perihp_grf", "pclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 4, GFLAGS),
+	GATE(PCLK_PCIE, "pclk_pcie", "pclk_perihp", 0,
+			RK3399_CLKGATE_CON(20), 11, GFLAGS),
+	GATE(0, "pclk_perihp_noc", "pclk_perihp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(20), 14, GFLAGS),
+	GATE(PCLK_HSICPHY, "pclk_hsicphy", "pclk_perihp", 0,
+			RK3399_CLKGATE_CON(31), 8, GFLAGS),
+
+	/* sdio & sdmmc */
+	COMPOSITE(HCLK_SD, "hclk_sd", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(13), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 13, GFLAGS),
+	GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0,
+			RK3399_CLKGATE_CON(33), 8, GFLAGS),
+	GATE(0, "hclk_sdmmc_noc", "hclk_sd", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(33), 9, GFLAGS),
+
+	COMPOSITE(SCLK_SDIO, "clk_sdio", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0,
+			RK3399_CLKSEL_CON(15), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 0, GFLAGS),
+
+	COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0,
+			RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 1, GFLAGS),
+
+	MMC(SCLK_SDMMC_DRV,     "sdmmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
+	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
+
+	MMC(SCLK_SDIO_DRV,      "sdio_drv",    "clk_sdio",  RK3399_SDIO_CON0,  1),
+	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  1),
+
+	/* pcie */
+	COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, 0,
+			RK3399_CLKSEL_CON(17), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 2, GFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_PCIEPHY_REF100M, "clk_pciephy_ref100m", "npll", 0,
+			RK3399_CLKSEL_CON(18), 11, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 6, GFLAGS),
+	MUX(SCLK_PCIEPHY_REF, "clk_pciephy_ref", mux_pll_src_24m_pciephy_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(18), 10, 1, MFLAGS),
+
+	COMPOSITE(0, "clk_pcie_core_cru", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(18), 8, 2, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 3, GFLAGS),
+	MUX(SCLK_PCIE_CORE, "clk_pcie_core", mux_pciecore_cru_phy_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(18), 7, 1, MFLAGS),
+
+	/* emmc */
+	COMPOSITE(SCLK_EMMC, "clk_emmc", mux_pll_src_cpll_gpll_npll_upll_24m_p, 0,
+			RK3399_CLKSEL_CON(22), 8, 3, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(6), 14, GFLAGS),
+
+	GATE(0, "cpll_aclk_emmc_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 13, GFLAGS),
+	GATE(0, "gpll_aclk_emmc_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(6), 12, GFLAGS),
+	COMPOSITE_NOGATE(ACLK_EMMC, "aclk_emmc", mux_aclk_emmc_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(21), 7, 1, MFLAGS, 0, 5, DFLAGS),
+	GATE(ACLK_EMMC_CORE, "aclk_emmccore", "aclk_emmc", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 8, GFLAGS),
+	GATE(ACLK_EMMC_NOC, "aclk_emmc_noc", "aclk_emmc", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 9, GFLAGS),
+	GATE(ACLK_EMMC_GRF, "aclk_emmcgrf", "aclk_emmc", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 10, GFLAGS),
+
+	/* perilp0 */
+	GATE(0, "cpll_aclk_perilp0_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(7), 1, GFLAGS),
+	GATE(0, "gpll_aclk_perilp0_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(7), 0, GFLAGS),
+	COMPOSITE(ACLK_PERILP0, "aclk_perilp0", mux_aclk_perilp0_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(23), 7, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 2, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_PERILP0, "hclk_perilp0", "aclk_perilp0", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(23), 8, 2, DFLAGS,
+			RK3399_CLKGATE_CON(7), 3, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERILP0, "pclk_perilp0", "aclk_perilp0", 0,
+			RK3399_CLKSEL_CON(23), 12, 3, DFLAGS,
+			RK3399_CLKGATE_CON(7), 4, GFLAGS),
+
+	/* aclk_perilp0 gates */
+	GATE(ACLK_INTMEM, "aclk_intmem", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 0, GFLAGS),
+	GATE(ACLK_TZMA, "aclk_tzma", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 1, GFLAGS),
+	GATE(SCLK_INTMEM0, "clk_intmem0", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 2, GFLAGS),
+	GATE(SCLK_INTMEM1, "clk_intmem1", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 3, GFLAGS),
+	GATE(SCLK_INTMEM2, "clk_intmem2", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 4, GFLAGS),
+	GATE(SCLK_INTMEM3, "clk_intmem3", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 5, GFLAGS),
+	GATE(SCLK_INTMEM4, "clk_intmem4", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 6, GFLAGS),
+	GATE(SCLK_INTMEM5, "clk_intmem5", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 7, GFLAGS),
+	GATE(ACLK_DCF, "aclk_dcf", "aclk_perilp0", 0, RK3399_CLKGATE_CON(23), 8, GFLAGS),
+	GATE(ACLK_DMAC0_PERILP, "aclk_dmac0_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 5, GFLAGS),
+	GATE(ACLK_DMAC1_PERILP, "aclk_dmac1_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 6, GFLAGS),
+	GATE(ACLK_PERILP0_NOC, "aclk_perilp0_noc", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 7, GFLAGS),
+
+	/* hclk_perilp0 gates */
+	GATE(HCLK_ROM, "hclk_rom", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 4, GFLAGS),
+	GATE(HCLK_M_CRYPTO0, "hclk_m_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 5, GFLAGS),
+	GATE(HCLK_S_CRYPTO0, "hclk_s_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 6, GFLAGS),
+	GATE(HCLK_M_CRYPTO1, "hclk_m_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 14, GFLAGS),
+	GATE(HCLK_S_CRYPTO1, "hclk_s_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 15, GFLAGS),
+	GATE(HCLK_PERILP0_NOC, "hclk_perilp0_noc", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 8, GFLAGS),
+
+	/* pclk_perilp0 gates */
+	GATE(PCLK_DCF, "pclk_dcf", "pclk_perilp0", 0, RK3399_CLKGATE_CON(23), 9, GFLAGS),
+
+	/* crypto */
+	COMPOSITE(SCLK_CRYPTO0, "clk_crypto0", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(24), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 7, GFLAGS),
+
+	COMPOSITE(SCLK_CRYPTO1, "clk_crypto1", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(26), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 8, GFLAGS),
+
+	/* cm0s_perilp */
+	GATE(0, "cpll_fclk_cm0s_src", "cpll", 0,
+			RK3399_CLKGATE_CON(7), 6, GFLAGS),
+	GATE(0, "gpll_fclk_cm0s_src", "gpll", 0,
+			RK3399_CLKGATE_CON(7), 5, GFLAGS),
+	COMPOSITE(FCLK_CM0S, "fclk_cm0s", mux_fclk_cm0s_p, 0,
+			RK3399_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(7), 9, GFLAGS),
+
+	/* fclk_cm0s gates */
+	GATE(SCLK_M0_PERILP, "sclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 8, GFLAGS),
+	GATE(HCLK_M0_PERILP, "hclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 9, GFLAGS),
+	GATE(DCLK_M0_PERILP, "dclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 10, GFLAGS),
+	GATE(SCLK_M0_PERILP_DEC, "clk_m0_perilp_dec", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 11, GFLAGS),
+	GATE(HCLK_M0_PERILP_NOC, "hclk_m0_perilp_noc", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 11, GFLAGS),
+
+	/* perilp1 */
+	GATE(0, "cpll_hclk_perilp1_src", "cpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(8), 1, GFLAGS),
+	GATE(0, "gpll_hclk_perilp1_src", "gpll", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(8), 0, GFLAGS),
+	COMPOSITE_NOGATE(HCLK_PERILP1, "hclk_perilp1", mux_hclk_perilp1_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(25), 7, 1, MFLAGS, 0, 5, DFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERILP1, "pclk_perilp1", "hclk_perilp1", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(25), 8, 3, DFLAGS,
+			RK3399_CLKGATE_CON(8), 2, GFLAGS),
+
+	/* hclk_perilp1 gates */
+	GATE(0, "hclk_perilp1_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 9, GFLAGS),
+	GATE(0, "hclk_sdio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 12, GFLAGS),
+	GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 0, GFLAGS),
+	GATE(HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 1, GFLAGS),
+	GATE(HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 2, GFLAGS),
+	GATE(HCLK_SPDIF, "hclk_spdif", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 3, GFLAGS),
+	GATE(HCLK_SDIO, "hclk_sdio", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 4, GFLAGS),
+	GATE(PCLK_SPI5, "pclk_spi5", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 5, GFLAGS),
+	GATE(0, "hclk_sdioaudio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 6, GFLAGS),
+
+	/* pclk_perilp1 gates */
+	GATE(PCLK_UART0, "pclk_uart0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 0, GFLAGS),
+	GATE(PCLK_UART1, "pclk_uart1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 1, GFLAGS),
+	GATE(PCLK_UART2, "pclk_uart2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 2, GFLAGS),
+	GATE(PCLK_UART3, "pclk_uart3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 3, GFLAGS),
+	GATE(PCLK_I2C7, "pclk_rki2c7", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 5, GFLAGS),
+	GATE(PCLK_I2C1, "pclk_rki2c1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 6, GFLAGS),
+	GATE(PCLK_I2C5, "pclk_rki2c5", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 7, GFLAGS),
+	GATE(PCLK_I2C6, "pclk_rki2c6", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 8, GFLAGS),
+	GATE(PCLK_I2C2, "pclk_rki2c2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 9, GFLAGS),
+	GATE(PCLK_I2C3, "pclk_rki2c3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 10, GFLAGS),
+	GATE(PCLK_MAILBOX0, "pclk_mailbox0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 11, GFLAGS),
+	GATE(PCLK_SARADC, "pclk_saradc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 12, GFLAGS),
+	GATE(PCLK_TSADC, "pclk_tsadc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 13, GFLAGS),
+	GATE(PCLK_EFUSE1024NS, "pclk_efuse1024ns", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 14, GFLAGS),
+	GATE(PCLK_EFUSE1024S, "pclk_efuse1024s", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 15, GFLAGS),
+	GATE(PCLK_SPI0, "pclk_spi0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 10, GFLAGS),
+	GATE(PCLK_SPI1, "pclk_spi1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 11, GFLAGS),
+	GATE(PCLK_SPI2, "pclk_spi2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 12, GFLAGS),
+	GATE(PCLK_SPI4, "pclk_spi4", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 13, GFLAGS),
+	GATE(PCLK_PERIHP_GRF, "pclk_perilp_sgrf", "pclk_perilp1", 0, RK3399_CLKGATE_CON(24), 13, GFLAGS),
+	GATE(0, "pclk_perilp1_noc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(25), 10, GFLAGS),
+
+	/* saradc */
+	COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "xin24m", 0,
+			RK3399_CLKSEL_CON(26), 8, 8, DFLAGS,
+			RK3399_CLKGATE_CON(9), 11, GFLAGS),
+
+	/* tsadc */
+	COMPOSITE(SCLK_TSADC, "clk_tsadc", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(27), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(9), 10, GFLAGS),
+
+	/* cif_testout */
+	MUX(0, "clk_testout1_pll_src", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(38), 6, 2, MFLAGS),
+	COMPOSITE(SCLK_TESTCLKOUT1, "clk_testout1", mux_clk_testout1_p, 0,
+			RK3399_CLKSEL_CON(38), 5, 1, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 14, GFLAGS),
+
+	MUX(0, "clk_testout2_pll_src", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(38), 14, 2, MFLAGS),
+	COMPOSITE(SCLK_TESTCLKOUT2, "clk_testout2", mux_clk_testout2_p, 0,
+			RK3399_CLKSEL_CON(38), 13, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 15, GFLAGS),
+
+	/* vio */
+	COMPOSITE(ACLK_VIO, "aclk_vio", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 0, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_VIO, "pclk_vio", "aclk_vio", 0,
+			RK3399_CLKSEL_CON(43), 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 1, GFLAGS),
+
+	GATE(ACLK_VIO_NOC, "aclk_vio_noc", "aclk_vio", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 0, GFLAGS),
+
+	GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "pclk_vio", 0,
+			RK3399_CLKGATE_CON(29), 1, GFLAGS),
+	GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "pclk_vio", 0,
+			RK3399_CLKGATE_CON(29), 2, GFLAGS),
+	GATE(PCLK_VIO_GRF, "pclk_vio_grf", "pclk_vio", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 12, GFLAGS),
+
+	/* hdcp */
+	COMPOSITE(ACLK_HDCP, "aclk_hdcp", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 12, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_HDCP, "hclk_hdcp", "aclk_hdcp", 0,
+			RK3399_CLKSEL_CON(43), 5, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 3, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_HDCP, "pclk_hdcp", "aclk_hdcp", 0,
+			RK3399_CLKSEL_CON(43), 10, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 10, GFLAGS),
+
+	GATE(ACLK_HDCP_NOC, "aclk_hdcp_noc", "aclk_hdcp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 4, GFLAGS),
+	GATE(ACLK_HDCP22, "aclk_hdcp22", "aclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 10, GFLAGS),
+
+	GATE(HCLK_HDCP_NOC, "hclk_hdcp_noc", "hclk_hdcp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 5, GFLAGS),
+	GATE(HCLK_HDCP22, "hclk_hdcp22", "hclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 9, GFLAGS),
+
+	GATE(PCLK_HDCP_NOC, "pclk_hdcp_noc", "pclk_hdcp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(29), 3, GFLAGS),
+	GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 6, GFLAGS),
+	GATE(PCLK_DP_CTRL, "pclk_dp_ctrl", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 7, GFLAGS),
+	GATE(PCLK_HDCP22, "pclk_hdcp22", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 8, GFLAGS),
+	GATE(PCLK_GASKET, "pclk_gasket", "pclk_hdcp", 0,
+			RK3399_CLKGATE_CON(29), 11, GFLAGS),
+
+	/* edp */
+	COMPOSITE(SCLK_DP_CORE, "clk_dp_core", mux_pll_src_npll_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 8, GFLAGS),
+
+	COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 6, DFLAGS,
+			RK3399_CLKGATE_CON(11), 11, GFLAGS),
+	GATE(PCLK_EDP_NOC, "pclk_edp_noc", "pclk_edp", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(32), 12, GFLAGS),
+	GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "pclk_edp", 0,
+			RK3399_CLKGATE_CON(32), 13, GFLAGS),
+
+	/* hdmi */
+	GATE(SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", 0,
+			RK3399_CLKGATE_CON(11), 6, GFLAGS),
+
+	COMPOSITE(SCLK_HDMI_CEC, "clk_hdmi_cec", mux_pll_p, 0,
+			RK3399_CLKSEL_CON(45), 15, 1, MFLAGS, 0, 10, DFLAGS,
+			RK3399_CLKGATE_CON(11), 7, GFLAGS),
+
+	/* vop0 */
+	COMPOSITE(ACLK_VOP0_PRE, "aclk_vop0_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(47), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 8, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vop0_pre", "aclk_vop0_pre", 0,
+			RK3399_CLKSEL_CON(47), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 9, GFLAGS),
+
+	GATE(ACLK_VOP0, "aclk_vop0", "aclk_vop0_pre", 0,
+			RK3399_CLKGATE_CON(28), 3, GFLAGS),
+	GATE(ACLK_VOP0_NOC, "aclk_vop0_noc", "aclk_vop0_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 1, GFLAGS),
+
+	GATE(HCLK_VOP0, "hclk_vop0", "hclk_vop0_pre", 0,
+			RK3399_CLKGATE_CON(28), 2, GFLAGS),
+	GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 0, GFLAGS),
+
+	COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS,
+			RK3399_CLKGATE_CON(10), 12, GFLAGS),
+
+	COMPOSITE_FRACMUX_NOGATE(DCLK_VOP0_FRAC, "dclk_vop0_frac", "dclk_vop0_div", 0,
+			RK3399_CLKSEL_CON(106), 0,
+			&rk3399_dclk_vop0_fracmux),
+
+	COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, 0,
+			RK3399_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 14, GFLAGS),
+
+	/* vop1 */
+	COMPOSITE(ACLK_VOP1_PRE, "aclk_vop1_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 10, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_vop1_pre", "aclk_vop1_pre", 0,
+			RK3399_CLKSEL_CON(48), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 11, GFLAGS),
+
+	GATE(ACLK_VOP1, "aclk_vop1", "aclk_vop1_pre", 0,
+			RK3399_CLKGATE_CON(28), 7, GFLAGS),
+	GATE(ACLK_VOP1_NOC, "aclk_vop1_noc", "aclk_vop1_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 5, GFLAGS),
+
+	GATE(HCLK_VOP1, "hclk_vop1", "hclk_vop1_pre", 0,
+			RK3399_CLKGATE_CON(28), 6, GFLAGS),
+	GATE(HCLK_VOP1_NOC, "hclk_vop1_noc", "hclk_vop1_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(28), 4, GFLAGS),
+
+	COMPOSITE(DCLK_VOP1_DIV, "dclk_vop1_div", mux_pll_src_vpll_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS,
+			RK3399_CLKGATE_CON(10), 13, GFLAGS),
+
+	COMPOSITE_FRACMUX_NOGATE(DCLK_VOP1_FRAC, "dclk_vop1_frac", "dclk_vop1_div", 0,
+			RK3399_CLKSEL_CON(107), 0,
+			&rk3399_dclk_vop1_fracmux),
+
+	COMPOSITE(SCLK_VOP1_PWM, "clk_vop1_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(10), 15, GFLAGS),
+
+	/* isp */
+	COMPOSITE(ACLK_ISP0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(53), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 8, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_ISP0, "hclk_isp0", "aclk_isp0", 0,
+			RK3399_CLKSEL_CON(53), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 9, GFLAGS),
+
+	GATE(ACLK_ISP0_NOC, "aclk_isp0_noc", "aclk_isp0", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 1, GFLAGS),
+	GATE(ACLK_ISP0_WRAPPER, "aclk_isp0_wrapper", "aclk_isp0", 0,
+			RK3399_CLKGATE_CON(27), 5, GFLAGS),
+	GATE(HCLK_ISP1_WRAPPER, "hclk_isp1_wrapper", "aclk_isp0", 0,
+			RK3399_CLKGATE_CON(27), 7, GFLAGS),
+
+	GATE(HCLK_ISP0_NOC, "hclk_isp0_noc", "hclk_isp0", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 0, GFLAGS),
+	GATE(HCLK_ISP0_WRAPPER, "hclk_isp0_wrapper", "hclk_isp0", 0,
+			RK3399_CLKGATE_CON(27), 4, GFLAGS),
+
+	COMPOSITE(SCLK_ISP0, "clk_isp0", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 4, GFLAGS),
+
+	COMPOSITE(ACLK_ISP1, "aclk_isp1", mux_pll_src_cpll_gpll_ppll_p, 0,
+			RK3399_CLKSEL_CON(54), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 10, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_ISP1, "hclk_isp1", "aclk_isp1", 0,
+			RK3399_CLKSEL_CON(54), 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 11, GFLAGS),
+
+	GATE(ACLK_ISP1_NOC, "aclk_isp1_noc", "aclk_isp1", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 3, GFLAGS),
+
+	GATE(HCLK_ISP1_NOC, "hclk_isp1_noc", "hclk_isp1", CLK_IGNORE_UNUSED,
+			RK3399_CLKGATE_CON(27), 2, GFLAGS),
+	GATE(ACLK_ISP1_WRAPPER, "aclk_isp1_wrapper", "hclk_isp1", 0,
+			RK3399_CLKGATE_CON(27), 8, GFLAGS),
+
+	COMPOSITE(SCLK_ISP1, "clk_isp1", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(55), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(11), 5, GFLAGS),
+
+	/*
+	 * We use pclkin_cifinv by default GRF_SOC_CON20[9] (GSC20_9) setting in system,
+	 * so we ignore the mux and make clocks nodes as following,
+	 *
+	 * pclkin_cifinv --|-------\
+	 *                 |GSC20_9|-- pclkin_cifmux -- |G27_6| -- pclkin_isp1_wrapper
+	 * pclkin_cif    --|-------/
+	 */
+	GATE(PCLK_ISP1_WRAPPER, "pclkin_isp1_wrapper", "pclkin_cif", 0,
+			RK3399_CLKGATE_CON(27), 6, GFLAGS),
+
+	/* cif */
+	COMPOSITE_NODIV(0, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0,
+			RK3399_CLKSEL_CON(56), 6, 2, MFLAGS,
+			RK3399_CLKGATE_CON(10), 7, GFLAGS),
+
+	COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, 0,
+			 RK3399_CLKSEL_CON(56), 5, 1, MFLAGS, 0, 5, DFLAGS),
+
+	/* gic */
+	COMPOSITE(ACLK_GIC_PRE, "aclk_gic_pre", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(56), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_CLKGATE_CON(12), 12, GFLAGS),
+
+	GATE(ACLK_GIC, "aclk_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 0, GFLAGS),
+	GATE(ACLK_GIC_NOC, "aclk_gic_noc", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 1, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_gic_adb400_core_l_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 2, GFLAGS),
+	GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_gic_adb400_core_b_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 3, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_gic_adb400_gic_2_core_l", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 4, GFLAGS),
+	GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_gic_adb400_gic_2_core_b", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 5, GFLAGS),
+
+	/* alive */
+	/* pclk_alive_gpll_src is controlled by PMUGRF_SOC_CON0[6] */
+	DIV(PCLK_ALIVE, "pclk_alive", "gpll", 0,
+			RK3399_CLKSEL_CON(57), 0, 5, DFLAGS),
+
+	GATE(PCLK_USBPHY_MUX_G, "pclk_usbphy_mux_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 4, GFLAGS),
+	GATE(PCLK_UPHY0_TCPHY_G, "pclk_uphy0_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 5, GFLAGS),
+	GATE(PCLK_UPHY0_TCPD_G, "pclk_uphy0_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 6, GFLAGS),
+	GATE(PCLK_UPHY1_TCPHY_G, "pclk_uphy1_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 8, GFLAGS),
+	GATE(PCLK_UPHY1_TCPD_G, "pclk_uphy1_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 9, GFLAGS),
+
+	GATE(PCLK_GRF, "pclk_grf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 1, GFLAGS),
+	GATE(PCLK_INTR_ARB, "pclk_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 2, GFLAGS),
+	GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 3, GFLAGS),
+	GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 4, GFLAGS),
+	GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 5, GFLAGS),
+	GATE(PCLK_TIMER0, "pclk_timer0", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 6, GFLAGS),
+	GATE(PCLK_TIMER1, "pclk_timer1", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 7, GFLAGS),
+	GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS),
+	GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS),
+
+	/* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
+	SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_alive"),
+
+	GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", 0, RK3399_CLKGATE_CON(11), 14, GFLAGS),
+	GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS),
+
+	GATE(SCLK_MIPIDPHY_CFG, "clk_mipidphy_cfg", "xin24m", 0, RK3399_CLKGATE_CON(11), 15, GFLAGS),
+	GATE(SCLK_DPHY_TX0_CFG, "clk_dphy_tx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 1, GFLAGS),
+	GATE(SCLK_DPHY_TX1RX1_CFG, "clk_dphy_tx1rx1_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 2, GFLAGS),
+	GATE(SCLK_DPHY_RX0_CFG, "clk_dphy_rx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 3, GFLAGS),
+
+	/* testout */
+	MUX(0, "clk_test_pre", mux_pll_src_cpll_gpll_p, CLK_SET_RATE_PARENT,
+			RK3399_CLKSEL_CON(58), 7, 1, MFLAGS),
+	COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", 0,
+			RK3399_CLKSEL_CON(105), 0,
+			RK3399_CLKGATE_CON(13), 9, GFLAGS),
+
+	DIV(0, "clk_test_24m", "xin24m", 0,
+			RK3399_CLKSEL_CON(57), 6, 10, DFLAGS),
+
+	/* spi */
+	COMPOSITE(SCLK_SPI0, "clk_spi0", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(59), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 12, GFLAGS),
+
+	COMPOSITE(SCLK_SPI1, "clk_spi1", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(59), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 13, GFLAGS),
+
+	COMPOSITE(SCLK_SPI2, "clk_spi2", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(60), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 14, GFLAGS),
+
+	COMPOSITE(SCLK_SPI4, "clk_spi4", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(60), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(9), 15, GFLAGS),
+
+	COMPOSITE(SCLK_SPI5, "clk_spi5", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(58), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(13), 13, GFLAGS),
+
+	/* i2c */
+	COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(61), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 0, GFLAGS),
+
+	COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(62), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 2, GFLAGS),
+
+	COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(63), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 4, GFLAGS),
+
+	COMPOSITE(SCLK_I2C5, "clk_i2c5", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(61), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 1, GFLAGS),
+
+	COMPOSITE(SCLK_I2C6, "clk_i2c6", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(62), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 3, GFLAGS),
+
+	COMPOSITE(SCLK_I2C7, "clk_i2c7", mux_pll_src_cpll_gpll_p, 0,
+			RK3399_CLKSEL_CON(63), 15, 1, MFLAGS, 8, 7, DFLAGS,
+			RK3399_CLKGATE_CON(10), 5, GFLAGS),
+
+	/* timer */
+	GATE(SCLK_TIMER00, "clk_timer00", "xin24m", 0, RK3399_CLKGATE_CON(26), 0, GFLAGS),
+	GATE(SCLK_TIMER01, "clk_timer01", "xin24m", 0, RK3399_CLKGATE_CON(26), 1, GFLAGS),
+	GATE(SCLK_TIMER02, "clk_timer02", "xin24m", 0, RK3399_CLKGATE_CON(26), 2, GFLAGS),
+	GATE(SCLK_TIMER03, "clk_timer03", "xin24m", 0, RK3399_CLKGATE_CON(26), 3, GFLAGS),
+	GATE(SCLK_TIMER04, "clk_timer04", "xin24m", 0, RK3399_CLKGATE_CON(26), 4, GFLAGS),
+	GATE(SCLK_TIMER05, "clk_timer05", "xin24m", 0, RK3399_CLKGATE_CON(26), 5, GFLAGS),
+	GATE(SCLK_TIMER06, "clk_timer06", "xin24m", 0, RK3399_CLKGATE_CON(26), 6, GFLAGS),
+	GATE(SCLK_TIMER07, "clk_timer07", "xin24m", 0, RK3399_CLKGATE_CON(26), 7, GFLAGS),
+	GATE(SCLK_TIMER08, "clk_timer08", "xin24m", 0, RK3399_CLKGATE_CON(26), 8, GFLAGS),
+	GATE(SCLK_TIMER09, "clk_timer09", "xin24m", 0, RK3399_CLKGATE_CON(26), 9, GFLAGS),
+	GATE(SCLK_TIMER10, "clk_timer10", "xin24m", 0, RK3399_CLKGATE_CON(26), 10, GFLAGS),
+	GATE(SCLK_TIMER11, "clk_timer11", "xin24m", 0, RK3399_CLKGATE_CON(26), 11, GFLAGS),
+
+	/* clk_test */
+	/* clk_test_pre is controlled by CRU_MISC_CON[3] */
+	COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED,
+			RK3399_CLKSEL_CON(58), 0, 5, DFLAGS,
+			RK3399_CLKGATE_CON(13), 11, GFLAGS),
+
+	/* ddrc */
+	GATE(0, "clk_ddrc_lpll_src", "lpll", 0, RK3399_CLKGATE_CON(3),
+	     0, GFLAGS),
+	GATE(0, "clk_ddrc_bpll_src", "bpll", 0, RK3399_CLKGATE_CON(3),
+	     1, GFLAGS),
+	GATE(0, "clk_ddrc_dpll_src", "dpll", 0, RK3399_CLKGATE_CON(3),
+	     2, GFLAGS),
+	GATE(0, "clk_ddrc_gpll_src", "gpll", 0, RK3399_CLKGATE_CON(3),
+	     3, GFLAGS),
+	COMPOSITE_DDRCLK(SCLK_DDRC, "sclk_ddrc", mux_ddrclk_p, 0,
+		       RK3399_CLKSEL_CON(6), 4, 2, 0, 0, ROCKCHIP_DDRCLK_SIP),
+};
+
+static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
+	/*
+	 * PMU CRU Clock-Architecture
+	 */
+
+	GATE(0, "fclk_cm0s_pmu_ppll_src", "ppll", 0,
+			RK3399_PMU_CLKGATE_CON(0), 1, GFLAGS),
+
+	COMPOSITE_NOGATE(FCLK_CM0S_SRC_PMU, "fclk_cm0s_src_pmu", mux_fclk_cm0s_pmu_ppll_p, 0,
+			RK3399_PMU_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS),
+
+	COMPOSITE(SCLK_SPI3_PMU, "clk_spi3_pmu", mux_24m_ppll_p, 0,
+			RK3399_PMU_CLKSEL_CON(1), 7, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 2, GFLAGS),
+
+	COMPOSITE(0, "clk_wifi_div", mux_ppll_24m_p, CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(1), 13, 1, MFLAGS, 8, 5, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 8, GFLAGS),
+
+	COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", 0,
+			RK3399_PMU_CLKSEL_CON(7), 0,
+			&rk3399_pmuclk_wifi_fracmux),
+
+	MUX(0, "clk_timer_src_pmu", mux_pll_p, CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(1), 15, 1, MFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_I2C0_PMU, "clk_i2c0_pmu", "ppll", 0,
+			RK3399_PMU_CLKSEL_CON(2), 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 9, GFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_I2C4_PMU, "clk_i2c4_pmu", "ppll", 0,
+			RK3399_PMU_CLKSEL_CON(3), 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 10, GFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_I2C8_PMU, "clk_i2c8_pmu", "ppll", 0,
+			RK3399_PMU_CLKSEL_CON(2), 8, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 11, GFLAGS),
+
+	DIV(0, "clk_32k_suspend_pmu", "xin24m", CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(4), 0, 10, DFLAGS),
+	MUX(0, "clk_testout_2io", mux_clk_testout2_2io_p, CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(4), 15, 1, MFLAGS),
+
+	COMPOSITE(0, "clk_uart4_div", mux_24m_ppll_p, 0,
+			RK3399_PMU_CLKSEL_CON(5), 10, 1, MFLAGS, 0, 7, DFLAGS,
+			RK3399_PMU_CLKGATE_CON(0), 5, GFLAGS),
+
+	COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", 0,
+			RK3399_PMU_CLKSEL_CON(6), 0,
+			RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS,
+			&rk3399_uart4_pmu_fracmux),
+
+	DIV(PCLK_SRC_PMU, "pclk_pmu_src", "ppll", CLK_IGNORE_UNUSED,
+			RK3399_PMU_CLKSEL_CON(0), 0, 5, DFLAGS),
+
+	/* pmu clock gates */
+	GATE(SCLK_TIMER12_PMU, "clk_timer0_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 3, GFLAGS),
+	GATE(SCLK_TIMER13_PMU, "clk_timer1_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 4, GFLAGS),
+
+	GATE(SCLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 7, GFLAGS),
+
+	GATE(PCLK_PMU, "pclk_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 0, GFLAGS),
+	GATE(PCLK_PMUGRF_PMU, "pclk_pmugrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 1, GFLAGS),
+	GATE(PCLK_INTMEM1_PMU, "pclk_intmem1_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 2, GFLAGS),
+	GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 3, GFLAGS),
+	GATE(PCLK_GPIO1_PMU, "pclk_gpio1_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 4, GFLAGS),
+	GATE(PCLK_SGRF_PMU, "pclk_sgrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 5, GFLAGS),
+	GATE(PCLK_NOC_PMU, "pclk_noc_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 6, GFLAGS),
+	GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 7, GFLAGS),
+	GATE(PCLK_I2C4_PMU, "pclk_i2c4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 8, GFLAGS),
+	GATE(PCLK_I2C8_PMU, "pclk_i2c8_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 9, GFLAGS),
+	GATE(PCLK_RKPWM_PMU, "pclk_rkpwm_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 10, GFLAGS),
+	GATE(PCLK_SPI3_PMU, "pclk_spi3_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 11, GFLAGS),
+	GATE(PCLK_TIMER_PMU, "pclk_timer_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 12, GFLAGS),
+	GATE(PCLK_MAILBOX_PMU, "pclk_mailbox_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 13, GFLAGS),
+	GATE(PCLK_UART4_PMU, "pclk_uart4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 14, GFLAGS),
+	GATE(PCLK_WDT_M0_PMU, "pclk_wdt_m0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 15, GFLAGS),
+
+	GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS),
+	GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS),
+	GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS),
+	GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS),
+	GATE(HCLK_NOC_PMU, "hclk_noc_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 5, GFLAGS),
+};
+
+static const char *const rk3399_cru_critical_clocks[] __initconst = {
+	"aclk_cci_pre",
+	"aclk_gic",
+	"aclk_gic_noc",
+	"aclk_hdcp_noc",
+	"hclk_hdcp_noc",
+	"pclk_hdcp_noc",
+	"pclk_perilp0",
+	"pclk_perilp0",
+	"hclk_perilp0",
+	"hclk_perilp0_noc",
+	"pclk_perilp1",
+	"pclk_perilp1_noc",
+	"pclk_perihp",
+	"pclk_perihp_noc",
+	"hclk_perihp",
+	"aclk_perihp",
+	"aclk_perihp_noc",
+	"aclk_perilp0",
+	"aclk_perilp0_noc",
+	"hclk_perilp1",
+	"hclk_perilp1_noc",
+	"aclk_dmac0_perilp",
+	"aclk_emmc_noc",
+	"gpll_hclk_perilp1_src",
+	"gpll_aclk_perilp0_src",
+	"gpll_aclk_perihp_src",
+	"aclk_vio_noc",
+
+	/* ddrc */
+	"sclk_ddrc",
+
+	"armclkl",
+	"armclkb",
+};
+
+static const char *const rk3399_pmucru_critical_clocks[] __initconst = {
+	"ppll",
+	"pclk_pmu_src",
+	"fclk_cm0s_src_pmu",
+	"clk_timer_src_pmu",
+	"pclk_rkpwm_pmu",
+};
+
+static void __init rk3399_clk_init(struct device_node *np)
+{
+	struct rockchip_clk_provider *ctx;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru region\n", __func__);
+		return;
+	}
+
+	ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip clk init failed\n", __func__);
+		return;
+	}
+
+	rockchip_clk_register_plls(ctx, rk3399_pll_clks,
+				   ARRAY_SIZE(rk3399_pll_clks), -1);
+
+	rockchip_clk_register_branches(ctx, rk3399_clk_branches,
+				  ARRAY_SIZE(rk3399_clk_branches));
+
+	rockchip_clk_register_armclk(ctx, ARMCLKL, "armclkl",
+			mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p),
+			&rk3399_cpuclkl_data, rk3399_cpuclkl_rates,
+			ARRAY_SIZE(rk3399_cpuclkl_rates));
+
+	rockchip_clk_register_armclk(ctx, ARMCLKB, "armclkb",
+			mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p),
+			&rk3399_cpuclkb_data, rk3399_cpuclkb_rates,
+			ARRAY_SIZE(rk3399_cpuclkb_rates));
+
+	rockchip_clk_protect_critical(rk3399_cru_critical_clocks,
+				      ARRAY_SIZE(rk3399_cru_critical_clocks));
+
+	rockchip_register_softrst(np, 21, reg_base + RK3399_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_register_restart_notifier(ctx, RK3399_GLB_SRST_FST);
+
+	rockchip_clk_of_add_provider(np, ctx);
+}
+
+static void __init rk3399_pmu_clk_init(struct device_node *np)
+{
+	struct rockchip_clk_provider *ctx;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru pmu region\n", __func__);
+		return;
+	}
+
+	ctx = rockchip_clk_init(np, reg_base, CLKPMU_NR_CLKS);
+	if (IS_ERR(ctx)) {
+		pr_err("%s: rockchip pmu clk init failed\n", __func__);
+		return;
+	}
+
+	rockchip_clk_register_plls(ctx, rk3399_pmu_pll_clks,
+				   ARRAY_SIZE(rk3399_pmu_pll_clks), -1);
+
+	rockchip_clk_register_branches(ctx, rk3399_clk_pmu_branches,
+				  ARRAY_SIZE(rk3399_clk_pmu_branches));
+
+	rockchip_clk_protect_critical(rk3399_pmucru_critical_clocks,
+				  ARRAY_SIZE(rk3399_pmucru_critical_clocks));
+
+	rockchip_register_softrst(np, 2, reg_base + RK3399_PMU_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_clk_of_add_provider(np, ctx);
+}
+
+struct clk_rk3399_inits {
+	void (*inits)(struct device_node *np);
+};
+
+static const struct clk_rk3399_inits clk_rk3399_pmucru_init = {
+	.inits = rk3399_pmu_clk_init,
+};
+
+static const struct clk_rk3399_inits clk_rk3399_cru_init = {
+	.inits = rk3399_clk_init,
+};
+
+static const struct of_device_id clk_rk3399_match_table[] = {
+	{
+		.compatible = "rockchip,rk3399-cru",
+		.data = &clk_rk3399_cru_init,
+	},  {
+		.compatible = "rockchip,rk3399-pmucru",
+		.data = &clk_rk3399_pmucru_init,
+	},
+	{ }
+};
+
+static int __init clk_rk3399_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	const struct of_device_id *match;
+	const struct clk_rk3399_inits *init_data;
+
+	match = of_match_device(clk_rk3399_match_table, dev);
+	if (!match || !match->data)
+		return -EINVAL;
+
+	init_data = match->data;
+	if (init_data->inits)
+		init_data->inits(np);
+
+	return 0;
+}
+
+static struct driver_d clk_rk3399_driver = {
+	.probe  = clk_rk3399_probe,
+	.name   = "clk-rk3399",
+	.of_compatible = DRV_OF_COMPAT(clk_rk3399_match_table),
+};
+
+core_platform_driver(clk_rk3399_driver);
-- 
2.33.0



From a.fatoum at pengutronix.de  Fri Jan 14 00:42:27 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:42:27 +0100
Subject: [PATCH v2 3/3] ARM: rpi: use ENTRY_FUNCTION_WITHSTACK to prepare for
 ARM64 support
In-Reply-To: <20220114084227.308804-1-a.fatoum@pengutronix.de>
References: <20220114084227.308804-1-a.fatoum@pengutronix.de>
Message-ID: <20220114084227.308804-3-a.fatoum@pengutronix.de>

arm_setup_stack used in start_raspberry_pi is not safe on ARM64, due to
lack of __naked support. since 76bced6fe146 ("ARM: document
arm_setup_stack() pitfalls"), its use in ARM64 code is a compile-time
error.

The Raspberry Pi 4 support will be ARM64. To allow it to reuse
the existing low-level code, use the new ENTRY_FUNCTION_WITHSTACK,
which will set up stack appropriately for both ARM32 and ARM64.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/lowlevel.c | 35 ++++++++++++-------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/arch/arm/boards/raspberry-pi/lowlevel.c b/arch/arm/boards/raspberry-pi/lowlevel.c
index 29162ff02d54..e9314fb27b25 100644
--- a/arch/arm/boards/raspberry-pi/lowlevel.c
+++ b/arch/arm/boards/raspberry-pi/lowlevel.c
@@ -33,52 +33,51 @@ static void copy_vc_fdt(void *dest, void *src, unsigned long max_size)
 	memmove(dest, src, size);
 }
 
+/* A pointer to the FDT created by VideoCore was passed to us in r2. We
+ * reserve some memory just above the region used for Barebox and copy
+ * this FDT there. We fetch it from there later in rpi_devices_init().
+ */
+#define rpi_stack_top(memsize) \
+	arm_mem_stack_top(BCM2835_SDRAM_BASE, BCM2835_SDRAM_BASE + memsize - VIDEOCORE_FDT_SZ)
+
 /* Must be inline since stack isn't setup yet. */
 static inline void start_raspberry_pi(unsigned long memsize, void *fdt,
 								void *vc_fdt)
 {
-	void *saved_vc_fdt;
-	unsigned long membase = BCM2835_SDRAM_BASE;
-
-	/* A pointer to the FDT created by VideoCore was passed to us in r2. We
-	 * reserve some memory just above the region used for Basebox and copy
-	 * this FDT there. We fetch it from there later in rpi_devices_init().*/
-	memsize -= VIDEOCORE_FDT_SZ;
+	unsigned long endmem = rpi_stack_top(memsize);
 
 	arm_cpu_lowlevel_init();
 
-	/* Copied from barebox_arm_entry(). We need stack here early
-	 * for normal function calls to work. */
-	arm_setup_stack(arm_mem_stack_top(membase, membase + memsize));
+	copy_vc_fdt((void *)endmem, vc_fdt, VIDEOCORE_FDT_SZ);
 
 	fdt += get_runtime_offset();
 
-	saved_vc_fdt = (void *)(membase + memsize);
-	copy_vc_fdt(saved_vc_fdt, vc_fdt, VIDEOCORE_FDT_SZ);
-
-	barebox_arm_entry(membase, memsize, fdt);
+	barebox_arm_entry(BCM2835_SDRAM_BASE, endmem - BCM2835_SDRAM_BASE, fdt);
 }
 
+#define RPI_ENTRY_FUNCTION(name, memsize, r2) \
+	ENTRY_FUNCTION_WITHSTACK(name, rpi_stack_top(memsize), __r0, __r1, r2)
+
 extern char __dtb_bcm2835_rpi_start[];
-ENTRY_FUNCTION(start_raspberry_pi1, r0, r1, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi1, SZ_128M, r2)
 {
 	start_raspberry_pi(SZ_128M, __dtb_bcm2835_rpi_start, (void *)r2);
 }
 
 extern char __dtb_bcm2836_rpi_2_start[];
-ENTRY_FUNCTION(start_raspberry_pi2, r0, r1, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi2, SZ_512M, r2)
 {
 	start_raspberry_pi(SZ_512M, __dtb_bcm2836_rpi_2_start, (void *)r2);
 }
 
 extern char __dtb_bcm2837_rpi_3_start[];
-ENTRY_FUNCTION(start_raspberry_pi3, r0, r1, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi3, SZ_512M, r2)
 {
 	start_raspberry_pi(SZ_512M, __dtb_bcm2837_rpi_3_start, (void *)r2);
 }
 
 extern char __dtb_bcm2837_rpi_cm3_start[];
-ENTRY_FUNCTION(start_raspberry_pi_cm3, r0, r1, r2)
+RPI_ENTRY_FUNCTION(start_raspberry_pi_cm3, SZ_512M, r2)
 {
 	start_raspberry_pi(SZ_512M, __dtb_bcm2837_rpi_cm3_start, (void *)r2);
 }
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:42:25 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:42:25 +0100
Subject: [PATCH v2 1/3] ARM: implement ENTRY_FUNCTION_WITHSTACK
Message-ID: <20220114084227.308804-1-a.fatoum@pengutronix.de>

The point of ENTRY_FUNCTION is to write the entry point in C. Due to
lack of __naked on ARM64, the start of the entry point will have prologue
using stack and it's not possible to set up the stack safely without
branching into non-inline assembly[0]. On ARM32, where we got __naked, we
have the potential for a different problem: If BootROM sets up stack for
us and we branch to a naked function, which doesn't set up its own
stack, compiler may decide to spill local variables overwriting
instructions it had already run[1].

For code reuse between ARM and ARM64, it would be nice to use the same
entry point structure for both. Currently, the only way is to write it
in non-inline assembly using the ENTRY_PROC macro.

This introduces another way: the ARM64 barebox header has enough space
for 8 instructions of which 5 are unused (2 instructions compiler prologue
+ 1 instruction to jump after the header), we could place a stack setup
routine there to avoid having to write a separate assembly file.
For ARM32, we just call arm_setup_stack and branch out directly after,
freeing board porters of the burden of getting it right.

Add a new ENTRY_FUNCTION_WITHSTACK to realize this.

[0]: 76bced6fe146 ("ARM: document arm_setup_stack() pitfalls"),
[1]: b51b15ba1738 ("RISC-V: board-dt-2nd: move low level init into nonnaked function")

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
 - add __ARM_SETUP_STACK(0) to normal ENTRY_FUNCTION. On ARM32, it's a
   no-op, but on ARM64, it ensures the header isn't shifted
---
 arch/arm/include/asm/barebox-arm-head.h |  6 +---
 arch/arm/include/asm/barebox-arm.h      | 46 +++++++++++++++++++++++++
 arch/arm/lib/pbl.lds.S                  |  1 +
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/barebox-arm-head.h b/arch/arm/include/asm/barebox-arm-head.h
index fcb7e31d8531..099e1bef3cb8 100644
--- a/arch/arm/include/asm/barebox-arm-head.h
+++ b/arch/arm/include/asm/barebox-arm-head.h
@@ -46,14 +46,10 @@ static inline void __barebox_arm_head(void)
 		"1: b 1b\n"
 #endif
 #else
+		/* 5 instructions added by ENTRY_FUNCTION */
 		/* two instruction long function prologue */
 		/* only use if stack is initialized! */
 		"b 2f\n"
-		"nop\n"
-		"nop\n"
-		"nop\n"
-		"nop\n"
-		"nop\n"
 #endif
 		".asciz \"barebox\"\n"
 #ifdef CONFIG_CPU_32
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index cfb5943f33d6..5018b3e2f57a 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -161,6 +161,51 @@ static inline unsigned long arm_mem_barebox_image(unsigned long membase,
 	}
 }
 
+#ifdef CONFIG_CPU_64
+
+#define ____emit_entry_prologue(instr, ...) do { \
+	static __attribute__ ((unused,section(".text_head_prologue"))) \
+		const u32 __entry_prologue[] = {(instr), ##__VA_ARGS__}; \
+	barrier_data(__entry_prologue); \
+} while(0)
+
+#define __emit_entry_prologue(instr1, instr2, instr3, instr4, instr5) \
+	____emit_entry_prologue(instr1, instr2, instr3, instr4, instr5)
+
+#define __ARM_SETUP_STACK(stack_top) \
+	__emit_entry_prologue(0x14000002	/* b pc+0x8 */,		\
+			      stack_top		/* 32-bit literal */,	\
+			      0x18ffffe9	/* ldr w9, top */,	\
+			      0xb4000049	/* cbz x9, pc+0x8 */,	\
+			      0x9100013f	/* mov sp, x9 */)
+#else
+#define __ARM_SETUP_STACK(stack_top) if (stack_top) arm_setup_stack(stack_top)
+#endif
+
+/*
+ * Unlike ENTRY_FUNCTION, this can be used to setup stack for a C entry
+ * point on both ARM32 and ARM64. ENTRY_FUNCTION on ARM64 can only be used
+ * if preceding boot stage has initialized the stack pointer.
+ *
+ * Stack top of 0 means stack is already set up. In that case, the follow-up
+ * code block will not be inlined and may spill to stack right away.
+ */
+#define ENTRY_FUNCTION_WITHSTACK(name, stack_top, arg0, arg1, arg2)	\
+	void name(ulong r0, ulong r1, ulong r2);			\
+									\
+	static void __##name(ulong, ulong, ulong);			\
+									\
+	void NAKED __section(.text_head_entry_##name)	name		\
+				(ulong r0, ulong r1, ulong r2)		\
+		{							\
+			__barebox_arm_head();				\
+			__ARM_SETUP_STACK(stack_top);			\
+			__##name(r0, r1, r2);				\
+		}							\
+		static void noinline __##name				\
+			(ulong arg0, ulong arg1, ulong arg2)
+
+
 #define ENTRY_FUNCTION(name, arg0, arg1, arg2)				\
 	void name(ulong r0, ulong r1, ulong r2);			\
 									\
@@ -170,6 +215,7 @@ static inline unsigned long arm_mem_barebox_image(unsigned long membase,
 				(ulong r0, ulong r1, ulong r2)		\
 		{							\
 			__barebox_arm_head();				\
+			__ARM_SETUP_STACK(0);				\
 			__##name(r0, r1, r2);				\
 		}							\
 		static void NAKED noinline __##name			\
diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S
index 0a0fb8b5ac13..e77b3220fcb0 100644
--- a/arch/arm/lib/pbl.lds.S
+++ b/arch/arm/lib/pbl.lds.S
@@ -31,6 +31,7 @@ SECTIONS
 	.text      :
 	{
 		_stext = .;
+		*(.text_head_prologue*)
 		*(.text_head_entry*)
 		__bare_init_start = .;
 		*(.text_bare_init*)
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:42:26 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:42:26 +0100
Subject: [PATCH v2 2/3] ARM: turn arm_mem_stack_top into a macro
In-Reply-To: <20220114084227.308804-1-a.fatoum@pengutronix.de>
References: <20220114084227.308804-1-a.fatoum@pengutronix.de>
Message-ID: <20220114084227.308804-2-a.fatoum@pengutronix.de>

This makes it possible to use for static initialization, like done in a
follow-up commit.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - drop OPTEE_SIZE on non OPTEE builds
---
 arch/arm/include/asm/barebox-arm.h | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index 5018b3e2f57a..1c8cdfd16e62 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -97,14 +97,13 @@ static inline void arm_fixup_vectors(void)
 
 void *barebox_arm_boot_dtb(void);
 
-static inline unsigned long arm_mem_stack_top(unsigned long membase,
-					      unsigned long endmem)
-{
-	if (IS_ENABLED(CONFIG_BOOTM_OPTEE) || IS_ENABLED(CONFIG_PBL_OPTEE))
-		endmem -= OPTEE_SIZE;
+#define __arm_mem_stack_top(membase, endmem) ((endmem) - SZ_64K)
 
-	return endmem - SZ_64K;
-}
+#if defined(CONFIG_BOOTM_OPTEE) || defined(CONFIG_PBL_OPTEE)
+#define arm_mem_stack_top(membase, endmem) (__arm_mem_stack_top(membase, endmem) - OPTEE_SIZE)
+#else
+#define arm_mem_stack_top(membase, endmem)  __arm_mem_stack_top(membase, endmem)
+#endif
 
 static inline unsigned long arm_mem_stack(unsigned long membase,
 					  unsigned long endmem)
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:47:28 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:47:28 +0100
Subject: [PATCH] mfd: implement mfd_add_devices
Message-ID: <20220114084728.311277-1-a.fatoum@pengutronix.de>

This makes it easier to port Linux drivers like PMICs, where a device
tree probed MFD node exists and the driver matching against it then
registers a number of MFD cell devices, which don't have their own
DT compatibles.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/base/resource.c  |  2 +-
 drivers/mfd/Makefile     |  2 ++
 drivers/mfd/core.c       | 25 +++++++++++++++++++++++++
 include/driver.h         |  2 +-
 include/linux/mfd/core.h | 23 +++++++++++++++++++++++
 5 files changed, 52 insertions(+), 2 deletions(-)
 create mode 100644 drivers/mfd/core.c
 create mode 100644 include/linux/mfd/core.h

diff --git a/drivers/base/resource.c b/drivers/base/resource.c
index d0d39620772e..0134456ffac2 100644
--- a/drivers/base/resource.c
+++ b/drivers/base/resource.c
@@ -20,7 +20,7 @@ struct device_d *device_alloc(const char *devname, int id)
 	return dev;
 }
 
-int device_add_data(struct device_d *dev, void *data, size_t size)
+int device_add_data(struct device_d *dev, const void *data, size_t size)
 {
 	free(dev->platform_data);
 
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2bcf90078ab4..a00119a1d5f4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-y				+= core.o
+
 obj-$(CONFIG_MFD_ACT8846)	+= act8846.o
 obj-$(CONFIG_MFD_DA9053)	+= da9053.o
 obj-$(CONFIG_MFD_DA9063)	+= da9063.o
diff --git a/drivers/mfd/core.c b/drivers/mfd/core.c
new file mode 100644
index 000000000000..fa6aa1c74a18
--- /dev/null
+++ b/drivers/mfd/core.c
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <linux/mfd/core.h>
+#include <driver.h>
+
+int mfd_add_devices(struct device_d *parent, const struct mfd_cell *cells, int n_devs)
+{
+	struct device_d *dev;
+	int ret, i;
+
+	for (i = 0; i < n_devs; i++) {
+		dev = device_alloc(cells[i].name, DEVICE_ID_DYNAMIC);
+		dev->parent = parent;
+
+		ret = platform_device_register(dev);
+		if (ret)
+			return ret;
+
+		ret = device_add_data(dev, &cells[i], sizeof(cells[i]));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
diff --git a/include/driver.h b/include/driver.h
index 4f6d40e17c14..513b9ea794e6 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -234,7 +234,7 @@ int device_add_resources(struct device_d *dev, const struct resource *res, int n
 int device_add_resource(struct device_d *dev, const char *resname,
 		resource_size_t start, resource_size_t size, unsigned int flags);
 
-int device_add_data(struct device_d *dev, void *data, size_t size);
+int device_add_data(struct device_d *dev, const void *data, size_t size);
 
 /*
  * register a generic device
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
new file mode 100644
index 000000000000..2b3b51c69e5f
--- /dev/null
+++ b/include/linux/mfd/core.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2006 Ian Molton
+ * Copyright (c) 2007 Dmitry Baryshkov
+ */
+
+#ifndef MFD_CORE_H
+#define MFD_CORE_H
+
+struct device_d;
+
+/*
+ * This struct describes the MFD part ("cell").
+ * After registration the copy of this structure will become the platform data
+ * of the resulting device_d
+ */
+struct mfd_cell {
+	const char		*name;
+};
+
+int mfd_add_devices(struct device_d *parent, const struct mfd_cell *cells, int n_devs);
+
+#endif
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:47:56 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:47:56 +0100
Subject: [PATCH 1/2] pinctrl: rockchip: use alias rather than full of name
Message-ID: <20220114084757.311697-1-a.fatoum@pengutronix.de>

From: Michael Riesch <michael.riesch at wolfvision.net>

We've so far relied on GPIO controllers being named "gpioX", while the
binding mandates gpio controllers being just called "gpio". This already
broke rk3288 support and rk3568.dtsi upstream also differs from the
version in barebox' arch/arm/dts in that regard.

Instead, do like Linux does and use the alias to match the controllers to
the GPIO banks with a fallback to probe order.

Fixes: 3f2f5980d517 ("dts: update to v5.16-rc1")
Signed-off-by: Michael Riesch <michael.riesch at wolfvision.net>
[afa: drop strncmp in favor of id comparison, reword commit message]
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 5cf77c58b218..ea748b600419 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -877,18 +877,24 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
 	struct rockchip_pin_bank *bank;
 	char *name;
 	int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
+	int gpio = 0;
 
 	match = of_match_node(rockchip_pinctrl_dt_match, node);
 	ctrl = (struct rockchip_pin_ctrl *)match->data;
 
 	for_each_child_of_node(node, np) {
+		int id;
+
 		if (!of_find_property(np, "gpio-controller", NULL))
 			continue;
 
+		id = of_alias_get_id(np, "gpio");
+		if (id < 0)
+			id = gpio++;
+
 		bank = ctrl->pin_banks;
 		for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
-			name = bank->name;
-			if (!strncmp(name, np->name, strlen(name))) {
+			if (bank->bank_num == id) {
 				bank->of_node = np;
 				if (!rockchip_get_bank_data(bank, dev))
 					bank->valid = true;
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:47:57 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:47:57 +0100
Subject: [PATCH 2/2] pinctrl: Rockchip: abort GPIO probe gracefully on
 out-of-range alias id
In-Reply-To: <20220114084757.311697-1-a.fatoum@pengutronix.de>
References: <20220114084757.311697-1-a.fatoum@pengutronix.de>
Message-ID: <20220114084757.311697-2-a.fatoum@pengutronix.de>

&{/aliases} { gpio120 = &gpio1; } so far led to an out-of-bounds read
when probing &gpio1. Fix this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/pinctrl/pinctrl-rockchip.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index ea748b600419..869cce198239 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -334,6 +334,8 @@ static int rockchip_gpio_probe(struct device_d *dev)
 	int ret, bankno;
 
 	bankno = of_alias_get_id(dev->device_node, "gpio");
+	if (bankno >= ctrl->nr_banks)
+		bankno = -EINVAL;
 	if (bankno < 0)
 		return bankno;
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:49:00 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:49:00 +0100
Subject: [PATCH 1/2] pinctrl: rockchip: use alias rather than full of name
In-Reply-To: <20220114084757.311697-1-a.fatoum@pengutronix.de>
References: <20220114084757.311697-1-a.fatoum@pengutronix.de>
Message-ID: <54068c9b-f272-d89c-1e8e-b12f72864c06@pengutronix.de>

On 14.01.22 09:47, Ahmad Fatoum wrote:
> From: Michael Riesch <michael.riesch at wolfvision.net>
> 
> We've so far relied on GPIO controllers being named "gpioX", while the
> binding mandates gpio controllers being just called "gpio". This already
> broke rk3288 support and rk3568.dtsi upstream also differs from the
> version in barebox' arch/arm/dts in that regard.
> 
> Instead, do like Linux does and use the alias to match the controllers to
> the GPIO banks with a fallback to probe order.
> 
> Fixes: 3f2f5980d517 ("dts: update to v5.16-rc1")
> Signed-off-by: Michael Riesch <michael.riesch at wolfvision.net>
> [afa: drop strncmp in favor of id comparison, reword commit message]
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

@Sascha, can this go into a master? V7 Rockchip boards should be broken
without this.

> ---
>  drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
> index 5cf77c58b218..ea748b600419 100644
> --- a/drivers/pinctrl/pinctrl-rockchip.c
> +++ b/drivers/pinctrl/pinctrl-rockchip.c
> @@ -877,18 +877,24 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
>  	struct rockchip_pin_bank *bank;
>  	char *name;
>  	int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
> +	int gpio = 0;
>  
>  	match = of_match_node(rockchip_pinctrl_dt_match, node);
>  	ctrl = (struct rockchip_pin_ctrl *)match->data;
>  
>  	for_each_child_of_node(node, np) {
> +		int id;
> +
>  		if (!of_find_property(np, "gpio-controller", NULL))
>  			continue;
>  
> +		id = of_alias_get_id(np, "gpio");
> +		if (id < 0)
> +			id = gpio++;
> +
>  		bank = ctrl->pin_banks;
>  		for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
> -			name = bank->name;
> -			if (!strncmp(name, np->name, strlen(name))) {
> +			if (bank->bank_num == id) {
>  				bank->of_node = np;
>  				if (!rockchip_get_bank_data(bank, dev))
>  					bank->valid = true;
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Fri Jan 14 00:50:46 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:50:46 +0100
Subject: [PATCH 2/2] nvmem: add Rockchip eFuse support
In-Reply-To: <20220114085046.313677-1-a.fatoum@pengutronix.de>
References: <20220114085046.313677-1-a.fatoum@pengutronix.de>
Message-ID: <20220114085046.313677-2-a.fatoum@pengutronix.de>

The driver allows read-only support to e.g. the Hardware UID, which
could in future be used to derive a MAC like U-Boot does.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/nvmem/Kconfig          |   8 +
 drivers/nvmem/Makefile         |   1 +
 drivers/nvmem/rockchip-efuse.c | 299 +++++++++++++++++++++++++++++++++
 3 files changed, 308 insertions(+)
 create mode 100644 drivers/nvmem/rockchip-efuse.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 7b1ebe1d689d..ea1156918a34 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -84,4 +84,12 @@ config STARFIVE_OTP
 	  This adds support for the StarFive OTP controller. Only reading
 	  is currently supported.
 
+config ROCKCHIP_EFUSE
+	tristate "Rockchip eFuse Support"
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	depends on OFDEVICE
+	help
+	  This is a simple drive to dump specified values of Rockchip SoC
+	  from eFuse, such as CPU ID.
+
 endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 586591961215..2261816c189c 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_STM32_BSEC)	+= nvmem_bsec.o
 nvmem_bsec-y			:= bsec.o
 
 obj-$(CONFIG_STARFIVE_OTP)	+= starfive-otp.o
+obj-$(CONFIG_ROCKCHIP_EFUSE)	+= rockchip-efuse.o
diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
new file mode 100644
index 000000000000..24e7de0aa9ce
--- /dev/null
+++ b/drivers/nvmem/rockchip-efuse.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Rockchip eFuse Driver
+ *
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Caesar Wang <wxt at rock-chips.com>
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <linux/overflow.h>
+#include <clock.h>
+#include <driver.h>
+#include <io.h>
+#include <linux/nvmem-provider.h>
+#include <of.h>
+#include <init.h>
+
+#define clk_prepare_enable clk_enable
+#define clk_disable_unprepare clk_disable
+
+#define RK3288_A_SHIFT		6
+#define RK3288_A_MASK		0x3ff
+#define RK3288_PGENB		BIT(3)
+#define RK3288_LOAD		BIT(2)
+#define RK3288_STROBE		BIT(1)
+#define RK3288_CSB		BIT(0)
+
+#define RK3328_SECURE_SIZES	96
+#define RK3328_INT_STATUS	0x0018
+#define RK3328_DOUT		0x0020
+#define RK3328_AUTO_CTRL	0x0024
+#define RK3328_INT_FINISH	BIT(0)
+#define RK3328_AUTO_ENB		BIT(0)
+#define RK3328_AUTO_RD		BIT(1)
+
+#define RK3399_A_SHIFT		16
+#define RK3399_A_MASK		0x3ff
+#define RK3399_NBYTES		4
+#define RK3399_STROBSFTSEL	BIT(9)
+#define RK3399_RSB		BIT(7)
+#define RK3399_PD		BIT(5)
+#define RK3399_PGENB		BIT(3)
+#define RK3399_LOAD		BIT(2)
+#define RK3399_STROBE		BIT(1)
+#define RK3399_CSB		BIT(0)
+
+#define REG_EFUSE_CTRL		0x0000
+#define REG_EFUSE_DOUT		0x0004
+
+struct rockchip_efuse_chip {
+	struct device_d *dev;
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static int rockchip_rk3288_efuse_read(void *context, unsigned int offset,
+				      void *val, size_t bytes)
+{
+	struct rockchip_efuse_chip *efuse = context;
+	u8 *buf = val;
+	int ret;
+
+	ret = clk_prepare_enable(efuse->clk);
+	if (ret < 0) {
+		dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
+		return ret;
+	}
+
+	writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL);
+	udelay(1);
+	while (bytes--) {
+		writel(readl(efuse->base + REG_EFUSE_CTRL) &
+			     (~(RK3288_A_MASK << RK3288_A_SHIFT)),
+			     efuse->base + REG_EFUSE_CTRL);
+		writel(readl(efuse->base + REG_EFUSE_CTRL) |
+			     ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
+			     efuse->base + REG_EFUSE_CTRL);
+		udelay(1);
+		writel(readl(efuse->base + REG_EFUSE_CTRL) |
+			     RK3288_STROBE, efuse->base + REG_EFUSE_CTRL);
+		udelay(1);
+		*buf++ = readb(efuse->base + REG_EFUSE_DOUT);
+		writel(readl(efuse->base + REG_EFUSE_CTRL) &
+		       (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL);
+		udelay(1);
+	}
+
+	/* Switch to standby mode */
+	writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL);
+
+	clk_disable_unprepare(efuse->clk);
+
+	return 0;
+}
+
+static int rockchip_rk3328_efuse_read(void *context, unsigned int offset,
+				      void *val, size_t bytes)
+{
+	struct rockchip_efuse_chip *efuse = context;
+	unsigned int addr_start, addr_end, addr_offset, addr_len;
+	u32 out_value, status;
+	u8 *buf;
+	int ret, i = 0;
+
+	ret = clk_prepare_enable(efuse->clk);
+	if (ret < 0) {
+		dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
+		return ret;
+	}
+
+	/* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */
+	offset += RK3328_SECURE_SIZES;
+	addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
+	addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
+	addr_offset = offset % RK3399_NBYTES;
+	addr_len = addr_end - addr_start;
+
+	buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
+		      GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto nomem;
+	}
+
+	while (addr_len--) {
+		writel(RK3328_AUTO_RD | RK3328_AUTO_ENB |
+		       ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
+		       efuse->base + RK3328_AUTO_CTRL);
+		udelay(4);
+		status = readl(efuse->base + RK3328_INT_STATUS);
+		if (!(status & RK3328_INT_FINISH)) {
+			ret = -EIO;
+			goto err;
+		}
+		out_value = readl(efuse->base + RK3328_DOUT);
+		writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
+
+		memcpy(&buf[i], &out_value, RK3399_NBYTES);
+		i += RK3399_NBYTES;
+	}
+
+	memcpy(val, buf + addr_offset, bytes);
+err:
+	kfree(buf);
+nomem:
+	clk_disable_unprepare(efuse->clk);
+
+	return ret;
+}
+
+static int rockchip_rk3399_efuse_read(void *context, unsigned int offset,
+				      void *val, size_t bytes)
+{
+	struct rockchip_efuse_chip *efuse = context;
+	unsigned int addr_start, addr_end, addr_offset, addr_len;
+	u32 out_value;
+	u8 *buf;
+	int ret, i = 0;
+
+	ret = clk_prepare_enable(efuse->clk);
+	if (ret < 0) {
+		dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
+		return ret;
+	}
+
+	addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
+	addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
+	addr_offset = offset % RK3399_NBYTES;
+	addr_len = addr_end - addr_start;
+
+	buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
+		      GFP_KERNEL);
+	if (!buf) {
+		clk_disable_unprepare(efuse->clk);
+		return -ENOMEM;
+	}
+
+	writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
+	       efuse->base + REG_EFUSE_CTRL);
+	udelay(1);
+	while (addr_len--) {
+		writel(readl(efuse->base + REG_EFUSE_CTRL) | RK3399_STROBE |
+		       ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
+		       efuse->base + REG_EFUSE_CTRL);
+		udelay(1);
+		out_value = readl(efuse->base + REG_EFUSE_DOUT);
+		writel(readl(efuse->base + REG_EFUSE_CTRL) & (~RK3399_STROBE),
+		       efuse->base + REG_EFUSE_CTRL);
+		udelay(1);
+
+		memcpy(&buf[i], &out_value, RK3399_NBYTES);
+		i += RK3399_NBYTES;
+	}
+
+	/* Switch to standby mode */
+	writel(RK3399_PD | RK3399_CSB, efuse->base + REG_EFUSE_CTRL);
+
+	memcpy(val, buf + addr_offset, bytes);
+
+	kfree(buf);
+
+	clk_disable_unprepare(efuse->clk);
+
+	return 0;
+}
+
+static struct nvmem_config econfig = {
+	.name = "rockchip-efuse",
+	.stride = 1,
+	.word_size = 1,
+	.read_only = true,
+};
+
+static const struct of_device_id rockchip_efuse_match[] = {
+	/* deprecated but kept around for dts binding compatibility */
+	{
+		.compatible = "rockchip,rockchip-efuse",
+		.data = (void *)&rockchip_rk3288_efuse_read,
+	},
+	{
+		.compatible = "rockchip,rk3066a-efuse",
+		.data = (void *)&rockchip_rk3288_efuse_read,
+	},
+	{
+		.compatible = "rockchip,rk3188-efuse",
+		.data = (void *)&rockchip_rk3288_efuse_read,
+	},
+	{
+		.compatible = "rockchip,rk3228-efuse",
+		.data = (void *)&rockchip_rk3288_efuse_read,
+	},
+	{
+		.compatible = "rockchip,rk3288-efuse",
+		.data = (void *)&rockchip_rk3288_efuse_read,
+	},
+	{
+		.compatible = "rockchip,rk3368-efuse",
+		.data = (void *)&rockchip_rk3288_efuse_read,
+	},
+	{
+		.compatible = "rockchip,rk3328-efuse",
+		.data = (void *)&rockchip_rk3328_efuse_read,
+	},
+	{
+		.compatible = "rockchip,rk3399-efuse",
+		.data = (void *)&rockchip_rk3399_efuse_read,
+	},
+	{ /* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, rockchip_efuse_match);
+
+static int rockchip_efuse_probe(struct device_d *dev)
+{
+	struct resource *res;
+	struct nvmem_device *nvmem;
+	struct rockchip_efuse_chip *efuse;
+	const void *data;
+
+	data = device_get_match_data(dev);
+	if (!data) {
+		dev_err(dev, "failed to get match data\n");
+		return -EINVAL;
+	}
+
+	efuse = kzalloc(sizeof(struct rockchip_efuse_chip), GFP_KERNEL);
+	if (!efuse)
+		return -ENOMEM;
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	efuse->base = IOMEM(res->start);
+
+	efuse->clk = clk_get(dev, "pclk_efuse");
+	if (IS_ERR(efuse->clk))
+		return PTR_ERR(efuse->clk);
+
+	efuse->dev = dev;
+	if (of_property_read_u32(dev->device_node, "rockchip,efuse-size",
+				 &econfig.size))
+		econfig.size = resource_size(res);
+	econfig.reg_read = data;
+	econfig.priv = efuse;
+	econfig.dev = efuse->dev;
+	nvmem = nvmem_register(&econfig);
+
+	return PTR_ERR_OR_ZERO(nvmem);
+}
+
+static struct driver_d rockchip_efuse_driver = {
+	.name = "rockchip-efuse",
+	.of_compatible = rockchip_efuse_match,
+	.probe = rockchip_efuse_probe,
+};
+device_platform_driver(rockchip_efuse_driver);
+MODULE_DESCRIPTION("rockchip_efuse driver");
+MODULE_LICENSE("GPL v2");
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:50:45 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:50:45 +0100
Subject: [PATCH 1/2] nvmem: retire struct nvmem_bus for better Linux
 compatibility
Message-ID: <20220114085046.313677-1-a.fatoum@pengutronix.de>

nvmem_bus is arguably a confusing name and serves no real purpose over
just embedding its two members directly. That's what Linux currently
does, so follow suit.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/eeprom/at24.c            |  8 ++------
 drivers/net/phy/mv88e6xxx/chip.c |  8 ++------
 drivers/nvmem/core.c             | 22 +++++++++++++---------
 drivers/nvmem/eeprom_93xx46.c    |  9 +++------
 drivers/nvmem/ocotp.c            |  8 ++------
 drivers/nvmem/partition.c        |  8 ++------
 drivers/nvmem/rave-sp-eeprom.c   |  8 ++------
 drivers/nvmem/regmap.c           |  8 ++------
 drivers/nvmem/rmem.c             |  6 +-----
 drivers/nvmem/snvs_lpgpr.c       |  8 ++------
 drivers/rtc/rtc-imxdi.c          |  8 ++------
 include/linux/nvmem-provider.h   | 10 ++++------
 12 files changed, 37 insertions(+), 74 deletions(-)

diff --git a/drivers/eeprom/at24.c b/drivers/eeprom/at24.c
index 3103d7722a40..22f3d6d880ed 100644
--- a/drivers/eeprom/at24.c
+++ b/drivers/eeprom/at24.c
@@ -361,11 +361,6 @@ static int at24_nvmem_write(void *ctx, unsigned off, const void *buf, size_t cou
 	return at24_write(ctx, buf, off, count);
 }
 
-static const struct nvmem_bus at24_nvmem_bus = {
-	.write = at24_nvmem_write,
-	.read  = at24_nvmem_read,
-};
-
 static int at24_probe(struct device_d *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -487,7 +482,8 @@ static int at24_probe(struct device_d *dev)
 	at24->nvmem_config.dev = dev;
 	at24->nvmem_config.priv = at24;
 	at24->nvmem_config.read_only = !writable;
-	at24->nvmem_config.bus = &at24_nvmem_bus;
+	at24->nvmem_config.reg_write = at24_nvmem_write;
+	at24->nvmem_config.reg_read  = at24_nvmem_read;
 	at24->nvmem_config.stride = 1;
 	at24->nvmem_config.word_size = 1;
 	at24->nvmem_config.size = chip.byte_len;
diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
index ae59d134e792..88e0ab5c42af 100644
--- a/drivers/net/phy/mv88e6xxx/chip.c
+++ b/drivers/net/phy/mv88e6xxx/chip.c
@@ -808,11 +808,6 @@ static int mv88e6xxx_eeprom_write(void *ctx, unsigned offset, const void *val, s
 	return chip->info->ops->set_eeprom(chip, &eeprom, (void *)val);
 }
 
-static const struct nvmem_bus mv88e6xxx_eeprom_nvmem_bus = {
-	.write = mv88e6xxx_eeprom_write,
-	.read  = mv88e6xxx_eeprom_read,
-};
-
 static int mv88e6xxx_probe(struct device_d *dev)
 {
 	struct device_node *np = dev->device_node;
@@ -887,7 +882,8 @@ static int mv88e6xxx_probe(struct device_d *dev)
 			.stride = 1,
 			.size = eeprom_len,
 			.read_only = false,
-			.bus = &mv88e6xxx_eeprom_nvmem_bus,
+			.reg_write = mv88e6xxx_eeprom_write,
+			.reg_read = mv88e6xxx_eeprom_read,
 		};
 
 		if (IS_ERR(nvmem_register(&config)))
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index fed387c43a26..f1df0969ecfd 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -16,7 +16,6 @@
 struct nvmem_device {
 	const char		*name;
 	struct device_d		dev;
-	const struct nvmem_bus	*bus;
 	struct list_head	node;
 	int			stride;
 	int			word_size;
@@ -26,6 +25,10 @@ struct nvmem_device {
 	bool			read_only;
 	struct cdev		cdev;
 	void			*priv;
+	int			(*reg_write)(void *ctx, unsigned int reg,
+					     const void *val, size_t val_size);
+	int			(*reg_read)(void *ctx, unsigned int reg,
+					    void *val, size_t val_size);
 };
 
 struct nvmem_cell {
@@ -205,12 +208,13 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 	nvmem->word_size = config->word_size;
 	nvmem->size = config->size;
 	nvmem->dev.parent = config->dev;
-	nvmem->bus = config->bus;
+	nvmem->reg_read = config->reg_read;
+	nvmem->reg_write = config->reg_write;
 	np = config->cdev ? config->cdev->device_node : config->dev->device_node;
 	nvmem->dev.device_node = np;
 	nvmem->priv = config->priv;
 
-	if (config->read_only || !config->bus->write || of_property_read_bool(np, "read-only"))
+	if (config->read_only || !config->reg_write || of_property_read_bool(np, "read-only"))
 		nvmem->read_only = true;
 
 	dev_set_name(&nvmem->dev, config->name);
@@ -525,7 +529,7 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem,
 {
 	int rc;
 
-	rc = nvmem->bus->read(nvmem->priv, cell->offset, buf, cell->bytes);
+	rc = nvmem->reg_read(nvmem->priv, cell->offset, buf, cell->bytes);
 	if (IS_ERR_VALUE(rc))
 		return rc;
 
@@ -590,7 +594,7 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
 		*b <<= bit_offset;
 
 		/* setup the first byte with lsb bits from nvmem */
-		rc = nvmem->bus->read(nvmem->priv, cell->offset, &v, 1);
+		rc = nvmem->reg_read(nvmem->priv, cell->offset, &v, 1);
 		*b++ |= GENMASK(bit_offset - 1, 0) & v;
 
 		/* setup rest of the byte if any */
@@ -607,7 +611,7 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
 	/* if it's not end on byte boundary */
 	if ((nbits + bit_offset) % BITS_PER_BYTE) {
 		/* setup the last byte with msb bits from nvmem */
-		rc = nvmem->bus->read(nvmem->priv, cell->offset + cell->bytes - 1,
+		rc = nvmem->reg_read(nvmem->priv, cell->offset + cell->bytes - 1,
 				      &v, 1);
 		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
 
@@ -640,7 +644,7 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
 			return PTR_ERR(buf);
 	}
 
-	rc = nvmem->bus->write(nvmem->priv, cell->offset, buf, cell->bytes);
+	rc = nvmem->reg_write(nvmem->priv, cell->offset, buf, cell->bytes);
 
 	/* free the tmp buffer */
 	if (cell->bit_offset || cell->nbits)
@@ -737,7 +741,7 @@ int nvmem_device_read(struct nvmem_device *nvmem,
 	if (!bytes)
 		return 0;
 
-	rc = nvmem->bus->read(nvmem->priv, offset, buf, bytes);
+	rc = nvmem->reg_read(nvmem->priv, offset, buf, bytes);
 
 	if (IS_ERR_VALUE(rc))
 		return rc;
@@ -771,7 +775,7 @@ int nvmem_device_write(struct nvmem_device *nvmem,
 	if (!bytes)
 		return 0;
 
-	rc = nvmem->bus->write(nvmem->priv, offset, buf, bytes);
+	rc = nvmem->reg_write(nvmem->priv, offset, buf, bytes);
 
 	if (IS_ERR_VALUE(rc))
 		return rc;
diff --git a/drivers/nvmem/eeprom_93xx46.c b/drivers/nvmem/eeprom_93xx46.c
index 2f598fbc97f6..b76750ebbd33 100644
--- a/drivers/nvmem/eeprom_93xx46.c
+++ b/drivers/nvmem/eeprom_93xx46.c
@@ -364,11 +364,6 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi)
 	return 0;
 }
 
-static const struct nvmem_bus eeprom_93xx46_nvmem_bus = {
-	.write = eeprom_93xx46_write,
-	.read  = eeprom_93xx46_read,
-};
-
 static int eeprom_93xx46_probe(struct device_d *dev)
 {
 	struct spi_device *spi = (struct spi_device *)dev->type_data;
@@ -408,7 +403,9 @@ static int eeprom_93xx46_probe(struct device_d *dev)
 	edev->nvmem_config.dev = &spi->dev;
 	edev->nvmem_config.priv = edev;
 	edev->nvmem_config.read_only = pd->flags & EE_READONLY;
-	edev->nvmem_config.bus = &eeprom_93xx46_nvmem_bus;
+	edev->nvmem_config.reg_write = eeprom_93xx46_write;
+	edev->nvmem_config.reg_read  = eeprom_93xx46_read;
+
 	edev->nvmem_config.stride = 4;
 	edev->nvmem_config.word_size = 1;
 	edev->nvmem_config.size = edev->size;
diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c
index 1f99a8012f7a..e7212f144c35 100644
--- a/drivers/nvmem/ocotp.c
+++ b/drivers/nvmem/ocotp.c
@@ -697,11 +697,6 @@ static void imx_ocotp_set_unique_machine_id(void)
 	machine_id_set_hashable(unique_id_parts, sizeof(unique_id_parts));
 }
 
-static const struct nvmem_bus imx_ocotp_nvmem_bus = {
-	.write = imx_ocotp_write,
-	.read  = imx_ocotp_read,
-};
-
 static int imx_ocotp_probe(struct device_d *dev)
 {
 	struct resource *iores;
@@ -745,7 +740,8 @@ static int imx_ocotp_probe(struct device_d *dev)
 	priv->config.stride = 4;
 	priv->config.word_size = 4;
 	priv->config.size = data->num_regs;
-	priv->config.bus = &imx_ocotp_nvmem_bus;
+	priv->config.reg_write = imx_ocotp_write;
+	priv->config.reg_read  = imx_ocotp_read;
 
 	nvmem = nvmem_register(&priv->config);
 	if (IS_ERR(nvmem))
diff --git a/drivers/nvmem/partition.c b/drivers/nvmem/partition.c
index a034c6c4d55a..14907e05ba2d 100644
--- a/drivers/nvmem/partition.c
+++ b/drivers/nvmem/partition.c
@@ -18,11 +18,6 @@ static int nvmem_cdev_read(void *ctx, unsigned offset, void *buf, size_t bytes)
 	return cdev_read(ctx, buf, bytes, offset, 0);
 }
 
-static struct nvmem_bus nvmem_cdev_bus = {
-	.read = nvmem_cdev_read,
-	.write = nvmem_cdev_write,
-};
-
 struct nvmem_device *nvmem_partition_register(struct cdev *cdev)
 {
 	struct nvmem_config config = {};
@@ -34,7 +29,8 @@ struct nvmem_device *nvmem_partition_register(struct cdev *cdev)
 	config.stride = 1;
 	config.word_size = 1;
 	config.size = cdev->size;
-	config.bus = &nvmem_cdev_bus;
+	config.reg_read = nvmem_cdev_read;
+	config.reg_write = nvmem_cdev_write;
 
 	return nvmem_register(&config);
 }
diff --git a/drivers/nvmem/rave-sp-eeprom.c b/drivers/nvmem/rave-sp-eeprom.c
index 2345b24936be..26367a02de17 100644
--- a/drivers/nvmem/rave-sp-eeprom.c
+++ b/drivers/nvmem/rave-sp-eeprom.c
@@ -280,11 +280,6 @@ static int rave_sp_eeprom_write(void *ctx, unsigned offset, const void *val, siz
 				     offset, (void *)val, bytes);
 }
 
-static const struct nvmem_bus rave_sp_eeprom_nvmem_bus = {
-	.write = rave_sp_eeprom_write,
-	.read  = rave_sp_eeprom_read,
-};
-
 static int rave_sp_eeprom_probe(struct device_d *dev)
 {
 	struct rave_sp *sp = dev->parent->priv;
@@ -329,7 +324,8 @@ static int rave_sp_eeprom_probe(struct device_d *dev)
 	config.word_size = 1;
 	config.stride    = 1;
 	config.size      = reg[1];
-	config.bus       = &rave_sp_eeprom_nvmem_bus;
+	config.reg_write = rave_sp_eeprom_write;
+	config.reg_read  = rave_sp_eeprom_read;
 
 	nvmem = nvmem_register(&config);
 	if (IS_ERR(nvmem)) {
diff --git a/drivers/nvmem/regmap.c b/drivers/nvmem/regmap.c
index 56611819a2b4..3c33a8aa75a8 100644
--- a/drivers/nvmem/regmap.c
+++ b/drivers/nvmem/regmap.c
@@ -53,11 +53,6 @@ static int nvmem_regmap_read(void *ctx, unsigned offset, void *buf, size_t bytes
 	return 0;
 }
 
-static struct nvmem_bus nvmem_regmap_bus = {
-	.read = nvmem_regmap_read,
-	.write = nvmem_regmap_write,
-};
-
 struct nvmem_device *nvmem_regmap_register(struct regmap *map, const char *name)
 {
 	struct nvmem_config config = {};
@@ -72,7 +67,8 @@ struct nvmem_device *nvmem_regmap_register(struct regmap *map, const char *name)
 	config.stride = 1;
 	config.word_size = 1;
 	config.size = regmap_get_max_register(map) * regmap_get_reg_stride(map);
-	config.bus = &nvmem_regmap_bus;
+	config.reg_read = nvmem_regmap_read;
+	config.reg_write = nvmem_regmap_write;
 
 	return nvmem_register(&config);
 }
diff --git a/drivers/nvmem/rmem.c b/drivers/nvmem/rmem.c
index cd735e5ef39d..e0b9bd6d39f7 100644
--- a/drivers/nvmem/rmem.c
+++ b/drivers/nvmem/rmem.c
@@ -21,10 +21,6 @@ static int rmem_read(void *context, unsigned int offset,
 			bytes, offset, 0);
 }
 
-static struct nvmem_bus rmem_nvmem_bus = {
-	.read = rmem_read,
-};
-
 static int rmem_probe(struct device_d *dev)
 {
 	struct nvmem_config config = { };
@@ -45,7 +41,7 @@ static int rmem_probe(struct device_d *dev)
 	config.priv = priv;
 	config.name = "rmem";
 	config.size = resource_size(mem);
-	config.bus = &rmem_nvmem_bus;
+	config.reg_read = rmem_read;
 
 	return PTR_ERR_OR_ZERO(nvmem_register(&config));
 }
diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c
index ddfc15e1479a..767ce0d17f61 100644
--- a/drivers/nvmem/snvs_lpgpr.c
+++ b/drivers/nvmem/snvs_lpgpr.c
@@ -73,11 +73,6 @@ static int snvs_lpgpr_read(void *ctx, unsigned offset, void *val, size_t bytes)
 				val, bytes);
 }
 
-static const struct nvmem_bus snvs_lpgpr_nvmem_bus = {
-	.write = snvs_lpgpr_write,
-	.read  = snvs_lpgpr_read,
-};
-
 static int snvs_lpgpr_probe(struct device_d *dev)
 {
 	struct device_node *node = dev->device_node;
@@ -112,7 +107,8 @@ static int snvs_lpgpr_probe(struct device_d *dev)
 	cfg->stride = 4;
 	cfg->word_size = 4;
 	cfg->size = 4;
-	cfg->bus = &snvs_lpgpr_nvmem_bus;
+	cfg->bus.reg_write = snvs_lpgpr_write;
+	cfg->bus.reg_read  = snvs_lpgpr_read;
 
 	nvmem = nvmem_register(cfg);
 	if (IS_ERR(nvmem)) {
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 297fdc17b986..01d3b26aa2b6 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -529,17 +529,13 @@ static int nvstore_read(void *ctx, unsigned reg, void *val, size_t bytes)
 	return 0;
 }
 
-static struct nvmem_bus nvstore_nvmem_bus = {
-	.write = nvstore_write,
-	.read  = nvstore_read,
-};
-
 static struct nvmem_config nvstore_nvmem_config = {
 	.name = "nvstore",
 	.stride = 4,
 	.word_size = 4,
 	.size = 4,
-	.bus = &nvstore_nvmem_bus,
+	.reg_write = nvstore_write,
+	.reg_read = nvstore_read,
 };
 
 static int __init dryice_rtc_probe(struct device_d *dev)
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index a293f60c1ef3..560c78ded376 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -17,11 +17,6 @@
 
 struct nvmem_device;
 
-struct nvmem_bus {
-	int (*write)(void *ctx, unsigned int reg, const void *val, size_t val_size);
-	int (*read)(void *ctx, unsigned int reg, void *val, size_t val_size);
-};
-
 struct nvmem_config {
 	struct device_d		*dev;
 	const char		*name;
@@ -30,7 +25,10 @@ struct nvmem_config {
 	int			stride;
 	int			word_size;
 	int			size;
-	const struct nvmem_bus	*bus;
+	int			(*reg_write)(void *ctx, unsigned int reg,
+					     const void *val, size_t val_size);
+	int			(*reg_read)(void *ctx, unsigned int reg,
+					    void *val, size_t val_size);
 	void			*priv;
 };
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Fri Jan 14 00:54:25 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:54:25 +0100
Subject: [PATCH v2] i2c: add Rockchip i2c controller support
Message-ID: <20220114085425.315113-1-a.fatoum@pengutronix.de>

For addressing the PMIC on Rockchip platforms, add an i2c controller
driver. Tested with rk3399 and rk808.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - remove unneeded udelay(1)s (Sascha)
  - use readl_poll_timeout
  - fix typos, copy-paste leftovers (Sascha)
  - early exit on NAK (Sascha)
---
 drivers/i2c/busses/Kconfig        |   8 +
 drivers/i2c/busses/Makefile       |   1 +
 drivers/i2c/busses/i2c-rockchip.c | 458 ++++++++++++++++++++++++++++++
 3 files changed, 467 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-rockchip.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c1e76a04096e..a551df537a69 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -62,4 +62,12 @@ config I2C_STM32
 	depends on HAVE_CLK
 	depends on ARCH_STM32MP || COMPILE_TEST
 
+config I2C_RK3X
+	tristate "Rockchip RK3xxx I2C adapter"
+	depends on HAVE_CLK
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	help
+	  Say Y here to include support for the I2C adapter in Rockchip RK3xxx
+	  SoCs.
+
 endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 34a12fcbea96..d6273f3d8679 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
 obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o
 obj-$(CONFIG_I2C_STM32)		+= i2c-stm32.o
+obj-$(CONFIG_I2C_RK3X)		+= i2c-rockchip.o
diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
new file mode 100644
index 000000000000..4990735a4b11
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rockchip.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ * Peter, Software Engineering, <superpeter.cai at gmail.com>.
+ */
+
+#include <common.h>
+#include <i2c/i2c.h>
+#include <linux/iopoll.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <driver.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+#include <linux/sizes.h>
+
+struct i2c_regs {
+	u32 con;
+	u32 clkdiv;
+	u32 mrxaddr;
+	u32 mrxraddr;
+	u32 mtxcnt;
+	u32 mrxcnt;
+	u32 ien;
+	u32 ipd;
+	u32 fcnt;
+	u32 reserved0[0x37];
+	u32 txdata[8];
+	u32 reserved1[0x38];
+	u32 rxdata[8];
+};
+
+/* Control register */
+#define I2C_CON_EN		(1 << 0)
+#define I2C_CON_MOD(mod)	((mod) << 1)
+#define I2C_MODE_TX		0x00
+#define I2C_MODE_TRX		0x01
+#define I2C_MODE_RX		0x02
+#define I2C_MODE_RRX		0x03
+#define I2C_CON_MASK		(3 << 1)
+
+#define I2C_CON_START		(1 << 3)
+#define I2C_CON_STOP		(1 << 4)
+#define I2C_CON_LASTACK		(1 << 5)
+#define I2C_CON_ACTACK		(1 << 6)
+
+/* Clock divider register */
+#define I2C_CLKDIV_VAL(divl, divh) \
+	(((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))
+
+/* the slave address accessed  for master rx mode */
+#define I2C_MRXADDR_SET(vld, addr)	(((vld) << 24) | (addr))
+
+/* the slave register address accessed  for master rx mode */
+#define I2C_MRXRADDR_SET(vld, raddr)	(((vld) << 24) | (raddr))
+
+/* interrupt enable register */
+#define I2C_BTFIEN		(1 << 0)
+#define I2C_BRFIEN		(1 << 1)
+#define I2C_MBTFIEN		(1 << 2)
+#define I2C_MBRFIEN		(1 << 3)
+#define I2C_STARTIEN		(1 << 4)
+#define I2C_STOPIEN		(1 << 5)
+#define I2C_NAKRCVIEN		(1 << 6)
+
+/* interrupt pending register */
+#define I2C_BTFIPD              (1 << 0)
+#define I2C_BRFIPD              (1 << 1)
+#define I2C_MBTFIPD             (1 << 2)
+#define I2C_MBRFIPD             (1 << 3)
+#define I2C_STARTIPD            (1 << 4)
+#define I2C_STOPIPD             (1 << 5)
+#define I2C_NAKRCVIPD           (1 << 6)
+#define I2C_IPD_ALL_CLEAN       0x7f
+
+/* i2c timeout */
+#define I2C_TIMEOUT_US		(100 * USEC_PER_MSEC)
+
+/* rk i2c fifo max transfer bytes */
+#define RK_I2C_FIFO_SIZE	32
+
+struct rk_i2c {
+	struct i2c_adapter	adapter;
+	struct clk *clk;
+	struct i2c_regs *regs;
+	unsigned int speed;
+};
+
+static inline struct rk_i2c *to_rk_i2c(struct i2c_adapter *adapter)
+{
+	return container_of(adapter, struct rk_i2c, adapter);
+}
+
+static inline void rk_i2c_get_div(int div, int *divh, int *divl)
+{
+	*divl = div / 2;
+	*divh = DIV_ROUND_UP(div, 2);
+}
+
+/*
+ * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
+ * SCL = PCLK / SCLK Divisor
+ * i2c_rate = PCLK
+ */
+static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
+{
+	struct device_d *dev = i2c->adapter.dev.parent;
+	uint32_t i2c_rate;
+	int div, divl, divh;
+
+	/* First get i2c rate from pclk */
+	i2c_rate = clk_get_rate(i2c->clk);
+
+	div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
+	divh = 0;
+	divl = 0;
+	if (div >= 0)
+		rk_i2c_get_div(div, &divh, &divl);
+	writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
+
+	dev_dbg(dev, "rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
+		scl_rate);
+	dev_dbg(dev, "set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
+	dev_dbg(dev, "set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
+}
+
+static void rk_i2c_show_regs(struct rk_i2c *i2c)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	int i;
+
+	dev_dbg(dev, "i2c_con: 0x%08x\n", readl(&regs->con));
+	dev_dbg(dev, "i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
+	dev_dbg(dev, "i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
+	dev_dbg(dev, "i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
+	dev_dbg(dev, "i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
+	dev_dbg(dev, "i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
+	dev_dbg(dev, "i2c_ien: 0x%08x\n", readl(&regs->ien));
+	dev_dbg(dev, "i2c_ipd: 0x%08x\n", readl(&regs->ipd));
+	dev_dbg(dev, "i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
+
+	for (i = 0; i < 8; i++)
+		dev_dbg(dev, "i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
+	for (i = 0; i < 8; i++)
+		dev_dbg(dev, "i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
+}
+
+static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	u32 val;
+	int err;
+
+	dev_dbg(dev, "I2c Send Start bit.\n");
+	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
+
+	writel(I2C_CON_EN | I2C_CON_START, &regs->con);
+	writel(I2C_STARTIEN, &regs->ien);
+
+	err = readl_poll_timeout(&regs->ipd, val, val & I2C_STARTIPD, I2C_TIMEOUT_US);
+	if (err) {
+		dev_dbg(dev, "I2C Send Start Bit Timeout\n");
+		rk_i2c_show_regs(i2c);
+		return err;
+	}
+
+	writel(I2C_STARTIPD, &regs->ipd);
+	return 0;
+}
+
+static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	u32 val;
+	int err;
+
+	dev_dbg(dev, "I2c Send Stop bit.\n");
+	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
+
+	writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
+	writel(I2C_CON_STOP, &regs->ien);
+
+	err = readl_poll_timeout(&regs->ipd, val, val & I2C_STOPIPD, I2C_TIMEOUT_US);
+	if (err) {
+		dev_dbg(dev, "I2C Send Start Bit Timeout\n");
+		rk_i2c_show_regs(i2c);
+		return err;
+	}
+
+	writel(I2C_STOPIPD, &regs->ipd);
+	return 0;
+}
+
+static inline void rk_i2c_disable(struct rk_i2c *i2c)
+{
+	writel(0, &i2c->regs->con);
+}
+
+static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
+		       uchar *buf, uint b_len)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	uchar *pbuf = buf;
+	uint bytes_remain_len = b_len;
+	uint bytes_xferred = 0;
+	uint words_xferred = 0;
+	uint con = 0;
+	uint rxdata;
+	uint i, j;
+	int err;
+	u32 val;
+	bool snd_chunk = false;
+
+	dev_dbg(dev, "rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
+	      chip, reg, r_len, b_len);
+
+	err = rk_i2c_send_start_bit(i2c);
+	if (err)
+		return err;
+
+	writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
+	if (r_len == 0) {
+		writel(0, &regs->mrxraddr);
+	} else if (r_len < 4) {
+		writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
+	} else {
+		dev_dbg(dev, "I2C Read: addr len %d not supported\n", r_len);
+		return -EIO;
+	}
+
+	while (bytes_remain_len) {
+		if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
+			con = I2C_CON_EN;
+			bytes_xferred = RK_I2C_FIFO_SIZE;
+		} else {
+			/*
+			 * The hw can read up to 32 bytes at a time. If we need
+			 * more than one chunk, send an ACK after the last byte.
+			 */
+			con = I2C_CON_EN | I2C_CON_LASTACK;
+			bytes_xferred = bytes_remain_len;
+		}
+		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
+
+		/*
+		 * make sure we are in plain RX mode if we read a second chunk
+		 */
+		if (snd_chunk)
+			con |= I2C_CON_MOD(I2C_MODE_RX);
+		else
+			con |= I2C_CON_MOD(I2C_MODE_TRX);
+
+		writel(con, &regs->con);
+		writel(bytes_xferred, &regs->mrxcnt);
+		writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
+
+		err = readl_poll_timeout(&regs->ipd, val, val & (I2C_NAKRCVIPD|I2C_MBRFIPD), I2C_TIMEOUT_US);
+		if (err) {
+			dev_dbg(dev, "I2C Read Data Timeout\n");
+			goto i2c_exit;
+		}
+
+		if (val & I2C_NAKRCVIPD) {
+			writel(I2C_NAKRCVIPD, &regs->ipd);
+			err = -EREMOTEIO;
+			goto i2c_exit;
+		}
+
+		writel(I2C_MBRFIPD, &regs->ipd);
+
+		for (i = 0; i < words_xferred; i++) {
+			rxdata = readl(&regs->rxdata[i]);
+			dev_dbg(dev, "I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
+			for (j = 0; j < 4; j++) {
+				if ((i * 4 + j) == bytes_xferred)
+					break;
+				*pbuf++ = (rxdata >> (j * 8)) & 0xff;
+			}
+		}
+
+		bytes_remain_len -= bytes_xferred;
+		snd_chunk = true;
+		dev_dbg(dev, "I2C Read bytes_remain_len %d\n", bytes_remain_len);
+	}
+
+i2c_exit:
+	if (err)
+		rk_i2c_show_regs(i2c);
+	rk_i2c_disable(i2c);
+
+	return err;
+}
+
+static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
+			uchar *buf, uint b_len)
+{
+	struct device_d *dev = &i2c->adapter.dev;
+	struct i2c_regs *regs = i2c->regs;
+	u32 val;
+	int err;
+	uchar *pbuf = buf;
+	uint bytes_remain_len = b_len + r_len + 1;
+	uint bytes_xferred = 0;
+	uint words_xferred = 0;
+	uint txdata;
+	uint i, j;
+
+	dev_dbg(dev, "rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
+	      chip, reg, r_len, b_len);
+	err = rk_i2c_send_start_bit(i2c);
+	if (err)
+		return err;
+
+	while (bytes_remain_len) {
+		if (bytes_remain_len > RK_I2C_FIFO_SIZE)
+			bytes_xferred = RK_I2C_FIFO_SIZE;
+		else
+			bytes_xferred = bytes_remain_len;
+		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
+
+		for (i = 0; i < words_xferred; i++) {
+			txdata = 0;
+			for (j = 0; j < 4; j++) {
+				if ((i * 4 + j) == bytes_xferred)
+					break;
+
+				if (i == 0 && j == 0 && pbuf == buf) {
+					txdata |= (chip << 1);
+				} else if (i == 0 && j <= r_len && pbuf == buf) {
+					txdata |= (reg &
+						(0xff << ((j - 1) * 8))) << 8;
+				} else {
+					txdata |= (*pbuf++)<<(j * 8);
+				}
+			}
+			writel(txdata, &regs->txdata[i]);
+			dev_dbg(dev, "I2c Write TXDATA[%d] = 0x%08x\n", i, txdata);
+		}
+
+		writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
+		writel(bytes_xferred, &regs->mtxcnt);
+		writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
+
+		err = readl_poll_timeout(&regs->ipd, val, val & (I2C_NAKRCVIPD|I2C_MBTFIPD), I2C_TIMEOUT_US);
+		if (err) {
+			dev_dbg(dev, "I2C Write Data Timeout\n");
+			goto i2c_exit;
+		}
+
+		if (val & I2C_NAKRCVIPD) {
+			writel(I2C_NAKRCVIPD, &regs->ipd);
+			err = -EREMOTEIO;
+			goto i2c_exit;
+		}
+
+		writel(I2C_MBTFIPD, &regs->ipd);
+
+		bytes_remain_len -= bytes_xferred;
+		dev_dbg(dev, "I2C Write bytes_remain_len %d\n", bytes_remain_len);
+	}
+
+i2c_exit:
+	if (err)
+		rk_i2c_show_regs(i2c);
+	rk_i2c_disable(i2c);
+
+	return err;
+}
+
+static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+			     int nmsgs)
+{
+	struct rk_i2c *i2c = to_rk_i2c(adapter);
+	struct device_d *dev = &adapter->dev;
+	int ret;
+
+	dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+		if (msg->flags & I2C_M_RD) {
+			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
+					  msg->len);
+		} else {
+			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
+					   msg->len);
+		}
+		if (ret) {
+			dev_dbg(dev, "i2c_write: error sending: %pe\n",
+				ERR_PTR(ret));
+			return -EREMOTEIO;
+		}
+	}
+
+	rk_i2c_send_stop_bit(i2c);
+	rk_i2c_disable(i2c);
+
+	return 0;
+}
+
+static int rk_i2c_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	struct resource *iores;
+	struct rk_i2c *i2c;
+	unsigned bitrate;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	i2c = kzalloc(sizeof(struct rk_i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	dev->priv = i2c;
+	i2c->regs = IOMEM(iores->start);
+
+	/* Only one clock to use for bus clock and peripheral clock */
+	i2c->clk = clk_get(dev, NULL);
+	if (IS_ERR(i2c->clk))
+		return dev_err_probe(dev, PTR_ERR(i2c->clk), "Can't get bus clk\n");
+
+	i2c->adapter.master_xfer = rockchip_i2c_xfer;
+	i2c->adapter.nr = dev->id;
+	i2c->adapter.dev.parent = dev;
+	i2c->adapter.dev.device_node = np;
+
+	/* Set up clock divider */
+	bitrate = 100000;
+	of_property_read_u32(np, "clock-frequency", &bitrate);
+
+	rk_i2c_set_clk(i2c, bitrate);
+
+	return i2c_add_numbered_adapter(&i2c->adapter);
+}
+
+static const struct of_device_id rk_i2c_match[] = {
+	{ .compatible = "rockchip,rv1108-i2c" },
+	{ .compatible = "rockchip,rk3228-i2c" },
+	{ .compatible = "rockchip,rk3288-i2c" },
+	{ .compatible = "rockchip,rk3399-i2c" },
+	{},
+};
+
+static struct driver_d rk_i2c_driver = {
+	.name  = "rk3x-i2c",
+	.of_compatible = rk_i2c_match,
+	.probe   = rk_i2c_probe,
+};
+coredevice_platform_driver(rk_i2c_driver);
-- 
2.30.2



From ahmad at a3f.at  Fri Jan 14 00:57:35 2022
From: ahmad at a3f.at (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 09:57:35 +0100
Subject: [PATCH] fixup! of: implement new of_property_sprintf
Message-ID: <20220114085735.731631-1-ahmad@a3f.at>

Otherwise, tools like of_dump will consider the output to be byte
arrays.

Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
---
 drivers/of/base.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 06e37b0fca4a..80465d6d5062 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2285,6 +2285,8 @@ int of_property_sprintf(struct device_node *np,
 	if (len < 0)
 		return -ENOMEM;
 
+	len++; /* trailing NUL */
+
 	pp = of_find_property(np, propname, NULL);
 	of_delete_property(pp);
 
-- 
2.33.0



From a.fatoum at pengutronix.de  Fri Jan 14 01:00:31 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 10:00:31 +0100
Subject: [PATCH 1/5] filetype: Add QOI format image type
In-Reply-To: <20220110221255.5003-2-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
 <20220110221255.5003-2-jmaselbas@kalray.eu>
Message-ID: <7fba581c-019e-7e51-29e9-ce75e60e5945@pengutronix.de>

On 10.01.22 23:12, Jules Maselbas wrote:
> QOI image format is a "Quite OK" image format, it's simplicity is it's
> strength and could be a good replacement of bmp, maybe even for png.
> 
> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>

Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

> ---
>  common/filetype.c  | 3 +++
>  include/filetype.h | 1 +
>  2 files changed, 4 insertions(+)
> 
> diff --git a/common/filetype.c b/common/filetype.c
> index 8ffcd6adcd..e5245668e2 100644
> --- a/common/filetype.c
> +++ b/common/filetype.c
> @@ -45,6 +45,7 @@ static const struct filetype_str filetype_str[] = {
>  	[filetype_mbr] = { "MBR sector", "mbr" },
>  	[filetype_bmp] = { "BMP image", "bmp" },
>  	[filetype_png] = { "PNG image", "png" },
> +	[filetype_qoi] = { "QOI image", "qoi" },
>  	[filetype_ext] = { "EXT filesystem", "ext" },
>  	[filetype_gpt] = { "GUID Partition Table", "gpt" },
>  	[filetype_ubifs] = { "UBIFS image", "ubifs" },
> @@ -300,6 +301,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
>  		return filetype_aimage;
>  	if (buf64[0] == le64_to_cpu(0x0a1a0a0d474e5089ull))
>  		return filetype_png;
> +	if (strncmp(buf8, "qoif", 4) == 0)
> +		return filetype_qoi;
>  	if (is_barebox_mips_head(_buf))
>  		return filetype_mips_barebox;
>  	if (buf[0] == be32_to_cpu(0x534F4659))
> diff --git a/include/filetype.h b/include/filetype.h
> index 2640847e1f..8bc179ac08 100644
> --- a/include/filetype.h
> +++ b/include/filetype.h
> @@ -28,6 +28,7 @@ enum filetype {
>  	filetype_mbr,
>  	filetype_bmp,
>  	filetype_png,
> +	filetype_qoi,
>  	filetype_ext,
>  	filetype_gpt,
>  	filetype_ubifs,
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 01:15:00 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 10:15:00 +0100
Subject: [RFC PATCH] bootsource: add helper to set instance by name
In-Reply-To: <20211117142448.2091017-1-michael.riesch@wolfvision.net>
References: <3fb6debc-4891-c366-94df-0d7c0b80685c@wolfvision.net>
 <20211117142448.2091017-1-michael.riesch@wolfvision.net>
Message-ID: <20220114091500.GA2312@pengutronix.de>

On Wed, Nov 17, 2021 at 03:24:48PM +0100, Michael Riesch wrote:
> Instance numbers should be related to device tree aliases, which may be
> board-specific.

When instance numbers were introduced they were meant to be SoC
specific, i.e. they should correspond to the numbers in the manual.
When starting with device tree aliases the alias numbers were assumed to
match the numbers in the manual. On i.MX this is still mostly true, but
on (most?) other SoCs it is not. In barebox we have several users of
bootsource_get_instance() which rely on the instance being the hardware
instance number, so we can't just change that.

If we have to keep track of both hardware numbers and alias numbers we
have to store both separately and not change the meaning of the existing
instance number.

Thinking this further I don't think the alias is worth anything because
it may differ between the barebox internal device tree and the one the
kernel is booted with. We should rather store the device node providing
the bootsource. From that we can retrieve the alias matching a given
device tree if we still need it.

That said, I don't know a good way how we get there from our existing
codebase.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 01:21:28 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 10:21:28 +0100
Subject: [PATCH 1/3] ARM: rockchip: add new ARCH_ROCKCHIP_{V7,V8} symbols
In-Reply-To: <20220114083825.726347-1-ahmad@a3f.at>
References: <20220114083825.726347-1-ahmad@a3f.at>
Message-ID: <20220114092128.GT26619@pengutronix.de>

On Fri, Jan 14, 2022 at 09:38:23AM +0100, Ahmad Fatoum wrote:
> In preparation for adding rk3399 support, which is another SoC with
> ARMv8 CPUs, add new ARCH_ROCKCHIP_{V7,V8} symbols for the common
> functionality.
> 
> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
> ---
>  arch/arm/mach-rockchip/Kconfig  | 18 ++++++++++++------
>  arch/arm/mach-rockchip/Makefile |  5 +++--
>  2 files changed, 15 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
> index 2e855714f7da..596de663f9e3 100644
> --- a/arch/arm/mach-rockchip/Kconfig
> +++ b/arch/arm/mach-rockchip/Kconfig
> @@ -12,24 +12,30 @@ config RK_TIMER
>  	hex
>  	default 1
>  
> -config ARCH_RK3188
> +config ARCH_ROCKCHIP_V7
>  	bool
>  	select CPU_V7
>  	select ARM_SMP_TWD
>  	select ARCH_HAS_L2X0
>  
> +config ARCH_RK3188
> +	bool
> +	select ARCH_ROCKCHIP_V7
> +
>  config ARCH_RK3288
>  	bool
> -	select CPU_V7
> -	select ARM_SMP_TWD
> -	select ARCH_HAS_L2X0
> +	select ARCH_ROCKCHIP_V7
>  	select CLOCKSOURCE_ROCKCHIP
>  
> -config ARCH_RK3568
> +config ARCH_ROCKCHIP_V8
>  	bool
>  	select CPU_V8
> -	select ARM_ATF
>  	select SYS_SUPPORTS_64BIT_KERNEL
> +	select ARM_ATF
> +
> +config ARCH_RK3568
> +	bool
> +	select ARCH_ROCKCHIP_V8
>  
>  comment "select Rockchip boards:"
>  
> diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
> index 72bf77c1e124..474b8629d13f 100644
> --- a/arch/arm/mach-rockchip/Makefile
> +++ b/arch/arm/mach-rockchip/Makefile
> @@ -1,9 +1,10 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  
>  obj-y += rockchip.o
> -pbl-$(CONFIG_ARCH_RK3568) += atf.o
> +pbl-$(CONFIG_ARCH_ROCKCHIP_V8) += atf.o
>  obj-$(CONFIG_ARCH_RK3188) += rk3188.o
>  obj-$(CONFIG_ARCH_RK3288) += rk3288.o
> +obj-pbl-$(CONFIG_ARCH_RK3399) += rk3399.o

We don't have this yet, removed this hunk while applying.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 01:29:02 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 10:29:02 +0100
Subject: [PATCH v2 1/3] ARM: implement ENTRY_FUNCTION_WITHSTACK
In-Reply-To: <20220114084227.308804-1-a.fatoum@pengutronix.de>
References: <20220114084227.308804-1-a.fatoum@pengutronix.de>
Message-ID: <20220114092902.GU26619@pengutronix.de>

On Fri, Jan 14, 2022 at 09:42:25AM +0100, Ahmad Fatoum wrote:
> The point of ENTRY_FUNCTION is to write the entry point in C. Due to
> lack of __naked on ARM64, the start of the entry point will have prologue
> using stack and it's not possible to set up the stack safely without
> branching into non-inline assembly[0]. On ARM32, where we got __naked, we
> have the potential for a different problem: If BootROM sets up stack for
> us and we branch to a naked function, which doesn't set up its own
> stack, compiler may decide to spill local variables overwriting
> instructions it had already run[1].
> 
> For code reuse between ARM and ARM64, it would be nice to use the same
> entry point structure for both. Currently, the only way is to write it
> in non-inline assembly using the ENTRY_PROC macro.
> 
> This introduces another way: the ARM64 barebox header has enough space
> for 8 instructions of which 5 are unused (2 instructions compiler prologue
> + 1 instruction to jump after the header), we could place a stack setup
> routine there to avoid having to write a separate assembly file.
> For ARM32, we just call arm_setup_stack and branch out directly after,
> freeing board porters of the burden of getting it right.
> 
> Add a new ENTRY_FUNCTION_WITHSTACK to realize this.
> 
> [0]: 76bced6fe146 ("ARM: document arm_setup_stack() pitfalls"),
> [1]: b51b15ba1738 ("RISC-V: board-dt-2nd: move low level init into nonnaked function")
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> v1 -> v2:
>  - add __ARM_SETUP_STACK(0) to normal ENTRY_FUNCTION. On ARM32, it's a
>    no-op, but on ARM64, it ensures the header isn't shifted
> ---
>  arch/arm/include/asm/barebox-arm-head.h |  6 +---
>  arch/arm/include/asm/barebox-arm.h      | 46 +++++++++++++++++++++++++
>  arch/arm/lib/pbl.lds.S                  |  1 +
>  3 files changed, 48 insertions(+), 5 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 01:33:11 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 10:33:11 +0100
Subject: [PATCH 1/2] pinctrl: rockchip: use alias rather than full of name
In-Reply-To: <20220114084757.311697-1-a.fatoum@pengutronix.de>
References: <20220114084757.311697-1-a.fatoum@pengutronix.de>
Message-ID: <20220114093311.GV26619@pengutronix.de>

On Fri, Jan 14, 2022 at 09:47:56AM +0100, Ahmad Fatoum wrote:
> From: Michael Riesch <michael.riesch at wolfvision.net>
> 
> We've so far relied on GPIO controllers being named "gpioX", while the
> binding mandates gpio controllers being just called "gpio". This already
> broke rk3288 support and rk3568.dtsi upstream also differs from the
> version in barebox' arch/arm/dts in that regard.
> 
> Instead, do like Linux does and use the alias to match the controllers to
> the GPIO banks with a fallback to probe order.
> 
> Fixes: 3f2f5980d517 ("dts: update to v5.16-rc1")
> Signed-off-by: Michael Riesch <michael.riesch at wolfvision.net>
> [afa: drop strncmp in favor of id comparison, reword commit message]
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)

Applied to master, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Fri Jan 14 01:33:25 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 10:33:25 +0100
Subject: [PATCH 1/3] ARM: rockchip: add new ARCH_ROCKCHIP_{V7,V8} symbols
In-Reply-To: <20220114092128.GT26619@pengutronix.de>
References: <20220114083825.726347-1-ahmad@a3f.at>
 <20220114092128.GT26619@pengutronix.de>
Message-ID: <176bb9ec-8382-de2e-5109-17d519730aa8@pengutronix.de>

On 14.01.22 10:21, Sascha Hauer wrote:
> On Fri, Jan 14, 2022 at 09:38:23AM +0100, Ahmad Fatoum wrote:
>> In preparation for adding rk3399 support, which is another SoC with
>> ARMv8 CPUs, add new ARCH_ROCKCHIP_{V7,V8} symbols for the common
>> functionality.
>>
>> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
>> ---
>>  arch/arm/mach-rockchip/Kconfig  | 18 ++++++++++++------
>>  arch/arm/mach-rockchip/Makefile |  5 +++--
>>  2 files changed, 15 insertions(+), 8 deletions(-)
>>
>> diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
>> index 2e855714f7da..596de663f9e3 100644
>> --- a/arch/arm/mach-rockchip/Kconfig
>> +++ b/arch/arm/mach-rockchip/Kconfig
>> @@ -12,24 +12,30 @@ config RK_TIMER
>>  	hex
>>  	default 1
>>  
>> -config ARCH_RK3188
>> +config ARCH_ROCKCHIP_V7
>>  	bool
>>  	select CPU_V7
>>  	select ARM_SMP_TWD
>>  	select ARCH_HAS_L2X0
>>  
>> +config ARCH_RK3188
>> +	bool
>> +	select ARCH_ROCKCHIP_V7
>> +
>>  config ARCH_RK3288
>>  	bool
>> -	select CPU_V7
>> -	select ARM_SMP_TWD
>> -	select ARCH_HAS_L2X0
>> +	select ARCH_ROCKCHIP_V7
>>  	select CLOCKSOURCE_ROCKCHIP
>>  
>> -config ARCH_RK3568
>> +config ARCH_ROCKCHIP_V8
>>  	bool
>>  	select CPU_V8
>> -	select ARM_ATF
>>  	select SYS_SUPPORTS_64BIT_KERNEL
>> +	select ARM_ATF
>> +
>> +config ARCH_RK3568
>> +	bool
>> +	select ARCH_ROCKCHIP_V8
>>  
>>  comment "select Rockchip boards:"
>>  
>> diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
>> index 72bf77c1e124..474b8629d13f 100644
>> --- a/arch/arm/mach-rockchip/Makefile
>> +++ b/arch/arm/mach-rockchip/Makefile
>> @@ -1,9 +1,10 @@
>>  # SPDX-License-Identifier: GPL-2.0-only
>>  
>>  obj-y += rockchip.o
>> -pbl-$(CONFIG_ARCH_RK3568) += atf.o
>> +pbl-$(CONFIG_ARCH_ROCKCHIP_V8) += atf.o
>>  obj-$(CONFIG_ARCH_RK3188) += rk3188.o
>>  obj-$(CONFIG_ARCH_RK3288) += rk3288.o
>> +obj-pbl-$(CONFIG_ARCH_RK3399) += rk3399.o
> 
> We don't have this yet, removed this hunk while applying.

Thanks, missed that during the rebase. I want to polish that
a bit before sending out in the following weeks.

Thanks,
Ahmad

> 
> Sascha
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Fri Jan 14 02:05:15 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 11:05:15 +0100
Subject: [PATCH 2/5] gui: Add qoi image format
In-Reply-To: <20220110221255.5003-3-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
 <20220110221255.5003-3-jmaselbas@kalray.eu>
Message-ID: <0ca90254-a1d1-7151-0236-4dd92ee4d620@pengutronix.de>

On 10.01.22 23:12, Jules Maselbas wrote:

Could you add a link there the project is from, what version
you're importing. Perhaps how to update them in the future?
(Do we touch the header, or is it just some macros we define
outside).

> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> ---
>  lib/gui/Kconfig  |   5 +
>  lib/gui/Makefile |   1 +
>  lib/gui/qoi.c    |  94 +++++++
>  lib/gui/qoi.h    | 671 +++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 771 insertions(+)
>  create mode 100644 lib/gui/qoi.c
>  create mode 100644 lib/gui/qoi.h
> 
> diff --git a/lib/gui/Kconfig b/lib/gui/Kconfig
> index 2625d9fb2f..f0263c71cc 100644
> --- a/lib/gui/Kconfig
> +++ b/lib/gui/Kconfig
> @@ -16,6 +16,11 @@ config PNG
>  	bool "png"
>  	select ZLIB
>  
> +config QOI
> +	bool "qoi"
> +	help
> +	  Support for the Quite OK Image format
> +
>  if PNG
>  
>  choice
> diff --git a/lib/gui/Makefile b/lib/gui/Makefile
> index 31e66225d7..5ed190e9f8 100644
> --- a/lib/gui/Makefile
> +++ b/lib/gui/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_BMP)	+= bmp.o
>  obj-$(CONFIG_IMAGE_RENDERER)	+= image_renderer.o graphic_utils.o
> +obj-$(CONFIG_QOI)	+= qoi.o
>  obj-$(CONFIG_PNG)	+= png.o
>  obj-$(CONFIG_LODEPNG)	+= png_lode.o lodepng.o
>  obj-$(CONFIG_PICOPNG)	+= png_pico.o picopng.o
> diff --git a/lib/gui/qoi.c b/lib/gui/qoi.c
> new file mode 100644
> index 0000000000..f6c1bc1b94
> --- /dev/null
> +++ b/lib/gui/qoi.c

License statement missing.

> @@ -0,0 +1,94 @@
> +#include <common.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <fb.h>
> +#include <asm/byteorder.h>
> +#include <gui/graphic_utils.h>
> +#include <init.h>
> +#include <gui/image_renderer.h>
> +#include <asm/unaligned.h>
> +
> +#define QOI_NO_STDIO
> +#define QOI_IMPLEMENTATION
> +#include "qoi.h"
> +
> +static struct image *qoi_open(char *inbuf, int insize)
> +{
> +	struct image *img;
> +	void *data;
> +	qoi_desc qoi;
> +
> +	img = calloc(1, sizeof(*img));
> +	if (!img)
> +		return ERR_PTR(-ENOMEM);
> +
> +	data = qoi_decode(inbuf, insize, &qoi, 0);
> +	if (!data) {
> +		free(img);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	img->data = data;
> +	img->height = qoi.height;
> +	img->width = qoi.width;
> +	img->bits_per_pixel = qoi.channels * 8;
> +
> +	pr_debug("qoi: %d x %d  x %d data at 0x%p\n", img->width, img->height,
> +		 img->bits_per_pixel, img->data);

Nitpick: You can define a common prefix
with pr_fmt at the top of the file, e.g

#define pr_fmt(fmt) "qoi: " fmt

> +	return img;
> +}
> +
> +static void qoi_close(struct image *img)
> +{
> +	free(img->data);

Curious API that open() is allocating, but close's caller is
the one resposible for freeing. Should probably be fixed up.

> +}
> +
> +static int qoi_renderer(struct screen *sc, struct surface *s, struct image *img)
> +{
> +	int alpha = img->bits_per_pixel == (4 * 8);
> +	int width = s->width;
> +	int height = s->height;
> +	int startx = s->x;
> +	int starty = s->y;
> +	void *buf;
> +
> +	if (s->width < 0)
> +		width = img->width;
> +	if (s->height < 0)
> +		height = img->height;
> +
> +	if (startx < 0) {
> +		startx = (sc->s.width - width) / 2;
> +		if (startx < 0)
> +			startx = 0;
> +	}
> +
> +	if (starty < 0) {
> +		starty = (sc->s.height - height) / 2;
> +		if (starty < 0)
> +			starty = 0;
> +	}
> +
> +	width = min(width, sc->s.width - startx);
> +	height = min(height, sc->s.height - starty);
> +
> +	buf = gui_screen_render_buffer(sc);
> +
> +	gu_rgba_blend(sc->info, img, buf, height, width, startx, starty, alpha);
> +
> +	return img->height;
> +}
> +
> +static struct image_renderer qoi = {
> +	.type = filetype_qoi,
> +	.open = qoi_open,
> +	.close = qoi_close,
> +	.renderer = qoi_renderer,
> +	.keep_file_data = 1,

Do you really need this? For bmp, it makes sense, because the pixel data isn't
compressed, so there are direct pointers into it. But if you uncompress into a
newly allocated buffer, you should not need to keep (and leak) inbuf's content

> +};
> +
> +static int qoi_init(void)
> +{
> +	return image_renderer_register(&qoi);
> +}
> +fs_initcall(qoi_init);
> diff --git a/lib/gui/qoi.h b/lib/gui/qoi.h
> new file mode 100644
> index 0000000000..988f9edcb4
> --- /dev/null
> +++ b/lib/gui/qoi.h
> @@ -0,0 +1,671 @@
> +/*
> +
> +QOI - The "Quite OK Image" format for fast, lossless image compression
> +
> +Dominic Szablewski - https://phoboslab.org
> +
> +
> +-- LICENSE: The MIT License(MIT)

Can you turn this into a SPDX-License-Identifier: please?

> +
> +Copyright(c) 2021 Dominic Szablewski
> +
> +Permission is hereby granted, free of charge, to any person obtaining a copy of
> +this software and associated documentation files(the "Software"), to deal in
> +the Software without restriction, including without limitation the rights to
> +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
> +of the Software, and to permit persons to whom the Software is furnished to do
> +so, subject to the following conditions :
> +The above copyright notice and this permission notice shall be included in all
> +copies or substantial portions of the Software.
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> +SOFTWARE.
> +
> +
> +-- About
> +
> +QOI encodes and decodes images in a lossless format. Compared to stb_image and
> +stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and
> +20% better compression.
> +
> +
> +-- Synopsis
> +
> +// Define `QOI_IMPLEMENTATION` in *one* C/C++ file before including this
> +// library to create the implementation.
> +
> +#define QOI_IMPLEMENTATION
> +#include "qoi.h"
> +
> +// Encode and store an RGBA buffer to the file system. The qoi_desc describes
> +// the input pixel data.
> +qoi_write("image_new.qoi", rgba_pixels, &(qoi_desc){
> +	.width = 1920,
> +	.height = 1080,
> +	.channels = 4,
> +	.colorspace = QOI_SRGB
> +});
> +
> +// Load and decode a QOI image from the file system into a 32bbp RGBA buffer.
> +// The qoi_desc struct will be filled with the width, height, number of channels
> +// and colorspace read from the file header.
> +qoi_desc desc;
> +void *rgba_pixels = qoi_read("image.qoi", &desc, 4);
> +
> +
> +
> +-- Documentation
> +
> +This library provides the following functions;
> +- qoi_read    -- read and decode a QOI file
> +- qoi_decode  -- decode the raw bytes of a QOI image from memory
> +- qoi_write   -- encode and write a QOI file
> +- qoi_encode  -- encode an rgba buffer into a QOI image in memory
> +
> +See the function declaration below for the signature and more information.
> +
> +If you don't want/need the qoi_read and qoi_write functions, you can define
> +QOI_NO_STDIO before including this library.
> +
> +This library uses malloc() and free(). To supply your own malloc implementation
> +you can define QOI_MALLOC and QOI_FREE before including this library.
> +
> +This library uses memset() to zero-initialize the index. To supply your own
> +implementation you can define QOI_ZEROARR before including this library.
> +
> +
> +-- Data Format
> +
> +A QOI file has a 14 byte header, followed by any number of data "chunks" and an
> +8-byte end marker.
> +
> +struct qoi_header_t {
> +	char     magic[4];   // magic bytes "qoif"
> +	uint32_t width;      // image width in pixels (BE)
> +	uint32_t height;     // image height in pixels (BE)
> +	uint8_t  channels;   // 3 = RGB, 4 = RGBA
> +	uint8_t  colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
> +};
> +
> +Images are encoded row by row, left to right, top to bottom. The decoder and
> +encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An
> +image is complete when all pixels specified by width * height have been covered.
> +
> +Pixels are encoded as
> + - a run of the previous pixel
> + - an index into an array of previously seen pixels
> + - a difference to the previous pixel value in r,g,b
> + - full r,g,b or r,g,b,a values
> +
> +The color channels are assumed to not be premultiplied with the alpha channel
> +("un-premultiplied alpha").
> +
> +A running array[64] (zero-initialized) of previously seen pixel values is
> +maintained by the encoder and decoder. Each pixel that is seen by the encoder
> +and decoder is put into this array at the position formed by a hash function of
> +the color value. In the encoder, if the pixel value at the index matches the
> +current pixel, this index position is written to the stream as QOI_OP_INDEX.
> +The hash function for the index is:
> +
> +	index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64
> +
> +Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The
> +bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All
> +values encoded in these data bits have the most significant bit on the left.
> +
> +The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the
> +presence of an 8-bit tag first.
> +
> +The byte stream's end is marked with 7 0x00 bytes followed a single 0x01 byte.
> +
> +
> +The possible chunks are:
> +
> +
> +.- QOI_OP_INDEX ----------.
> +|         Byte[0]         |
> +|  7  6  5  4  3  2  1  0 |
> +|-------+-----------------|
> +|  0  0 |     index       |
> +`-------------------------`
> +2-bit tag b00
> +6-bit index into the color index array: 0..63
> +
> +A valid encoder must not issue 2 or more consecutive QOI_OP_INDEX chunks to the
> +same index. QOI_OP_RUN should be used instead.
> +
> +
> +.- QOI_OP_DIFF -----------.
> +|         Byte[0]         |
> +|  7  6  5  4  3  2  1  0 |
> +|-------+-----+-----+-----|
> +|  0  1 |  dr |  dg |  db |
> +`-------------------------`
> +2-bit tag b01
> +2-bit   red channel difference from the previous pixel between -2..1
> +2-bit green channel difference from the previous pixel between -2..1
> +2-bit  blue channel difference from the previous pixel between -2..1
> +
> +The difference to the current channel values are using a wraparound operation,
> +so "1 - 2" will result in 255, while "255 + 1" will result in 0.
> +
> +Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
> +0 (b00). 1 is stored as 3 (b11).
> +
> +The alpha value remains unchanged from the previous pixel.
> +
> +
> +.- QOI_OP_LUMA -------------------------------------.
> +|         Byte[0]         |         Byte[1]         |
> +|  7  6  5  4  3  2  1  0 |  7  6  5  4  3  2  1  0 |
> +|-------+-----------------+-------------+-----------|
> +|  1  0 |  green diff     |   dr - dg   |  db - dg  |
> +`---------------------------------------------------`
> +2-bit tag b10
> +6-bit green channel difference from the previous pixel -32..31
> +4-bit   red channel difference minus green channel difference -8..7
> +4-bit  blue channel difference minus green channel difference -8..7
> +
> +The green channel is used to indicate the general direction of change and is
> +encoded in 6 bits. The red and blue channels (dr and db) base their diffs off
> +of the green channel difference and are encoded in 4 bits. I.e.:
> +	dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g)
> +	db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g)
> +
> +The difference to the current channel values are using a wraparound operation,
> +so "10 - 13" will result in 253, while "250 + 7" will result in 1.
> +
> +Values are stored as unsigned integers with a bias of 32 for the green channel
> +and a bias of 8 for the red and blue channel.
> +
> +The alpha value remains unchanged from the previous pixel.
> +
> +
> +.- QOI_OP_RUN ------------.
> +|         Byte[0]         |
> +|  7  6  5  4  3  2  1  0 |
> +|-------+-----------------|
> +|  1  1 |       run       |
> +`-------------------------`
> +2-bit tag b11
> +6-bit run-length repeating the previous pixel: 1..62
> +
> +The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64
> +(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and
> +QOI_OP_RGBA tags.
> +
> +
> +.- QOI_OP_RGB ------------------------------------------.
> +|         Byte[0]         | Byte[1] | Byte[2] | Byte[3] |
> +|  7  6  5  4  3  2  1  0 | 7 .. 0  | 7 .. 0  | 7 .. 0  |
> +|-------------------------+---------+---------+---------|
> +|  1  1  1  1  1  1  1  0 |   red   |  green  |  blue   |
> +`-------------------------------------------------------`
> +8-bit tag b11111110
> +8-bit   red channel value
> +8-bit green channel value
> +8-bit  blue channel value
> +
> +The alpha value remains unchanged from the previous pixel.
> +
> +
> +.- QOI_OP_RGBA ---------------------------------------------------.
> +|         Byte[0]         | Byte[1] | Byte[2] | Byte[3] | Byte[4] |
> +|  7  6  5  4  3  2  1  0 | 7 .. 0  | 7 .. 0  | 7 .. 0  | 7 .. 0  |
> +|-------------------------+---------+---------+---------+---------|
> +|  1  1  1  1  1  1  1  1 |   red   |  green  |  blue   |  alpha  |
> +`-----------------------------------------------------------------`
> +8-bit tag b11111111
> +8-bit   red channel value
> +8-bit green channel value
> +8-bit  blue channel value
> +8-bit alpha channel value
> +
> +*/
> +
> +
> +/* -----------------------------------------------------------------------------
> +Header - Public functions */
> +
> +#ifndef QOI_H
> +#define QOI_H
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
> +It describes either the input format (for qoi_write and qoi_encode), or is
> +filled with the description read from the file header (for qoi_read and
> +qoi_decode).
> +
> +The colorspace in this qoi_desc is an enum where
> +	0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel
> +	1 = all channels are linear
> +You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
> +informative. It will be saved to the file header, but does not affect
> +how chunks are en-/decoded. */
> +
> +#define QOI_SRGB   0
> +#define QOI_LINEAR 1
> +
> +typedef struct {
> +	unsigned int width;
> +	unsigned int height;
> +	unsigned char channels;
> +	unsigned char colorspace;
> +} qoi_desc;
> +
> +#ifndef QOI_NO_STDIO
> +
> +/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file
> +system. The qoi_desc struct must be filled with the image width, height,
> +number of channels (3 = RGB, 4 = RGBA) and the colorspace.
> +
> +The function returns 0 on failure (invalid parameters, or fopen or malloc
> +failed) or the number of bytes written on success. */
> +
> +int qoi_write(const char *filename, const void *data, const qoi_desc *desc);
> +
> +
> +/* Read and decode a QOI image from the file system. If channels is 0, the
> +number of channels from the file header is used. If channels is 3 or 4 the
> +output format will be forced into this number of channels.
> +
> +The function either returns NULL on failure (invalid data, or malloc or fopen
> +failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
> +will be filled with the description from the file header.
> +
> +The returned pixel data should be free()d after use. */
> +
> +void *qoi_read(const char *filename, qoi_desc *desc, int channels);
> +
> +#endif /* QOI_NO_STDIO */
> +
> +
> +/* Encode raw RGB or RGBA pixels into a QOI image in memory.
> +
> +The function either returns NULL on failure (invalid parameters or malloc
> +failed) or a pointer to the encoded data on success. On success the out_len
> +is set to the size in bytes of the encoded data.
> +
> +The returned qoi data should be free()d after use. */
> +
> +void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len);
> +
> +
> +/* Decode a QOI image from memory.
> +
> +The function either returns NULL on failure (invalid parameters or malloc
> +failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
> +is filled with the description from the file header.
> +
> +The returned pixel data should be free()d after use. */
> +
> +void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels);
> +
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +#endif /* QOI_H */
> +
> +
> +/* -----------------------------------------------------------------------------
> +Implementation */
> +
> +#ifdef QOI_IMPLEMENTATION
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#ifndef QOI_MALLOC
> +	#define QOI_MALLOC(sz) malloc(sz)
> +	#define QOI_FREE(p)    free(p)
> +#endif
> +#ifndef QOI_ZEROARR
> +	#define QOI_ZEROARR(a) memset((a),0,sizeof(a))
> +#endif
> +
> +#define QOI_OP_INDEX  0x00 /* 00xxxxxx */
> +#define QOI_OP_DIFF   0x40 /* 01xxxxxx */
> +#define QOI_OP_LUMA   0x80 /* 10xxxxxx */
> +#define QOI_OP_RUN    0xc0 /* 11xxxxxx */
> +#define QOI_OP_RGB    0xfe /* 11111110 */
> +#define QOI_OP_RGBA   0xff /* 11111111 */
> +
> +#define QOI_MASK_2    0xc0 /* 11000000 */
> +
> +#define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11)
> +#define QOI_MAGIC \
> +	(((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \
> +	 ((unsigned int)'i') <<  8 | ((unsigned int)'f'))
> +#define QOI_HEADER_SIZE 14
> +
> +/* 2GB is the max file size that this implementation can safely handle. We guard
> +against anything larger than that, assuming the worst case with 5 bytes per
> +pixel, rounded down to a nice clean value. 400 million pixels ought to be
> +enough for anybody. */
> +#define QOI_PIXELS_MAX ((unsigned int)400000000)
> +
> +typedef union {
> +	struct { unsigned char r, g, b, a; } rgba;
> +	unsigned int v;
> +} qoi_rgba_t;
> +
> +static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1};
> +
> +static void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) {
> +	bytes[(*p)++] = (0xff000000 & v) >> 24;
> +	bytes[(*p)++] = (0x00ff0000 & v) >> 16;
> +	bytes[(*p)++] = (0x0000ff00 & v) >> 8;
> +	bytes[(*p)++] = (0x000000ff & v);
> +}
> +
> +static unsigned int qoi_read_32(const unsigned char *bytes, int *p) {
> +	unsigned int a = bytes[(*p)++];
> +	unsigned int b = bytes[(*p)++];
> +	unsigned int c = bytes[(*p)++];
> +	unsigned int d = bytes[(*p)++];
> +	return a << 24 | b << 16 | c << 8 | d;
> +}
> +
> +void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
> +	int i, max_size, p, run;
> +	int px_len, px_end, px_pos, channels;
> +	unsigned char *bytes;
> +	const unsigned char *pixels;
> +	qoi_rgba_t index[64];
> +	qoi_rgba_t px, px_prev;
> +
> +	if (
> +		data == NULL || out_len == NULL || desc == NULL ||
> +		desc->width == 0 || desc->height == 0 ||
> +		desc->channels < 3 || desc->channels > 4 ||
> +		desc->colorspace > 1 ||
> +		desc->height >= QOI_PIXELS_MAX / desc->width
> +	) {
> +		return NULL;
> +	}
> +
> +	max_size =
> +		desc->width * desc->height * (desc->channels + 1) +
> +		QOI_HEADER_SIZE + sizeof(qoi_padding);
> +
> +	p = 0;
> +	bytes = (unsigned char *) QOI_MALLOC(max_size);
> +	if (!bytes) {
> +		return NULL;
> +	}
> +
> +	qoi_write_32(bytes, &p, QOI_MAGIC);
> +	qoi_write_32(bytes, &p, desc->width);
> +	qoi_write_32(bytes, &p, desc->height);
> +	bytes[p++] = desc->channels;
> +	bytes[p++] = desc->colorspace;
> +
> +
> +	pixels = (const unsigned char *)data;
> +
> +	QOI_ZEROARR(index);
> +
> +	run = 0;
> +	px_prev.rgba.r = 0;
> +	px_prev.rgba.g = 0;
> +	px_prev.rgba.b = 0;
> +	px_prev.rgba.a = 255;
> +	px = px_prev;
> +
> +	px_len = desc->width * desc->height * desc->channels;
> +	px_end = px_len - desc->channels;
> +	channels = desc->channels;
> +
> +	for (px_pos = 0; px_pos < px_len; px_pos += channels) {
> +		if (channels == 4) {
> +			px = *(qoi_rgba_t *)(pixels + px_pos);
> +		}
> +		else {
> +			px.rgba.r = pixels[px_pos + 0];
> +			px.rgba.g = pixels[px_pos + 1];
> +			px.rgba.b = pixels[px_pos + 2];
> +		}
> +
> +		if (px.v == px_prev.v) {
> +			run++;
> +			if (run == 62 || px_pos == px_end) {
> +				bytes[p++] = QOI_OP_RUN | (run - 1);
> +				run = 0;
> +			}
> +		}
> +		else {
> +			int index_pos;
> +
> +			if (run > 0) {
> +				bytes[p++] = QOI_OP_RUN | (run - 1);
> +				run = 0;
> +			}
> +
> +			index_pos = QOI_COLOR_HASH(px) % 64;
> +
> +			if (index[index_pos].v == px.v) {
> +				bytes[p++] = QOI_OP_INDEX | index_pos;
> +			}
> +			else {
> +				index[index_pos] = px;
> +
> +				if (px.rgba.a == px_prev.rgba.a) {
> +					signed char vr = px.rgba.r - px_prev.rgba.r;
> +					signed char vg = px.rgba.g - px_prev.rgba.g;
> +					signed char vb = px.rgba.b - px_prev.rgba.b;
> +
> +					signed char vg_r = vr - vg;
> +					signed char vg_b = vb - vg;
> +
> +					if (
> +						vr > -3 && vr < 2 &&
> +						vg > -3 && vg < 2 &&
> +						vb > -3 && vb < 2
> +					) {
> +						bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2);
> +					}
> +					else if (
> +						vg_r >  -9 && vg_r <  8 &&
> +						vg   > -33 && vg   < 32 &&
> +						vg_b >  -9 && vg_b <  8
> +					) {
> +						bytes[p++] = QOI_OP_LUMA     | (vg   + 32);
> +						bytes[p++] = (vg_r + 8) << 4 | (vg_b +  8);
> +					}
> +					else {
> +						bytes[p++] = QOI_OP_RGB;
> +						bytes[p++] = px.rgba.r;
> +						bytes[p++] = px.rgba.g;
> +						bytes[p++] = px.rgba.b;
> +					}
> +				}
> +				else {
> +					bytes[p++] = QOI_OP_RGBA;
> +					bytes[p++] = px.rgba.r;
> +					bytes[p++] = px.rgba.g;
> +					bytes[p++] = px.rgba.b;
> +					bytes[p++] = px.rgba.a;
> +				}
> +			}
> +		}
> +		px_prev = px;
> +	}
> +
> +	for (i = 0; i < (int)sizeof(qoi_padding); i++) {
> +		bytes[p++] = qoi_padding[i];
> +	}
> +
> +	*out_len = p;
> +	return bytes;
> +}
> +
> +void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
> +	const unsigned char *bytes;
> +	unsigned int header_magic;
> +	unsigned char *pixels;
> +	qoi_rgba_t index[64];
> +	qoi_rgba_t px;
> +	int px_len, chunks_len, px_pos;
> +	int p = 0, run = 0;
> +
> +	if (
> +		data == NULL || desc == NULL ||
> +		(channels != 0 && channels != 3 && channels != 4) ||
> +		size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding)
> +	) {
> +		return NULL;
> +	}
> +
> +	bytes = (const unsigned char *)data;
> +
> +	header_magic = qoi_read_32(bytes, &p);
> +	desc->width = qoi_read_32(bytes, &p);
> +	desc->height = qoi_read_32(bytes, &p);
> +	desc->channels = bytes[p++];
> +	desc->colorspace = bytes[p++];
> +
> +	if (
> +		desc->width == 0 || desc->height == 0 ||
> +		desc->channels < 3 || desc->channels > 4 ||
> +		desc->colorspace > 1 ||
> +		header_magic != QOI_MAGIC ||
> +		desc->height >= QOI_PIXELS_MAX / desc->width
> +	) {
> +		return NULL;
> +	}
> +
> +	if (channels == 0) {
> +		channels = desc->channels;
> +	}
> +
> +	px_len = desc->width * desc->height * channels;
> +	pixels = (unsigned char *) QOI_MALLOC(px_len);
> +	if (!pixels) {
> +		return NULL;
> +	}
> +
> +	QOI_ZEROARR(index);
> +	px.rgba.r = 0;
> +	px.rgba.g = 0;
> +	px.rgba.b = 0;
> +	px.rgba.a = 255;
> +
> +	chunks_len = size - (int)sizeof(qoi_padding);
> +	for (px_pos = 0; px_pos < px_len; px_pos += channels) {
> +		if (run > 0) {
> +			run--;
> +		}
> +		else if (p < chunks_len) {
> +			int b1 = bytes[p++];
> +
> +			if (b1 == QOI_OP_RGB) {
> +				px.rgba.r = bytes[p++];
> +				px.rgba.g = bytes[p++];
> +				px.rgba.b = bytes[p++];
> +			}
> +			else if (b1 == QOI_OP_RGBA) {
> +				px.rgba.r = bytes[p++];
> +				px.rgba.g = bytes[p++];
> +				px.rgba.b = bytes[p++];
> +				px.rgba.a = bytes[p++];
> +			}
> +			else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) {
> +				px = index[b1];
> +			}
> +			else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) {
> +				px.rgba.r += ((b1 >> 4) & 0x03) - 2;
> +				px.rgba.g += ((b1 >> 2) & 0x03) - 2;
> +				px.rgba.b += ( b1       & 0x03) - 2;
> +			}
> +			else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) {
> +				int b2 = bytes[p++];
> +				int vg = (b1 & 0x3f) - 32;
> +				px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f);
> +				px.rgba.g += vg;
> +				px.rgba.b += vg - 8 +  (b2       & 0x0f);
> +			}
> +			else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) {
> +				run = (b1 & 0x3f);
> +			}
> +
> +			index[QOI_COLOR_HASH(px) % 64] = px;
> +		}
> +
> +		if (channels == 4) {
> +			*(qoi_rgba_t*)(pixels + px_pos) = px;
> +		}
> +		else {
> +			pixels[px_pos + 0] = px.rgba.r;
> +			pixels[px_pos + 1] = px.rgba.g;
> +			pixels[px_pos + 2] = px.rgba.b;
> +		}
> +	}
> +
> +	return pixels;
> +}
> +
> +#ifndef QOI_NO_STDIO
> +#include <stdio.h>
> +
> +int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
> +	FILE *f = fopen(filename, "wb");
> +	int size;
> +	void *encoded;
> +
> +	if (!f) {
> +		return 0;
> +	}
> +
> +	encoded = qoi_encode(data, desc, &size);
> +	if (!encoded) {
> +		fclose(f);
> +		return 0;
> +	}
> +
> +	fwrite(encoded, 1, size, f);
> +	fclose(f);
> +
> +	QOI_FREE(encoded);
> +	return size;
> +}
> +
> +void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
> +	FILE *f = fopen(filename, "rb");
> +	int size, bytes_read;
> +	void *pixels, *data;
> +
> +	if (!f) {
> +		return NULL;
> +	}
> +
> +	fseek(f, 0, SEEK_END);
> +	size = ftell(f);
> +	if (size <= 0) {
> +		fclose(f);
> +		return NULL;
> +	}
> +	fseek(f, 0, SEEK_SET);
> +
> +	data = QOI_MALLOC(size);
> +	if (!data) {
> +		fclose(f);
> +		return NULL;
> +	}
> +
> +	bytes_read = fread(data, 1, size, f);
> +	fclose(f);
> +
> +	pixels = qoi_decode(data, bytes_read, desc, channels);
> +	QOI_FREE(data);
> +	return pixels;
> +}
> +
> +#endif /* QOI_NO_STDIO */
> +#endif /* QOI_IMPLEMENTATION */
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From o.rempel at pengutronix.de  Fri Jan 14 02:12:46 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 14 Jan 2022 11:12:46 +0100
Subject: [PATCH v1 2/2] ARM: rpi: set uart0-pl0110 clk to 48MHz
In-Reply-To: <20220114083018.GS26619@pengutronix.de>
References: <20220114082141.302151-1-o.rempel@pengutronix.de>
 <20220114082141.302151-2-o.rempel@pengutronix.de>
 <20220114083018.GS26619@pengutronix.de>
Message-ID: <20220114101246.GA21557@pengutronix.de>

On Fri, Jan 14, 2022 at 09:30:18AM +0100, Sascha Hauer wrote:
> On Fri, Jan 14, 2022 at 09:21:41AM +0100, Oleksij Rempel wrote:
> > At least on RPi2 this clock is 48MHz. This issue was not visible,
> > becouse amba-pl011 driver was not reseting UART controller after
> > changing baudrate. So, clk settings was not updated for some time.
> 
> We have an rpi3 and rpi4 in our lab. Could you give this a test on these
> boards?

Yes, rpi3 is tested and rpi4 is currently not supported.

> Sascha
> 
> > 
> > Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
> > ---
> >  arch/arm/boards/raspberry-pi/rpi-common.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
> > index 6c5df6fd69..2684bd5ed7 100644
> > --- a/arch/arm/boards/raspberry-pi/rpi-common.c
> > +++ b/arch/arm/boards/raspberry-pi/rpi-common.c
> > @@ -374,7 +374,7 @@ static int rpi_console_clock_init(void)
> >  	clk = clk_fixed("apb_pclk", 0);
> >  	clk_register_clkdev(clk, "apb_pclk", NULL);
> >  
> > -	clk = clk_fixed("uart0-pl0110", 3 * 1000 * 1000);
> > +	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
> >  	clk_register_clkdev(clk, NULL, "uart0-pl0110");
> >  	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
> >  	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
> > -- 
> > 2.30.2
> > 
> > 
> > _______________________________________________
> > barebox mailing list
> > barebox at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/barebox
> > 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Fri Jan 14 02:17:20 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 11:17:20 +0100
Subject: [PATCH v1 2/2] ARM: rpi: set uart0-pl0110 clk to 48MHz
In-Reply-To: <20220114101246.GA21557@pengutronix.de>
References: <20220114082141.302151-1-o.rempel@pengutronix.de>
 <20220114082141.302151-2-o.rempel@pengutronix.de>
 <20220114083018.GS26619@pengutronix.de>
 <20220114101246.GA21557@pengutronix.de>
Message-ID: <99bb2c58-ce8c-36ea-fc49-80ada8fe9cd3@pengutronix.de>

On 14.01.22 11:12, Oleksij Rempel wrote:
> On Fri, Jan 14, 2022 at 09:30:18AM +0100, Sascha Hauer wrote:
>> On Fri, Jan 14, 2022 at 09:21:41AM +0100, Oleksij Rempel wrote:
>>> At least on RPi2 this clock is 48MHz. This issue was not visible,
>>> becouse amba-pl011 driver was not reseting UART controller after
>>> changing baudrate. So, clk settings was not updated for some time.
>>
>> We have an rpi3 and rpi4 in our lab. Could you give this a test on these
>> boards?
> 
> Yes, rpi3 is tested and rpi4 is currently not supported.

Uwe's finger is surely hovering over the send button right now ;)

> 
>> Sascha
>>
>>>
>>> Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
>>> ---
>>>  arch/arm/boards/raspberry-pi/rpi-common.c | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
>>> index 6c5df6fd69..2684bd5ed7 100644
>>> --- a/arch/arm/boards/raspberry-pi/rpi-common.c
>>> +++ b/arch/arm/boards/raspberry-pi/rpi-common.c
>>> @@ -374,7 +374,7 @@ static int rpi_console_clock_init(void)
>>>  	clk = clk_fixed("apb_pclk", 0);
>>>  	clk_register_clkdev(clk, "apb_pclk", NULL);
>>>  
>>> -	clk = clk_fixed("uart0-pl0110", 3 * 1000 * 1000);
>>> +	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
>>>  	clk_register_clkdev(clk, NULL, "uart0-pl0110");
>>>  	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
>>>  	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
>>> -- 
>>> 2.30.2
>>>
>>>
>>> _______________________________________________
>>> barebox mailing list
>>> barebox at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/barebox
>>>
>>
>> -- 
>> Pengutronix e.K.                           |                             |
>> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
>> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
>> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>>
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 02:21:22 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 11:21:22 +0100
Subject: [PATCH 2/2] nvmem: add Rockchip eFuse support
In-Reply-To: <20220114085046.313677-2-a.fatoum@pengutronix.de>
References: <20220114085046.313677-1-a.fatoum@pengutronix.de>
 <20220114085046.313677-2-a.fatoum@pengutronix.de>
Message-ID: <20220114102122.GW26619@pengutronix.de>

On Fri, Jan 14, 2022 at 09:50:46AM +0100, Ahmad Fatoum wrote:
> The driver allows read-only support to e.g. the Hardware UID, which
> could in future be used to derive a MAC like U-Boot does.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/nvmem/Kconfig          |   8 +
>  drivers/nvmem/Makefile         |   1 +
>  drivers/nvmem/rockchip-efuse.c | 299 +++++++++++++++++++++++++++++++++
>  3 files changed, 308 insertions(+)
>  create mode 100644 drivers/nvmem/rockchip-efuse.c
> 
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index 7b1ebe1d689d..ea1156918a34 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -84,4 +84,12 @@ config STARFIVE_OTP
>  	  This adds support for the StarFive OTP controller. Only reading
>  	  is currently supported.
>  
> +config ROCKCHIP_EFUSE
> +	tristate "Rockchip eFuse Support"
> +	depends on ARCH_ROCKCHIP || COMPILE_TEST
> +	depends on OFDEVICE
> +	help
> +	  This is a simple drive to dump specified values of Rockchip SoC
> +	  from eFuse, such as CPU ID.
> +
>  endif
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index 586591961215..2261816c189c 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -25,3 +25,4 @@ obj-$(CONFIG_STM32_BSEC)	+= nvmem_bsec.o
>  nvmem_bsec-y			:= bsec.o
>  
>  obj-$(CONFIG_STARFIVE_OTP)	+= starfive-otp.o
> +obj-$(CONFIG_ROCKCHIP_EFUSE)	+= rockchip-efuse.o
> diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
> new file mode 100644
> index 000000000000..24e7de0aa9ce
> --- /dev/null
> +++ b/drivers/nvmem/rockchip-efuse.c
> @@ -0,0 +1,299 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Rockchip eFuse Driver
> + *
> + * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
> + * Author: Caesar Wang <wxt at rock-chips.com>
> + */
> +
> +#include <common.h>
> +#include <linux/clk.h>
> +#include <linux/overflow.h>
> +#include <clock.h>
> +#include <driver.h>
> +#include <io.h>
> +#include <linux/nvmem-provider.h>
> +#include <of.h>
> +#include <init.h>
> +
> +#define clk_prepare_enable clk_enable
> +#define clk_disable_unprepare clk_disable

Please use the functions directly.

> +static int rockchip_efuse_probe(struct device_d *dev)
> +{
> +	struct resource *res;
> +	struct nvmem_device *nvmem;
> +	struct rockchip_efuse_chip *efuse;
> +	const void *data;
> +
> +	data = device_get_match_data(dev);
> +	if (!data) {
> +		dev_err(dev, "failed to get match data\n");
> +		return -EINVAL;
> +	}
> +
> +	efuse = kzalloc(sizeof(struct rockchip_efuse_chip), GFP_KERNEL);
> +	if (!efuse)
> +		return -ENOMEM;
> +
> +	res = dev_request_mem_resource(dev, 0);
> +	if (IS_ERR(res))
> +		return PTR_ERR(res);
> +
> +	efuse->base = IOMEM(res->start);
> +
> +	efuse->clk = clk_get(dev, "pclk_efuse");
> +	if (IS_ERR(efuse->clk))
> +		return PTR_ERR(efuse->clk);
> +
> +	efuse->dev = dev;
> +	if (of_property_read_u32(dev->device_node, "rockchip,efuse-size",
> +				 &econfig.size))
> +		econfig.size = resource_size(res);

resource_size(res) is the size of the register space which has nothing
to do with the size of the provided nvmem space.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Fri Jan 14 02:28:02 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 11:28:02 +0100
Subject: [PATCH 0/5] Add support for QOI image format
In-Reply-To: <20220110221255.5003-1-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
Message-ID: <81e99997-3fe7-9f4f-03f9-ff1cc4ed800d@pengutronix.de>

Hi,

On 10.01.22 23:12, Jules Maselbas wrote:
> Ho ho ho,
> 
> I had some fun past weeks playing with the QOI image format[1] and I've
> added it's support to barebox. I also made the builtin barebox logo image
> format selectable, with bmp, png, and qoi...
> 
> I am not sure if this be of a great interest to barebox anyway here it is.

If it hits a sweet spot between size and speed, it may be interesting.
Optimally, you wouldn't need a boot splash, but for cases where you have one,
you don't want to delay the boot process any longer. I guess it currently
looks like this:

  CPU usage: png > qoi > bmp
  IO  usage: bmp > qoi > png

So there's a case to be made for its inclusion.

> 
> [1] https://qoiformat.org/
> 
> ---
> 
> Jules Maselbas (5):
>   filetype: Add QOI format image type
>   gui: Add qoi image format
>   scripts: Add qoiconv to convert png to qoi
>   logo: Enable image format selection for the logo
>   logo: Add choice for the QOI image format option
> 
>  common/filetype.c   |    3 +
>  include/filetype.h  |    1 +
>  lib/gui/Kconfig     |    5 +
>  lib/gui/Makefile    |    1 +
>  lib/gui/qoi.c       |   94 +
>  lib/gui/qoi.h       |  671 ++++
>  lib/logo/Kconfig    |   27 +-
>  lib/logo/Makefile   |   55 +-
>  lib/logo/logo.c     |   10 +-
>  scripts/Kconfig     |    5 +
>  scripts/Makefile    |    1 +
>  scripts/qoiconv.c   |   91 +
>  scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
>  13 files changed, 8705 insertions(+), 15 deletions(-)
>  create mode 100644 lib/gui/qoi.c
>  create mode 100644 lib/gui/qoi.h
>  create mode 100644 scripts/qoiconv.c
>  create mode 100644 scripts/stb_image.h
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 02:29:11 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 11:29:11 +0100
Subject: [PATCH] fixup! of: implement new of_property_sprintf
In-Reply-To: <20220114085735.731631-1-ahmad@a3f.at>
References: <20220114085735.731631-1-ahmad@a3f.at>
Message-ID: <20220114102911.GX26619@pengutronix.de>

On Fri, Jan 14, 2022 at 09:57:35AM +0100, Ahmad Fatoum wrote:
> Otherwise, tools like of_dump will consider the output to be byte
> arrays.
> 
> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
> ---
>  drivers/of/base.c | 2 ++
>  1 file changed, 2 insertions(+)

Applied, thanks.

I've rewritten the commit message as it's too late for a fixup.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Fri Jan 14 02:29:58 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 11:29:58 +0100
Subject: [PATCH 3/5] scripts: Add qoiconv to convert png to qoi
In-Reply-To: <20220110221255.5003-4-jmaselbas@kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
 <20220110221255.5003-4-jmaselbas@kalray.eu>
Message-ID: <ec782b1e-ffed-3f01-71a7-f28c161d802d@pengutronix.de>

On 10.01.22 23:12, Jules Maselbas wrote:
> ImageMagick will eventually support the qoi image format, in the
> mean time add a png to qoi conversion program.
> 
> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> ---
>  scripts/Kconfig     |    5 +
>  scripts/Makefile    |    1 +
>  scripts/qoiconv.c   |   91 +
>  scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 7853 insertions(+)
>  create mode 100644 scripts/qoiconv.c
>  create mode 100644 scripts/stb_image.h
> 
> diff --git a/scripts/Kconfig b/scripts/Kconfig
> index 9b744deba9..747f665e02 100644
> --- a/scripts/Kconfig
> +++ b/scripts/Kconfig
> @@ -110,6 +110,11 @@ config RK_USB_LOADER
>  
>  	  You need libusb-1.0 to compile this tool.
>  
> +config QOICONV
> +	bool "QOI image format conversion" if COMPILE_HOST_TOOLS
> +	help
> +	  This enable converting png to qoi images to generate boot logo.
> +
>  endmenu
>  
>  menu "Target Tools"
> diff --git a/scripts/Makefile b/scripts/Makefile
> index dc5fa75f90..cbaf2d55ff 100644
> --- a/scripts/Makefile
> +++ b/scripts/Makefile
> @@ -8,6 +8,7 @@ hostprogs-always-y					+= fix_size
>  hostprogs-always-y					+= bareboxenv
>  hostprogs-always-y					+= bareboxcrc32
>  hostprogs-always-y					+= kernel-install
> +hostprogs-always-$(CONFIG_QOICONV)			+= qoiconv
>  hostprogs-always-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS)	+= rsatoc
>  HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl`
>  HOSTLDLIBS_rsatoc = `pkg-config --libs openssl`
> diff --git a/scripts/qoiconv.c b/scripts/qoiconv.c
> new file mode 100644
> index 0000000000..010c70ead0
> --- /dev/null
> +++ b/scripts/qoiconv.c
> @@ -0,0 +1,91 @@
> +/*
> +
> +Command line tool to convert between png <> qoi format
> +
> +Requires "stb_image.h" and "stb_image_write.h"
> +Compile with: 
> +	gcc qoiconv.c -std=c99 -O3 -o qoiconv
> +
> +Dominic Szablewski - https://phoboslab.org
> +
> +
> +-- LICENSE: The MIT License(MIT)
> +
> +Copyright(c) 2021 Dominic Szablewski
> +
> +Permission is hereby granted, free of charge, to any person obtaining a copy of
> +this software and associated documentation files(the "Software"), to deal in
> +the Software without restriction, including without limitation the rights to
> +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
> +of the Software, and to permit persons to whom the Software is furnished to do
> +so, subject to the following conditions :
> +The above copyright notice and this permission notice shall be included in all
> +copies or substantial portions of the Software.
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> +SOFTWARE.
> +
> +*/

Can you not reuse the header added in the previous commit?

> +
> +
> +#define STB_IMAGE_IMPLEMENTATION
> +#define STBI_ONLY_PNG
> +#define STBI_NO_LINEAR
> +#include "stb_image.h"
> +
> +#define QOI_IMPLEMENTATION
> +#include "../lib/gui/qoi.h"
> +
> +#define STR_ENDS_WITH(S, E) (strcmp(S + strlen(S) - (sizeof(E)-1), E) == 0)
> +
> +int main(int argc, char **argv) {
> +	if (argc < 3) {
> +		puts("Usage: qoiconv <infile> <outfile>");
> +		puts("Examples:");
> +		puts("  qoiconv input.png output.qoi");
> +		puts("  qoiconv input.qoi output.png");
> +		exit(1);
> +	}
> +
> +	void *pixels = NULL;
> +	int w, h, channels;
> +	if (STR_ENDS_WITH(argv[1], ".png")) {
> +		if(!stbi_info(argv[1], &w, &h, &channels)) {
> +			printf("Couldn't read header %s\n", argv[1]);
> +			exit(1);
> +		}
> +
> +		// Force all odd encodings to be RGBA
> +		if(channels != 3) {
> +			channels = 4;
> +		}
> +
> +		pixels = (void *)stbi_load(argv[1], &w, &h, NULL, channels);
> +	}
> +	if (pixels == NULL) {
> +		printf("Couldn't load/decode %s\n", argv[1]);
> +		exit(1);
> +	}
> +
> +	int encoded = 0;
> +	if (STR_ENDS_WITH(argv[2], ".qoi")) {
> +		encoded = qoi_write(argv[2], pixels, &(qoi_desc){
> +			.width = w,
> +			.height = h, 
> +			.channels = channels,
> +			.colorspace = QOI_SRGB
> +		});
> +	}
> +
> +	if (!encoded) {
> +		printf("Couldn't write/encode %s\n", argv[2]);
> +		exit(1);
> +	}
> +
> +	free(pixels);
> +	return 0;
> +}
> diff --git a/scripts/stb_image.h b/scripts/stb_image.h
> new file mode 100644
> index 0000000000..742fac74f7
> --- /dev/null
> +++ b/scripts/stb_image.h
> @@ -0,0 +1,7756 @@
> +/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb
> +                                  no warranty implied; use at your own risk
> +
> +   Do this:
> +      #define STB_IMAGE_IMPLEMENTATION
> +   before you include this file in *one* C or C++ file to create the implementation.
> +
> +   // i.e. it should look like this:
> +   #include ...
> +   #include ...
> +   #include ...
> +   #define STB_IMAGE_IMPLEMENTATION
> +   #include "stb_image.h"
> +
> +   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
> +   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
> +
> +
> +   QUICK NOTES:
> +      Primarily of interest to game developers and other people who can
> +          avoid problematic images and only need the trivial interface
> +
> +      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
> +      PNG 1/2/4/8/16-bit-per-channel
> +
> +      TGA (not sure what subset, if a subset)
> +      BMP non-1bpp, non-RLE
> +      PSD (composited view only, no extra channels, 8/16 bit-per-channel)
> +
> +      GIF (*comp always reports as 4-channel)
> +      HDR (radiance rgbE format)
> +      PIC (Softimage PIC)
> +      PNM (PPM and PGM binary only)
> +
> +      Animated GIF still needs a proper API, but here's one way to do it:
> +          http://gist.github.com/urraka/685d9a6340b26b830d49
> +
> +      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
> +      - decode from arbitrary I/O callbacks
> +      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
> +
> +   Full documentation under "DOCUMENTATION" below.
> +
> +
> +LICENSE
> +
> +  See end of file for license information.
> +
> +RECENT REVISION HISTORY:
> +
> +      2.26  (2020-07-13) many minor fixes
> +      2.25  (2020-02-02) fix warnings
> +      2.24  (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
> +      2.23  (2019-08-11) fix clang static analysis warning
> +      2.22  (2019-03-04) gif fixes, fix warnings
> +      2.21  (2019-02-25) fix typo in comment
> +      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
> +      2.19  (2018-02-11) fix warning
> +      2.18  (2018-01-30) fix warnings
> +      2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
> +      2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
> +      2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
> +      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
> +      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
> +      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
> +      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
> +                         RGB-format JPEG; remove white matting in PSD;
> +                         allocate large structures on the stack;
> +                         correct channel count for PNG & BMP
> +      2.10  (2016-01-22) avoid warning introduced in 2.09
> +      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
> +
> +   See end of file for full revision history.
> +
> +
> + ============================    Contributors    =========================
> +
> + Image formats                          Extensions, features
> +    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)
> +    Nicolas Schulz (hdr, psd)              Martin "SpartanJ" Golini (stbi_info)
> +    Jonathan Dummer (tga)                  James "moose2000" Brown (iPhone PNG)
> +    Jean-Marc Lienher (gif)                Ben "Disch" Wenger (io callbacks)
> +    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)
> +    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)
> +    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)
> +    github:urraka (animated gif)           Junggon Kim (PNM comments)
> +    Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA)
> +                                           socks-the-fox (16-bit PNG)
> +                                           Jeremy Sawicki (handle all ImageNet JPGs)
> + Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP)
> +    Fabian "ryg" Giesen                    Anael Seghezzi (is-16-bit query)
> +    Arseny Kapoulkine
> +    John-Mark Allen
> +    Carmelo J Fdez-Aguera
> +
> + Bug & warning fixes
> +    Marc LeBlanc            David Woo          Guillaume George     Martins Mozeiko
> +    Christpher Lloyd        Jerry Jansson      Joseph Thomson       Blazej Dariusz Roszkowski
> +    Phil Jordan                                Dave Moore           Roy Eltham
> +    Hayaki Saito            Nathan Reed        Won Chun
> +    Luke Graham             Johan Duparc       Nick Verigakis       the Horde3D community
> +    Thomas Ruf              Ronny Chevalier                         github:rlyeh
> +    Janez Zemva             John Bartholomew   Michal Cichon        github:romigrou
> +    Jonathan Blow           Ken Hamada         Tero Hanninen        github:svdijk
> +                            Laurent Gomila     Cort Stratton        github:snagar
> +    Aruelien Pocheville     Sergio Gonzalez    Thibault Reuille     github:Zelex
> +    Cass Everitt            Ryamond Barbiero                        github:grim210
> +    Paul Du Bois            Engin Manap        Aldo Culquicondor    github:sammyhw
> +    Philipp Wiesemann       Dale Weiler        Oriol Ferrer Mesia   github:phprus
> +    Josh Tobin                                 Matthew Gregan       github:poppolopoppo
> +    Julian Raschke          Gregory Mullen     Christian Floisand   github:darealshinji
> +    Baldur Karlsson         Kevin Schmidt      JR Smith             github:Michaelangel007
> +                            Brad Weinberger    Matvey Cherevko      [reserved]
> +    Luca Sas                Alexander Veselov  Zack Middleton       [reserved]
> +    Ryan C. Gordon          [reserved]                              [reserved]
> +                     DO NOT ADD YOUR NAME HERE
> +
> +  To add your name to the credits, pick a random blank space in the middle and fill it.
> +  80% of merge conflicts on stb PRs are due to people adding their name at the end
> +  of the credits.
> +*/
> +
> +#ifndef STBI_INCLUDE_STB_IMAGE_H
> +#define STBI_INCLUDE_STB_IMAGE_H
> +
> +// DOCUMENTATION
> +//
> +// Limitations:
> +//    - no 12-bit-per-channel JPEG
> +//    - no JPEGs with arithmetic coding
> +//    - GIF always returns *comp=4
> +//
> +// Basic usage (see HDR discussion below for HDR usage):
> +//    int x,y,n;
> +//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
> +//    // ... process data if not NULL ...
> +//    // ... x = width, y = height, n = # 8-bit components per pixel ...
> +//    // ... replace '0' with '1'..'4' to force that many components per pixel
> +//    // ... but 'n' will always be the number that it would have been if you said 0
> +//    stbi_image_free(data)
> +//
> +// Standard parameters:
> +//    int *x                 -- outputs image width in pixels
> +//    int *y                 -- outputs image height in pixels
> +//    int *channels_in_file  -- outputs # of image components in image file
> +//    int desired_channels   -- if non-zero, # of image components requested in result
> +//
> +// The return value from an image loader is an 'unsigned char *' which points
> +// to the pixel data, or NULL on an allocation failure or if the image is
> +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
> +// with each pixel consisting of N interleaved 8-bit components; the first
> +// pixel pointed to is top-left-most in the image. There is no padding between
> +// image scanlines or between pixels, regardless of format. The number of
> +// components N is 'desired_channels' if desired_channels is non-zero, or
> +// *channels_in_file otherwise. If desired_channels is non-zero,
> +// *channels_in_file has the number of components that _would_ have been
> +// output otherwise. E.g. if you set desired_channels to 4, you will always
> +// get RGBA output, but you can check *channels_in_file to see if it's trivially
> +// opaque because e.g. there were only 3 channels in the source image.
> +//
> +// An output image with N components has the following components interleaved
> +// in this order in each pixel:
> +//
> +//     N=#comp     components
> +//       1           grey
> +//       2           grey, alpha
> +//       3           red, green, blue
> +//       4           red, green, blue, alpha
> +//
> +// If image loading fails for any reason, the return value will be NULL,
> +// and *x, *y, *channels_in_file will be unchanged. The function
> +// stbi_failure_reason() can be queried for an extremely brief, end-user
> +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
> +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
> +// more user-friendly ones.
> +//
> +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
> +//
> +// ===========================================================================
> +//
> +// UNICODE:
> +//
> +//   If compiling for Windows and you wish to use Unicode filenames, compile
> +//   with
> +//       #define STBI_WINDOWS_UTF8
> +//   and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
> +//   Windows wchar_t filenames to utf8.
> +//
> +// ===========================================================================
> +//
> +// Philosophy
> +//
> +// stb libraries are designed with the following priorities:
> +//
> +//    1. easy to use
> +//    2. easy to maintain
> +//    3. good performance
> +//
> +// Sometimes I let "good performance" creep up in priority over "easy to maintain",
> +// and for best performance I may provide less-easy-to-use APIs that give higher
> +// performance, in addition to the easy-to-use ones. Nevertheless, it's important
> +// to keep in mind that from the standpoint of you, a client of this library,
> +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
> +//
> +// Some secondary priorities arise directly from the first two, some of which
> +// provide more explicit reasons why performance can't be emphasized.
> +//
> +//    - Portable ("ease of use")
> +//    - Small source code footprint ("easy to maintain")
> +//    - No dependencies ("ease of use")
> +//
> +// ===========================================================================
> +//
> +// I/O callbacks
> +//
> +// I/O callbacks allow you to read from arbitrary sources, like packaged
> +// files or some other source. Data read from callbacks are processed
> +// through a small internal buffer (currently 128 bytes) to try to reduce
> +// overhead.
> +//
> +// The three functions you must define are "read" (reads some bytes of data),
> +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
> +//
> +// ===========================================================================
> +//
> +// SIMD support
> +//
> +// The JPEG decoder will try to automatically use SIMD kernels on x86 when
> +// supported by the compiler. For ARM Neon support, you must explicitly
> +// request it.
> +//
> +// (The old do-it-yourself SIMD API is no longer supported in the current
> +// code.)
> +//
> +// On x86, SSE2 will automatically be used when available based on a run-time
> +// test; if not, the generic C versions are used as a fall-back. On ARM targets,
> +// the typical path is to have separate builds for NEON and non-NEON devices
> +// (at least this is true for iOS and Android). Therefore, the NEON support is
> +// toggled by a build flag: define STBI_NEON to get NEON loops.
> +//
> +// If for some reason you do not want to use any of SIMD code, or if
> +// you have issues compiling it, you can disable it entirely by
> +// defining STBI_NO_SIMD.
> +//
> +// ===========================================================================
> +//
> +// HDR image support   (disable by defining STBI_NO_HDR)
> +//
> +// stb_image supports loading HDR images in general, and currently the Radiance
> +// .HDR file format specifically. You can still load any file through the existing
> +// interface; if you attempt to load an HDR file, it will be automatically remapped
> +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
> +// both of these constants can be reconfigured through this interface:
> +//
> +//     stbi_hdr_to_ldr_gamma(2.2f);
> +//     stbi_hdr_to_ldr_scale(1.0f);
> +//
> +// (note, do not use _inverse_ constants; stbi_image will invert them
> +// appropriately).
> +//
> +// Additionally, there is a new, parallel interface for loading files as
> +// (linear) floats to preserve the full dynamic range:
> +//
> +//    float *data = stbi_loadf(filename, &x, &y, &n, 0);
> +//
> +// If you load LDR images through this interface, those images will
> +// be promoted to floating point values, run through the inverse of
> +// constants corresponding to the above:
> +//
> +//     stbi_ldr_to_hdr_scale(1.0f);
> +//     stbi_ldr_to_hdr_gamma(2.2f);
> +//
> +// Finally, given a filename (or an open file or memory block--see header
> +// file for details) containing image data, you can query for the "most
> +// appropriate" interface to use (that is, whether the image is HDR or
> +// not), using:
> +//
> +//     stbi_is_hdr(char *filename);
> +//
> +// ===========================================================================
> +//
> +// iPhone PNG support:
> +//
> +// By default we convert iphone-formatted PNGs back to RGB, even though
> +// they are internally encoded differently. You can disable this conversion
> +// by calling stbi_convert_iphone_png_to_rgb(0), in which case
> +// you will always just get the native iphone "format" through (which
> +// is BGR stored in RGB).
> +//
> +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
> +// pixel to remove any premultiplied alpha *only* if the image file explicitly
> +// says there's premultiplied data (currently only happens in iPhone images,
> +// and only if iPhone convert-to-rgb processing is on).
> +//
> +// ===========================================================================
> +//
> +// ADDITIONAL CONFIGURATION
> +//
> +//  - You can suppress implementation of any of the decoders to reduce
> +//    your code footprint by #defining one or more of the following
> +//    symbols before creating the implementation.
> +//
> +//        STBI_NO_JPEG
> +//        STBI_NO_PNG
> +//        STBI_NO_BMP
> +//        STBI_NO_PSD
> +//        STBI_NO_TGA
> +//        STBI_NO_GIF
> +//        STBI_NO_HDR
> +//        STBI_NO_PIC
> +//        STBI_NO_PNM   (.ppm and .pgm)
> +//
> +//  - You can request *only* certain decoders and suppress all other ones
> +//    (this will be more forward-compatible, as addition of new decoders
> +//    doesn't require you to disable them explicitly):
> +//
> +//        STBI_ONLY_JPEG
> +//        STBI_ONLY_PNG
> +//        STBI_ONLY_BMP
> +//        STBI_ONLY_PSD
> +//        STBI_ONLY_TGA
> +//        STBI_ONLY_GIF
> +//        STBI_ONLY_HDR
> +//        STBI_ONLY_PIC
> +//        STBI_ONLY_PNM   (.ppm and .pgm)
> +//
> +//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
> +//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
> +//
> +//  - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
> +//    than that size (in either width or height) without further processing.
> +//    This is to let programs in the wild set an upper bound to prevent
> +//    denial-of-service attacks on untrusted data, as one could generate a
> +//    valid image of gigantic dimensions and force stb_image to allocate a
> +//    huge block of memory and spend disproportionate time decoding it. By
> +//    default this is set to (1 << 24), which is 16777216, but that's still
> +//    very big.
> +
> +#ifndef STBI_NO_STDIO
> +#include <stdio.h>
> +#endif // STBI_NO_STDIO
> +
> +#define STBI_VERSION 1
> +
> +enum
> +{
> +   STBI_default = 0, // only used for desired_channels
> +
> +   STBI_grey       = 1,
> +   STBI_grey_alpha = 2,
> +   STBI_rgb        = 3,
> +   STBI_rgb_alpha  = 4
> +};
> +
> +#include <stdlib.h>
> +typedef unsigned char stbi_uc;
> +typedef unsigned short stbi_us;
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#ifndef STBIDEF
> +#ifdef STB_IMAGE_STATIC
> +#define STBIDEF static
> +#else
> +#define STBIDEF extern
> +#endif
> +#endif
> +
> +//////////////////////////////////////////////////////////////////////////////
> +//
> +// PRIMARY API - works on images of any type
> +//
> +
> +//
> +// load image by filename, open file, or memory buffer
> +//
> +
> +typedef struct
> +{
> +   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read
> +   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
> +   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
> +} stbi_io_callbacks;
> +
> +////////////////////////////////////
> +//
> +// 8-bits-per-channel interface
> +//
> +
> +STBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);
> +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
> +
> +#ifndef STBI_NO_STDIO
> +STBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
> +STBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
> +// for stbi_load_from_file, file pointer is left pointing immediately after image
> +#endif
> +
> +#ifndef STBI_NO_GIF
> +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
> +#endif
> +
> +#ifdef STBI_WINDOWS_UTF8
> +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
> +#endif
> +
> +////////////////////////////////////
> +//
> +// 16-bits-per-channel interface
> +//
> +
> +STBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
> +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
> +
> +#ifndef STBI_NO_STDIO
> +STBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
> +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
> +#endif
> +
> +////////////////////////////////////
> +//
> +// float-per-channel interface
> +//
> +#ifndef STBI_NO_LINEAR
> +   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
> +   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);
> +
> +   #ifndef STBI_NO_STDIO
> +   STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
> +   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
> +   #endif
> +#endif
> +
> +#ifndef STBI_NO_HDR
> +   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);
> +   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);
> +#endif // STBI_NO_HDR
> +
> +#ifndef STBI_NO_LINEAR
> +   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);
> +   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);
> +#endif // STBI_NO_LINEAR
> +
> +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
> +STBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
> +STBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
> +#ifndef STBI_NO_STDIO
> +STBIDEF int      stbi_is_hdr          (char const *filename);
> +STBIDEF int      stbi_is_hdr_from_file(FILE *f);
> +#endif // STBI_NO_STDIO
> +
> +
> +// get a VERY brief reason for failure
> +// on most compilers (and ALL modern mainstream compilers) this is threadsafe
> +STBIDEF const char *stbi_failure_reason  (void);
> +
> +// free the loaded image -- this is just free()
> +STBIDEF void     stbi_image_free      (void *retval_from_stbi_load);
> +
> +// get image dimensions & components without fully decoding
> +STBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
> +STBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
> +STBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
> +STBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
> +
> +#ifndef STBI_NO_STDIO
> +STBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp);
> +STBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp);
> +STBIDEF int      stbi_is_16_bit          (char const *filename);
> +STBIDEF int      stbi_is_16_bit_from_file(FILE *f);
> +#endif
> +
> +
> +
> +// for image formats that explicitly notate that they have premultiplied alpha,
> +// we just return the colors as stored in the file. set this flag to force
> +// unpremultiplication. results are undefined if the unpremultiply overflow.
> +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
> +
> +// indicate whether we should process iphone images back to canonical format,
> +// or just pass them through "as-is"
> +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
> +
> +// flip the image vertically, so the first pixel in the output array is the bottom left
> +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
> +
> +// as above, but only applies to images loaded on the thread that calls the function
> +// this function is only available if your compiler supports thread-local variables;
> +// calling it will fail to link if your compiler doesn't
> +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
> +
> +// ZLIB client - used by PNG, available for other purposes
> +
> +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
> +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
> +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
> +STBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
> +
> +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
> +STBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
> +
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +//
> +//
> +////   end header file   /////////////////////////////////////////////////////
> +#endif // STBI_INCLUDE_STB_IMAGE_H
> +
> +#ifdef STB_IMAGE_IMPLEMENTATION
> +
> +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
> +  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
> +  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
> +  || defined(STBI_ONLY_ZLIB)
> +   #ifndef STBI_ONLY_JPEG
> +   #define STBI_NO_JPEG
> +   #endif
> +   #ifndef STBI_ONLY_PNG
> +   #define STBI_NO_PNG
> +   #endif
> +   #ifndef STBI_ONLY_BMP
> +   #define STBI_NO_BMP
> +   #endif
> +   #ifndef STBI_ONLY_PSD
> +   #define STBI_NO_PSD
> +   #endif
> +   #ifndef STBI_ONLY_TGA
> +   #define STBI_NO_TGA
> +   #endif
> +   #ifndef STBI_ONLY_GIF
> +   #define STBI_NO_GIF
> +   #endif
> +   #ifndef STBI_ONLY_HDR
> +   #define STBI_NO_HDR
> +   #endif
> +   #ifndef STBI_ONLY_PIC
> +   #define STBI_NO_PIC
> +   #endif
> +   #ifndef STBI_ONLY_PNM
> +   #define STBI_NO_PNM
> +   #endif
> +#endif
> +
> +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
> +#define STBI_NO_ZLIB
> +#endif
> +
> +
> +#include <stdarg.h>
> +#include <stddef.h> // ptrdiff_t on osx
> +#include <stdlib.h>
> +#include <string.h>
> +#include <limits.h>
> +
> +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
> +#include <math.h>  // ldexp, pow
> +#endif
> +
> +#ifndef STBI_NO_STDIO
> +#include <stdio.h>
> +#endif
> +
> +#ifndef STBI_ASSERT
> +#include <assert.h>
> +#define STBI_ASSERT(x) assert(x)
> +#endif
> +
> +#ifdef __cplusplus
> +#define STBI_EXTERN extern "C"
> +#else
> +#define STBI_EXTERN extern
> +#endif
> +
> +
> +#ifndef _MSC_VER
> +   #ifdef __cplusplus
> +   #define stbi_inline inline
> +   #else
> +   #define stbi_inline
> +   #endif
> +#else
> +   #define stbi_inline __forceinline
> +#endif
> +
> +#ifndef STBI_NO_THREAD_LOCALS
> +   #if defined(__cplusplus) &&  __cplusplus >= 201103L
> +      #define STBI_THREAD_LOCAL       thread_local
> +   #elif defined(__GNUC__) && __GNUC__ < 5
> +      #define STBI_THREAD_LOCAL       __thread
> +   #elif defined(_MSC_VER)
> +      #define STBI_THREAD_LOCAL       __declspec(thread)
> +   #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
> +      #define STBI_THREAD_LOCAL       _Thread_local
> +   #endif
> +
> +   #ifndef STBI_THREAD_LOCAL
> +      #if defined(__GNUC__)
> +        #define STBI_THREAD_LOCAL       __thread
> +      #endif
> +   #endif
> +#endif
> +
> +#ifdef _MSC_VER
> +typedef unsigned short stbi__uint16;
> +typedef   signed short stbi__int16;
> +typedef unsigned int   stbi__uint32;
> +typedef   signed int   stbi__int32;
> +#else
> +#include <stdint.h>
> +typedef uint16_t stbi__uint16;
> +typedef int16_t  stbi__int16;
> +typedef uint32_t stbi__uint32;
> +typedef int32_t  stbi__int32;
> +#endif
> +
> +// should produce compiler error if size is wrong
> +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
> +
> +#ifdef _MSC_VER
> +#define STBI_NOTUSED(v)  (void)(v)
> +#else
> +#define STBI_NOTUSED(v)  (void)sizeof(v)
> +#endif
> +
> +#ifdef _MSC_VER
> +#define STBI_HAS_LROTL
> +#endif
> +
> +#ifdef STBI_HAS_LROTL
> +   #define stbi_lrot(x,y)  _lrotl(x,y)
> +#else
> +   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
> +#endif
> +
> +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
> +// ok
> +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
> +// ok
> +#else
> +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
> +#endif
> +
> +#ifndef STBI_MALLOC
> +#define STBI_MALLOC(sz)           malloc(sz)
> +#define STBI_REALLOC(p,newsz)     realloc(p,newsz)
> +#define STBI_FREE(p)              free(p)
> +#endif
> +
> +#ifndef STBI_REALLOC_SIZED
> +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
> +#endif
> +
> +// x86/x64 detection
> +#if defined(__x86_64__) || defined(_M_X64)
> +#define STBI__X64_TARGET
> +#elif defined(__i386) || defined(_M_IX86)
> +#define STBI__X86_TARGET
> +#endif
> +
> +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
> +// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
> +// which in turn means it gets to use SSE2 everywhere. This is unfortunate,
> +// but previous attempts to provide the SSE2 functions with runtime
> +// detection caused numerous issues. The way architecture extensions are
> +// exposed in GCC/Clang is, sadly, not really suited for one-file libs.
> +// New behavior: if compiled with -msse2, we use SSE2 without any
> +// detection; if not, we don't use it at all.
> +#define STBI_NO_SIMD
> +#endif
> +
> +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
> +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
> +//
> +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
> +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
> +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
> +// simultaneously enabling "-mstackrealign".
> +//
> +// See https://github.com/nothings/stb/issues/81 for more information.
> +//
> +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
> +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
> +#define STBI_NO_SIMD
> +#endif
> +
> +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
> +#define STBI_SSE2
> +#include <emmintrin.h>
> +
> +#ifdef _MSC_VER
> +
> +#if _MSC_VER >= 1400  // not VC6
> +#include <intrin.h> // __cpuid
> +static int stbi__cpuid3(void)
> +{
> +   int info[4];
> +   __cpuid(info,1);
> +   return info[3];
> +}
> +#else
> +static int stbi__cpuid3(void)
> +{
> +   int res;
> +   __asm {
> +      mov  eax,1
> +      cpuid
> +      mov  res,edx
> +   }
> +   return res;
> +}
> +#endif
> +
> +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
> +
> +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
> +static int stbi__sse2_available(void)
> +{
> +   int info3 = stbi__cpuid3();
> +   return ((info3 >> 26) & 1) != 0;
> +}
> +#endif
> +
> +#else // assume GCC-style if not VC++
> +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
> +
> +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
> +static int stbi__sse2_available(void)
> +{
> +   // If we're even attempting to compile this on GCC/Clang, that means
> +   // -msse2 is on, which means the compiler is allowed to use SSE2
> +   // instructions at will, and so are we.
> +   return 1;
> +}
> +#endif
> +
> +#endif
> +#endif
> +
> +// ARM NEON
> +#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
> +#undef STBI_NEON
> +#endif
> +
> +#ifdef STBI_NEON
> +#include <arm_neon.h>
> +// assume GCC or Clang on ARM targets
> +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
> +#endif
> +
> +#ifndef STBI_SIMD_ALIGN
> +#define STBI_SIMD_ALIGN(type, name) type name
> +#endif
> +
> +#ifndef STBI_MAX_DIMENSIONS
> +#define STBI_MAX_DIMENSIONS (1 << 24)
> +#endif
> +
> +///////////////////////////////////////////////
> +//
> +//  stbi__context struct and start_xxx functions
> +
> +// stbi__context structure is our basic context used by all images, so it
> +// contains all the IO context, plus some basic image information
> +typedef struct
> +{
> +   stbi__uint32 img_x, img_y;
> +   int img_n, img_out_n;
> +
> +   stbi_io_callbacks io;
> +   void *io_user_data;
> +
> +   int read_from_callbacks;
> +   int buflen;
> +   stbi_uc buffer_start[128];
> +   int callback_already_read;
> +
> +   stbi_uc *img_buffer, *img_buffer_end;
> +   stbi_uc *img_buffer_original, *img_buffer_original_end;
> +} stbi__context;
> +
> +
> +static void stbi__refill_buffer(stbi__context *s);
> +
> +// initialize a memory-decode context
> +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
> +{
> +   s->io.read = NULL;
> +   s->read_from_callbacks = 0;
> +   s->callback_already_read = 0;
> +   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
> +   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
> +}
> +
> +// initialize a callback-based context
> +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
> +{
> +   s->io = *c;
> +   s->io_user_data = user;
> +   s->buflen = sizeof(s->buffer_start);
> +   s->read_from_callbacks = 1;
> +   s->callback_already_read = 0;
> +   s->img_buffer = s->img_buffer_original = s->buffer_start;
> +   stbi__refill_buffer(s);
> +   s->img_buffer_original_end = s->img_buffer_end;
> +}
> +
> +#ifndef STBI_NO_STDIO
> +
> +static int stbi__stdio_read(void *user, char *data, int size)
> +{
> +   return (int) fread(data,1,size,(FILE*) user);
> +}
> +
> +static void stbi__stdio_skip(void *user, int n)
> +{
> +   int ch;
> +   fseek((FILE*) user, n, SEEK_CUR);
> +   ch = fgetc((FILE*) user);  /* have to read a byte to reset feof()'s flag */
> +   if (ch != EOF) {
> +      ungetc(ch, (FILE *) user);  /* push byte back onto stream if valid. */
> +   }
> +}
> +
> +static int stbi__stdio_eof(void *user)
> +{
> +   return feof((FILE*) user) || ferror((FILE *) user);
> +}
> +
> +static stbi_io_callbacks stbi__stdio_callbacks =
> +{
> +   stbi__stdio_read,
> +   stbi__stdio_skip,
> +   stbi__stdio_eof,
> +};
> +
> +static void stbi__start_file(stbi__context *s, FILE *f)
> +{
> +   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
> +}
> +
> +//static void stop_file(stbi__context *s) { }
> +
> +#endif // !STBI_NO_STDIO
> +
> +static void stbi__rewind(stbi__context *s)
> +{
> +   // conceptually rewind SHOULD rewind to the beginning of the stream,
> +   // but we just rewind to the beginning of the initial buffer, because
> +   // we only use it after doing 'test', which only ever looks at at most 92 bytes
> +   s->img_buffer = s->img_buffer_original;
> +   s->img_buffer_end = s->img_buffer_original_end;
> +}
> +
> +enum
> +{
> +   STBI_ORDER_RGB,
> +   STBI_ORDER_BGR
> +};
> +
> +typedef struct
> +{
> +   int bits_per_channel;
> +   int num_channels;
> +   int channel_order;
> +} stbi__result_info;
> +
> +#ifndef STBI_NO_JPEG
> +static int      stbi__jpeg_test(stbi__context *s);
> +static void    *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
> +#endif
> +
> +#ifndef STBI_NO_PNG
> +static int      stbi__png_test(stbi__context *s);
> +static void    *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
> +static int      stbi__png_is16(stbi__context *s);
> +#endif
> +
> +#ifndef STBI_NO_BMP
> +static int      stbi__bmp_test(stbi__context *s);
> +static void    *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
> +#endif
> +
> +#ifndef STBI_NO_TGA
> +static int      stbi__tga_test(stbi__context *s);
> +static void    *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
> +#endif
> +
> +#ifndef STBI_NO_PSD
> +static int      stbi__psd_test(stbi__context *s);
> +static void    *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
> +static int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
> +static int      stbi__psd_is16(stbi__context *s);
> +#endif
> +
> +#ifndef STBI_NO_HDR
> +static int      stbi__hdr_test(stbi__context *s);
> +static float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
> +#endif
> +
> +#ifndef STBI_NO_PIC
> +static int      stbi__pic_test(stbi__context *s);
> +static void    *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
> +#endif
> +
> +#ifndef STBI_NO_GIF
> +static int      stbi__gif_test(stbi__context *s);
> +static void    *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static void    *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
> +static int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
> +#endif
> +
> +#ifndef STBI_NO_PNM
> +static int      stbi__pnm_test(stbi__context *s);
> +static void    *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
> +static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
> +#endif
> +
> +static
> +#ifdef STBI_THREAD_LOCAL
> +STBI_THREAD_LOCAL
> +#endif
> +const char *stbi__g_failure_reason;
> +
> +STBIDEF const char *stbi_failure_reason(void)
> +{
> +   return stbi__g_failure_reason;
> +}
> +
> +#ifndef STBI_NO_FAILURE_STRINGS
> +static int stbi__err(const char *str)
> +{
> +   stbi__g_failure_reason = str;
> +   return 0;
> +}
> +#endif
> +
> +static void *stbi__malloc(size_t size)
> +{
> +    return STBI_MALLOC(size);
> +}
> +
> +// stb_image uses ints pervasively, including for offset calculations.
> +// therefore the largest decoded image size we can support with the
> +// current code, even on 64-bit targets, is INT_MAX. this is not a
> +// significant limitation for the intended use case.
> +//
> +// we do, however, need to make sure our size calculations don't
> +// overflow. hence a few helper functions for size calculations that
> +// multiply integers together, making sure that they're non-negative
> +// and no overflow occurs.
> +
> +// return 1 if the sum is valid, 0 on overflow.
> +// negative terms are considered invalid.
> +static int stbi__addsizes_valid(int a, int b)
> +{
> +   if (b < 0) return 0;
> +   // now 0 <= b <= INT_MAX, hence also
> +   // 0 <= INT_MAX - b <= INTMAX.
> +   // And "a + b <= INT_MAX" (which might overflow) is the
> +   // same as a <= INT_MAX - b (no overflow)
> +   return a <= INT_MAX - b;
> +}
> +
> +// returns 1 if the product is valid, 0 on overflow.
> +// negative factors are considered invalid.
> +static int stbi__mul2sizes_valid(int a, int b)
> +{
> +   if (a < 0 || b < 0) return 0;
> +   if (b == 0) return 1; // mul-by-0 is always safe
> +   // portable way to check for no overflows in a*b
> +   return a <= INT_MAX/b;
> +}
> +
> +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
> +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
> +static int stbi__mad2sizes_valid(int a, int b, int add)
> +{
> +   return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
> +}
> +#endif
> +
> +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
> +static int stbi__mad3sizes_valid(int a, int b, int c, int add)
> +{
> +   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
> +      stbi__addsizes_valid(a*b*c, add);
> +}
> +
> +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
> +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
> +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
> +{
> +   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
> +      stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
> +}
> +#endif
> +
> +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
> +// mallocs with size overflow checking
> +static void *stbi__malloc_mad2(int a, int b, int add)
> +{
> +   if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
> +   return stbi__malloc(a*b + add);
> +}
> +#endif
> +
> +static void *stbi__malloc_mad3(int a, int b, int c, int add)
> +{
> +   if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
> +   return stbi__malloc(a*b*c + add);
> +}
> +
> +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
> +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
> +{
> +   if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
> +   return stbi__malloc(a*b*c*d + add);
> +}
> +#endif
> +
> +// stbi__err - error
> +// stbi__errpf - error returning pointer to float
> +// stbi__errpuc - error returning pointer to unsigned char
> +
> +#ifdef STBI_NO_FAILURE_STRINGS
> +   #define stbi__err(x,y)  0
> +#elif defined(STBI_FAILURE_USERMSG)
> +   #define stbi__err(x,y)  stbi__err(y)
> +#else
> +   #define stbi__err(x,y)  stbi__err(x)
> +#endif
> +
> +#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
> +#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
> +
> +STBIDEF void stbi_image_free(void *retval_from_stbi_load)
> +{
> +   STBI_FREE(retval_from_stbi_load);
> +}
> +
> +#ifndef STBI_NO_LINEAR
> +static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
> +#endif
> +
> +#ifndef STBI_NO_HDR
> +static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);
> +#endif
> +
> +static int stbi__vertically_flip_on_load_global = 0;
> +
> +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
> +{
> +   stbi__vertically_flip_on_load_global = flag_true_if_should_flip;
> +}
> +
> +#ifndef STBI_THREAD_LOCAL
> +#define stbi__vertically_flip_on_load  stbi__vertically_flip_on_load_global
> +#else
> +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;
> +
> +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)
> +{
> +   stbi__vertically_flip_on_load_local = flag_true_if_should_flip;
> +   stbi__vertically_flip_on_load_set = 1;
> +}
> +
> +#define stbi__vertically_flip_on_load  (stbi__vertically_flip_on_load_set       \
> +                                         ? stbi__vertically_flip_on_load_local  \
> +                                         : stbi__vertically_flip_on_load_global)
> +#endif // STBI_THREAD_LOCAL
> +
> +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
> +{
> +   memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
> +   ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
> +   ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
> +   ri->num_channels = 0;
> +
> +   #ifndef STBI_NO_JPEG
> +   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
> +   #endif
> +   #ifndef STBI_NO_PNG
> +   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp, ri);
> +   #endif
> +   #ifndef STBI_NO_BMP
> +   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp, ri);
> +   #endif
> +   #ifndef STBI_NO_GIF
> +   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp, ri);
> +   #endif
> +   #ifndef STBI_NO_PSD
> +   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
> +   #else
> +   STBI_NOTUSED(bpc);
> +   #endif
> +   #ifndef STBI_NO_PIC
> +   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp, ri);
> +   #endif
> +   #ifndef STBI_NO_PNM
> +   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp, ri);
> +   #endif
> +
> +   #ifndef STBI_NO_HDR
> +   if (stbi__hdr_test(s)) {
> +      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);
> +      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
> +   }
> +   #endif
> +
> +   #ifndef STBI_NO_TGA
> +   // test tga last because it's a crappy test!
> +   if (stbi__tga_test(s))
> +      return stbi__tga_load(s,x,y,comp,req_comp, ri);
> +   #endif
> +
> +   return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
> +}
> +
> +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
> +{
> +   int i;
> +   int img_len = w * h * channels;
> +   stbi_uc *reduced;
> +
> +   reduced = (stbi_uc *) stbi__malloc(img_len);
> +   if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
> +
> +   for (i = 0; i < img_len; ++i)
> +      reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
> +
> +   STBI_FREE(orig);
> +   return reduced;
> +}
> +
> +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
> +{
> +   int i;
> +   int img_len = w * h * channels;
> +   stbi__uint16 *enlarged;
> +
> +   enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
> +   if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
> +
> +   for (i = 0; i < img_len; ++i)
> +      enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
> +
> +   STBI_FREE(orig);
> +   return enlarged;
> +}
> +
> +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
> +{
> +   int row;
> +   size_t bytes_per_row = (size_t)w * bytes_per_pixel;
> +   stbi_uc temp[2048];
> +   stbi_uc *bytes = (stbi_uc *)image;
> +
> +   for (row = 0; row < (h>>1); row++) {
> +      stbi_uc *row0 = bytes + row*bytes_per_row;
> +      stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
> +      // swap row0 with row1
> +      size_t bytes_left = bytes_per_row;
> +      while (bytes_left) {
> +         size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
> +         memcpy(temp, row0, bytes_copy);
> +         memcpy(row0, row1, bytes_copy);
> +         memcpy(row1, temp, bytes_copy);
> +         row0 += bytes_copy;
> +         row1 += bytes_copy;
> +         bytes_left -= bytes_copy;
> +      }
> +   }
> +}
> +
> +#ifndef STBI_NO_GIF
> +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
> +{
> +   int slice;
> +   int slice_size = w * h * bytes_per_pixel;
> +
> +   stbi_uc *bytes = (stbi_uc *)image;
> +   for (slice = 0; slice < z; ++slice) {
> +      stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
> +      bytes += slice_size;
> +   }
> +}
> +#endif
> +
> +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__result_info ri;
> +   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
> +
> +   if (result == NULL)
> +      return NULL;
> +
> +   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
> +   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
> +
> +   if (ri.bits_per_channel != 8) {
> +      result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
> +      ri.bits_per_channel = 8;
> +   }
> +
> +   // @TODO: move stbi__convert_format to here
> +
> +   if (stbi__vertically_flip_on_load) {
> +      int channels = req_comp ? req_comp : *comp;
> +      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
> +   }
> +
> +   return (unsigned char *) result;
> +}
> +
> +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__result_info ri;
> +   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
> +
> +   if (result == NULL)
> +      return NULL;
> +
> +   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
> +   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
> +
> +   if (ri.bits_per_channel != 16) {
> +      result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
> +      ri.bits_per_channel = 16;
> +   }
> +
> +   // @TODO: move stbi__convert_format16 to here
> +   // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
> +
> +   if (stbi__vertically_flip_on_load) {
> +      int channels = req_comp ? req_comp : *comp;
> +      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
> +   }
> +
> +   return (stbi__uint16 *) result;
> +}
> +
> +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)
> +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
> +{
> +   if (stbi__vertically_flip_on_load && result != NULL) {
> +      int channels = req_comp ? req_comp : *comp;
> +      stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
> +   }
> +}
> +#endif
> +
> +#ifndef STBI_NO_STDIO
> +
> +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
> +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
> +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
> +#endif
> +
> +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
> +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
> +{
> +	return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
> +}
> +#endif
> +
> +static FILE *stbi__fopen(char const *filename, char const *mode)
> +{
> +   FILE *f;
> +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
> +   wchar_t wMode[64];
> +   wchar_t wFilename[1024];
> +	if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
> +      return 0;
> +
> +	if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
> +      return 0;
> +
> +#if _MSC_VER >= 1400
> +	if (0 != _wfopen_s(&f, wFilename, wMode))
> +		f = 0;
> +#else
> +   f = _wfopen(wFilename, wMode);
> +#endif
> +
> +#elif defined(_MSC_VER) && _MSC_VER >= 1400
> +   if (0 != fopen_s(&f, filename, mode))
> +      f=0;
> +#else
> +   f = fopen(filename, mode);
> +#endif
> +   return f;
> +}
> +
> +
> +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
> +{
> +   FILE *f = stbi__fopen(filename, "rb");
> +   unsigned char *result;
> +   if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
> +   result = stbi_load_from_file(f,x,y,comp,req_comp);
> +   fclose(f);
> +   return result;
> +}
> +
> +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
> +{
> +   unsigned char *result;
> +   stbi__context s;
> +   stbi__start_file(&s,f);
> +   result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
> +   if (result) {
> +      // need to 'unget' all the characters in the IO buffer
> +      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
> +   }
> +   return result;
> +}
> +
> +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__uint16 *result;
> +   stbi__context s;
> +   stbi__start_file(&s,f);
> +   result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
> +   if (result) {
> +      // need to 'unget' all the characters in the IO buffer
> +      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
> +   }
> +   return result;
> +}
> +
> +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)
> +{
> +   FILE *f = stbi__fopen(filename, "rb");
> +   stbi__uint16 *result;
> +   if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file");
> +   result = stbi_load_from_file_16(f,x,y,comp,req_comp);
> +   fclose(f);
> +   return result;
> +}
> +
> +
> +#endif //!STBI_NO_STDIO
> +
> +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
> +{
> +   stbi__context s;
> +   stbi__start_mem(&s,buffer,len);
> +   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
> +}
> +
> +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
> +{
> +   stbi__context s;
> +   stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
> +   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
> +}
> +
> +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__context s;
> +   stbi__start_mem(&s,buffer,len);
> +   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
> +}
> +
> +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__context s;
> +   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
> +   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
> +}
> +
> +#ifndef STBI_NO_GIF
> +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
> +{
> +   unsigned char *result;
> +   stbi__context s;
> +   stbi__start_mem(&s,buffer,len);
> +
> +   result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
> +   if (stbi__vertically_flip_on_load) {
> +      stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
> +   }
> +
> +   return result;
> +}
> +#endif
> +
> +#ifndef STBI_NO_LINEAR
> +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
> +{
> +   unsigned char *data;
> +   #ifndef STBI_NO_HDR
> +   if (stbi__hdr_test(s)) {
> +      stbi__result_info ri;
> +      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);
> +      if (hdr_data)
> +         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
> +      return hdr_data;
> +   }
> +   #endif
> +   data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
> +   if (data)
> +      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
> +   return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
> +}
> +
> +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__context s;
> +   stbi__start_mem(&s,buffer,len);
> +   return stbi__loadf_main(&s,x,y,comp,req_comp);
> +}
> +
> +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__context s;
> +   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
> +   return stbi__loadf_main(&s,x,y,comp,req_comp);
> +}
> +
> +#ifndef STBI_NO_STDIO
> +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
> +{
> +   float *result;
> +   FILE *f = stbi__fopen(filename, "rb");
> +   if (!f) return stbi__errpf("can't fopen", "Unable to open file");
> +   result = stbi_loadf_from_file(f,x,y,comp,req_comp);
> +   fclose(f);
> +   return result;
> +}
> +
> +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
> +{
> +   stbi__context s;
> +   stbi__start_file(&s,f);
> +   return stbi__loadf_main(&s,x,y,comp,req_comp);
> +}
> +#endif // !STBI_NO_STDIO
> +
> +#endif // !STBI_NO_LINEAR
> +
> +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
> +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
> +// reports false!
> +
> +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
> +{
> +   #ifndef STBI_NO_HDR
> +   stbi__context s;
> +   stbi__start_mem(&s,buffer,len);
> +   return stbi__hdr_test(&s);
> +   #else
> +   STBI_NOTUSED(buffer);
> +   STBI_NOTUSED(len);
> +   return 0;
> +   #endif
> +}
> +
> +#ifndef STBI_NO_STDIO
> +STBIDEF int      stbi_is_hdr          (char const *filename)
> +{
> +   FILE *f = stbi__fopen(filename, "rb");
> +   int result=0;
> +   if (f) {
> +      result = stbi_is_hdr_from_file(f);
> +      fclose(f);
> +   }
> +   return result;
> +}
> +
> +STBIDEF int stbi_is_hdr_from_file(FILE *f)
> +{
> +   #ifndef STBI_NO_HDR
> +   long pos = ftell(f);
> +   int res;
> +   stbi__context s;
> +   stbi__start_file(&s,f);
> +   res = stbi__hdr_test(&s);
> +   fseek(f, pos, SEEK_SET);
> +   return res;
> +   #else
> +   STBI_NOTUSED(f);
> +   return 0;
> +   #endif
> +}
> +#endif // !STBI_NO_STDIO
> +
> +STBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
> +{
> +   #ifndef STBI_NO_HDR
> +   stbi__context s;
> +   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
> +   return stbi__hdr_test(&s);
> +   #else
> +   STBI_NOTUSED(clbk);
> +   STBI_NOTUSED(user);
> +   return 0;
> +   #endif
> +}
> +
> +#ifndef STBI_NO_LINEAR
> +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
> +
> +STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
> +STBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
> +#endif
> +
> +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
> +
> +STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
> +STBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
> +
> +
> +//////////////////////////////////////////////////////////////////////////////
> +//
> +// Common code used by all image loaders
> +//
> +
> +enum
> +{
> +   STBI__SCAN_load=0,
> +   STBI__SCAN_type,
> +   STBI__SCAN_header
> +};
> +
> +static void stbi__refill_buffer(stbi__context *s)
> +{
> +   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
> +   s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);
> +   if (n == 0) {
> +      // at end of file, treat same as if from memory, but need to handle case
> +      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
> +      s->read_from_callbacks = 0;
> +      s->img_buffer = s->buffer_start;
> +      s->img_buffer_end = s->buffer_start+1;
> +      *s->img_buffer = 0;
> +   } else {
> +      s->img_buffer = s->buffer_start;
> +      s->img_buffer_end = s->buffer_start + n;
> +   }
> +}
> +
> +stbi_inline static stbi_uc stbi__get8(stbi__context *s)
> +{
> +   if (s->img_buffer < s->img_buffer_end)
> +      return *s->img_buffer++;
> +   if (s->read_from_callbacks) {
> +      stbi__refill_buffer(s);
> +      return *s->img_buffer++;
> +   }
> +   return 0;
> +}
> +
> +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
> +// nothing
> +#else
> +stbi_inline static int stbi__at_eof(stbi__context *s)
> +{
> +   if (s->io.read) {
> +      if (!(s->io.eof)(s->io_user_data)) return 0;
> +      // if feof() is true, check if buffer = end
> +      // special case: we've only got the special 0 character at the end
> +      if (s->read_from_callbacks == 0) return 1;
> +   }
> +
> +   return s->img_buffer >= s->img_buffer_end;
> +}
> +#endif
> +
> +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)
> +// nothing
> +#else
> +static void stbi__skip(stbi__context *s, int n)
> +{
> +   if (n == 0) return;  // already there!
> +   if (n < 0) {
> +      s->img_buffer = s->img_buffer_end;
> +      return;
> +   }
> +   if (s->io.read) {
> +      int blen = (int) (s->img_buffer_end - s->img_buffer);
> +      if (blen < n) {
> +         s->img_buffer = s->img_buffer_end;
> +         (s->io.skip)(s->io_user_data, n - blen);
> +         return;
> +      }
> +   }
> +   s->img_buffer += n;
> +}
> +#endif
> +
> +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)
> +// nothing
> +#else
> +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
> +{
> +   if (s->io.read) {
> +      int blen = (int) (s->img_buffer_end - s->img_buffer);
> +      if (blen < n) {
> +         int res, count;
> +
> +         memcpy(buffer, s->img_buffer, blen);
> +
> +         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
> +         res = (count == (n-blen));
> +         s->img_buffer = s->img_buffer_end;
> +         return res;
> +      }
> +   }
> +
> +   if (s->img_buffer+n <= s->img_buffer_end) {
> +      memcpy(buffer, s->img_buffer, n);
> +      s->img_buffer += n;
> +      return 1;
> +   } else
> +      return 0;
> +}
> +#endif
> +
> +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
> +// nothing
> +#else
> +static int stbi__get16be(stbi__context *s)
> +{
> +   int z = stbi__get8(s);
> +   return (z << 8) + stbi__get8(s);
> +}
> +#endif
> +
> +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
> +// nothing
> +#else
> +static stbi__uint32 stbi__get32be(stbi__context *s)
> +{
> +   stbi__uint32 z = stbi__get16be(s);
> +   return (z << 16) + stbi__get16be(s);
> +}
> +#endif
> +
> +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
> +// nothing
> +#else
> +static int stbi__get16le(stbi__context *s)
> +{
> +   int z = stbi__get8(s);
> +   return z + (stbi__get8(s) << 8);
> +}
> +#endif
> +
> +#ifndef STBI_NO_BMP
> +static stbi__uint32 stbi__get32le(stbi__context *s)
> +{
> +   stbi__uint32 z = stbi__get16le(s);
> +   return z + (stbi__get16le(s) << 16);
> +}
> +#endif
> +
> +#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings
> +
> +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
> +// nothing
> +#else
> +//////////////////////////////////////////////////////////////////////////////
> +//
> +//  generic converter from built-in img_n to req_comp
> +//    individual types do this automatically as much as possible (e.g. jpeg
> +//    does all cases internally since it needs to colorspace convert anyway,
> +//    and it never has alpha, so very few cases ). png can automatically
> +//    interleave an alpha=255 channel, but falls back to this for other cases
> +//
> +//  assume data buffer is malloced, so malloc a new one and free that one
> +//  only failure mode is malloc failing
> +
> +static stbi_uc stbi__compute_y(int r, int g, int b)
> +{
> +   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);
> +}
> +#endif
> +
> +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
> +// nothing
> +#else
> +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
> +{
> +   int i,j;
> +   unsigned char *good;
> +
> +   if (req_comp == img_n) return data;
> +   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
> +
> +   good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
> +   if (good == NULL) {
> +      STBI_FREE(data);
> +      return stbi__errpuc("outofmem", "Out of memory");
> +   }
> +
> +   for (j=0; j < (int) y; ++j) {
> +      unsigned char *src  = data + j * x * img_n   ;
> +      unsigned char *dest = good + j * x * req_comp;
> +
> +      #define STBI__COMBO(a,b)  ((a)*8+(b))
> +      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
> +      // convert source image with img_n components to one with req_comp components;
> +      // avoid switch per pixel, so use switch per scanline and massive macros
> +      switch (STBI__COMBO(img_n, req_comp)) {
> +         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255;                                     } break;
> +         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;
> +         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255;                     } break;
> +         STBI__CASE(2,1) { dest[0]=src[0];                                                  } break;
> +         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;
> +         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                  } break;
> +         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255;        } break;
> +         STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;
> +         STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255;    } break;
> +         STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;
> +         STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;
> +         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                    } break;
> +         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion");
> +      }
> +      #undef STBI__CASE
> +   }
> +
> +   STBI_FREE(data);
> +   return good;
> +}
> +#endif
> +
> +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
> +// nothing
> +#else
> +static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
> +{
> +   return (stbi__uint16) (((r*77) + (g*150) +  (29*b)) >> 8);
> +}
> +#endif
> +
> +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
> +// nothing
> +#else
> +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
> +{
> +   int i,j;
> +   stbi__uint16 *good;
> +
> +   if (req_comp == img_n) return data;
> +   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
> +
> +   good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
> +   if (good == NULL) {
> +      STBI_FREE(data);
> +      return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
> +   }
> +
> +   for (j=0; j < (int) y; ++j) {
> +      stbi__uint16 *src  = data + j * x * img_n   ;
> +      stbi__uint16 *dest = good + j * x * req_comp;
> +
> +      #define STBI__COMBO(a,b)  ((a)*8+(b))
> +      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
> +      // convert source image with img_n components to one with req_comp components;
> +      // avoid switch per pixel, so use switch per scanline and massive macros
> +      switch (STBI__COMBO(img_n, req_comp)) {
> +         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff;                                     } break;
> +         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;
> +         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff;                     } break;
> +         STBI__CASE(2,1) { dest[0]=src[0];                                                     } break;
> +         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;
> +         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                     } break;
> +         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff;        } break;
> +         STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;
> +         STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;
> +         STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;
> +         STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;
> +         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                       } break;
> +         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion");
> +      }
> +      #undef STBI__CASE
> +   }
> +
> +   STBI_FREE(data);
> +   return good;
> +}
> +#endif
> +
> +#ifndef STBI_NO_LINEAR
> +static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
> +{
> +   int i,k,n;
> +   float *output;
> +   if (!data) return NULL;
> +   output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
> +   if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
> +   // compute number of non-alpha components
> +   if (comp & 1) n = comp; else n = comp-1;
> +   for (i=0; i < x*y; ++i) {
> +      for (k=0; k < n; ++k) {
> +         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
> +      }
> +   }
> +   if (n < comp) {
> +      for (i=0; i < x*y; ++i) {
> +         output[i*comp + n] = data[i*comp + n]/255.0f;
> +      }
> +   }
> +   STBI_FREE(data);
> +   return output;
> +}
> +#endif
> +
> +#ifndef STBI_NO_HDR
> +#define stbi__float2int(x)   ((int) (x))
> +static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)
> +{
> +   int i,k,n;
> +   stbi_uc *output;
> +   if (!data) return NULL;
> +   output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);
> +   if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
> +   // compute number of non-alpha components
> +   if (comp & 1) n = comp; else n = comp-1;
> +   for (i=0; i < x*y; ++i) {
> +      for (k=0; k < n; ++k) {
> +         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
> +         if (z < 0) z = 0;
> +         if (z > 255) z = 255;
> +         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
> +      }
> +      if (k < comp) {
> +         float z = data[i*comp+k] * 255 + 0.5f;
> +         if (z < 0) z = 0;
> +         if (z > 255) z = 255;
> +         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
> +      }
> +   }
> +   STBI_FREE(data);
> +   return output;
> +}
> +#endif
> +
> +//////////////////////////////////////////////////////////////////////////////
> +//
> +//  "baseline" JPEG/JFIF decoder
> +//
> +//    simple implementation
> +//      - doesn't support delayed output of y-dimension
> +//      - simple interface (only one output format: 8-bit interleaved RGB)
> +//      - doesn't try to recover corrupt jpegs
> +//      - doesn't allow partial loading, loading multiple at once
> +//      - still fast on x86 (copying globals into locals doesn't help x86)
> +//      - allocates lots of intermediate memory (full size of all components)
> +//        - non-interleaved case requires this anyway
> +//        - allows good upsampling (see next)
> +//    high-quality
> +//      - upsampled channels are bilinearly interpolated, even across blocks
> +//      - quality integer IDCT derived from IJG's 'slow'
> +//    performance
> +//      - fast huffman; reasonable integer IDCT
> +//      - some SIMD kernels for common paths on targets with SSE2/NEON
> +//      - uses a lot of intermediate memory, could cache poorly
> +
> +#ifndef STBI_NO_JPEG
> +
> +// huffman decoding acceleration
> +#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache
> +
> +typedef struct
> +{
> +   stbi_uc  fast[1 << FAST_BITS];
> +   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
> +   stbi__uint16 code[256];
> +   stbi_uc  values[256];
> +   stbi_uc  size[257];
> +   unsigned int maxcode[18];
> +   int    delta[17];   // old 'firstsymbol' - old 'firstcode'
> +} stbi__huffman;
> +
> +typedef struct
> +{
> +   stbi__context *s;
> +   stbi__huffman huff_dc[4];
> +   stbi__huffman huff_ac[4];
> +   stbi__uint16 dequant[4][64];
> +   stbi__int16 fast_ac[4][1 << FAST_BITS];
> +
> +// sizes for components, interleaved MCUs
> +   int img_h_max, img_v_max;
> +   int img_mcu_x, img_mcu_y;
> +   int img_mcu_w, img_mcu_h;
> +
> +// definition of jpeg image component
> +   struct
> +   {
> +      int id;
> +      int h,v;
> +      int tq;
> +      int hd,ha;
> +      int dc_pred;
> +
> +      int x,y,w2,h2;
> +      stbi_uc *data;
> +      void *raw_data, *raw_coeff;
> +      stbi_uc *linebuf;
> +      short   *coeff;   // progressive only
> +      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks
> +   } img_comp[4];
> +
> +   stbi__uint32   code_buffer; // jpeg entropy-coded buffer
> +   int            code_bits;   // number of valid bits
> +   unsigned char  marker;      // marker seen while filling entropy buffer
> +   int            nomore;      // flag if we saw a marker so must stop
> +
> +   int            progressive;
> +   int            spec_start;
> +   int            spec_end;
> +   int            succ_high;
> +   int            succ_low;
> +   int            eob_run;
> +   int            jfif;
> +   int            app14_color_transform; // Adobe APP14 tag
> +   int            rgb;
> +
> +   int scan_n, order[4];
> +   int restart_interval, todo;
> +
> +// kernels
> +   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
> +   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
> +   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
> +} stbi__jpeg;
> +
> +static int stbi__build_huffman(stbi__huffman *h, int *count)
> +{
> +   int i,j,k=0;
> +   unsigned int code;
> +   // build size list for each symbol (from JPEG spec)
> +   for (i=0; i < 16; ++i)
> +      for (j=0; j < count[i]; ++j)
> +         h->size[k++] = (stbi_uc) (i+1);
> +   h->size[k] = 0;
> +
> +   // compute actual symbols (from jpeg spec)
> +   code = 0;
> +   k = 0;
> +   for(j=1; j <= 16; ++j) {
> +      // compute delta to add to code to compute symbol id
> +      h->delta[j] = k - code;
> +      if (h->size[k] == j) {
> +         while (h->size[k] == j)
> +            h->code[k++] = (stbi__uint16) (code++);
> +         if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
> +      }
> +      // compute largest code + 1 for this size, preshifted as needed later
> +      h->maxcode[j] = code << (16-j);
> +      code <<= 1;
> +   }
> +   h->maxcode[j] = 0xffffffff;
> +
> +   // build non-spec acceleration table; 255 is flag for not-accelerated
> +   memset(h->fast, 255, 1 << FAST_BITS);
> +   for (i=0; i < k; ++i) {
> +      int s = h->size[i];
> +      if (s <= FAST_BITS) {
> +         int c = h->code[i] << (FAST_BITS-s);
> +         int m = 1 << (FAST_BITS-s);
> +         for (j=0; j < m; ++j) {
> +            h->fast[c+j] = (stbi_uc) i;
> +         }
> +      }
> +   }
> +   return 1;
> +}
> +
> +// build a table that decodes both magnitude and value of small ACs in
> +// one go.
> +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
> +{
> +   int i;
> +   for (i=0; i < (1 << FAST_BITS); ++i) {
> +      stbi_uc fast = h->fast[i];
> +      fast_ac[i] = 0;
> +      if (fast < 255) {
> +         int rs = h->values[fast];
> +         int run = (rs >> 4) & 15;
> +         int magbits = rs & 15;
> +         int len = h->size[fast];
> +
> +         if (magbits && len + magbits <= FAST_BITS) {
> +            // magnitude code followed by receive_extend code
> +            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
> +            int m = 1 << (magbits - 1);
> +            if (k < m) k += (~0U << magbits) + 1;
> +            // if the result is small enough, we can fit it in fast_ac table
> +            if (k >= -128 && k <= 127)
> +               fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
> +         }
> +      }
> +   }
> +}
> +
> +static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
> +{
> +   do {
> +      unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
> +      if (b == 0xff) {
> +         int c = stbi__get8(j->s);
> +         while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
> +         if (c != 0) {
> +            j->marker = (unsigned char) c;
> +            j->nomore = 1;
> +            return;
> +         }
> +      }
> +      j->code_buffer |= b << (24 - j->code_bits);
> +      j->code_bits += 8;
> +   } while (j->code_bits <= 24);
> +}
> +
> +// (1 << n) - 1
> +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
> +
> +// decode a jpeg huffman value from the bitstream
> +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
> +{
> +   unsigned int temp;
> +   int c,k;
> +
> +   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
> +
> +   // look at the top FAST_BITS and determine what symbol ID it is,
> +   // if the code is <= FAST_BITS
> +   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
> +   k = h->fast[c];
> +   if (k < 255) {
> +      int s = h->size[k];
> +      if (s > j->code_bits)
> +         return -1;
> +      j->code_buffer <<= s;
> +      j->code_bits -= s;
> +      return h->values[k];
> +   }
> +
> +   // naive test is to shift the code_buffer down so k bits are
> +   // valid, then test against maxcode. To speed this up, we've
> +   // preshifted maxcode left so that it has (16-k) 0s at the
> +   // end; in other words, regardless of the number of bits, it
> +   // wants to be compared against something shifted to have 16;
> +   // that way we don't need to shift inside the loop.
> +   temp = j->code_buffer >> 16;
> +   for (k=FAST_BITS+1 ; ; ++k)
> +      if (temp < h->maxcode[k])
> +         break;
> +   if (k == 17) {
> +      // error! code not found
> +      j->code_bits -= 16;
> +      return -1;
> +   }
> +
> +   if (k > j->code_bits)
> +      return -1;
> +
> +   // convert the huffman code to the symbol id
> +   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
> +   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
> +
> +   // convert the id to a symbol
> +   j->code_bits -= k;
> +   j->code_buffer <<= k;
> +   return h->values[c];
> +}
> +
> +// bias[n] = (-1<<n) + 1
> +static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
> +
> +// combined JPEG 'receive' and JPEG 'extend', since baseline
> +// always extends everything it receives.
> +stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
> +{
> +   unsigned int k;
> +   int sgn;
> +   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
> +
> +   sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
> +   k = stbi_lrot(j->code_buffer, n);
> +   if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0;
> +   j->code_buffer = k & ~stbi__bmask[n];
> +   k &= stbi__bmask[n];
> +   j->code_bits -= n;
> +   return k + (stbi__jbias[n] & ~sgn);
> +}
> +
> +// get some unsigned bits
> +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
> +{
> +   unsigned int k;
> +   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
> +   k = stbi_lrot(j->code_buffer, n);
> +   j->code_buffer = k & ~stbi__bmask[n];
> +   k &= stbi__bmask[n];
> +   j->code_bits -= n;
> +   return k;
> +}
> +
> +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
> +{
> +   unsigned int k;
> +   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
> +   k = j->code_buffer;
> +   j->code_buffer <<= 1;
> +   --j->code_bits;
> +   return k & 0x80000000;
> +}
> +
> +// given a value that's at position X in the zigzag stream,
> +// where does it appear in the 8x8 matrix coded as row-major?
> +static const stbi_uc stbi__jpeg_dezigzag[64+15] =
> +{
> +    0,  1,  8, 16,  9,  2,  3, 10,
> +   17, 24, 32, 25, 18, 11,  4,  5,
> +   12, 19, 26, 33, 40, 48, 41, 34,
> +   27, 20, 13,  6,  7, 14, 21, 28,
> +   35, 42, 49, 56, 57, 50, 43, 36,
> +   29, 22, 15, 23, 30, 37, 44, 51,
> +   58, 59, 52, 45, 38, 31, 39, 46,
> +   53, 60, 61, 54, 47, 55, 62, 63,
> +   // let corrupt input sample past end
> +   63, 63, 63, 63, 63, 63, 63, 63,
> +   63, 63, 63, 63, 63, 63, 63
> +};
> +
> +// decode one 64-entry block--
> +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)
> +{
> +   int diff,dc,k;
> +   int t;
> +
> +   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
> +   t = stbi__jpeg_huff_decode(j, hdc);
> +   if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
> +
> +   // 0 all the ac values now so we can do it 32-bits at a time
> +   memset(data,0,64*sizeof(data[0]));
> +
> +   diff = t ? stbi__extend_receive(j, t) : 0;
> +   dc = j->img_comp[b].dc_pred + diff;
> +   j->img_comp[b].dc_pred = dc;
> +   data[0] = (short) (dc * dequant[0]);
> +
> +   // decode AC components, see JPEG spec
> +   k = 1;
> +   do {
> +      unsigned int zig;
> +      int c,r,s;
> +      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
> +      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
> +      r = fac[c];
> +      if (r) { // fast-AC path
> +         k += (r >> 4) & 15; // run
> +         s = r & 15; // combined length
> +         j->code_buffer <<= s;
> +         j->code_bits -= s;
> +         // decode into unzigzag'd location
> +         zig = stbi__jpeg_dezigzag[k++];
> +         data[zig] = (short) ((r >> 8) * dequant[zig]);
> +      } else {
> +         int rs = stbi__jpeg_huff_decode(j, hac);
> +         if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
> +         s = rs & 15;
> +         r = rs >> 4;
> +         if (s == 0) {
> +            if (rs != 0xf0) break; // end block
> +            k += 16;
> +         } else {
> +            k += r;
> +            // decode into unzigzag'd location
> +            zig = stbi__jpeg_dezigzag[k++];
> +            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
> +         }
> +      }
> +   } while (k < 64);
> +   return 1;
> +}
> +
> +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
> +{
> +   int diff,dc;
> +   int t;
> +   if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
> +
> +   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
> +
> +   if (j->succ_high == 0) {
> +      // first scan for DC coefficient, must be first
> +      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
> +      t = stbi__jpeg_huff_decode(j, hdc);
> +      if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
> +      diff = t ? stbi__extend_receive(j, t) : 0;
> +
> +      dc = j->img_comp[b].dc_pred + diff;
> +      j->img_comp[b].dc_pred = dc;
> +      data[0] = (short) (dc << j->succ_low);
> +   } else {
> +      // refinement scan for DC coefficient
> +      if (stbi__jpeg_get_bit(j))
> +         data[0] += (short) (1 << j->succ_low);
> +   }
> +   return 1;
> +}
> +
> +// @OPTIMIZE: store non-zigzagged during the decode passes,
> +// and only de-zigzag when dequantizing
> +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
> +{
> +   int k;
> +   if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
> +
> +   if (j->succ_high == 0) {
> +      int shift = j->succ_low;
> +
> +      if (j->eob_run) {
> +         --j->eob_run;
> +         return 1;
> +      }
> +
> +      k = j->spec_start;
> +      do {
> +         unsigned int zig;
> +         int c,r,s;
> +         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
> +         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
> +         r = fac[c];
> +         if (r) { // fast-AC path
> +            k += (r >> 4) & 15; // run
> +            s = r & 15; // combined length
> +            j->code_buffer <<= s;
> +            j->code_bits -= s;
> +            zig = stbi__jpeg_dezigzag[k++];
> +            data[zig] = (short) ((r >> 8) << shift);
> +         } else {
> +            int rs = stbi__jpeg_huff_decode(j, hac);
> +            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
> +            s = rs & 15;
> +            r = rs >> 4;
> +            if (s == 0) {
> +               if (r < 15) {
> +                  j->eob_run = (1 << r);
> +                  if (r)
> +                     j->eob_run += stbi__jpeg_get_bits(j, r);
> +                  --j->eob_run;
> +                  break;
> +               }
> +               k += 16;
> +            } else {
> +               k += r;
> +               zig = stbi__jpeg_dezigzag[k++];
> +               data[zig] = (short) (stbi__extend_receive(j,s) << shift);
> +            }
> +         }
> +      } while (k <= j->spec_end);
> +   } else {
> +      // refinement scan for these AC coefficients
> +
> +      short bit = (short) (1 << j->succ_low);
> +
> +      if (j->eob_run) {
> +         --j->eob_run;
> +         for (k = j->spec_start; k <= j->spec_end; ++k) {
> +            short *p = &data[stbi__jpeg_dezigzag[k]];
> +            if (*p != 0)
> +               if (stbi__jpeg_get_bit(j))
> +                  if ((*p & bit)==0) {
> +                     if (*p > 0)
> +                        *p += bit;
> +                     else
> +                        *p -= bit;
> +                  }
> +         }
> +      } else {
> +         k = j->spec_start;
> +         do {
> +            int r,s;
> +            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
> +            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
> +            s = rs & 15;
> +            r = rs >> 4;
> +            if (s == 0) {
> +               if (r < 15) {
> +                  j->eob_run = (1 << r) - 1;
> +                  if (r)
> +                     j->eob_run += stbi__jpeg_get_bits(j, r);
> +                  r = 64; // force end of block
> +               } else {
> +                  // r=15 s=0 should write 16 0s, so we just do
> +                  // a run of 15 0s and then write s (which is 0),
> +                  // so we don't have to do anything special here
> +               }
> +            } else {
> +               if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
> +               // sign bit
> +               if (stbi__jpeg_get_bit(j))
> +                  s = bit;
> +               else
> +                  s = -bit;
> +            }
> +
> +            // advance by r
> +            while (k <= j->spec_end) {
> +               short *p = &data[stbi__jpeg_dezigzag[k++]];
> +               if (*p != 0) {
> +                  if (stbi__jpeg_get_bit(j))
> +                     if ((*p & bit)==0) {
> +                        if (*p > 0)
> +                           *p += bit;
> +                        else
> +                           *p -= bit;
> +                     }
> +               } else {
> +                  if (r == 0) {
> +                     *p = (short) s;
> +                     break;
> +                  }
> +                  --r;
> +               }
> +            }
> +         } while (k <= j->spec_end);
> +      }
> +   }
> +   return 1;
> +}
> +
> +// take a -128..127 value and stbi__clamp it and convert to 0..255
> +stbi_inline static stbi_uc stbi__clamp(int x)
> +{
> +   // trick to use a single test to catch both cases
> +   if ((unsigned int) x > 255) {
> +      if (x < 0) return 0;
> +      if (x > 255) return 255;
> +   }
> +   return (stbi_uc) x;
> +}
> +
> +#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))
> +#define stbi__fsh(x)  ((x) * 4096)
> +
> +// derived from jidctint -- DCT_ISLOW
> +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
> +   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
> +   p2 = s2;                                    \
> +   p3 = s6;                                    \
> +   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \
> +   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \
> +   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \
> +   p2 = s0;                                    \
> +   p3 = s4;                                    \
> +   t0 = stbi__fsh(p2+p3);                      \
> +   t1 = stbi__fsh(p2-p3);                      \
> +   x0 = t0+t3;                                 \
> +   x3 = t0-t3;                                 \
> +   x1 = t1+t2;                                 \
> +   x2 = t1-t2;                                 \
> +   t0 = s7;                                    \
> +   t1 = s5;                                    \
> +   t2 = s3;                                    \
> +   t3 = s1;                                    \
> +   p3 = t0+t2;                                 \
> +   p4 = t1+t3;                                 \
> +   p1 = t0+t3;                                 \
> +   p2 = t1+t2;                                 \
> +   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \
> +   t0 = t0*stbi__f2f( 0.298631336f);           \
> +   t1 = t1*stbi__f2f( 2.053119869f);           \
> +   t2 = t2*stbi__f2f( 3.072711026f);           \
> +   t3 = t3*stbi__f2f( 1.501321110f);           \
> +   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \
> +   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \
> +   p3 = p3*stbi__f2f(-1.961570560f);           \
> +   p4 = p4*stbi__f2f(-0.390180644f);           \
> +   t3 += p1+p4;                                \
> +   t2 += p2+p3;                                \
> +   t1 += p2+p4;                                \
> +   t0 += p1+p3;
> +
> +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
> +{
> +   int i,val[64],*v=val;
> +   stbi_uc *o;
> +   short *d = data;
> +
> +   // columns
> +   for (i=0; i < 8; ++i,++d, ++v) {
> +      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
> +      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
> +           && d[40]==0 && d[48]==0 && d[56]==0) {
> +         //    no shortcut                 0     seconds
> +         //    (1|2|3|4|5|6|7)==0          0     seconds
> +         //    all separate               -0.047 seconds
> +         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds
> +         int dcterm = d[0]*4;
> +         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
> +      } else {
> +         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
> +         // constants scaled things up by 1<<12; let's bring them back
> +         // down, but keep 2 extra bits of precision
> +         x0 += 512; x1 += 512; x2 += 512; x3 += 512;
> +         v[ 0] = (x0+t3) >> 10;
> +         v[56] = (x0-t3) >> 10;
> +         v[ 8] = (x1+t2) >> 10;
> +         v[48] = (x1-t2) >> 10;
> +         v[16] = (x2+t1) >> 10;
> +         v[40] = (x2-t1) >> 10;
> +         v[24] = (x3+t0) >> 10;
> +         v[32] = (x3-t0) >> 10;
> +      }
> +   }
> +
> +   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
> +      // no fast case since the first 1D IDCT spread components out
> +      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
> +      // constants scaled things up by 1<<12, plus we had 1<<2 from first
> +      // loop, plus horizontal and vertical each scale by sqrt(8) so together
> +      // we've got an extra 1<<3, so 1<<17 total we need to remove.
> +      // so we want to round that, which means adding 0.5 * 1<<17,
> +      // aka 65536. Also, we'll end up with -128 to 127 that we want
> +      // to encode as 0..255 by adding 128, so we'll add that before the shift
> +      x0 += 65536 + (128<<17);
> +      x1 += 65536 + (128<<17);
> +      x2 += 65536 + (128<<17);
> +      x3 += 65536 + (128<<17);
> +      // tried computing the shifts into temps, or'ing the temps to see
> +      // if any were out of range, but that was slower
> +      o[0] = stbi__clamp((x0+t3) >> 17);
> +      o[7] = stbi__clamp((x0-t3) >> 17);
> +      o[1] = stbi__clamp((x1+t2) >> 17);
> +      o[6] = stbi__clamp((x1-t2) >> 17);
> +      o[2] = stbi__clamp((x2+t1) >> 17);
> +      o[5] = stbi__clamp((x2-t1) >> 17);
> +      o[3] = stbi__clamp((x3+t0) >> 17);
> +      o[4] = stbi__clamp((x3-t0) >> 17);
> +   }
> +}
> +
> +#ifdef STBI_SSE2
> +// sse2 integer IDCT. not the fastest possible implementation but it
> +// produces bit-identical results to the generic C version so it's
> +// fully "transparent".
> +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
> +{
> +   // This is constructed to match our regular (generic) integer IDCT exactly.
> +   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
> +   __m128i tmp;
> +
> +   // dot product constant: even elems=x, odd elems=y
> +   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
> +
> +   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
> +   // out(1) = c1[even]*x + c1[odd]*y
> +   #define dct_rot(out0,out1, x,y,c0,c1) \
> +      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
> +      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
> +      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
> +      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
> +      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
> +      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
> +
> +   // out = in << 12  (in 16-bit, out 32-bit)
> +   #define dct_widen(out, in) \
> +      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
> +      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
> +
> +   // wide add
> +   #define dct_wadd(out, a, b) \
> +      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
> +      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
> +
> +   // wide sub
> +   #define dct_wsub(out, a, b) \
> +      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
> +      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
> +
> +   // butterfly a/b, add bias, then shift by "s" and pack
> +   #define dct_bfly32o(out0, out1, a,b,bias,s) \
> +      { \
> +         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
> +         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
> +         dct_wadd(sum, abiased, b); \
> +         dct_wsub(dif, abiased, b); \
> +         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
> +         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
> +      }
> +
> +   // 8-bit interleave step (for transposes)
> +   #define dct_interleave8(a, b) \
> +      tmp = a; \
> +      a = _mm_unpacklo_epi8(a, b); \
> +      b = _mm_unpackhi_epi8(tmp, b)
> +
> +   // 16-bit interleave step (for transposes)
> +   #define dct_interleave16(a, b) \
> +      tmp = a; \
> +      a = _mm_unpacklo_epi16(a, b); \
> +      b = _mm_unpackhi_epi16(tmp, b)
> +
> +   #define dct_pass(bias,shift) \
> +      { \
> +         /* even part */ \
> +         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
> +         __m128i sum04 = _mm_add_epi16(row0, row4); \
> +         __m128i dif04 = _mm_sub_epi16(row0, row4); \
> +         dct_widen(t0e, sum04); \
> +         dct_widen(t1e, dif04); \
> +         dct_wadd(x0, t0e, t3e); \
> +         dct_wsub(x3, t0e, t3e); \
> +         dct_wadd(x1, t1e, t2e); \
> +         dct_wsub(x2, t1e, t2e); \
> +         /* odd part */ \
> +         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
> +         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
> +         __m128i sum17 = _mm_add_epi16(row1, row7); \
> +         __m128i sum35 = _mm_add_epi16(row3, row5); \
> +         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
> +         dct_wadd(x4, y0o, y4o); \
> +         dct_wadd(x5, y1o, y5o); \
> +         dct_wadd(x6, y2o, y5o); \
> +         dct_wadd(x7, y3o, y4o); \
> +         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
> +         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
> +         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
> +         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
> +      }
> +
> +   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
> +   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
> +   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
> +   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
> +   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
> +   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
> +   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
> +   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
> +
> +   // rounding biases in column/row passes, see stbi__idct_block for explanation.
> +   __m128i bias_0 = _mm_set1_epi32(512);
> +   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
> +
> +   // load
> +   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
> +   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
> +   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
> +   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
> +   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
> +   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
> +   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
> +   row7 = _mm_load_si128((const __m128i *) (data + 7*8));
> +
> +   // column pass
> +   dct_pass(bias_0, 10);
> +
> +   {
> +      // 16bit 8x8 transpose pass 1
> +      dct_interleave16(row0, row4);
> +      dct_interleave16(row1, row5);
> +      dct_interleave16(row2, row6);
> +      dct_interleave16(row3, row7);
> +
> +      // transpose pass 2
> +      dct_interleave16(row0, row2);
> +      dct_interleave16(row1, row3);
> +      dct_interleave16(row4, row6);
> +      dct_interleave16(row5, row7);
> +
> +      // transpose pass 3
> +      dct_interleave16(row0, row1);
> +      dct_interleave16(row2, row3);
> +      dct_interleave16(row4, row5);
> +      dct_interleave16(row6, row7);
> +   }
> +
> +   // row pass
> +   dct_pass(bias_1, 17);
> +
> +   {
> +      // pack
> +      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
> +      __m128i p1 = _mm_packus_epi16(row2, row3);
> +      __m128i p2 = _mm_packus_epi16(row4, row5);
> +      __m128i p3 = _mm_packus_epi16(row6, row7);
> +
> +      // 8bit 8x8 transpose pass 1
> +      dct_interleave8(p0, p2); // a0e0a1e1...
> +      dct_interleave8(p1, p3); // c0g0c1g1...
> +
> +      // transpose pass 2
> +      dct_interleave8(p0, p1); // a0c0e0g0...
> +      dct_interleave8(p2, p3); // b0d0f0h0...
> +
> +      // transpose pass 3
> +      dct_interleave8(p0, p2); // a0b0c0d0...
> +      dct_interleave8(p1, p3); // a4b4c4d4...
> +
> +      // store
> +      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
> +      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
> +      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
> +      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
> +      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
> +      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
> +      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
> +      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
> +   }
> +
> +#undef dct_const
> +#undef dct_rot
> +#undef dct_widen
> +#undef dct_wadd
> +#undef dct_wsub
> +#undef dct_bfly32o
> +#undef dct_interleave8
> +#undef dct_interleave16
> +#undef dct_pass
> +}
> +
> +#endif // STBI_SSE2
> +
> +#ifdef STBI_NEON
> +
> +// NEON integer IDCT. should produce bit-identical
> +// results to the generic C version.
> +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
> +{
> +   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
> +
> +   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
> +   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
> +   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
> +   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
> +   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
> +   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
> +   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
> +   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
> +   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
> +   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
> +   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
> +   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
> +
> +#define dct_long_mul(out, inq, coeff) \
> +   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
> +   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
> +
> +#define dct_long_mac(out, acc, inq, coeff) \
> +   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
> +   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
> +
> +#define dct_widen(out, inq) \
> +   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
> +   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
> +
> +// wide add
> +#define dct_wadd(out, a, b) \
> +   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
> +   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
> +
> +// wide sub
> +#define dct_wsub(out, a, b) \
> +   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
> +   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
> +
> +// butterfly a/b, then shift using "shiftop" by "s" and pack
> +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
> +   { \
> +      dct_wadd(sum, a, b); \
> +      dct_wsub(dif, a, b); \
> +      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
> +      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
> +   }
> +
> +#define dct_pass(shiftop, shift) \
> +   { \
> +      /* even part */ \
> +      int16x8_t sum26 = vaddq_s16(row2, row6); \
> +      dct_long_mul(p1e, sum26, rot0_0); \
> +      dct_long_mac(t2e, p1e, row6, rot0_1); \
> +      dct_long_mac(t3e, p1e, row2, rot0_2); \
> +      int16x8_t sum04 = vaddq_s16(row0, row4); \
> +      int16x8_t dif04 = vsubq_s16(row0, row4); \
> +      dct_widen(t0e, sum04); \
> +      dct_widen(t1e, dif04); \
> +      dct_wadd(x0, t0e, t3e); \
> +      dct_wsub(x3, t0e, t3e); \
> +      dct_wadd(x1, t1e, t2e); \
> +      dct_wsub(x2, t1e, t2e); \
> +      /* odd part */ \
> +      int16x8_t sum15 = vaddq_s16(row1, row5); \
> +      int16x8_t sum17 = vaddq_s16(row1, row7); \
> +      int16x8_t sum35 = vaddq_s16(row3, row5); \
> +      int16x8_t sum37 = vaddq_s16(row3, row7); \
> +      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
> +      dct_long_mul(p5o, sumodd, rot1_0); \
> +      dct_long_mac(p1o, p5o, sum17, rot1_1); \
> +      dct_long_mac(p2o, p5o, sum35, rot1_2); \
> +      dct_long_mul(p3o, sum37, rot2_0); \
> +      dct_long_mul(p4o, sum15, rot2_1); \
> +      dct_wadd(sump13o, p1o, p3o); \
> +      dct_wadd(sump24o, p2o, p4o); \
> +      dct_wadd(sump23o, p2o, p3o); \
> +      dct_wadd(sump14o, p1o, p4o); \
> +      dct_long_mac(x4, sump13o, row7, rot3_0); \
> +      dct_long_mac(x5, sump24o, row5, rot3_1); \
> +      dct_long_mac(x6, sump23o, row3, rot3_2); \
> +      dct_long_mac(x7, sump14o, row1, rot3_3); \
> +      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
> +      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
> +      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
> +      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
> +   }
> +
> +   // load
> +   row0 = vld1q_s16(data + 0*8);
> +   row1 = vld1q_s16(data + 1*8);
> +   row2 = vld1q_s16(data + 2*8);
> +   row3 = vld1q_s16(data + 3*8);
> +   row4 = vld1q_s16(data + 4*8);
> +   row5 = vld1q_s16(data + 5*8);
> +   row6 = vld1q_s16(data + 6*8);
> +   row7 = vld1q_s16(data + 7*8);
> +
> +   // add DC bias
> +   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
> +
> +   // column pass
> +   dct_pass(vrshrn_n_s32, 10);
> +
> +   // 16bit 8x8 transpose
> +   {
> +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
> +// whether compilers actually get this is another story, sadly.
> +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
> +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
> +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
> +
> +      // pass 1
> +      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
> +      dct_trn16(row2, row3);
> +      dct_trn16(row4, row5);
> +      dct_trn16(row6, row7);
> +
> +      // pass 2
> +      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
> +      dct_trn32(row1, row3);
> +      dct_trn32(row4, row6);
> +      dct_trn32(row5, row7);
> +
> +      // pass 3
> +      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
> +      dct_trn64(row1, row5);
> +      dct_trn64(row2, row6);
> +      dct_trn64(row3, row7);
> +
> +#undef dct_trn16
> +#undef dct_trn32
> +#undef dct_trn64
> +   }
> +
> +   // row pass
> +   // vrshrn_n_s32 only supports shifts up to 16, we need
> +   // 17. so do a non-rounding shift of 16 first then follow
> +   // up with a rounding shift by 1.
> +   dct_pass(vshrn_n_s32, 16);
> +
> +   {
> +      // pack and round
> +      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
> +      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
> +      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
> +      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
> +      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
> +      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
> +      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
> +      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
> +
> +      // again, these can translate into one instruction, but often don't.
> +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
> +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
> +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
> +
> +      // sadly can't use interleaved stores here since we only write
> +      // 8 bytes to each scan line!
> +
> +      // 8x8 8-bit transpose pass 1
> +      dct_trn8_8(p0, p1);
> +      dct_trn8_8(p2, p3);
> +      dct_trn8_8(p4, p5);
> +      dct_trn8_8(p6, p7);
> +
> +      // pass 2
> +      dct_trn8_16(p0, p2);
> +      dct_trn8_16(p1, p3);
> +      dct_trn8_16(p4, p6);
> +      dct_trn8_16(p5, p7);
> +
> +      // pass 3
> +      dct_trn8_32(p0, p4);
> +      dct_trn8_32(p1, p5);
> +      dct_trn8_32(p2, p6);
> +      dct_trn8_32(p3, p7);
> +
> +      // store
> +      vst1_u8(out, p0); out += out_stride;
> +      vst1_u8(out, p1); out += out_stride;
> +      vst1_u8(out, p2); out += out_stride;
> +      vst1_u8(out, p3); out += out_stride;
> +      vst1_u8(out, p4); out += out_stride;
> +      vst1_u8(out, p5); out += out_stride;
> +      vst1_u8(out, p6); out += out_stride;
> +      vst1_u8(out, p7);
> +
> +#undef dct_trn8_8
> +#undef dct_trn8_16
> +#undef dct_trn8_32
> +   }
> +
> +#undef dct_long_mul
> +#undef dct_long_mac
> +#undef dct_widen
> +#undef dct_wadd
> +#undef dct_wsub
> +#undef dct_bfly32o
> +#undef dct_pass
> +}
> +
> +#endif // STBI_NEON
> +
> +#define STBI__MARKER_none  0xff
> +// if there's a pending marker from the entropy stream, return that
> +// otherwise, fetch from the stream and get a marker. if there's no
> +// marker, return 0xff, which is never a valid marker value
> +static stbi_uc stbi__get_marker(stbi__jpeg *j)
> +{
> +   stbi_uc x;
> +   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
> +   x = stbi__get8(j->s);
> +   if (x != 0xff) return STBI__MARKER_none;
> +   while (x == 0xff)
> +      x = stbi__get8(j->s); // consume repeated 0xff fill bytes
> +   return x;
> +}
> +
> +// in each scan, we'll have scan_n components, and the order
> +// of the components is specified by order[]
> +#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
> +
> +// after a restart interval, stbi__jpeg_reset the entropy decoder and
> +// the dc prediction
> +static void stbi__jpeg_reset(stbi__jpeg *j)
> +{
> +   j->code_bits = 0;
> +   j->code_buffer = 0;
> +   j->nomore = 0;
> +   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;
> +   j->marker = STBI__MARKER_none;
> +   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
> +   j->eob_run = 0;
> +   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
> +   // since we don't even allow 1<<30 pixels
> +}
> +
> +static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
> +{
> +   stbi__jpeg_reset(z);
> +   if (!z->progressive) {
> +      if (z->scan_n == 1) {
> +         int i,j;
> +         STBI_SIMD_ALIGN(short, data[64]);
> +         int n = z->order[0];
> +         // non-interleaved data, we just need to process one block at a time,
> +         // in trivial scanline order
> +         // number of blocks to do just depends on how many actual "pixels" this
> +         // component has, independent of interleaved MCU blocking and such
> +         int w = (z->img_comp[n].x+7) >> 3;
> +         int h = (z->img_comp[n].y+7) >> 3;
> +         for (j=0; j < h; ++j) {
> +            for (i=0; i < w; ++i) {
> +               int ha = z->img_comp[n].ha;
> +               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
> +               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
> +               // every data block is an MCU, so countdown the restart interval
> +               if (--z->todo <= 0) {
> +                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
> +                  // if it's NOT a restart, then just bail, so we get corrupt data
> +                  // rather than no data
> +                  if (!STBI__RESTART(z->marker)) return 1;
> +                  stbi__jpeg_reset(z);
> +               }
> +            }
> +         }
> +         return 1;
> +      } else { // interleaved
> +         int i,j,k,x,y;
> +         STBI_SIMD_ALIGN(short, data[64]);
> +         for (j=0; j < z->img_mcu_y; ++j) {
> +            for (i=0; i < z->img_mcu_x; ++i) {
> +               // scan an interleaved mcu... process scan_n components in order
> +               for (k=0; k < z->scan_n; ++k) {
> +                  int n = z->order[k];
> +                  // scan out an mcu's worth of this component; that's just determined
> +                  // by the basic H and V specified for the component
> +                  for (y=0; y < z->img_comp[n].v; ++y) {
> +                     for (x=0; x < z->img_comp[n].h; ++x) {
> +                        int x2 = (i*z->img_comp[n].h + x)*8;
> +                        int y2 = (j*z->img_comp[n].v + y)*8;
> +                        int ha = z->img_comp[n].ha;
> +                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
> +                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
> +                     }
> +                  }
> +               }
> +               // after all interleaved components, that's an interleaved MCU,
> +               // so now count down the restart interval
> +               if (--z->todo <= 0) {
> +                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
> +                  if (!STBI__RESTART(z->marker)) return 1;
> +                  stbi__jpeg_reset(z);
> +               }
> +            }
> +         }
> +         return 1;
> +      }
> +   } else {
> +      if (z->scan_n == 1) {
> +         int i,j;
> +         int n = z->order[0];
> +         // non-interleaved data, we just need to process one block at a time,
> +         // in trivial scanline order
> +         // number of blocks to do just depends on how many actual "pixels" this
> +         // component has, independent of interleaved MCU blocking and such
> +         int w = (z->img_comp[n].x+7) >> 3;
> +         int h = (z->img_comp[n].y+7) >> 3;
> +         for (j=0; j < h; ++j) {
> +            for (i=0; i < w; ++i) {
> +               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
> +               if (z->spec_start == 0) {
> +                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
> +                     return 0;
> +               } else {
> +                  int ha = z->img_comp[n].ha;
> +                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
> +                     return 0;
> +               }
> +               // every data block is an MCU, so countdown the restart interval
> +               if (--z->todo <= 0) {
> +                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
> +                  if (!STBI__RESTART(z->marker)) return 1;
> +                  stbi__jpeg_reset(z);
> +               }
> +            }
> +         }
> +         return 1;
> +      } else { // interleaved
> +         int i,j,k,x,y;
> +         for (j=0; j < z->img_mcu_y; ++j) {
> +            for (i=0; i < z->img_mcu_x; ++i) {
> +               // scan an interleaved mcu... process scan_n components in order
> +               for (k=0; k < z->scan_n; ++k) {
> +                  int n = z->order[k];
> +                  // scan out an mcu's worth of this component; that's just determined
> +                  // by the basic H and V specified for the component
> +                  for (y=0; y < z->img_comp[n].v; ++y) {
> +                     for (x=0; x < z->img_comp[n].h; ++x) {
> +                        int x2 = (i*z->img_comp[n].h + x);
> +                        int y2 = (j*z->img_comp[n].v + y);
> +                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
> +                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
> +                           return 0;
> +                     }
> +                  }
> +               }
> +               // after all interleaved components, that's an interleaved MCU,
> +               // so now count down the restart interval
> +               if (--z->todo <= 0) {
> +                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
> +                  if (!STBI__RESTART(z->marker)) return 1;
> +                  stbi__jpeg_reset(z);
> +               }
> +            }
> +         }
> +         return 1;
> +      }
> +   }
> +}
> +
> +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)
> +{
> +   int i;
> +   for (i=0; i < 64; ++i)
> +      data[i] *= dequant[i];
> +}
> +
> +static void stbi__jpeg_finish(stbi__jpeg *z)
> +{
> +   if (z->progressive) {
> +      // dequantize and idct the data
> +      int i,j,n;
> +      for (n=0; n < z->s->img_n; ++n) {
> +         int w = (z->img_comp[n].x+7) >> 3;
> +         int h = (z->img_comp[n].y+7) >> 3;
> +         for (j=0; j < h; ++j) {
> +            for (i=0; i < w; ++i) {
> +               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
> +               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
> +               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
> +            }
> +         }
> +      }
> +   }
> +}
> +
> +static int stbi__process_marker(stbi__jpeg *z, int m)
> +{
> +   int L;
> +   switch (m) {
> +      case STBI__MARKER_none: // no marker found
> +         return stbi__err("expected marker","Corrupt JPEG");
> +
> +      case 0xDD: // DRI - specify restart interval
> +         if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
> +         z->restart_interval = stbi__get16be(z->s);
> +         return 1;
> +
> +      case 0xDB: // DQT - define quantization table
> +         L = stbi__get16be(z->s)-2;
> +         while (L > 0) {
> +            int q = stbi__get8(z->s);
> +            int p = q >> 4, sixteen = (p != 0);
> +            int t = q & 15,i;
> +            if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG");
> +            if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
> +
> +            for (i=0; i < 64; ++i)
> +               z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));
> +            L -= (sixteen ? 129 : 65);
> +         }
> +         return L==0;
> +
> +      case 0xC4: // DHT - define huffman table
> +         L = stbi__get16be(z->s)-2;
> +         while (L > 0) {
> +            stbi_uc *v;
> +            int sizes[16],i,n=0;
> +            int q = stbi__get8(z->s);
> +            int tc = q >> 4;
> +            int th = q & 15;
> +            if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
> +            for (i=0; i < 16; ++i) {
> +               sizes[i] = stbi__get8(z->s);
> +               n += sizes[i];
> +            }
> +            L -= 17;
> +            if (tc == 0) {
> +               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
> +               v = z->huff_dc[th].values;
> +            } else {
> +               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
> +               v = z->huff_ac[th].values;
> +            }
> +            for (i=0; i < n; ++i)
> +               v[i] = stbi__get8(z->s);
> +            if (tc != 0)
> +               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
> +            L -= n;
> +         }
> +         return L==0;
> +   }
> +
> +   // check for comment block or APP blocks
> +   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
> +      L = stbi__get16be(z->s);
> +      if (L < 2) {
> +         if (m == 0xFE)
> +            return stbi__err("bad COM len","Corrupt JPEG");
> +         else
> +            return stbi__err("bad APP len","Corrupt JPEG");
> +      }
> +      L -= 2;
> +
> +      if (m == 0xE0 && L >= 5) { // JFIF APP0 segment
> +         static const unsigned char tag[5] = {'J','F','I','F','\0'};
> +         int ok = 1;
> +         int i;
> +         for (i=0; i < 5; ++i)
> +            if (stbi__get8(z->s) != tag[i])
> +               ok = 0;
> +         L -= 5;
> +         if (ok)
> +            z->jfif = 1;
> +      } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment
> +         static const unsigned char tag[6] = {'A','d','o','b','e','\0'};
> +         int ok = 1;
> +         int i;
> +         for (i=0; i < 6; ++i)
> +            if (stbi__get8(z->s) != tag[i])
> +               ok = 0;
> +         L -= 6;
> +         if (ok) {
> +            stbi__get8(z->s); // version
> +            stbi__get16be(z->s); // flags0
> +            stbi__get16be(z->s); // flags1
> +            z->app14_color_transform = stbi__get8(z->s); // color transform
> +            L -= 6;
> +         }
> +      }
> +
> +      stbi__skip(z->s, L);
> +      return 1;
> +   }
> +
> +   return stbi__err("unknown marker","Corrupt JPEG");
> +}
> +
> +// after we see SOS
> +static int stbi__process_scan_header(stbi__jpeg *z)
> +{
> +   int i;
> +   int Ls = stbi__get16be(z->s);
> +   z->scan_n = stbi__get8(z->s);
> +   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
> +   if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
> +   for (i=0; i < z->scan_n; ++i) {
> +      int id = stbi__get8(z->s), which;
> +      int q = stbi__get8(z->s);
> +      for (which = 0; which < z->s->img_n; ++which)
> +         if (z->img_comp[which].id == id)
> +            break;
> +      if (which == z->s->img_n) return 0; // no match
> +      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
> +      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
> +      z->order[i] = which;
> +   }
> +
> +   {
> +      int aa;
> +      z->spec_start = stbi__get8(z->s);
> +      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0
> +      aa = stbi__get8(z->s);
> +      z->succ_high = (aa >> 4);
> +      z->succ_low  = (aa & 15);
> +      if (z->progressive) {
> +         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
> +            return stbi__err("bad SOS", "Corrupt JPEG");
> +      } else {
> +         if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
> +         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
> +         z->spec_end = 63;
> +      }
> +   }
> +
> +   return 1;
> +}
> +
> +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)
> +{
> +   int i;
> +   for (i=0; i < ncomp; ++i) {
> +      if (z->img_comp[i].raw_data) {
> +         STBI_FREE(z->img_comp[i].raw_data);
> +         z->img_comp[i].raw_data = NULL;
> +         z->img_comp[i].data = NULL;
> +      }
> +      if (z->img_comp[i].raw_coeff) {
> +         STBI_FREE(z->img_comp[i].raw_coeff);
> +         z->img_comp[i].raw_coeff = 0;
> +         z->img_comp[i].coeff = 0;
> +      }
> +      if (z->img_comp[i].linebuf) {
> +         STBI_FREE(z->img_comp[i].linebuf);
> +         z->img_comp[i].linebuf = NULL;
> +      }
> +   }
> +   return why;
> +}
> +
> +static int stbi__process_frame_header(stbi__jpeg *z, int scan)
> +{
> +   stbi__context *s = z->s;
> +   int Lf,p,i,q, h_max=1,v_max=1,c;
> +   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
> +   p  = stbi__get8(s);            if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
> +   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
> +   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
> +   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
> +   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
> +   c = stbi__get8(s);
> +   if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
> +   s->img_n = c;
> +   for (i=0; i < c; ++i) {
> +      z->img_comp[i].data = NULL;
> +      z->img_comp[i].linebuf = NULL;
> +   }
> +
> +   if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
> +
> +   z->rgb = 0;
> +   for (i=0; i < s->img_n; ++i) {
> +      static const unsigned char rgb[3] = { 'R', 'G', 'B' };
> +      z->img_comp[i].id = stbi__get8(s);
> +      if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
> +         ++z->rgb;
> +      q = stbi__get8(s);
> +      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
> +      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
> +      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
> +   }
> +
> +   if (scan != STBI__SCAN_load) return 1;
> +
> +   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode");
> +
> +   for (i=0; i < s->img_n; ++i) {
> +      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
> +      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
> +   }
> +
> +   // compute interleaved mcu info
> +   z->img_h_max = h_max;
> +   z->img_v_max = v_max;
> +   z->img_mcu_w = h_max * 8;
> +   z->img_mcu_h = v_max * 8;
> +   // these sizes can't be more than 17 bits
> +   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
> +   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
> +
> +   for (i=0; i < s->img_n; ++i) {
> +      // number of effective pixels (e.g. for non-interleaved MCU)
> +      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
> +      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
> +      // to simplify generation, we'll allocate enough memory to decode
> +      // the bogus oversized data from using interleaved MCUs and their
> +      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
> +      // discard the extra data until colorspace conversion
> +      //
> +      // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)
> +      // so these muls can't overflow with 32-bit ints (which we require)
> +      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
> +      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
> +      z->img_comp[i].coeff = 0;
> +      z->img_comp[i].raw_coeff = 0;
> +      z->img_comp[i].linebuf = NULL;
> +      z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);
> +      if (z->img_comp[i].raw_data == NULL)
> +         return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
> +      // align blocks for idct using mmx/sse
> +      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
> +      if (z->progressive) {
> +         // w2, h2 are multiples of 8 (see above)
> +         z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;
> +         z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;
> +         z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);
> +         if (z->img_comp[i].raw_coeff == NULL)
> +            return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
> +         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
> +      }
> +   }
> +
> +   return 1;
> +}
> +
> +// use comparisons since in some cases we handle more than one case (e.g. SOF)
> +#define stbi__DNL(x)         ((x) == 0xdc)
> +#define stbi__SOI(x)         ((x) == 0xd8)
> +#define stbi__EOI(x)         ((x) == 0xd9)
> +#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
> +#define stbi__SOS(x)         ((x) == 0xda)
> +
> +#define stbi__SOF_progressive(x)   ((x) == 0xc2)
> +
> +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
> +{
> +   int m;
> +   z->jfif = 0;
> +   z->app14_color_transform = -1; // valid values are 0,1,2
> +   z->marker = STBI__MARKER_none; // initialize cached marker to empty
> +   m = stbi__get_marker(z);
> +   if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
> +   if (scan == STBI__SCAN_type) return 1;
> +   m = stbi__get_marker(z);
> +   while (!stbi__SOF(m)) {
> +      if (!stbi__process_marker(z,m)) return 0;
> +      m = stbi__get_marker(z);
> +      while (m == STBI__MARKER_none) {
> +         // some files have extra padding after their blocks, so ok, we'll scan
> +         if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
> +         m = stbi__get_marker(z);
> +      }
> +   }
> +   z->progressive = stbi__SOF_progressive(m);
> +   if (!stbi__process_frame_header(z, scan)) return 0;
> +   return 1;
> +}
> +
> +// decode image to YCbCr format
> +static int stbi__decode_jpeg_image(stbi__jpeg *j)
> +{
> +   int m;
> +   for (m = 0; m < 4; m++) {
> +      j->img_comp[m].raw_data = NULL;
> +      j->img_comp[m].raw_coeff = NULL;
> +   }
> +   j->restart_interval = 0;
> +   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
> +   m = stbi__get_marker(j);
> +   while (!stbi__EOI(m)) {
> +      if (stbi__SOS(m)) {
> +         if (!stbi__process_scan_header(j)) return 0;
> +         if (!stbi__parse_entropy_coded_data(j)) return 0;
> +         if (j->marker == STBI__MARKER_none ) {
> +            // handle 0s at the end of image data from IP Kamera 9060
> +            while (!stbi__at_eof(j->s)) {
> +               int x = stbi__get8(j->s);
> +               if (x == 255) {
> +                  j->marker = stbi__get8(j->s);
> +                  break;
> +               }
> +            }
> +            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
> +         }
> +      } else if (stbi__DNL(m)) {
> +         int Ld = stbi__get16be(j->s);
> +         stbi__uint32 NL = stbi__get16be(j->s);
> +         if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
> +         if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
> +      } else {
> +         if (!stbi__process_marker(j, m)) return 0;
> +      }
> +      m = stbi__get_marker(j);
> +   }
> +   if (j->progressive)
> +      stbi__jpeg_finish(j);
> +   return 1;
> +}
> +
> +// static jfif-centered resampling (across block boundaries)
> +
> +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
> +                                    int w, int hs);
> +
> +#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
> +
> +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
> +{
> +   STBI_NOTUSED(out);
> +   STBI_NOTUSED(in_far);
> +   STBI_NOTUSED(w);
> +   STBI_NOTUSED(hs);
> +   return in_near;
> +}
> +
> +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
> +{
> +   // need to generate two samples vertically for every one in input
> +   int i;
> +   STBI_NOTUSED(hs);
> +   for (i=0; i < w; ++i)
> +      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
> +   return out;
> +}
> +
> +static stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
> +{
> +   // need to generate two samples horizontally for every one in input
> +   int i;
> +   stbi_uc *input = in_near;
> +
> +   if (w == 1) {
> +      // if only one sample, can't do any interpolation
> +      out[0] = out[1] = input[0];
> +      return out;
> +   }
> +
> +   out[0] = input[0];
> +   out[1] = stbi__div4(input[0]*3 + input[1] + 2);
> +   for (i=1; i < w-1; ++i) {
> +      int n = 3*input[i]+2;
> +      out[i*2+0] = stbi__div4(n+input[i-1]);
> +      out[i*2+1] = stbi__div4(n+input[i+1]);
> +   }
> +   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
> +   out[i*2+1] = input[w-1];
> +
> +   STBI_NOTUSED(in_far);
> +   STBI_NOTUSED(hs);
> +
> +   return out;
> +}
> +
> +#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
> +
> +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
> +{
> +   // need to generate 2x2 samples for every one in input
> +   int i,t0,t1;
> +   if (w == 1) {
> +      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
> +      return out;
> +   }
> +
> +   t1 = 3*in_near[0] + in_far[0];
> +   out[0] = stbi__div4(t1+2);
> +   for (i=1; i < w; ++i) {
> +      t0 = t1;
> +      t1 = 3*in_near[i]+in_far[i];
> +      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
> +      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
> +   }
> +   out[w*2-1] = stbi__div4(t1+2);
> +
> +   STBI_NOTUSED(hs);
> +
> +   return out;
> +}
> +
> +#if defined(STBI_SSE2) || defined(STBI_NEON)
> +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
> +{
> +   // need to generate 2x2 samples for every one in input
> +   int i=0,t0,t1;
> +
> +   if (w == 1) {
> +      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
> +      return out;
> +   }
> +
> +   t1 = 3*in_near[0] + in_far[0];
> +   // process groups of 8 pixels for as long as we can.
> +   // note we can't handle the last pixel in a row in this loop
> +   // because we need to handle the filter boundary conditions.
> +   for (; i < ((w-1) & ~7); i += 8) {
> +#if defined(STBI_SSE2)
> +      // load and perform the vertical filtering pass
> +      // this uses 3*x + y = 4*x + (y - x)
> +      __m128i zero  = _mm_setzero_si128();
> +      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
> +      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
> +      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
> +      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
> +      __m128i diff  = _mm_sub_epi16(farw, nearw);
> +      __m128i nears = _mm_slli_epi16(nearw, 2);
> +      __m128i curr  = _mm_add_epi16(nears, diff); // current row
> +
> +      // horizontal filter works the same based on shifted vers of current
> +      // row. "prev" is current row shifted right by 1 pixel; we need to
> +      // insert the previous pixel value (from t1).
> +      // "next" is current row shifted left by 1 pixel, with first pixel
> +      // of next block of 8 pixels added in.
> +      __m128i prv0 = _mm_slli_si128(curr, 2);
> +      __m128i nxt0 = _mm_srli_si128(curr, 2);
> +      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
> +      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
> +
> +      // horizontal filter, polyphase implementation since it's convenient:
> +      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
> +      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
> +      // note the shared term.
> +      __m128i bias  = _mm_set1_epi16(8);
> +      __m128i curs = _mm_slli_epi16(curr, 2);
> +      __m128i prvd = _mm_sub_epi16(prev, curr);
> +      __m128i nxtd = _mm_sub_epi16(next, curr);
> +      __m128i curb = _mm_add_epi16(curs, bias);
> +      __m128i even = _mm_add_epi16(prvd, curb);
> +      __m128i odd  = _mm_add_epi16(nxtd, curb);
> +
> +      // interleave even and odd pixels, then undo scaling.
> +      __m128i int0 = _mm_unpacklo_epi16(even, odd);
> +      __m128i int1 = _mm_unpackhi_epi16(even, odd);
> +      __m128i de0  = _mm_srli_epi16(int0, 4);
> +      __m128i de1  = _mm_srli_epi16(int1, 4);
> +
> +      // pack and write output
> +      __m128i outv = _mm_packus_epi16(de0, de1);
> +      _mm_storeu_si128((__m128i *) (out + i*2), outv);
> +#elif defined(STBI_NEON)
> +      // load and perform the vertical filtering pass
> +      // this uses 3*x + y = 4*x + (y - x)
> +      uint8x8_t farb  = vld1_u8(in_far + i);
> +      uint8x8_t nearb = vld1_u8(in_near + i);
> +      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
> +      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
> +      int16x8_t curr  = vaddq_s16(nears, diff); // current row
> +
> +      // horizontal filter works the same based on shifted vers of current
> +      // row. "prev" is current row shifted right by 1 pixel; we need to
> +      // insert the previous pixel value (from t1).
> +      // "next" is current row shifted left by 1 pixel, with first pixel
> +      // of next block of 8 pixels added in.
> +      int16x8_t prv0 = vextq_s16(curr, curr, 7);
> +      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
> +      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
> +      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
> +
> +      // horizontal filter, polyphase implementation since it's convenient:
> +      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
> +      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
> +      // note the shared term.
> +      int16x8_t curs = vshlq_n_s16(curr, 2);
> +      int16x8_t prvd = vsubq_s16(prev, curr);
> +      int16x8_t nxtd = vsubq_s16(next, curr);
> +      int16x8_t even = vaddq_s16(curs, prvd);
> +      int16x8_t odd  = vaddq_s16(curs, nxtd);
> +
> +      // undo scaling and round, then store with even/odd phases interleaved
> +      uint8x8x2_t o;
> +      o.val[0] = vqrshrun_n_s16(even, 4);
> +      o.val[1] = vqrshrun_n_s16(odd,  4);
> +      vst2_u8(out + i*2, o);
> +#endif
> +
> +      // "previous" value for next iter
> +      t1 = 3*in_near[i+7] + in_far[i+7];
> +   }
> +
> +   t0 = t1;
> +   t1 = 3*in_near[i] + in_far[i];
> +   out[i*2] = stbi__div16(3*t1 + t0 + 8);
> +
> +   for (++i; i < w; ++i) {
> +      t0 = t1;
> +      t1 = 3*in_near[i]+in_far[i];
> +      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
> +      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
> +   }
> +   out[w*2-1] = stbi__div4(t1+2);
> +
> +   STBI_NOTUSED(hs);
> +
> +   return out;
> +}
> +#endif
> +
> +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
> +{
> +   // resample with nearest-neighbor
> +   int i,j;
> +   STBI_NOTUSED(in_far);
> +   for (i=0; i < w; ++i)
> +      for (j=0; j < hs; ++j)
> +         out[i*hs+j] = in_near[i];
> +   return out;
> +}
> +
> +// this is a reduced-precision calculation of YCbCr-to-RGB introduced
> +// to make sure the code produces the same results in both SIMD and scalar
> +#define stbi__float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)
> +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
> +{
> +   int i;
> +   for (i=0; i < count; ++i) {
> +      int y_fixed = (y[i] << 20) + (1<<19); // rounding
> +      int r,g,b;
> +      int cr = pcr[i] - 128;
> +      int cb = pcb[i] - 128;
> +      r = y_fixed +  cr* stbi__float2fixed(1.40200f);
> +      g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
> +      b = y_fixed                                     +   cb* stbi__float2fixed(1.77200f);
> +      r >>= 20;
> +      g >>= 20;
> +      b >>= 20;
> +      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
> +      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
> +      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
> +      out[0] = (stbi_uc)r;
> +      out[1] = (stbi_uc)g;
> +      out[2] = (stbi_uc)b;
> +      out[3] = 255;
> +      out += step;
> +   }
> +}
> +
> +#if defined(STBI_SSE2) || defined(STBI_NEON)
> +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
> +{
> +   int i = 0;
> +
> +#ifdef STBI_SSE2
> +   // step == 3 is pretty ugly on the final interleave, and i'm not convinced
> +   // it's useful in practice (you wouldn't use it for textures, for example).
> +   // so just accelerate step == 4 case.
> +   if (step == 4) {
> +      // this is a fairly straightforward implementation and not super-optimized.
> +      __m128i signflip  = _mm_set1_epi8(-0x80);
> +      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
> +      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
> +      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
> +      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
> +      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
> +      __m128i xw = _mm_set1_epi16(255); // alpha channel
> +
> +      for (; i+7 < count; i += 8) {
> +         // load
> +         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
> +         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
> +         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
> +         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
> +         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
> +
> +         // unpack to short (and left-shift cr, cb by 8)
> +         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
> +         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
> +         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
> +
> +         // color transform
> +         __m128i yws = _mm_srli_epi16(yw, 4);
> +         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
> +         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
> +         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
> +         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
> +         __m128i rws = _mm_add_epi16(cr0, yws);
> +         __m128i gwt = _mm_add_epi16(cb0, yws);
> +         __m128i bws = _mm_add_epi16(yws, cb1);
> +         __m128i gws = _mm_add_epi16(gwt, cr1);
> +
> +         // descale
> +         __m128i rw = _mm_srai_epi16(rws, 4);
> +         __m128i bw = _mm_srai_epi16(bws, 4);
> +         __m128i gw = _mm_srai_epi16(gws, 4);
> +
> +         // back to byte, set up for transpose
> +         __m128i brb = _mm_packus_epi16(rw, bw);
> +         __m128i gxb = _mm_packus_epi16(gw, xw);
> +
> +         // transpose to interleave channels
> +         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
> +         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
> +         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
> +         __m128i o1 = _mm_unpackhi_epi16(t0, t1);
> +
> +         // store
> +         _mm_storeu_si128((__m128i *) (out + 0), o0);
> +         _mm_storeu_si128((__m128i *) (out + 16), o1);
> +         out += 32;
> +      }
> +   }
> +#endif
> +
> +#ifdef STBI_NEON
> +   // in this version, step=3 support would be easy to add. but is there demand?
> +   if (step == 4) {
> +      // this is a fairly straightforward implementation and not super-optimized.
> +      uint8x8_t signflip = vdup_n_u8(0x80);
> +      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
> +      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
> +      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
> +      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));
> +
> +      for (; i+7 < count; i += 8) {
> +         // load
> +         uint8x8_t y_bytes  = vld1_u8(y + i);
> +         uint8x8_t cr_bytes = vld1_u8(pcr + i);
> +         uint8x8_t cb_bytes = vld1_u8(pcb + i);
> +         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
> +         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
> +
> +         // expand to s16
> +         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
> +         int16x8_t crw = vshll_n_s8(cr_biased, 7);
> +         int16x8_t cbw = vshll_n_s8(cb_biased, 7);
> +
> +         // color transform
> +         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
> +         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
> +         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
> +         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
> +         int16x8_t rws = vaddq_s16(yws, cr0);
> +         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
> +         int16x8_t bws = vaddq_s16(yws, cb1);
> +
> +         // undo scaling, round, convert to byte
> +         uint8x8x4_t o;
> +         o.val[0] = vqrshrun_n_s16(rws, 4);
> +         o.val[1] = vqrshrun_n_s16(gws, 4);
> +         o.val[2] = vqrshrun_n_s16(bws, 4);
> +         o.val[3] = vdup_n_u8(255);
> +
> +         // store, interleaving r/g/b/a
> +         vst4_u8(out, o);
> +         out += 8*4;
> +      }
> +   }
> +#endif
> +
> +   for (; i < count; ++i) {
> +      int y_fixed = (y[i] << 20) + (1<<19); // rounding
> +      int r,g,b;
> +      int cr = pcr[i] - 128;
> +      int cb = pcb[i] - 128;
> +      r = y_fixed + cr* stbi__float2fixed(1.40200f);
> +      g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
> +      b = y_fixed                                   +   cb* stbi__float2fixed(1.77200f);
> +      r >>= 20;
> +      g >>= 20;
> +      b >>= 20;
> +      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
> +      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
> +      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
> +      out[0] = (stbi_uc)r;
> +      out[1] = (stbi_uc)g;
> +      out[2] = (stbi_uc)b;
> +      out[3] = 255;
> +      out += step;
> +   }
> +}
> +#endif
> +
> +// set up the kernels
> +static void stbi__setup_jpeg(stbi__jpeg *j)
> +{
> +   j->idct_block_kernel = stbi__idct_block;
> +   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
> +   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
> +
> +#ifdef STBI_SSE2
> +   if (stbi__sse2_available()) {
> +      j->idct_block_kernel = stbi__idct_simd;
> +      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
> +      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
> +   }
> +#endif
> +
> +#ifdef STBI_NEON
> +   j->idct_block_kernel = stbi__idct_simd;
> +   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
> +   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
> +#endif
> +}
> +
> +// clean up the temporary component buffers
> +static void stbi__cleanup_jpeg(stbi__jpeg *j)
> +{
> +   stbi__free_jpeg_components(j, j->s->img_n, 0);
> +}
> +
> +typedef struct
> +{
> +   resample_row_func resample;
> +   stbi_uc *line0,*line1;
> +   int hs,vs;   // expansion factor in each axis
> +   int w_lores; // horizontal pixels pre-expansion
> +   int ystep;   // how far through vertical expansion we are
> +   int ypos;    // which pre-expansion row we're on
> +} stbi__resample;
> +
> +// fast 0..255 * 0..255 => 0..255 rounded multiplication
> +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)
> +{
> +   unsigned int t = x*y + 128;
> +   return (stbi_uc) ((t + (t >>8)) >> 8);
> +}
> +
> +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
> +{
> +   int n, decode_n, is_rgb;
> +   z->s->img_n = 0; // make stbi__cleanup_jpeg safe
> +
> +   // validate req_comp
> +   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
> +
> +   // load a jpeg image from whichever source, but leave in YCbCr format
> +   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
> +
> +   // determine actual number of components to generate
> +   n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;
> +
> +   is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));
> +
> +   if (z->s->img_n == 3 && n < 3 && !is_rgb)
> +      decode_n = 1;
> +   else
> +      decode_n = z->s->img_n;
> +
> +   // resample and color-convert
> +   {
> +      int k;
> +      unsigned int i,j;
> +      stbi_uc *output;
> +      stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };
> +
> +      stbi__resample res_comp[4];
> +
> +      for (k=0; k < decode_n; ++k) {
> +         stbi__resample *r = &res_comp[k];
> +
> +         // allocate line buffer big enough for upsampling off the edges
> +         // with upsample factor of 4
> +         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
> +         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
> +
> +         r->hs      = z->img_h_max / z->img_comp[k].h;
> +         r->vs      = z->img_v_max / z->img_comp[k].v;
> +         r->ystep   = r->vs >> 1;
> +         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
> +         r->ypos    = 0;
> +         r->line0   = r->line1 = z->img_comp[k].data;
> +
> +         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
> +         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
> +         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
> +         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
> +         else                               r->resample = stbi__resample_row_generic;
> +      }
> +
> +      // can't error after this so, this is safe
> +      output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);
> +      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
> +
> +      // now go ahead and resample
> +      for (j=0; j < z->s->img_y; ++j) {
> +         stbi_uc *out = output + n * z->s->img_x * j;
> +         for (k=0; k < decode_n; ++k) {
> +            stbi__resample *r = &res_comp[k];
> +            int y_bot = r->ystep >= (r->vs >> 1);
> +            coutput[k] = r->resample(z->img_comp[k].linebuf,
> +                                     y_bot ? r->line1 : r->line0,
> +                                     y_bot ? r->line0 : r->line1,
> +                                     r->w_lores, r->hs);
> +            if (++r->ystep >= r->vs) {
> +               r->ystep = 0;
> +               r->line0 = r->line1;
> +               if (++r->ypos < z->img_comp[k].y)
> +                  r->line1 += z->img_comp[k].w2;
> +            }
> +         }
> +         if (n >= 3) {
> +            stbi_uc *y = coutput[0];
> +            if (z->s->img_n == 3) {
> +               if (is_rgb) {
> +                  for (i=0; i < z->s->img_x; ++i) {
> +                     out[0] = y[i];
> +                     out[1] = coutput[1][i];
> +                     out[2] = coutput[2][i];
> +                     out[3] = 255;
> +                     out += n;
> +                  }
> +               } else {
> +                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
> +               }
> +            } else if (z->s->img_n == 4) {
> +               if (z->app14_color_transform == 0) { // CMYK
> +                  for (i=0; i < z->s->img_x; ++i) {
> +                     stbi_uc m = coutput[3][i];
> +                     out[0] = stbi__blinn_8x8(coutput[0][i], m);
> +                     out[1] = stbi__blinn_8x8(coutput[1][i], m);
> +                     out[2] = stbi__blinn_8x8(coutput[2][i], m);
> +                     out[3] = 255;
> +                     out += n;
> +                  }
> +               } else if (z->app14_color_transform == 2) { // YCCK
> +                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
> +                  for (i=0; i < z->s->img_x; ++i) {
> +                     stbi_uc m = coutput[3][i];
> +                     out[0] = stbi__blinn_8x8(255 - out[0], m);
> +                     out[1] = stbi__blinn_8x8(255 - out[1], m);
> +                     out[2] = stbi__blinn_8x8(255 - out[2], m);
> +                     out += n;
> +                  }
> +               } else { // YCbCr + alpha?  Ignore the fourth channel for now
> +                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
> +               }
> +            } else
> +               for (i=0; i < z->s->img_x; ++i) {
> +                  out[0] = out[1] = out[2] = y[i];
> +                  out[3] = 255; // not used if n==3
> +                  out += n;
> +               }
> +         } else {
> +            if (is_rgb) {
> +               if (n == 1)
> +                  for (i=0; i < z->s->img_x; ++i)
> +                     *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
> +               else {
> +                  for (i=0; i < z->s->img_x; ++i, out += 2) {
> +                     out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
> +                     out[1] = 255;
> +                  }
> +               }
> +            } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
> +               for (i=0; i < z->s->img_x; ++i) {
> +                  stbi_uc m = coutput[3][i];
> +                  stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);
> +                  stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);
> +                  stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);
> +                  out[0] = stbi__compute_y(r, g, b);
> +                  out[1] = 255;
> +                  out += n;
> +               }
> +            } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {
> +               for (i=0; i < z->s->img_x; ++i) {
> +                  out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);
> +                  out[1] = 255;
> +                  out += n;
> +               }
> +            } else {
> +               stbi_uc *y = coutput[0];
> +               if (n == 1)
> +                  for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
> +               else
> +                  for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }
> +            }
> +         }
> +      }
> +      stbi__cleanup_jpeg(z);
> +      *out_x = z->s->img_x;
> +      *out_y = z->s->img_y;
> +      if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output
> +      return output;
> +   }
> +}
> +
> +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
> +{
> +   unsigned char* result;
> +   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
> +   STBI_NOTUSED(ri);
> +   j->s = s;
> +   stbi__setup_jpeg(j);
> +   result = load_jpeg_image(j, x,y,comp,req_comp);
> +   STBI_FREE(j);
> +   return result;
> +}
> +
> +static int stbi__jpeg_test(stbi__context *s)
> +{
> +   int r;
> +   stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
> +   j->s = s;
> +   stbi__setup_jpeg(j);
> +   r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
> +   stbi__rewind(s);
> +   STBI_FREE(j);
> +   return r;
> +}
> +
> +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
> +{
> +   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
> +      stbi__rewind( j->s );
> +      return 0;
> +   }
> +   if (x) *x = j->s->img_x;
> +   if (y) *y = j->s->img_y;
> +   if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;
> +   return 1;
> +}
> +
> +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   int result;
> +   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
> +   j->s = s;
> +   result = stbi__jpeg_info_raw(j, x, y, comp);
> +   STBI_FREE(j);
> +   return result;
> +}
> +#endif
> +
> +// public domain zlib decode    v0.2  Sean Barrett 2006-11-18
> +//    simple implementation
> +//      - all input must be provided in an upfront buffer
> +//      - all output is written to a single output buffer (can malloc/realloc)
> +//    performance
> +//      - fast huffman
> +
> +#ifndef STBI_NO_ZLIB
> +
> +// fast-way is faster to check than jpeg huffman, but slow way is slower
> +#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables
> +#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)
> +
> +// zlib-style huffman encoding
> +// (jpegs packs from left, zlib from right, so can't share code)
> +typedef struct
> +{
> +   stbi__uint16 fast[1 << STBI__ZFAST_BITS];
> +   stbi__uint16 firstcode[16];
> +   int maxcode[17];
> +   stbi__uint16 firstsymbol[16];
> +   stbi_uc  size[288];
> +   stbi__uint16 value[288];
> +} stbi__zhuffman;
> +
> +stbi_inline static int stbi__bitreverse16(int n)
> +{
> +  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);
> +  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);
> +  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);
> +  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);
> +  return n;
> +}
> +
> +stbi_inline static int stbi__bit_reverse(int v, int bits)
> +{
> +   STBI_ASSERT(bits <= 16);
> +   // to bit reverse n bits, reverse 16 and shift
> +   // e.g. 11 bits, bit reverse and shift away 5
> +   return stbi__bitreverse16(v) >> (16-bits);
> +}
> +
> +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)
> +{
> +   int i,k=0;
> +   int code, next_code[16], sizes[17];
> +
> +   // DEFLATE spec for generating codes
> +   memset(sizes, 0, sizeof(sizes));
> +   memset(z->fast, 0, sizeof(z->fast));
> +   for (i=0; i < num; ++i)
> +      ++sizes[sizelist[i]];
> +   sizes[0] = 0;
> +   for (i=1; i < 16; ++i)
> +      if (sizes[i] > (1 << i))
> +         return stbi__err("bad sizes", "Corrupt PNG");
> +   code = 0;
> +   for (i=1; i < 16; ++i) {
> +      next_code[i] = code;
> +      z->firstcode[i] = (stbi__uint16) code;
> +      z->firstsymbol[i] = (stbi__uint16) k;
> +      code = (code + sizes[i]);
> +      if (sizes[i])
> +         if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
> +      z->maxcode[i] = code << (16-i); // preshift for inner loop
> +      code <<= 1;
> +      k += sizes[i];
> +   }
> +   z->maxcode[16] = 0x10000; // sentinel
> +   for (i=0; i < num; ++i) {
> +      int s = sizelist[i];
> +      if (s) {
> +         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
> +         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
> +         z->size [c] = (stbi_uc     ) s;
> +         z->value[c] = (stbi__uint16) i;
> +         if (s <= STBI__ZFAST_BITS) {
> +            int j = stbi__bit_reverse(next_code[s],s);
> +            while (j < (1 << STBI__ZFAST_BITS)) {
> +               z->fast[j] = fastv;
> +               j += (1 << s);
> +            }
> +         }
> +         ++next_code[s];
> +      }
> +   }
> +   return 1;
> +}
> +
> +// zlib-from-memory implementation for PNG reading
> +//    because PNG allows splitting the zlib stream arbitrarily,
> +//    and it's annoying structurally to have PNG call ZLIB call PNG,
> +//    we require PNG read all the IDATs and combine them into a single
> +//    memory buffer
> +
> +typedef struct
> +{
> +   stbi_uc *zbuffer, *zbuffer_end;
> +   int num_bits;
> +   stbi__uint32 code_buffer;
> +
> +   char *zout;
> +   char *zout_start;
> +   char *zout_end;
> +   int   z_expandable;
> +
> +   stbi__zhuffman z_length, z_distance;
> +} stbi__zbuf;
> +
> +stbi_inline static int stbi__zeof(stbi__zbuf *z)
> +{
> +   return (z->zbuffer >= z->zbuffer_end);
> +}
> +
> +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
> +{
> +   return stbi__zeof(z) ? 0 : *z->zbuffer++;
> +}
> +
> +static void stbi__fill_bits(stbi__zbuf *z)
> +{
> +   do {
> +      if (z->code_buffer >= (1U << z->num_bits)) {
> +        z->zbuffer = z->zbuffer_end;  /* treat this as EOF so we fail. */
> +        return;
> +      }
> +      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
> +      z->num_bits += 8;
> +   } while (z->num_bits <= 24);
> +}
> +
> +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
> +{
> +   unsigned int k;
> +   if (z->num_bits < n) stbi__fill_bits(z);
> +   k = z->code_buffer & ((1 << n) - 1);
> +   z->code_buffer >>= n;
> +   z->num_bits -= n;
> +   return k;
> +}
> +
> +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
> +{
> +   int b,s,k;
> +   // not resolved by fast table, so compute it the slow way
> +   // use jpeg approach, which requires MSbits at top
> +   k = stbi__bit_reverse(a->code_buffer, 16);
> +   for (s=STBI__ZFAST_BITS+1; ; ++s)
> +      if (k < z->maxcode[s])
> +         break;
> +   if (s >= 16) return -1; // invalid code!
> +   // code size is s, so:
> +   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
> +   if ((long unsigned int) b >= sizeof (z->size)) return -1; // some data was corrupt somewhere!
> +   if (z->size[b] != s) return -1;  // was originally an assert, but report failure instead.
> +   a->code_buffer >>= s;
> +   a->num_bits -= s;
> +   return z->value[b];
> +}
> +
> +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
> +{
> +   int b,s;
> +   if (a->num_bits < 16) {
> +      if (stbi__zeof(a)) {
> +         return -1;   /* report error for unexpected end of data. */
> +      }
> +      stbi__fill_bits(a);
> +   }
> +   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
> +   if (b) {
> +      s = b >> 9;
> +      a->code_buffer >>= s;
> +      a->num_bits -= s;
> +      return b & 511;
> +   }
> +   return stbi__zhuffman_decode_slowpath(a, z);
> +}
> +
> +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes
> +{
> +   char *q;
> +   unsigned int cur, limit, old_limit;
> +   z->zout = zout;
> +   if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
> +   cur   = (unsigned int) (z->zout - z->zout_start);
> +   limit = old_limit = (unsigned) (z->zout_end - z->zout_start);
> +   if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory");
> +   while (cur + n > limit) {
> +      if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory");
> +      limit *= 2;
> +   }
> +   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
> +   STBI_NOTUSED(old_limit);
> +   if (q == NULL) return stbi__err("outofmem", "Out of memory");
> +   z->zout_start = q;
> +   z->zout       = q + cur;
> +   z->zout_end   = q + limit;
> +   return 1;
> +}
> +
> +static const int stbi__zlength_base[31] = {
> +   3,4,5,6,7,8,9,10,11,13,
> +   15,17,19,23,27,31,35,43,51,59,
> +   67,83,99,115,131,163,195,227,258,0,0 };
> +
> +static const int stbi__zlength_extra[31]=
> +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
> +
> +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
> +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
> +
> +static const int stbi__zdist_extra[32] =
> +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
> +
> +static int stbi__parse_huffman_block(stbi__zbuf *a)
> +{
> +   char *zout = a->zout;
> +   for(;;) {
> +      int z = stbi__zhuffman_decode(a, &a->z_length);
> +      if (z < 256) {
> +         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
> +         if (zout >= a->zout_end) {
> +            if (!stbi__zexpand(a, zout, 1)) return 0;
> +            zout = a->zout;
> +         }
> +         *zout++ = (char) z;
> +      } else {
> +         stbi_uc *p;
> +         int len,dist;
> +         if (z == 256) {
> +            a->zout = zout;
> +            return 1;
> +         }
> +         z -= 257;
> +         len = stbi__zlength_base[z];
> +         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
> +         z = stbi__zhuffman_decode(a, &a->z_distance);
> +         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
> +         dist = stbi__zdist_base[z];
> +         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
> +         if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
> +         if (zout + len > a->zout_end) {
> +            if (!stbi__zexpand(a, zout, len)) return 0;
> +            zout = a->zout;
> +         }
> +         p = (stbi_uc *) (zout - dist);
> +         if (dist == 1) { // run of one byte; common in images.
> +            stbi_uc v = *p;
> +            if (len) { do *zout++ = v; while (--len); }
> +         } else {
> +            if (len) { do *zout++ = *p++; while (--len); }
> +         }
> +      }
> +   }
> +}
> +
> +static int stbi__compute_huffman_codes(stbi__zbuf *a)
> +{
> +   static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
> +   stbi__zhuffman z_codelength;
> +   stbi_uc lencodes[286+32+137];//padding for maximum single op
> +   stbi_uc codelength_sizes[19];
> +   int i,n;
> +
> +   int hlit  = stbi__zreceive(a,5) + 257;
> +   int hdist = stbi__zreceive(a,5) + 1;
> +   int hclen = stbi__zreceive(a,4) + 4;
> +   int ntot  = hlit + hdist;
> +
> +   memset(codelength_sizes, 0, sizeof(codelength_sizes));
> +   for (i=0; i < hclen; ++i) {
> +      int s = stbi__zreceive(a,3);
> +      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
> +   }
> +   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
> +
> +   n = 0;
> +   while (n < ntot) {
> +      int c = stbi__zhuffman_decode(a, &z_codelength);
> +      if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
> +      if (c < 16)
> +         lencodes[n++] = (stbi_uc) c;
> +      else {
> +         stbi_uc fill = 0;
> +         if (c == 16) {
> +            c = stbi__zreceive(a,2)+3;
> +            if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
> +            fill = lencodes[n-1];
> +         } else if (c == 17) {
> +            c = stbi__zreceive(a,3)+3;
> +         } else if (c == 18) {
> +            c = stbi__zreceive(a,7)+11;
> +         } else {
> +            return stbi__err("bad codelengths", "Corrupt PNG");
> +         }
> +         if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
> +         memset(lencodes+n, fill, c);
> +         n += c;
> +      }
> +   }
> +   if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
> +   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
> +   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
> +   return 1;
> +}
> +
> +static int stbi__parse_uncompressed_block(stbi__zbuf *a)
> +{
> +   stbi_uc header[4];
> +   int len,nlen,k;
> +   if (a->num_bits & 7)
> +      stbi__zreceive(a, a->num_bits & 7); // discard
> +   // drain the bit-packed data into header
> +   k = 0;
> +   while (a->num_bits > 0) {
> +      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
> +      a->code_buffer >>= 8;
> +      a->num_bits -= 8;
> +   }
> +   if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG");
> +   // now fill header the normal way
> +   while (k < 4)
> +      header[k++] = stbi__zget8(a);
> +   len  = header[1] * 256 + header[0];
> +   nlen = header[3] * 256 + header[2];
> +   if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
> +   if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
> +   if (a->zout + len > a->zout_end)
> +      if (!stbi__zexpand(a, a->zout, len)) return 0;
> +   memcpy(a->zout, a->zbuffer, len);
> +   a->zbuffer += len;
> +   a->zout += len;
> +   return 1;
> +}
> +
> +static int stbi__parse_zlib_header(stbi__zbuf *a)
> +{
> +   int cmf   = stbi__zget8(a);
> +   int cm    = cmf & 15;
> +   /* int cinfo = cmf >> 4; */
> +   int flg   = stbi__zget8(a);
> +   if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
> +   if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
> +   if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
> +   if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
> +   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
> +   return 1;
> +}
> +
> +static const stbi_uc stbi__zdefault_length[288] =
> +{
> +   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
> +   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
> +   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
> +   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
> +   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
> +   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
> +   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
> +   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
> +   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8
> +};
> +static const stbi_uc stbi__zdefault_distance[32] =
> +{
> +   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
> +};
> +/*
> +Init algorithm:
> +{
> +   int i;   // use <= to match clearly with spec
> +   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;
> +   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;
> +   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;
> +   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;
> +
> +   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;
> +}
> +*/
> +
> +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
> +{
> +   int final, type;
> +   if (parse_header)
> +      if (!stbi__parse_zlib_header(a)) return 0;
> +   a->num_bits = 0;
> +   a->code_buffer = 0;
> +   do {
> +      final = stbi__zreceive(a,1);
> +      type = stbi__zreceive(a,2);
> +      if (type == 0) {
> +         if (!stbi__parse_uncompressed_block(a)) return 0;
> +      } else if (type == 3) {
> +         return 0;
> +      } else {
> +         if (type == 1) {
> +            // use fixed code lengths
> +            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , 288)) return 0;
> +            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;
> +         } else {
> +            if (!stbi__compute_huffman_codes(a)) return 0;
> +         }
> +         if (!stbi__parse_huffman_block(a)) return 0;
> +      }
> +   } while (!final);
> +   return 1;
> +}
> +
> +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
> +{
> +   a->zout_start = obuf;
> +   a->zout       = obuf;
> +   a->zout_end   = obuf + olen;
> +   a->z_expandable = exp;
> +
> +   return stbi__parse_zlib(a, parse_header);
> +}
> +
> +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
> +{
> +   stbi__zbuf a;
> +   char *p = (char *) stbi__malloc(initial_size);
> +   if (p == NULL) return NULL;
> +   a.zbuffer = (stbi_uc *) buffer;
> +   a.zbuffer_end = (stbi_uc *) buffer + len;
> +   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
> +      if (outlen) *outlen = (int) (a.zout - a.zout_start);
> +      return a.zout_start;
> +   } else {
> +      STBI_FREE(a.zout_start);
> +      return NULL;
> +   }
> +}
> +
> +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
> +{
> +   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
> +}
> +
> +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
> +{
> +   stbi__zbuf a;
> +   char *p = (char *) stbi__malloc(initial_size);
> +   if (p == NULL) return NULL;
> +   a.zbuffer = (stbi_uc *) buffer;
> +   a.zbuffer_end = (stbi_uc *) buffer + len;
> +   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
> +      if (outlen) *outlen = (int) (a.zout - a.zout_start);
> +      return a.zout_start;
> +   } else {
> +      STBI_FREE(a.zout_start);
> +      return NULL;
> +   }
> +}
> +
> +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
> +{
> +   stbi__zbuf a;
> +   a.zbuffer = (stbi_uc *) ibuffer;
> +   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
> +   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
> +      return (int) (a.zout - a.zout_start);
> +   else
> +      return -1;
> +}
> +
> +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
> +{
> +   stbi__zbuf a;
> +   char *p = (char *) stbi__malloc(16384);
> +   if (p == NULL) return NULL;
> +   a.zbuffer = (stbi_uc *) buffer;
> +   a.zbuffer_end = (stbi_uc *) buffer+len;
> +   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
> +      if (outlen) *outlen = (int) (a.zout - a.zout_start);
> +      return a.zout_start;
> +   } else {
> +      STBI_FREE(a.zout_start);
> +      return NULL;
> +   }
> +}
> +
> +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
> +{
> +   stbi__zbuf a;
> +   a.zbuffer = (stbi_uc *) ibuffer;
> +   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
> +   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
> +      return (int) (a.zout - a.zout_start);
> +   else
> +      return -1;
> +}
> +#endif
> +
> +// public domain "baseline" PNG decoder   v0.10  Sean Barrett 2006-11-18
> +//    simple implementation
> +//      - only 8-bit samples
> +//      - no CRC checking
> +//      - allocates lots of intermediate memory
> +//        - avoids problem of streaming data between subsystems
> +//        - avoids explicit window management
> +//    performance
> +//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding
> +
> +#ifndef STBI_NO_PNG
> +typedef struct
> +{
> +   stbi__uint32 length;
> +   stbi__uint32 type;
> +} stbi__pngchunk;
> +
> +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
> +{
> +   stbi__pngchunk c;
> +   c.length = stbi__get32be(s);
> +   c.type   = stbi__get32be(s);
> +   return c;
> +}
> +
> +static int stbi__check_png_header(stbi__context *s)
> +{
> +   static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
> +   int i;
> +   for (i=0; i < 8; ++i)
> +      if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
> +   return 1;
> +}
> +
> +typedef struct
> +{
> +   stbi__context *s;
> +   stbi_uc *idata, *expanded, *out;
> +   int depth;
> +} stbi__png;
> +
> +
> +enum {
> +   STBI__F_none=0,
> +   STBI__F_sub=1,
> +   STBI__F_up=2,
> +   STBI__F_avg=3,
> +   STBI__F_paeth=4,
> +   // synthetic filters used for first scanline to avoid needing a dummy row of 0s
> +   STBI__F_avg_first,
> +   STBI__F_paeth_first
> +};
> +
> +static stbi_uc first_row_filter[5] =
> +{
> +   STBI__F_none,
> +   STBI__F_sub,
> +   STBI__F_none,
> +   STBI__F_avg_first,
> +   STBI__F_paeth_first
> +};
> +
> +static int stbi__paeth(int a, int b, int c)
> +{
> +   int p = a + b - c;
> +   int pa = abs(p-a);
> +   int pb = abs(p-b);
> +   int pc = abs(p-c);
> +   if (pa <= pb && pa <= pc) return a;
> +   if (pb <= pc) return b;
> +   return c;
> +}
> +
> +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
> +
> +// create the png data from post-deflated data
> +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
> +{
> +   int bytes = (depth == 16? 2 : 1);
> +   stbi__context *s = a->s;
> +   stbi__uint32 i,j,stride = x*out_n*bytes;
> +   stbi__uint32 img_len, img_width_bytes;
> +   int k;
> +   int img_n = s->img_n; // copy it into a local for later
> +
> +   int output_bytes = out_n*bytes;
> +   int filter_bytes = img_n*bytes;
> +   int width = x;
> +
> +   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
> +   a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
> +   if (!a->out) return stbi__err("outofmem", "Out of memory");
> +
> +   if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
> +   img_width_bytes = (((img_n * x * depth) + 7) >> 3);
> +   img_len = (img_width_bytes + 1) * y;
> +
> +   // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
> +   // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
> +   // so just check for raw_len < img_len always.
> +   if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
> +
> +   for (j=0; j < y; ++j) {
> +      stbi_uc *cur = a->out + stride*j;
> +      stbi_uc *prior;
> +      int filter = *raw++;
> +
> +      if (filter > 4)
> +         return stbi__err("invalid filter","Corrupt PNG");
> +
> +      if (depth < 8) {
> +         if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
> +         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
> +         filter_bytes = 1;
> +         width = img_width_bytes;
> +      }
> +      prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
> +
> +      // if first row, use special filter that doesn't sample previous row
> +      if (j == 0) filter = first_row_filter[filter];
> +
> +      // handle first byte explicitly
> +      for (k=0; k < filter_bytes; ++k) {
> +         switch (filter) {
> +            case STBI__F_none       : cur[k] = raw[k]; break;
> +            case STBI__F_sub        : cur[k] = raw[k]; break;
> +            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
> +            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
> +            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
> +            case STBI__F_avg_first  : cur[k] = raw[k]; break;
> +            case STBI__F_paeth_first: cur[k] = raw[k]; break;
> +         }
> +      }
> +
> +      if (depth == 8) {
> +         if (img_n != out_n)
> +            cur[img_n] = 255; // first pixel
> +         raw += img_n;
> +         cur += out_n;
> +         prior += out_n;
> +      } else if (depth == 16) {
> +         if (img_n != out_n) {
> +            cur[filter_bytes]   = 255; // first pixel top byte
> +            cur[filter_bytes+1] = 255; // first pixel bottom byte
> +         }
> +         raw += filter_bytes;
> +         cur += output_bytes;
> +         prior += output_bytes;
> +      } else {
> +         raw += 1;
> +         cur += 1;
> +         prior += 1;
> +      }
> +
> +      // this is a little gross, so that we don't switch per-pixel or per-component
> +      if (depth < 8 || img_n == out_n) {
> +         int nk = (width - 1)*filter_bytes;
> +         #define STBI__CASE(f) \
> +             case f:     \
> +                for (k=0; k < nk; ++k)
> +         switch (filter) {
> +            // "none" filter turns into a memcpy here; make that explicit.
> +            case STBI__F_none:         memcpy(cur, raw, nk); break;
> +            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
> +            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
> +            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
> +            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
> +            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
> +            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
> +         }
> +         #undef STBI__CASE
> +         raw += nk;
> +      } else {
> +         STBI_ASSERT(img_n+1 == out_n);
> +         #define STBI__CASE(f) \
> +             case f:     \
> +                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
> +                   for (k=0; k < filter_bytes; ++k)
> +         switch (filter) {
> +            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;
> +            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
> +            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
> +            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
> +            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
> +            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
> +            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
> +         }
> +         #undef STBI__CASE
> +
> +         // the loop above sets the high byte of the pixels' alpha, but for
> +         // 16 bit png files we also need the low byte set. we'll do that here.
> +         if (depth == 16) {
> +            cur = a->out + stride*j; // start at the beginning of the row again
> +            for (i=0; i < x; ++i,cur+=output_bytes) {
> +               cur[filter_bytes+1] = 255;
> +            }
> +         }
> +      }
> +   }
> +
> +   // we make a separate pass to expand bits to pixels; for performance,
> +   // this could run two scanlines behind the above code, so it won't
> +   // intefere with filtering but will still be in the cache.
> +   if (depth < 8) {
> +      for (j=0; j < y; ++j) {
> +         stbi_uc *cur = a->out + stride*j;
> +         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;
> +         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
> +         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
> +         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
> +
> +         // note that the final byte might overshoot and write more data than desired.
> +         // we can allocate enough data that this never writes out of memory, but it
> +         // could also overwrite the next scanline. can it overwrite non-empty data
> +         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
> +         // so we need to explicitly clamp the final ones
> +
> +         if (depth == 4) {
> +            for (k=x*img_n; k >= 2; k-=2, ++in) {
> +               *cur++ = scale * ((*in >> 4)       );
> +               *cur++ = scale * ((*in     ) & 0x0f);
> +            }
> +            if (k > 0) *cur++ = scale * ((*in >> 4)       );
> +         } else if (depth == 2) {
> +            for (k=x*img_n; k >= 4; k-=4, ++in) {
> +               *cur++ = scale * ((*in >> 6)       );
> +               *cur++ = scale * ((*in >> 4) & 0x03);
> +               *cur++ = scale * ((*in >> 2) & 0x03);
> +               *cur++ = scale * ((*in     ) & 0x03);
> +            }
> +            if (k > 0) *cur++ = scale * ((*in >> 6)       );
> +            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
> +            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
> +         } else if (depth == 1) {
> +            for (k=x*img_n; k >= 8; k-=8, ++in) {
> +               *cur++ = scale * ((*in >> 7)       );
> +               *cur++ = scale * ((*in >> 6) & 0x01);
> +               *cur++ = scale * ((*in >> 5) & 0x01);
> +               *cur++ = scale * ((*in >> 4) & 0x01);
> +               *cur++ = scale * ((*in >> 3) & 0x01);
> +               *cur++ = scale * ((*in >> 2) & 0x01);
> +               *cur++ = scale * ((*in >> 1) & 0x01);
> +               *cur++ = scale * ((*in     ) & 0x01);
> +            }
> +            if (k > 0) *cur++ = scale * ((*in >> 7)       );
> +            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
> +            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
> +            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
> +            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
> +            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
> +            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
> +         }
> +         if (img_n != out_n) {
> +            int q;
> +            // insert alpha = 255
> +            cur = a->out + stride*j;
> +            if (img_n == 1) {
> +               for (q=x-1; q >= 0; --q) {
> +                  cur[q*2+1] = 255;
> +                  cur[q*2+0] = cur[q];
> +               }
> +            } else {
> +               STBI_ASSERT(img_n == 3);
> +               for (q=x-1; q >= 0; --q) {
> +                  cur[q*4+3] = 255;
> +                  cur[q*4+2] = cur[q*3+2];
> +                  cur[q*4+1] = cur[q*3+1];
> +                  cur[q*4+0] = cur[q*3+0];
> +               }
> +            }
> +         }
> +      }
> +   } else if (depth == 16) {
> +      // force the image data from big-endian to platform-native.
> +      // this is done in a separate pass due to the decoding relying
> +      // on the data being untouched, but could probably be done
> +      // per-line during decode if care is taken.
> +      stbi_uc *cur = a->out;
> +      stbi__uint16 *cur16 = (stbi__uint16*)cur;
> +
> +      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
> +         *cur16 = (cur[0] << 8) | cur[1];
> +      }
> +   }
> +
> +   return 1;
> +}
> +
> +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
> +{
> +   int bytes = (depth == 16 ? 2 : 1);
> +   int out_bytes = out_n * bytes;
> +   stbi_uc *final;
> +   int p;
> +   if (!interlaced)
> +      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
> +
> +   // de-interlacing
> +   final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
> +   for (p=0; p < 7; ++p) {
> +      int xorig[] = { 0,4,0,2,0,1,0 };
> +      int yorig[] = { 0,0,4,0,2,0,1 };
> +      int xspc[]  = { 8,8,4,4,2,2,1 };
> +      int yspc[]  = { 8,8,8,4,4,2,2 };
> +      int i,j,x,y;
> +      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
> +      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
> +      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
> +      if (x && y) {
> +         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
> +         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
> +            STBI_FREE(final);
> +            return 0;
> +         }
> +         for (j=0; j < y; ++j) {
> +            for (i=0; i < x; ++i) {
> +               int out_y = j*yspc[p]+yorig[p];
> +               int out_x = i*xspc[p]+xorig[p];
> +               memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
> +                      a->out + (j*x+i)*out_bytes, out_bytes);
> +            }
> +         }
> +         STBI_FREE(a->out);
> +         image_data += img_len;
> +         image_data_len -= img_len;
> +      }
> +   }
> +   a->out = final;
> +
> +   return 1;
> +}
> +
> +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
> +{
> +   stbi__context *s = z->s;
> +   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
> +   stbi_uc *p = z->out;
> +
> +   // compute color-based transparency, assuming we've
> +   // already got 255 as the alpha value in the output
> +   STBI_ASSERT(out_n == 2 || out_n == 4);
> +
> +   if (out_n == 2) {
> +      for (i=0; i < pixel_count; ++i) {
> +         p[1] = (p[0] == tc[0] ? 0 : 255);
> +         p += 2;
> +      }
> +   } else {
> +      for (i=0; i < pixel_count; ++i) {
> +         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
> +            p[3] = 0;
> +         p += 4;
> +      }
> +   }
> +   return 1;
> +}
> +
> +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
> +{
> +   stbi__context *s = z->s;
> +   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
> +   stbi__uint16 *p = (stbi__uint16*) z->out;
> +
> +   // compute color-based transparency, assuming we've
> +   // already got 65535 as the alpha value in the output
> +   STBI_ASSERT(out_n == 2 || out_n == 4);
> +
> +   if (out_n == 2) {
> +      for (i = 0; i < pixel_count; ++i) {
> +         p[1] = (p[0] == tc[0] ? 0 : 65535);
> +         p += 2;
> +      }
> +   } else {
> +      for (i = 0; i < pixel_count; ++i) {
> +         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
> +            p[3] = 0;
> +         p += 4;
> +      }
> +   }
> +   return 1;
> +}
> +
> +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
> +{
> +   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
> +   stbi_uc *p, *temp_out, *orig = a->out;
> +
> +   p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
> +   if (p == NULL) return stbi__err("outofmem", "Out of memory");
> +
> +   // between here and free(out) below, exitting would leak
> +   temp_out = p;
> +
> +   if (pal_img_n == 3) {
> +      for (i=0; i < pixel_count; ++i) {
> +         int n = orig[i]*4;
> +         p[0] = palette[n  ];
> +         p[1] = palette[n+1];
> +         p[2] = palette[n+2];
> +         p += 3;
> +      }
> +   } else {
> +      for (i=0; i < pixel_count; ++i) {
> +         int n = orig[i]*4;
> +         p[0] = palette[n  ];
> +         p[1] = palette[n+1];
> +         p[2] = palette[n+2];
> +         p[3] = palette[n+3];
> +         p += 4;
> +      }
> +   }
> +   STBI_FREE(a->out);
> +   a->out = temp_out;
> +
> +   STBI_NOTUSED(len);
> +
> +   return 1;
> +}
> +
> +static int stbi__unpremultiply_on_load = 0;
> +static int stbi__de_iphone_flag = 0;
> +
> +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
> +{
> +   stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
> +}
> +
> +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
> +{
> +   stbi__de_iphone_flag = flag_true_if_should_convert;
> +}
> +
> +static void stbi__de_iphone(stbi__png *z)
> +{
> +   stbi__context *s = z->s;
> +   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
> +   stbi_uc *p = z->out;
> +
> +   if (s->img_out_n == 3) {  // convert bgr to rgb
> +      for (i=0; i < pixel_count; ++i) {
> +         stbi_uc t = p[0];
> +         p[0] = p[2];
> +         p[2] = t;
> +         p += 3;
> +      }
> +   } else {
> +      STBI_ASSERT(s->img_out_n == 4);
> +      if (stbi__unpremultiply_on_load) {
> +         // convert bgr to rgb and unpremultiply
> +         for (i=0; i < pixel_count; ++i) {
> +            stbi_uc a = p[3];
> +            stbi_uc t = p[0];
> +            if (a) {
> +               stbi_uc half = a / 2;
> +               p[0] = (p[2] * 255 + half) / a;
> +               p[1] = (p[1] * 255 + half) / a;
> +               p[2] = ( t   * 255 + half) / a;
> +            } else {
> +               p[0] = p[2];
> +               p[2] = t;
> +            }
> +            p += 4;
> +         }
> +      } else {
> +         // convert bgr to rgb
> +         for (i=0; i < pixel_count; ++i) {
> +            stbi_uc t = p[0];
> +            p[0] = p[2];
> +            p[2] = t;
> +            p += 4;
> +         }
> +      }
> +   }
> +}
> +
> +#define STBI__PNG_TYPE(a,b,c,d)  (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
> +
> +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
> +{
> +   stbi_uc palette[1024], pal_img_n=0;
> +   stbi_uc has_trans=0, tc[3]={0};
> +   stbi__uint16 tc16[3];
> +   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
> +   int first=1,k,interlace=0, color=0, is_iphone=0;
> +   stbi__context *s = z->s;
> +
> +   z->expanded = NULL;
> +   z->idata = NULL;
> +   z->out = NULL;
> +
> +   if (!stbi__check_png_header(s)) return 0;
> +
> +   if (scan == STBI__SCAN_type) return 1;
> +
> +   for (;;) {
> +      stbi__pngchunk c = stbi__get_chunk_header(s);
> +      switch (c.type) {
> +         case STBI__PNG_TYPE('C','g','B','I'):
> +            is_iphone = 1;
> +            stbi__skip(s, c.length);
> +            break;
> +         case STBI__PNG_TYPE('I','H','D','R'): {
> +            int comp,filter;
> +            if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
> +            first = 0;
> +            if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
> +            s->img_x = stbi__get32be(s);
> +            s->img_y = stbi__get32be(s);
> +            if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
> +            if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
> +            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
> +            color = stbi__get8(s);  if (color > 6)         return stbi__err("bad ctype","Corrupt PNG");
> +            if (color == 3 && z->depth == 16)                  return stbi__err("bad ctype","Corrupt PNG");
> +            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
> +            comp  = stbi__get8(s);  if (comp) return stbi__err("bad comp method","Corrupt PNG");
> +            filter= stbi__get8(s);  if (filter) return stbi__err("bad filter method","Corrupt PNG");
> +            interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
> +            if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
> +            if (!pal_img_n) {
> +               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
> +               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
> +               if (scan == STBI__SCAN_header) return 1;
> +            } else {
> +               // if paletted, then pal_n is our final components, and
> +               // img_n is # components to decompress/filter.
> +               s->img_n = 1;
> +               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
> +               // if SCAN_header, have to scan to see if we have a tRNS
> +            }
> +            break;
> +         }
> +
> +         case STBI__PNG_TYPE('P','L','T','E'):  {
> +            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
> +            if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
> +            pal_len = c.length / 3;
> +            if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
> +            for (i=0; i < pal_len; ++i) {
> +               palette[i*4+0] = stbi__get8(s);
> +               palette[i*4+1] = stbi__get8(s);
> +               palette[i*4+2] = stbi__get8(s);
> +               palette[i*4+3] = 255;
> +            }
> +            break;
> +         }
> +
> +         case STBI__PNG_TYPE('t','R','N','S'): {
> +            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
> +            if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
> +            if (pal_img_n) {
> +               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
> +               if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
> +               if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
> +               pal_img_n = 4;
> +               for (i=0; i < c.length; ++i)
> +                  palette[i*4+3] = stbi__get8(s);
> +            } else {
> +               if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
> +               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
> +               has_trans = 1;
> +               if (z->depth == 16) {
> +                  for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
> +               } else {
> +                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
> +               }
> +            }
> +            break;
> +         }
> +
> +         case STBI__PNG_TYPE('I','D','A','T'): {
> +            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
> +            if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
> +            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
> +            if ((int)(ioff + c.length) < (int)ioff) return 0;
> +            if (ioff + c.length > idata_limit) {
> +               stbi__uint32 idata_limit_old = idata_limit;
> +               stbi_uc *p;
> +               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
> +               while (ioff + c.length > idata_limit)
> +                  idata_limit *= 2;
> +               STBI_NOTUSED(idata_limit_old);
> +               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
> +               z->idata = p;
> +            }
> +            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
> +            ioff += c.length;
> +            break;
> +         }
> +
> +         case STBI__PNG_TYPE('I','E','N','D'): {
> +            stbi__uint32 raw_len, bpl;
> +            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
> +            if (scan != STBI__SCAN_load) return 1;
> +            if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
> +            // initial guess for decoded data size to avoid unnecessary reallocs
> +            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component
> +            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
> +            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
> +            if (z->expanded == NULL) return 0; // zlib should set error
> +            STBI_FREE(z->idata); z->idata = NULL;
> +            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
> +               s->img_out_n = s->img_n+1;
> +            else
> +               s->img_out_n = s->img_n;
> +            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
> +            if (has_trans) {
> +               if (z->depth == 16) {
> +                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
> +               } else {
> +                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
> +               }
> +            }
> +            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
> +               stbi__de_iphone(z);
> +            if (pal_img_n) {
> +               // pal_img_n == 3 or 4
> +               s->img_n = pal_img_n; // record the actual colors we had
> +               s->img_out_n = pal_img_n;
> +               if (req_comp >= 3) s->img_out_n = req_comp;
> +               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
> +                  return 0;
> +            } else if (has_trans) {
> +               // non-paletted image with tRNS -> source image has (constant) alpha
> +               ++s->img_n;
> +            }
> +            STBI_FREE(z->expanded); z->expanded = NULL;
> +            // end of PNG chunk, read and skip CRC
> +            stbi__get32be(s);
> +            return 1;
> +         }
> +
> +         default:
> +            // if critical, fail
> +            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
> +            if ((c.type & (1 << 29)) == 0) {
> +               #ifndef STBI_NO_FAILURE_STRINGS
> +               // not threadsafe
> +               static char invalid_chunk[] = "XXXX PNG chunk not known";
> +               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
> +               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
> +               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);
> +               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);
> +               #endif
> +               return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
> +            }
> +            stbi__skip(s, c.length);
> +            break;
> +      }
> +      // end of PNG chunk, read and skip CRC
> +      stbi__get32be(s);
> +   }
> +}
> +
> +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
> +{
> +   void *result=NULL;
> +   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
> +   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
> +      if (p->depth <= 8)
> +         ri->bits_per_channel = 8;
> +      else if (p->depth == 16)
> +         ri->bits_per_channel = 16;
> +      else
> +         return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth");
> +      result = p->out;
> +      p->out = NULL;
> +      if (req_comp && req_comp != p->s->img_out_n) {
> +         if (ri->bits_per_channel == 8)
> +            result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
> +         else
> +            result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
> +         p->s->img_out_n = req_comp;
> +         if (result == NULL) return result;
> +      }
> +      *x = p->s->img_x;
> +      *y = p->s->img_y;
> +      if (n) *n = p->s->img_n;
> +   }
> +   STBI_FREE(p->out);      p->out      = NULL;
> +   STBI_FREE(p->expanded); p->expanded = NULL;
> +   STBI_FREE(p->idata);    p->idata    = NULL;
> +
> +   return result;
> +}
> +
> +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
> +{
> +   stbi__png p;
> +   p.s = s;
> +   return stbi__do_png(&p, x,y,comp,req_comp, ri);
> +}
> +
> +static int stbi__png_test(stbi__context *s)
> +{
> +   int r;
> +   r = stbi__check_png_header(s);
> +   stbi__rewind(s);
> +   return r;
> +}
> +
> +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
> +{
> +   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
> +      stbi__rewind( p->s );
> +      return 0;
> +   }
> +   if (x) *x = p->s->img_x;
> +   if (y) *y = p->s->img_y;
> +   if (comp) *comp = p->s->img_n;
> +   return 1;
> +}
> +
> +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   stbi__png p;
> +   p.s = s;
> +   return stbi__png_info_raw(&p, x, y, comp);
> +}
> +
> +static int stbi__png_is16(stbi__context *s)
> +{
> +   stbi__png p;
> +   p.s = s;
> +   if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
> +	   return 0;
> +   if (p.depth != 16) {
> +      stbi__rewind(p.s);
> +      return 0;
> +   }
> +   return 1;
> +}
> +#endif
> +
> +// Microsoft/Windows BMP image
> +
> +#ifndef STBI_NO_BMP
> +static int stbi__bmp_test_raw(stbi__context *s)
> +{
> +   int r;
> +   int sz;
> +   if (stbi__get8(s) != 'B') return 0;
> +   if (stbi__get8(s) != 'M') return 0;
> +   stbi__get32le(s); // discard filesize
> +   stbi__get16le(s); // discard reserved
> +   stbi__get16le(s); // discard reserved
> +   stbi__get32le(s); // discard data offset
> +   sz = stbi__get32le(s);
> +   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
> +   return r;
> +}
> +
> +static int stbi__bmp_test(stbi__context *s)
> +{
> +   int r = stbi__bmp_test_raw(s);
> +   stbi__rewind(s);
> +   return r;
> +}
> +
> +
> +// returns 0..31 for the highest set bit
> +static int stbi__high_bit(unsigned int z)
> +{
> +   int n=0;
> +   if (z == 0) return -1;
> +   if (z >= 0x10000) { n += 16; z >>= 16; }
> +   if (z >= 0x00100) { n +=  8; z >>=  8; }
> +   if (z >= 0x00010) { n +=  4; z >>=  4; }
> +   if (z >= 0x00004) { n +=  2; z >>=  2; }
> +   if (z >= 0x00002) { n +=  1;/* >>=  1;*/ }
> +   return n;
> +}
> +
> +static int stbi__bitcount(unsigned int a)
> +{
> +   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2
> +   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4
> +   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
> +   a = (a + (a >> 8)); // max 16 per 8 bits
> +   a = (a + (a >> 16)); // max 32 per 8 bits
> +   return a & 0xff;
> +}
> +
> +// extract an arbitrarily-aligned N-bit value (N=bits)
> +// from v, and then make it 8-bits long and fractionally
> +// extend it to full full range.
> +static int stbi__shiftsigned(unsigned int v, int shift, int bits)
> +{
> +   static unsigned int mul_table[9] = {
> +      0,
> +      0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
> +      0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
> +   };
> +   static unsigned int shift_table[9] = {
> +      0, 0,0,1,0,2,4,6,0,
> +   };
> +   if (shift < 0)
> +      v <<= -shift;
> +   else
> +      v >>= shift;
> +   STBI_ASSERT(v < 256);
> +   v >>= (8-bits);
> +   STBI_ASSERT(bits >= 0 && bits <= 8);
> +   return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
> +}
> +
> +typedef struct
> +{
> +   int bpp, offset, hsz;
> +   unsigned int mr,mg,mb,ma, all_a;
> +   int extra_read;
> +} stbi__bmp_data;
> +
> +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
> +{
> +   int hsz;
> +   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
> +   stbi__get32le(s); // discard filesize
> +   stbi__get16le(s); // discard reserved
> +   stbi__get16le(s); // discard reserved
> +   info->offset = stbi__get32le(s);
> +   info->hsz = hsz = stbi__get32le(s);
> +   info->mr = info->mg = info->mb = info->ma = 0;
> +   info->extra_read = 14;
> +
> +   if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP");
> +
> +   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
> +   if (hsz == 12) {
> +      s->img_x = stbi__get16le(s);
> +      s->img_y = stbi__get16le(s);
> +   } else {
> +      s->img_x = stbi__get32le(s);
> +      s->img_y = stbi__get32le(s);
> +   }
> +   if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
> +   info->bpp = stbi__get16le(s);
> +   if (hsz != 12) {
> +      int compress = stbi__get32le(s);
> +      if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
> +      stbi__get32le(s); // discard sizeof
> +      stbi__get32le(s); // discard hres
> +      stbi__get32le(s); // discard vres
> +      stbi__get32le(s); // discard colorsused
> +      stbi__get32le(s); // discard max important
> +      if (hsz == 40 || hsz == 56) {
> +         if (hsz == 56) {
> +            stbi__get32le(s);
> +            stbi__get32le(s);
> +            stbi__get32le(s);
> +            stbi__get32le(s);
> +         }
> +         if (info->bpp == 16 || info->bpp == 32) {
> +            if (compress == 0) {
> +               if (info->bpp == 32) {
> +                  info->mr = 0xffu << 16;
> +                  info->mg = 0xffu <<  8;
> +                  info->mb = 0xffu <<  0;
> +                  info->ma = 0xffu << 24;
> +                  info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
> +               } else {
> +                  info->mr = 31u << 10;
> +                  info->mg = 31u <<  5;
> +                  info->mb = 31u <<  0;
> +               }
> +            } else if (compress == 3) {
> +               info->mr = stbi__get32le(s);
> +               info->mg = stbi__get32le(s);
> +               info->mb = stbi__get32le(s);
> +               info->extra_read += 12;
> +               // not documented, but generated by photoshop and handled by mspaint
> +               if (info->mr == info->mg && info->mg == info->mb) {
> +                  // ?!?!?
> +                  return stbi__errpuc("bad BMP", "bad BMP");
> +               }
> +            } else
> +               return stbi__errpuc("bad BMP", "bad BMP");
> +         }
> +      } else {
> +         int i;
> +         if (hsz != 108 && hsz != 124)
> +            return stbi__errpuc("bad BMP", "bad BMP");
> +         info->mr = stbi__get32le(s);
> +         info->mg = stbi__get32le(s);
> +         info->mb = stbi__get32le(s);
> +         info->ma = stbi__get32le(s);
> +         stbi__get32le(s); // discard color space
> +         for (i=0; i < 12; ++i)
> +            stbi__get32le(s); // discard color space parameters
> +         if (hsz == 124) {
> +            stbi__get32le(s); // discard rendering intent
> +            stbi__get32le(s); // discard offset of profile data
> +            stbi__get32le(s); // discard size of profile data
> +            stbi__get32le(s); // discard reserved
> +         }
> +      }
> +   }
> +   return (void *) 1;
> +}
> +
> +
> +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
> +{
> +   stbi_uc *out;
> +   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
> +   stbi_uc pal[256][4];
> +   int psize=0,i,j,width;
> +   int flip_vertically, pad, target;
> +   stbi__bmp_data info;
> +   STBI_NOTUSED(ri);
> +
> +   info.all_a = 255;
> +   if (stbi__bmp_parse_header(s, &info) == NULL)
> +      return NULL; // error code already set
> +
> +   flip_vertically = ((int) s->img_y) > 0;
> +   s->img_y = abs((int) s->img_y);
> +
> +   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +
> +   mr = info.mr;
> +   mg = info.mg;
> +   mb = info.mb;
> +   ma = info.ma;
> +   all_a = info.all_a;
> +
> +   if (info.hsz == 12) {
> +      if (info.bpp < 24)
> +         psize = (info.offset - info.extra_read - 24) / 3;
> +   } else {
> +      if (info.bpp < 16)
> +         psize = (info.offset - info.extra_read - info.hsz) >> 2;
> +   }
> +   if (psize == 0) {
> +      STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original));
> +      if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) {
> +        return stbi__errpuc("bad offset", "Corrupt BMP");
> +      }
> +   }
> +
> +   if (info.bpp == 24 && ma == 0xff000000)
> +      s->img_n = 3;
> +   else
> +      s->img_n = ma ? 4 : 3;
> +   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
> +      target = req_comp;
> +   else
> +      target = s->img_n; // if they want monochrome, we'll post-convert
> +
> +   // sanity-check size
> +   if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))
> +      return stbi__errpuc("too large", "Corrupt BMP");
> +
> +   out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);
> +   if (!out) return stbi__errpuc("outofmem", "Out of memory");
> +   if (info.bpp < 16) {
> +      int z=0;
> +      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
> +      for (i=0; i < psize; ++i) {
> +         pal[i][2] = stbi__get8(s);
> +         pal[i][1] = stbi__get8(s);
> +         pal[i][0] = stbi__get8(s);
> +         if (info.hsz != 12) stbi__get8(s);
> +         pal[i][3] = 255;
> +      }
> +      stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
> +      if (info.bpp == 1) width = (s->img_x + 7) >> 3;
> +      else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
> +      else if (info.bpp == 8) width = s->img_x;
> +      else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
> +      pad = (-width)&3;
> +      if (info.bpp == 1) {
> +         for (j=0; j < (int) s->img_y; ++j) {
> +            int bit_offset = 7, v = stbi__get8(s);
> +            for (i=0; i < (int) s->img_x; ++i) {
> +               int color = (v>>bit_offset)&0x1;
> +               out[z++] = pal[color][0];
> +               out[z++] = pal[color][1];
> +               out[z++] = pal[color][2];
> +               if (target == 4) out[z++] = 255;
> +               if (i+1 == (int) s->img_x) break;
> +               if((--bit_offset) < 0) {
> +                  bit_offset = 7;
> +                  v = stbi__get8(s);
> +               }
> +            }
> +            stbi__skip(s, pad);
> +         }
> +      } else {
> +         for (j=0; j < (int) s->img_y; ++j) {
> +            for (i=0; i < (int) s->img_x; i += 2) {
> +               int v=stbi__get8(s),v2=0;
> +               if (info.bpp == 4) {
> +                  v2 = v & 15;
> +                  v >>= 4;
> +               }
> +               out[z++] = pal[v][0];
> +               out[z++] = pal[v][1];
> +               out[z++] = pal[v][2];
> +               if (target == 4) out[z++] = 255;
> +               if (i+1 == (int) s->img_x) break;
> +               v = (info.bpp == 8) ? stbi__get8(s) : v2;
> +               out[z++] = pal[v][0];
> +               out[z++] = pal[v][1];
> +               out[z++] = pal[v][2];
> +               if (target == 4) out[z++] = 255;
> +            }
> +            stbi__skip(s, pad);
> +         }
> +      }
> +   } else {
> +      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
> +      int z = 0;
> +      int easy=0;
> +      stbi__skip(s, info.offset - info.extra_read - info.hsz);
> +      if (info.bpp == 24) width = 3 * s->img_x;
> +      else if (info.bpp == 16) width = 2*s->img_x;
> +      else /* bpp = 32 and pad = 0 */ width=0;
> +      pad = (-width) & 3;
> +      if (info.bpp == 24) {
> +         easy = 1;
> +      } else if (info.bpp == 32) {
> +         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
> +            easy = 2;
> +      }
> +      if (!easy) {
> +         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
> +         // right shift amt to put high bit in position #7
> +         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
> +         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
> +         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
> +         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
> +         if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
> +      }
> +      for (j=0; j < (int) s->img_y; ++j) {
> +         if (easy) {
> +            for (i=0; i < (int) s->img_x; ++i) {
> +               unsigned char a;
> +               out[z+2] = stbi__get8(s);
> +               out[z+1] = stbi__get8(s);
> +               out[z+0] = stbi__get8(s);
> +               z += 3;
> +               a = (easy == 2 ? stbi__get8(s) : 255);
> +               all_a |= a;
> +               if (target == 4) out[z++] = a;
> +            }
> +         } else {
> +            int bpp = info.bpp;
> +            for (i=0; i < (int) s->img_x; ++i) {
> +               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
> +               unsigned int a;
> +               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
> +               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
> +               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
> +               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
> +               all_a |= a;
> +               if (target == 4) out[z++] = STBI__BYTECAST(a);
> +            }
> +         }
> +         stbi__skip(s, pad);
> +      }
> +   }
> +
> +   // if alpha channel is all 0s, replace with all 255s
> +   if (target == 4 && all_a == 0)
> +      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)
> +         out[i] = 255;
> +
> +   if (flip_vertically) {
> +      stbi_uc t;
> +      for (j=0; j < (int) s->img_y>>1; ++j) {
> +         stbi_uc *p1 = out +      j     *s->img_x*target;
> +         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
> +         for (i=0; i < (int) s->img_x*target; ++i) {
> +            t = p1[i]; p1[i] = p2[i]; p2[i] = t;
> +         }
> +      }
> +   }
> +
> +   if (req_comp && req_comp != target) {
> +      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
> +      if (out == NULL) return out; // stbi__convert_format frees input on failure
> +   }
> +
> +   *x = s->img_x;
> +   *y = s->img_y;
> +   if (comp) *comp = s->img_n;
> +   return out;
> +}
> +#endif
> +
> +// Targa Truevision - TGA
> +// by Jonathan Dummer
> +#ifndef STBI_NO_TGA
> +// returns STBI_rgb or whatever, 0 on error
> +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
> +{
> +   // only RGB or RGBA (incl. 16bit) or grey allowed
> +   if (is_rgb16) *is_rgb16 = 0;
> +   switch(bits_per_pixel) {
> +      case 8:  return STBI_grey;
> +      case 16: if(is_grey) return STBI_grey_alpha;
> +               // fallthrough
> +      case 15: if(is_rgb16) *is_rgb16 = 1;
> +               return STBI_rgb;
> +      case 24: // fallthrough
> +      case 32: return bits_per_pixel/8;
> +      default: return 0;
> +   }
> +}
> +
> +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
> +    int sz, tga_colormap_type;
> +    stbi__get8(s);                   // discard Offset
> +    tga_colormap_type = stbi__get8(s); // colormap type
> +    if( tga_colormap_type > 1 ) {
> +        stbi__rewind(s);
> +        return 0;      // only RGB or indexed allowed
> +    }
> +    tga_image_type = stbi__get8(s); // image type
> +    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
> +        if (tga_image_type != 1 && tga_image_type != 9) {
> +            stbi__rewind(s);
> +            return 0;
> +        }
> +        stbi__skip(s,4);       // skip index of first colormap entry and number of entries
> +        sz = stbi__get8(s);    //   check bits per palette color entry
> +        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
> +            stbi__rewind(s);
> +            return 0;
> +        }
> +        stbi__skip(s,4);       // skip image x and y origin
> +        tga_colormap_bpp = sz;
> +    } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
> +        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
> +            stbi__rewind(s);
> +            return 0; // only RGB or grey allowed, +/- RLE
> +        }
> +        stbi__skip(s,9); // skip colormap specification and image x/y origin
> +        tga_colormap_bpp = 0;
> +    }
> +    tga_w = stbi__get16le(s);
> +    if( tga_w < 1 ) {
> +        stbi__rewind(s);
> +        return 0;   // test width
> +    }
> +    tga_h = stbi__get16le(s);
> +    if( tga_h < 1 ) {
> +        stbi__rewind(s);
> +        return 0;   // test height
> +    }
> +    tga_bits_per_pixel = stbi__get8(s); // bits per pixel
> +    stbi__get8(s); // ignore alpha bits
> +    if (tga_colormap_bpp != 0) {
> +        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
> +            // when using a colormap, tga_bits_per_pixel is the size of the indexes
> +            // I don't think anything but 8 or 16bit indexes makes sense
> +            stbi__rewind(s);
> +            return 0;
> +        }
> +        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
> +    } else {
> +        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
> +    }
> +    if(!tga_comp) {
> +      stbi__rewind(s);
> +      return 0;
> +    }
> +    if (x) *x = tga_w;
> +    if (y) *y = tga_h;
> +    if (comp) *comp = tga_comp;
> +    return 1;                   // seems to have passed everything
> +}
> +
> +static int stbi__tga_test(stbi__context *s)
> +{
> +   int res = 0;
> +   int sz, tga_color_type;
> +   stbi__get8(s);      //   discard Offset
> +   tga_color_type = stbi__get8(s);   //   color type
> +   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed
> +   sz = stbi__get8(s);   //   image type
> +   if ( tga_color_type == 1 ) { // colormapped (paletted) image
> +      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
> +      stbi__skip(s,4);       // skip index of first colormap entry and number of entries
> +      sz = stbi__get8(s);    //   check bits per palette color entry
> +      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
> +      stbi__skip(s,4);       // skip image x and y origin
> +   } else { // "normal" image w/o colormap
> +      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
> +      stbi__skip(s,9); // skip colormap specification and image x/y origin
> +   }
> +   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width
> +   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height
> +   sz = stbi__get8(s);   //   bits per pixel
> +   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
> +   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
> +
> +   res = 1; // if we got this far, everything's good and we can return 1 instead of 0
> +
> +errorEnd:
> +   stbi__rewind(s);
> +   return res;
> +}
> +
> +// read 16bit value and convert to 24bit RGB
> +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
> +{
> +   stbi__uint16 px = (stbi__uint16)stbi__get16le(s);
> +   stbi__uint16 fiveBitMask = 31;
> +   // we have 3 channels with 5bits each
> +   int r = (px >> 10) & fiveBitMask;
> +   int g = (px >> 5) & fiveBitMask;
> +   int b = px & fiveBitMask;
> +   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
> +   out[0] = (stbi_uc)((r * 255)/31);
> +   out[1] = (stbi_uc)((g * 255)/31);
> +   out[2] = (stbi_uc)((b * 255)/31);
> +
> +   // some people claim that the most significant bit might be used for alpha
> +   // (possibly if an alpha-bit is set in the "image descriptor byte")
> +   // but that only made 16bit test images completely translucent..
> +   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.
> +}
> +
> +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
> +{
> +   //   read in the TGA header stuff
> +   int tga_offset = stbi__get8(s);
> +   int tga_indexed = stbi__get8(s);
> +   int tga_image_type = stbi__get8(s);
> +   int tga_is_RLE = 0;
> +   int tga_palette_start = stbi__get16le(s);
> +   int tga_palette_len = stbi__get16le(s);
> +   int tga_palette_bits = stbi__get8(s);
> +   int tga_x_origin = stbi__get16le(s);
> +   int tga_y_origin = stbi__get16le(s);
> +   int tga_width = stbi__get16le(s);
> +   int tga_height = stbi__get16le(s);
> +   int tga_bits_per_pixel = stbi__get8(s);
> +   int tga_comp, tga_rgb16=0;
> +   int tga_inverted = stbi__get8(s);
> +   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
> +   //   image data
> +   unsigned char *tga_data;
> +   unsigned char *tga_palette = NULL;
> +   int i, j;
> +   unsigned char raw_data[4] = {0};
> +   int RLE_count = 0;
> +   int RLE_repeating = 0;
> +   int read_next_pixel = 1;
> +   STBI_NOTUSED(ri);
> +   STBI_NOTUSED(tga_x_origin); // @TODO
> +   STBI_NOTUSED(tga_y_origin); // @TODO
> +
> +   if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +   if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +
> +   //   do a tiny bit of precessing
> +   if ( tga_image_type >= 8 )
> +   {
> +      tga_image_type -= 8;
> +      tga_is_RLE = 1;
> +   }
> +   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
> +
> +   //   If I'm paletted, then I'll use the number of bits from the palette
> +   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
> +   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
> +
> +   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
> +      return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
> +
> +   //   tga info
> +   *x = tga_width;
> +   *y = tga_height;
> +   if (comp) *comp = tga_comp;
> +
> +   if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))
> +      return stbi__errpuc("too large", "Corrupt TGA");
> +
> +   tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
> +   if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
> +
> +   // skip to the data's starting position (offset usually = 0)
> +   stbi__skip(s, tga_offset );
> +
> +   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
> +      for (i=0; i < tga_height; ++i) {
> +         int row = tga_inverted ? tga_height -i - 1 : i;
> +         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
> +         stbi__getn(s, tga_row, tga_width * tga_comp);
> +      }
> +   } else  {
> +      //   do I need to load a palette?
> +      if ( tga_indexed)
> +      {
> +         if (tga_palette_len == 0) {  /* you have to have at least one entry! */
> +            STBI_FREE(tga_data);
> +            return stbi__errpuc("bad palette", "Corrupt TGA");
> +         }
> +
> +         //   any data to skip? (offset usually = 0)
> +         stbi__skip(s, tga_palette_start );
> +         //   load the palette
> +         tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);
> +         if (!tga_palette) {
> +            STBI_FREE(tga_data);
> +            return stbi__errpuc("outofmem", "Out of memory");
> +         }
> +         if (tga_rgb16) {
> +            stbi_uc *pal_entry = tga_palette;
> +            STBI_ASSERT(tga_comp == STBI_rgb);
> +            for (i=0; i < tga_palette_len; ++i) {
> +               stbi__tga_read_rgb16(s, pal_entry);
> +               pal_entry += tga_comp;
> +            }
> +         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
> +               STBI_FREE(tga_data);
> +               STBI_FREE(tga_palette);
> +               return stbi__errpuc("bad palette", "Corrupt TGA");
> +         }
> +      }
> +      //   load the data
> +      for (i=0; i < tga_width * tga_height; ++i)
> +      {
> +         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
> +         if ( tga_is_RLE )
> +         {
> +            if ( RLE_count == 0 )
> +            {
> +               //   yep, get the next byte as a RLE command
> +               int RLE_cmd = stbi__get8(s);
> +               RLE_count = 1 + (RLE_cmd & 127);
> +               RLE_repeating = RLE_cmd >> 7;
> +               read_next_pixel = 1;
> +            } else if ( !RLE_repeating )
> +            {
> +               read_next_pixel = 1;
> +            }
> +         } else
> +         {
> +            read_next_pixel = 1;
> +         }
> +         //   OK, if I need to read a pixel, do it now
> +         if ( read_next_pixel )
> +         {
> +            //   load however much data we did have
> +            if ( tga_indexed )
> +            {
> +               // read in index, then perform the lookup
> +               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
> +               if ( pal_idx >= tga_palette_len ) {
> +                  // invalid index
> +                  pal_idx = 0;
> +               }
> +               pal_idx *= tga_comp;
> +               for (j = 0; j < tga_comp; ++j) {
> +                  raw_data[j] = tga_palette[pal_idx+j];
> +               }
> +            } else if(tga_rgb16) {
> +               STBI_ASSERT(tga_comp == STBI_rgb);
> +               stbi__tga_read_rgb16(s, raw_data);
> +            } else {
> +               //   read in the data raw
> +               for (j = 0; j < tga_comp; ++j) {
> +                  raw_data[j] = stbi__get8(s);
> +               }
> +            }
> +            //   clear the reading flag for the next pixel
> +            read_next_pixel = 0;
> +         } // end of reading a pixel
> +
> +         // copy data
> +         for (j = 0; j < tga_comp; ++j)
> +           tga_data[i*tga_comp+j] = raw_data[j];
> +
> +         //   in case we're in RLE mode, keep counting down
> +         --RLE_count;
> +      }
> +      //   do I need to invert the image?
> +      if ( tga_inverted )
> +      {
> +         for (j = 0; j*2 < tga_height; ++j)
> +         {
> +            int index1 = j * tga_width * tga_comp;
> +            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
> +            for (i = tga_width * tga_comp; i > 0; --i)
> +            {
> +               unsigned char temp = tga_data[index1];
> +               tga_data[index1] = tga_data[index2];
> +               tga_data[index2] = temp;
> +               ++index1;
> +               ++index2;
> +            }
> +         }
> +      }
> +      //   clear my palette, if I had one
> +      if ( tga_palette != NULL )
> +      {
> +         STBI_FREE( tga_palette );
> +      }
> +   }
> +
> +   // swap RGB - if the source data was RGB16, it already is in the right order
> +   if (tga_comp >= 3 && !tga_rgb16)
> +   {
> +      unsigned char* tga_pixel = tga_data;
> +      for (i=0; i < tga_width * tga_height; ++i)
> +      {
> +         unsigned char temp = tga_pixel[0];
> +         tga_pixel[0] = tga_pixel[2];
> +         tga_pixel[2] = temp;
> +         tga_pixel += tga_comp;
> +      }
> +   }
> +
> +   // convert to target component count
> +   if (req_comp && req_comp != tga_comp)
> +      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
> +
> +   //   the things I do to get rid of an error message, and yet keep
> +   //   Microsoft's C compilers happy... [8^(
> +   tga_palette_start = tga_palette_len = tga_palette_bits =
> +         tga_x_origin = tga_y_origin = 0;
> +   STBI_NOTUSED(tga_palette_start);
> +   //   OK, done
> +   return tga_data;
> +}
> +#endif
> +
> +// *************************************************************************************************
> +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
> +
> +#ifndef STBI_NO_PSD
> +static int stbi__psd_test(stbi__context *s)
> +{
> +   int r = (stbi__get32be(s) == 0x38425053);
> +   stbi__rewind(s);
> +   return r;
> +}
> +
> +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)
> +{
> +   int count, nleft, len;
> +
> +   count = 0;
> +   while ((nleft = pixelCount - count) > 0) {
> +      len = stbi__get8(s);
> +      if (len == 128) {
> +         // No-op.
> +      } else if (len < 128) {
> +         // Copy next len+1 bytes literally.
> +         len++;
> +         if (len > nleft) return 0; // corrupt data
> +         count += len;
> +         while (len) {
> +            *p = stbi__get8(s);
> +            p += 4;
> +            len--;
> +         }
> +      } else if (len > 128) {
> +         stbi_uc   val;
> +         // Next -len+1 bytes in the dest are replicated from next source byte.
> +         // (Interpret len as a negative 8-bit int.)
> +         len = 257 - len;
> +         if (len > nleft) return 0; // corrupt data
> +         val = stbi__get8(s);
> +         count += len;
> +         while (len) {
> +            *p = val;
> +            p += 4;
> +            len--;
> +         }
> +      }
> +   }
> +
> +   return 1;
> +}
> +
> +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
> +{
> +   int pixelCount;
> +   int channelCount, compression;
> +   int channel, i;
> +   int bitdepth;
> +   int w,h;
> +   stbi_uc *out;
> +   STBI_NOTUSED(ri);
> +
> +   // Check identifier
> +   if (stbi__get32be(s) != 0x38425053)   // "8BPS"
> +      return stbi__errpuc("not PSD", "Corrupt PSD image");
> +
> +   // Check file type version.
> +   if (stbi__get16be(s) != 1)
> +      return stbi__errpuc("wrong version", "Unsupported version of PSD image");
> +
> +   // Skip 6 reserved bytes.
> +   stbi__skip(s, 6 );
> +
> +   // Read the number of channels (R, G, B, A, etc).
> +   channelCount = stbi__get16be(s);
> +   if (channelCount < 0 || channelCount > 16)
> +      return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
> +
> +   // Read the rows and columns of the image.
> +   h = stbi__get32be(s);
> +   w = stbi__get32be(s);
> +
> +   if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +   if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +
> +   // Make sure the depth is 8 bits.
> +   bitdepth = stbi__get16be(s);
> +   if (bitdepth != 8 && bitdepth != 16)
> +      return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit");
> +
> +   // Make sure the color mode is RGB.
> +   // Valid options are:
> +   //   0: Bitmap
> +   //   1: Grayscale
> +   //   2: Indexed color
> +   //   3: RGB color
> +   //   4: CMYK color
> +   //   7: Multichannel
> +   //   8: Duotone
> +   //   9: Lab color
> +   if (stbi__get16be(s) != 3)
> +      return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
> +
> +   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
> +   stbi__skip(s,stbi__get32be(s) );
> +
> +   // Skip the image resources.  (resolution, pen tool paths, etc)
> +   stbi__skip(s, stbi__get32be(s) );
> +
> +   // Skip the reserved data.
> +   stbi__skip(s, stbi__get32be(s) );
> +
> +   // Find out if the data is compressed.
> +   // Known values:
> +   //   0: no compression
> +   //   1: RLE compressed
> +   compression = stbi__get16be(s);
> +   if (compression > 1)
> +      return stbi__errpuc("bad compression", "PSD has an unknown compression format");
> +
> +   // Check size
> +   if (!stbi__mad3sizes_valid(4, w, h, 0))
> +      return stbi__errpuc("too large", "Corrupt PSD");
> +
> +   // Create the destination image.
> +
> +   if (!compression && bitdepth == 16 && bpc == 16) {
> +      out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);
> +      ri->bits_per_channel = 16;
> +   } else
> +      out = (stbi_uc *) stbi__malloc(4 * w*h);
> +
> +   if (!out) return stbi__errpuc("outofmem", "Out of memory");
> +   pixelCount = w*h;
> +
> +   // Initialize the data to zero.
> +   //memset( out, 0, pixelCount * 4 );
> +
> +   // Finally, the image data.
> +   if (compression) {
> +      // RLE as used by .PSD and .TIFF
> +      // Loop until you get the number of unpacked bytes you are expecting:
> +      //     Read the next source byte into n.
> +      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
> +      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
> +      //     Else if n is 128, noop.
> +      // Endloop
> +
> +      // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,
> +      // which we're going to just skip.
> +      stbi__skip(s, h * channelCount * 2 );
> +
> +      // Read the RLE data by channel.
> +      for (channel = 0; channel < 4; channel++) {
> +         stbi_uc *p;
> +
> +         p = out+channel;
> +         if (channel >= channelCount) {
> +            // Fill this channel with default data.
> +            for (i = 0; i < pixelCount; i++, p += 4)
> +               *p = (channel == 3 ? 255 : 0);
> +         } else {
> +            // Read the RLE data.
> +            if (!stbi__psd_decode_rle(s, p, pixelCount)) {
> +               STBI_FREE(out);
> +               return stbi__errpuc("corrupt", "bad RLE data");
> +            }
> +         }
> +      }
> +
> +   } else {
> +      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
> +      // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.
> +
> +      // Read the data by channel.
> +      for (channel = 0; channel < 4; channel++) {
> +         if (channel >= channelCount) {
> +            // Fill this channel with default data.
> +            if (bitdepth == 16 && bpc == 16) {
> +               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
> +               stbi__uint16 val = channel == 3 ? 65535 : 0;
> +               for (i = 0; i < pixelCount; i++, q += 4)
> +                  *q = val;
> +            } else {
> +               stbi_uc *p = out+channel;
> +               stbi_uc val = channel == 3 ? 255 : 0;
> +               for (i = 0; i < pixelCount; i++, p += 4)
> +                  *p = val;
> +            }
> +         } else {
> +            if (ri->bits_per_channel == 16) {    // output bpc
> +               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
> +               for (i = 0; i < pixelCount; i++, q += 4)
> +                  *q = (stbi__uint16) stbi__get16be(s);
> +            } else {
> +               stbi_uc *p = out+channel;
> +               if (bitdepth == 16) {  // input bpc
> +                  for (i = 0; i < pixelCount; i++, p += 4)
> +                     *p = (stbi_uc) (stbi__get16be(s) >> 8);
> +               } else {
> +                  for (i = 0; i < pixelCount; i++, p += 4)
> +                     *p = stbi__get8(s);
> +               }
> +            }
> +         }
> +      }
> +   }
> +
> +   // remove weird white matte from PSD
> +   if (channelCount >= 4) {
> +      if (ri->bits_per_channel == 16) {
> +         for (i=0; i < w*h; ++i) {
> +            stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;
> +            if (pixel[3] != 0 && pixel[3] != 65535) {
> +               float a = pixel[3] / 65535.0f;
> +               float ra = 1.0f / a;
> +               float inv_a = 65535.0f * (1 - ra);
> +               pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);
> +               pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);
> +               pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);
> +            }
> +         }
> +      } else {
> +         for (i=0; i < w*h; ++i) {
> +            unsigned char *pixel = out + 4*i;
> +            if (pixel[3] != 0 && pixel[3] != 255) {
> +               float a = pixel[3] / 255.0f;
> +               float ra = 1.0f / a;
> +               float inv_a = 255.0f * (1 - ra);
> +               pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
> +               pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
> +               pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
> +            }
> +         }
> +      }
> +   }
> +
> +   // convert to desired output format
> +   if (req_comp && req_comp != 4) {
> +      if (ri->bits_per_channel == 16)
> +         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);
> +      else
> +         out = stbi__convert_format(out, 4, req_comp, w, h);
> +      if (out == NULL) return out; // stbi__convert_format frees input on failure
> +   }
> +
> +   if (comp) *comp = 4;
> +   *y = h;
> +   *x = w;
> +
> +   return out;
> +}
> +#endif
> +
> +// *************************************************************************************************
> +// Softimage PIC loader
> +// by Tom Seddon
> +//
> +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
> +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
> +
> +#ifndef STBI_NO_PIC
> +static int stbi__pic_is4(stbi__context *s,const char *str)
> +{
> +   int i;
> +   for (i=0; i<4; ++i)
> +      if (stbi__get8(s) != (stbi_uc)str[i])
> +         return 0;
> +
> +   return 1;
> +}
> +
> +static int stbi__pic_test_core(stbi__context *s)
> +{
> +   int i;
> +
> +   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
> +      return 0;
> +
> +   for(i=0;i<84;++i)
> +      stbi__get8(s);
> +
> +   if (!stbi__pic_is4(s,"PICT"))
> +      return 0;
> +
> +   return 1;
> +}
> +
> +typedef struct
> +{
> +   stbi_uc size,type,channel;
> +} stbi__pic_packet;
> +
> +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
> +{
> +   int mask=0x80, i;
> +
> +   for (i=0; i<4; ++i, mask>>=1) {
> +      if (channel & mask) {
> +         if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
> +         dest[i]=stbi__get8(s);
> +      }
> +   }
> +
> +   return dest;
> +}
> +
> +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
> +{
> +   int mask=0x80,i;
> +
> +   for (i=0;i<4; ++i, mask>>=1)
> +      if (channel&mask)
> +         dest[i]=src[i];
> +}
> +
> +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
> +{
> +   int act_comp=0,num_packets=0,y,chained;
> +   stbi__pic_packet packets[10];
> +
> +   // this will (should...) cater for even some bizarre stuff like having data
> +    // for the same channel in multiple packets.
> +   do {
> +      stbi__pic_packet *packet;
> +
> +      if (num_packets==sizeof(packets)/sizeof(packets[0]))
> +         return stbi__errpuc("bad format","too many packets");
> +
> +      packet = &packets[num_packets++];
> +
> +      chained = stbi__get8(s);
> +      packet->size    = stbi__get8(s);
> +      packet->type    = stbi__get8(s);
> +      packet->channel = stbi__get8(s);
> +
> +      act_comp |= packet->channel;
> +
> +      if (stbi__at_eof(s))          return stbi__errpuc("bad file","file too short (reading packets)");
> +      if (packet->size != 8)  return stbi__errpuc("bad format","packet isn't 8bpp");
> +   } while (chained);
> +
> +   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
> +
> +   for(y=0; y<height; ++y) {
> +      int packet_idx;
> +
> +      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
> +         stbi__pic_packet *packet = &packets[packet_idx];
> +         stbi_uc *dest = result+y*width*4;
> +
> +         switch (packet->type) {
> +            default:
> +               return stbi__errpuc("bad format","packet has bad compression type");
> +
> +            case 0: {//uncompressed
> +               int x;
> +
> +               for(x=0;x<width;++x, dest+=4)
> +                  if (!stbi__readval(s,packet->channel,dest))
> +                     return 0;
> +               break;
> +            }
> +
> +            case 1://Pure RLE
> +               {
> +                  int left=width, i;
> +
> +                  while (left>0) {
> +                     stbi_uc count,value[4];
> +
> +                     count=stbi__get8(s);
> +                     if (stbi__at_eof(s))   return stbi__errpuc("bad file","file too short (pure read count)");
> +
> +                     if (count > left)
> +                        count = (stbi_uc) left;
> +
> +                     if (!stbi__readval(s,packet->channel,value))  return 0;
> +
> +                     for(i=0; i<count; ++i,dest+=4)
> +                        stbi__copyval(packet->channel,dest,value);
> +                     left -= count;
> +                  }
> +               }
> +               break;
> +
> +            case 2: {//Mixed RLE
> +               int left=width;
> +               while (left>0) {
> +                  int count = stbi__get8(s), i;
> +                  if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (mixed read count)");
> +
> +                  if (count >= 128) { // Repeated
> +                     stbi_uc value[4];
> +
> +                     if (count==128)
> +                        count = stbi__get16be(s);
> +                     else
> +                        count -= 127;
> +                     if (count > left)
> +                        return stbi__errpuc("bad file","scanline overrun");
> +
> +                     if (!stbi__readval(s,packet->channel,value))
> +                        return 0;
> +
> +                     for(i=0;i<count;++i, dest += 4)
> +                        stbi__copyval(packet->channel,dest,value);
> +                  } else { // Raw
> +                     ++count;
> +                     if (count>left) return stbi__errpuc("bad file","scanline overrun");
> +
> +                     for(i=0;i<count;++i, dest+=4)
> +                        if (!stbi__readval(s,packet->channel,dest))
> +                           return 0;
> +                  }
> +                  left-=count;
> +               }
> +               break;
> +            }
> +         }
> +      }
> +   }
> +
> +   return result;
> +}
> +
> +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
> +{
> +   stbi_uc *result;
> +   int i, x,y, internal_comp;
> +   STBI_NOTUSED(ri);
> +
> +   if (!comp) comp = &internal_comp;
> +
> +   for (i=0; i<92; ++i)
> +      stbi__get8(s);
> +
> +   x = stbi__get16be(s);
> +   y = stbi__get16be(s);
> +
> +   if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +   if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +
> +   if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (pic header)");
> +   if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
> +
> +   stbi__get32be(s); //skip `ratio'
> +   stbi__get16be(s); //skip `fields'
> +   stbi__get16be(s); //skip `pad'
> +
> +   // intermediate buffer is RGBA
> +   result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
> +   memset(result, 0xff, x*y*4);
> +
> +   if (!stbi__pic_load_core(s,x,y,comp, result)) {
> +      STBI_FREE(result);
> +      result=0;
> +   }
> +   *px = x;
> +   *py = y;
> +   if (req_comp == 0) req_comp = *comp;
> +   result=stbi__convert_format(result,4,req_comp,x,y);
> +
> +   return result;
> +}
> +
> +static int stbi__pic_test(stbi__context *s)
> +{
> +   int r = stbi__pic_test_core(s);
> +   stbi__rewind(s);
> +   return r;
> +}
> +#endif
> +
> +// *************************************************************************************************
> +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
> +
> +#ifndef STBI_NO_GIF
> +typedef struct
> +{
> +   stbi__int16 prefix;
> +   stbi_uc first;
> +   stbi_uc suffix;
> +} stbi__gif_lzw;
> +
> +typedef struct
> +{
> +   int w,h;
> +   stbi_uc *out;                 // output buffer (always 4 components)
> +   stbi_uc *background;          // The current "background" as far as a gif is concerned
> +   stbi_uc *history;
> +   int flags, bgindex, ratio, transparent, eflags;
> +   stbi_uc  pal[256][4];
> +   stbi_uc lpal[256][4];
> +   stbi__gif_lzw codes[8192];
> +   stbi_uc *color_table;
> +   int parse, step;
> +   int lflags;
> +   int start_x, start_y;
> +   int max_x, max_y;
> +   int cur_x, cur_y;
> +   int line_size;
> +   int delay;
> +} stbi__gif;
> +
> +static int stbi__gif_test_raw(stbi__context *s)
> +{
> +   int sz;
> +   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
> +   sz = stbi__get8(s);
> +   if (sz != '9' && sz != '7') return 0;
> +   if (stbi__get8(s) != 'a') return 0;
> +   return 1;
> +}
> +
> +static int stbi__gif_test(stbi__context *s)
> +{
> +   int r = stbi__gif_test_raw(s);
> +   stbi__rewind(s);
> +   return r;
> +}
> +
> +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
> +{
> +   int i;
> +   for (i=0; i < num_entries; ++i) {
> +      pal[i][2] = stbi__get8(s);
> +      pal[i][1] = stbi__get8(s);
> +      pal[i][0] = stbi__get8(s);
> +      pal[i][3] = transp == i ? 0 : 255;
> +   }
> +}
> +
> +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
> +{
> +   stbi_uc version;
> +   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
> +      return stbi__err("not GIF", "Corrupt GIF");
> +
> +   version = stbi__get8(s);
> +   if (version != '7' && version != '9')    return stbi__err("not GIF", "Corrupt GIF");
> +   if (stbi__get8(s) != 'a')                return stbi__err("not GIF", "Corrupt GIF");
> +
> +   stbi__g_failure_reason = "";
> +   g->w = stbi__get16le(s);
> +   g->h = stbi__get16le(s);
> +   g->flags = stbi__get8(s);
> +   g->bgindex = stbi__get8(s);
> +   g->ratio = stbi__get8(s);
> +   g->transparent = -1;
> +
> +   if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
> +   if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
> +
> +   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments
> +
> +   if (is_info) return 1;
> +
> +   if (g->flags & 0x80)
> +      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
> +
> +   return 1;
> +}
> +
> +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
> +   if (!stbi__gif_header(s, g, comp, 1)) {
> +      STBI_FREE(g);
> +      stbi__rewind( s );
> +      return 0;
> +   }
> +   if (x) *x = g->w;
> +   if (y) *y = g->h;
> +   STBI_FREE(g);
> +   return 1;
> +}
> +
> +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
> +{
> +   stbi_uc *p, *c;
> +   int idx;
> +
> +   // recurse to decode the prefixes, since the linked-list is backwards,
> +   // and working backwards through an interleaved image would be nasty
> +   if (g->codes[code].prefix >= 0)
> +      stbi__out_gif_code(g, g->codes[code].prefix);
> +
> +   if (g->cur_y >= g->max_y) return;
> +
> +   idx = g->cur_x + g->cur_y;
> +   p = &g->out[idx];
> +   g->history[idx / 4] = 1;
> +
> +   c = &g->color_table[g->codes[code].suffix * 4];
> +   if (c[3] > 128) { // don't render transparent pixels;
> +      p[0] = c[2];
> +      p[1] = c[1];
> +      p[2] = c[0];
> +      p[3] = c[3];
> +   }
> +   g->cur_x += 4;
> +
> +   if (g->cur_x >= g->max_x) {
> +      g->cur_x = g->start_x;
> +      g->cur_y += g->step;
> +
> +      while (g->cur_y >= g->max_y && g->parse > 0) {
> +         g->step = (1 << g->parse) * g->line_size;
> +         g->cur_y = g->start_y + (g->step >> 1);
> +         --g->parse;
> +      }
> +   }
> +}
> +
> +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
> +{
> +   stbi_uc lzw_cs;
> +   stbi__int32 len, init_code;
> +   stbi__uint32 first;
> +   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
> +   stbi__gif_lzw *p;
> +
> +   lzw_cs = stbi__get8(s);
> +   if (lzw_cs > 12) return NULL;
> +   clear = 1 << lzw_cs;
> +   first = 1;
> +   codesize = lzw_cs + 1;
> +   codemask = (1 << codesize) - 1;
> +   bits = 0;
> +   valid_bits = 0;
> +   for (init_code = 0; init_code < clear; init_code++) {
> +      g->codes[init_code].prefix = -1;
> +      g->codes[init_code].first = (stbi_uc) init_code;
> +      g->codes[init_code].suffix = (stbi_uc) init_code;
> +   }
> +
> +   // support no starting clear code
> +   avail = clear+2;
> +   oldcode = -1;
> +
> +   len = 0;
> +   for(;;) {
> +      if (valid_bits < codesize) {
> +         if (len == 0) {
> +            len = stbi__get8(s); // start new block
> +            if (len == 0)
> +               return g->out;
> +         }
> +         --len;
> +         bits |= (stbi__int32) stbi__get8(s) << valid_bits;
> +         valid_bits += 8;
> +      } else {
> +         stbi__int32 code = bits & codemask;
> +         bits >>= codesize;
> +         valid_bits -= codesize;
> +         // @OPTIMIZE: is there some way we can accelerate the non-clear path?
> +         if (code == clear) {  // clear code
> +            codesize = lzw_cs + 1;
> +            codemask = (1 << codesize) - 1;
> +            avail = clear + 2;
> +            oldcode = -1;
> +            first = 0;
> +         } else if (code == clear + 1) { // end of stream code
> +            stbi__skip(s, len);
> +            while ((len = stbi__get8(s)) > 0)
> +               stbi__skip(s,len);
> +            return g->out;
> +         } else if (code <= avail) {
> +            if (first) {
> +               return stbi__errpuc("no clear code", "Corrupt GIF");
> +            }
> +
> +            if (oldcode >= 0) {
> +               p = &g->codes[avail++];
> +               if (avail > 8192) {
> +                  return stbi__errpuc("too many codes", "Corrupt GIF");
> +               }
> +
> +               p->prefix = (stbi__int16) oldcode;
> +               p->first = g->codes[oldcode].first;
> +               p->suffix = (code == avail) ? p->first : g->codes[code].first;
> +            } else if (code == avail)
> +               return stbi__errpuc("illegal code in raster", "Corrupt GIF");
> +
> +            stbi__out_gif_code(g, (stbi__uint16) code);
> +
> +            if ((avail & codemask) == 0 && avail <= 0x0FFF) {
> +               codesize++;
> +               codemask = (1 << codesize) - 1;
> +            }
> +
> +            oldcode = code;
> +         } else {
> +            return stbi__errpuc("illegal code in raster", "Corrupt GIF");
> +         }
> +      }
> +   }
> +}
> +
> +// this function is designed to support animated gifs, although stb_image doesn't support it
> +// two back is the image from two frames ago, used for a very specific disposal format
> +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
> +{
> +   int dispose;
> +   int first_frame;
> +   int pi;
> +   int pcount;
> +   STBI_NOTUSED(req_comp);
> +
> +   // on first frame, any non-written pixels get the background colour (non-transparent)
> +   first_frame = 0;
> +   if (g->out == 0) {
> +      if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
> +      if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))
> +         return stbi__errpuc("too large", "GIF image is too large");
> +      pcount = g->w * g->h;
> +      g->out = (stbi_uc *) stbi__malloc(4 * pcount);
> +      g->background = (stbi_uc *) stbi__malloc(4 * pcount);
> +      g->history = (stbi_uc *) stbi__malloc(pcount);
> +      if (!g->out || !g->background || !g->history)
> +         return stbi__errpuc("outofmem", "Out of memory");
> +
> +      // image is treated as "transparent" at the start - ie, nothing overwrites the current background;
> +      // background colour is only used for pixels that are not rendered first frame, after that "background"
> +      // color refers to the color that was there the previous frame.
> +      memset(g->out, 0x00, 4 * pcount);
> +      memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)
> +      memset(g->history, 0x00, pcount);        // pixels that were affected previous frame
> +      first_frame = 1;
> +   } else {
> +      // second frame - how do we dispose of the previous one?
> +      dispose = (g->eflags & 0x1C) >> 2;
> +      pcount = g->w * g->h;
> +
> +      if ((dispose == 3) && (two_back == 0)) {
> +         dispose = 2; // if I don't have an image to revert back to, default to the old background
> +      }
> +
> +      if (dispose == 3) { // use previous graphic
> +         for (pi = 0; pi < pcount; ++pi) {
> +            if (g->history[pi]) {
> +               memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
> +            }
> +         }
> +      } else if (dispose == 2) {
> +         // restore what was changed last frame to background before that frame;
> +         for (pi = 0; pi < pcount; ++pi) {
> +            if (g->history[pi]) {
> +               memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
> +            }
> +         }
> +      } else {
> +         // This is a non-disposal case eithe way, so just
> +         // leave the pixels as is, and they will become the new background
> +         // 1: do not dispose
> +         // 0:  not specified.
> +      }
> +
> +      // background is what out is after the undoing of the previou frame;
> +      memcpy( g->background, g->out, 4 * g->w * g->h );
> +   }
> +
> +   // clear my history;
> +   memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame
> +
> +   for (;;) {
> +      int tag = stbi__get8(s);
> +      switch (tag) {
> +         case 0x2C: /* Image Descriptor */
> +         {
> +            stbi__int32 x, y, w, h;
> +            stbi_uc *o;
> +
> +            x = stbi__get16le(s);
> +            y = stbi__get16le(s);
> +            w = stbi__get16le(s);
> +            h = stbi__get16le(s);
> +            if (((x + w) > (g->w)) || ((y + h) > (g->h)))
> +               return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
> +
> +            g->line_size = g->w * 4;
> +            g->start_x = x * 4;
> +            g->start_y = y * g->line_size;
> +            g->max_x   = g->start_x + w * 4;
> +            g->max_y   = g->start_y + h * g->line_size;
> +            g->cur_x   = g->start_x;
> +            g->cur_y   = g->start_y;
> +
> +            // if the width of the specified rectangle is 0, that means
> +            // we may not see *any* pixels or the image is malformed;
> +            // to make sure this is caught, move the current y down to
> +            // max_y (which is what out_gif_code checks).
> +            if (w == 0)
> +               g->cur_y = g->max_y;
> +
> +            g->lflags = stbi__get8(s);
> +
> +            if (g->lflags & 0x40) {
> +               g->step = 8 * g->line_size; // first interlaced spacing
> +               g->parse = 3;
> +            } else {
> +               g->step = g->line_size;
> +               g->parse = 0;
> +            }
> +
> +            if (g->lflags & 0x80) {
> +               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
> +               g->color_table = (stbi_uc *) g->lpal;
> +            } else if (g->flags & 0x80) {
> +               g->color_table = (stbi_uc *) g->pal;
> +            } else
> +               return stbi__errpuc("missing color table", "Corrupt GIF");
> +
> +            o = stbi__process_gif_raster(s, g);
> +            if (!o) return NULL;
> +
> +            // if this was the first frame,
> +            pcount = g->w * g->h;
> +            if (first_frame && (g->bgindex > 0)) {
> +               // if first frame, any pixel not drawn to gets the background color
> +               for (pi = 0; pi < pcount; ++pi) {
> +                  if (g->history[pi] == 0) {
> +                     g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
> +                     memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
> +                  }
> +               }
> +            }
> +
> +            return o;
> +         }
> +
> +         case 0x21: // Comment Extension.
> +         {
> +            int len;
> +            int ext = stbi__get8(s);
> +            if (ext == 0xF9) { // Graphic Control Extension.
> +               len = stbi__get8(s);
> +               if (len == 4) {
> +                  g->eflags = stbi__get8(s);
> +                  g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
> +
> +                  // unset old transparent
> +                  if (g->transparent >= 0) {
> +                     g->pal[g->transparent][3] = 255;
> +                  }
> +                  if (g->eflags & 0x01) {
> +                     g->transparent = stbi__get8(s);
> +                     if (g->transparent >= 0) {
> +                        g->pal[g->transparent][3] = 0;
> +                     }
> +                  } else {
> +                     // don't need transparent
> +                     stbi__skip(s, 1);
> +                     g->transparent = -1;
> +                  }
> +               } else {
> +                  stbi__skip(s, len);
> +                  break;
> +               }
> +            }
> +            while ((len = stbi__get8(s)) != 0) {
> +               stbi__skip(s, len);
> +            }
> +            break;
> +         }
> +
> +         case 0x3B: // gif stream termination code
> +            return (stbi_uc *) s; // using '1' causes warning on some compilers
> +
> +         default:
> +            return stbi__errpuc("unknown code", "Corrupt GIF");
> +      }
> +   }
> +}
> +
> +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
> +{
> +   if (stbi__gif_test(s)) {
> +      int layers = 0;
> +      stbi_uc *u = 0;
> +      stbi_uc *out = 0;
> +      stbi_uc *two_back = 0;
> +      stbi__gif g;
> +      int stride;
> +      memset(&g, 0, sizeof(g));
> +      if (delays) {
> +         *delays = 0;
> +      }
> +
> +      do {
> +         u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
> +         if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
> +
> +         if (u) {
> +            *x = g.w;
> +            *y = g.h;
> +            ++layers;
> +            stride = g.w * g.h * 4;
> +
> +            if (out) {
> +               void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, 0, layers * stride );
> +               if (NULL == tmp) {
> +                  STBI_FREE(g.out);
> +                  STBI_FREE(g.history);
> +                  STBI_FREE(g.background);
> +                  return stbi__errpuc("outofmem", "Out of memory");
> +               }
> +               else {
> +                   out = (stbi_uc*) tmp;
> +               }
> +
> +               if (delays) {
> +                  *delays = (int*) STBI_REALLOC_SIZED( *delays, 0, sizeof(int) * layers );
> +               }
> +            } else {
> +               out = (stbi_uc*)stbi__malloc( layers * stride );
> +               if (delays) {
> +                  *delays = (int*) stbi__malloc( layers * sizeof(int) );
> +               }
> +            }
> +            memcpy( out + ((layers - 1) * stride), u, stride );
> +            if (layers >= 2) {
> +               two_back = out - 2 * stride;
> +            }
> +
> +            if (delays) {
> +               (*delays)[layers - 1U] = g.delay;
> +            }
> +         }
> +      } while (u != 0);
> +
> +      // free temp buffer;
> +      STBI_FREE(g.out);
> +      STBI_FREE(g.history);
> +      STBI_FREE(g.background);
> +
> +      // do the final conversion after loading everything;
> +      if (req_comp && req_comp != 4)
> +         out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
> +
> +      *z = layers;
> +      return out;
> +   } else {
> +      return stbi__errpuc("not GIF", "Image was not as a gif type.");
> +   }
> +}
> +
> +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
> +{
> +   stbi_uc *u = 0;
> +   stbi__gif g;
> +   memset(&g, 0, sizeof(g));
> +   STBI_NOTUSED(ri);
> +
> +   u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
> +   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
> +   if (u) {
> +      *x = g.w;
> +      *y = g.h;
> +
> +      // moved conversion to after successful load so that the same
> +      // can be done for multiple frames.
> +      if (req_comp && req_comp != 4)
> +         u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
> +   } else if (g.out) {
> +      // if there was an error and we allocated an image buffer, free it!
> +      STBI_FREE(g.out);
> +   }
> +
> +   // free buffers needed for multiple frame loading;
> +   STBI_FREE(g.history);
> +   STBI_FREE(g.background);
> +
> +   return u;
> +}
> +
> +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   return stbi__gif_info_raw(s,x,y,comp);
> +}
> +#endif
> +
> +// *************************************************************************************************
> +// Radiance RGBE HDR loader
> +// originally by Nicolas Schulz
> +#ifndef STBI_NO_HDR
> +static int stbi__hdr_test_core(stbi__context *s, const char *signature)
> +{
> +   int i;
> +   for (i=0; signature[i]; ++i)
> +      if (stbi__get8(s) != signature[i])
> +          return 0;
> +   stbi__rewind(s);
> +   return 1;
> +}
> +
> +static int stbi__hdr_test(stbi__context* s)
> +{
> +   int r = stbi__hdr_test_core(s, "#?RADIANCE\n");
> +   stbi__rewind(s);
> +   if(!r) {
> +       r = stbi__hdr_test_core(s, "#?RGBE\n");
> +       stbi__rewind(s);
> +   }
> +   return r;
> +}
> +
> +#define STBI__HDR_BUFLEN  1024
> +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
> +{
> +   int len=0;
> +   char c = '\0';
> +
> +   c = (char) stbi__get8(z);
> +
> +   while (!stbi__at_eof(z) && c != '\n') {
> +      buffer[len++] = c;
> +      if (len == STBI__HDR_BUFLEN-1) {
> +         // flush to end of line
> +         while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
> +            ;
> +         break;
> +      }
> +      c = (char) stbi__get8(z);
> +   }
> +
> +   buffer[len] = 0;
> +   return buffer;
> +}
> +
> +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
> +{
> +   if ( input[3] != 0 ) {
> +      float f1;
> +      // Exponent
> +      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
> +      if (req_comp <= 2)
> +         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
> +      else {
> +         output[0] = input[0] * f1;
> +         output[1] = input[1] * f1;
> +         output[2] = input[2] * f1;
> +      }
> +      if (req_comp == 2) output[1] = 1;
> +      if (req_comp == 4) output[3] = 1;
> +   } else {
> +      switch (req_comp) {
> +         case 4: output[3] = 1; /* fallthrough */
> +         case 3: output[0] = output[1] = output[2] = 0;
> +                 break;
> +         case 2: output[1] = 1; /* fallthrough */
> +         case 1: output[0] = 0;
> +                 break;
> +      }
> +   }
> +}
> +
> +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
> +{
> +   char buffer[STBI__HDR_BUFLEN];
> +   char *token;
> +   int valid = 0;
> +   int width, height;
> +   stbi_uc *scanline;
> +   float *hdr_data;
> +   int len;
> +   unsigned char count, value;
> +   int i, j, k, c1,c2, z;
> +   const char *headerToken;
> +   STBI_NOTUSED(ri);
> +
> +   // Check identifier
> +   headerToken = stbi__hdr_gettoken(s,buffer);
> +   if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0)
> +      return stbi__errpf("not HDR", "Corrupt HDR image");
> +
> +   // Parse header
> +   for(;;) {
> +      token = stbi__hdr_gettoken(s,buffer);
> +      if (token[0] == 0) break;
> +      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
> +   }
> +
> +   if (!valid)    return stbi__errpf("unsupported format", "Unsupported HDR format");
> +
> +   // Parse width and height
> +   // can't use sscanf() if we're not using stdio!
> +   token = stbi__hdr_gettoken(s,buffer);
> +   if (strncmp(token, "-Y ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
> +   token += 3;
> +   height = (int) strtol(token, &token, 10);
> +   while (*token == ' ') ++token;
> +   if (strncmp(token, "+X ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
> +   token += 3;
> +   width = (int) strtol(token, NULL, 10);
> +
> +   if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
> +   if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
> +
> +   *x = width;
> +   *y = height;
> +
> +   if (comp) *comp = 3;
> +   if (req_comp == 0) req_comp = 3;
> +
> +   if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))
> +      return stbi__errpf("too large", "HDR image is too large");
> +
> +   // Read data
> +   hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
> +   if (!hdr_data)
> +      return stbi__errpf("outofmem", "Out of memory");
> +
> +   // Load image data
> +   // image data is stored as some number of sca
> +   if ( width < 8 || width >= 32768) {
> +      // Read flat data
> +      for (j=0; j < height; ++j) {
> +         for (i=0; i < width; ++i) {
> +            stbi_uc rgbe[4];
> +           main_decode_loop:
> +            stbi__getn(s, rgbe, 4);
> +            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
> +         }
> +      }
> +   } else {
> +      // Read RLE-encoded data
> +      scanline = NULL;
> +
> +      for (j = 0; j < height; ++j) {
> +         c1 = stbi__get8(s);
> +         c2 = stbi__get8(s);
> +         len = stbi__get8(s);
> +         if (c1 != 2 || c2 != 2 || (len & 0x80)) {
> +            // not run-length encoded, so we have to actually use THIS data as a decoded
> +            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
> +            stbi_uc rgbe[4];
> +            rgbe[0] = (stbi_uc) c1;
> +            rgbe[1] = (stbi_uc) c2;
> +            rgbe[2] = (stbi_uc) len;
> +            rgbe[3] = (stbi_uc) stbi__get8(s);
> +            stbi__hdr_convert(hdr_data, rgbe, req_comp);
> +            i = 1;
> +            j = 0;
> +            STBI_FREE(scanline);
> +            goto main_decode_loop; // yes, this makes no sense
> +         }
> +         len <<= 8;
> +         len |= stbi__get8(s);
> +         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
> +         if (scanline == NULL) {
> +            scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
> +            if (!scanline) {
> +               STBI_FREE(hdr_data);
> +               return stbi__errpf("outofmem", "Out of memory");
> +            }
> +         }
> +
> +         for (k = 0; k < 4; ++k) {
> +            int nleft;
> +            i = 0;
> +            while ((nleft = width - i) > 0) {
> +               count = stbi__get8(s);
> +               if (count > 128) {
> +                  // Run
> +                  value = stbi__get8(s);
> +                  count -= 128;
> +                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
> +                  for (z = 0; z < count; ++z)
> +                     scanline[i++ * 4 + k] = value;
> +               } else {
> +                  // Dump
> +                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
> +                  for (z = 0; z < count; ++z)
> +                     scanline[i++ * 4 + k] = stbi__get8(s);
> +               }
> +            }
> +         }
> +         for (i=0; i < width; ++i)
> +            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
> +      }
> +      if (scanline)
> +         STBI_FREE(scanline);
> +   }
> +
> +   return hdr_data;
> +}
> +
> +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   char buffer[STBI__HDR_BUFLEN];
> +   char *token;
> +   int valid = 0;
> +   int dummy;
> +
> +   if (!x) x = &dummy;
> +   if (!y) y = &dummy;
> +   if (!comp) comp = &dummy;
> +
> +   if (stbi__hdr_test(s) == 0) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +
> +   for(;;) {
> +      token = stbi__hdr_gettoken(s,buffer);
> +      if (token[0] == 0) break;
> +      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
> +   }
> +
> +   if (!valid) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   token = stbi__hdr_gettoken(s,buffer);
> +   if (strncmp(token, "-Y ", 3)) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   token += 3;
> +   *y = (int) strtol(token, &token, 10);
> +   while (*token == ' ') ++token;
> +   if (strncmp(token, "+X ", 3)) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   token += 3;
> +   *x = (int) strtol(token, NULL, 10);
> +   *comp = 3;
> +   return 1;
> +}
> +#endif // STBI_NO_HDR
> +
> +#ifndef STBI_NO_BMP
> +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   void *p;
> +   stbi__bmp_data info;
> +
> +   info.all_a = 255;
> +   p = stbi__bmp_parse_header(s, &info);
> +   stbi__rewind( s );
> +   if (p == NULL)
> +      return 0;
> +   if (x) *x = s->img_x;
> +   if (y) *y = s->img_y;
> +   if (comp) {
> +      if (info.bpp == 24 && info.ma == 0xff000000)
> +         *comp = 3;
> +      else
> +         *comp = info.ma ? 4 : 3;
> +   }
> +   return 1;
> +}
> +#endif
> +
> +#ifndef STBI_NO_PSD
> +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   int channelCount, dummy, depth;
> +   if (!x) x = &dummy;
> +   if (!y) y = &dummy;
> +   if (!comp) comp = &dummy;
> +   if (stbi__get32be(s) != 0x38425053) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   if (stbi__get16be(s) != 1) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   stbi__skip(s, 6);
> +   channelCount = stbi__get16be(s);
> +   if (channelCount < 0 || channelCount > 16) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   *y = stbi__get32be(s);
> +   *x = stbi__get32be(s);
> +   depth = stbi__get16be(s);
> +   if (depth != 8 && depth != 16) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   if (stbi__get16be(s) != 3) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   *comp = 4;
> +   return 1;
> +}
> +
> +static int stbi__psd_is16(stbi__context *s)
> +{
> +   int channelCount, depth;
> +   if (stbi__get32be(s) != 0x38425053) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   if (stbi__get16be(s) != 1) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   stbi__skip(s, 6);
> +   channelCount = stbi__get16be(s);
> +   if (channelCount < 0 || channelCount > 16) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   (void) stbi__get32be(s);
> +   (void) stbi__get32be(s);
> +   depth = stbi__get16be(s);
> +   if (depth != 16) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   return 1;
> +}
> +#endif
> +
> +#ifndef STBI_NO_PIC
> +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   int act_comp=0,num_packets=0,chained,dummy;
> +   stbi__pic_packet packets[10];
> +
> +   if (!x) x = &dummy;
> +   if (!y) y = &dummy;
> +   if (!comp) comp = &dummy;
> +
> +   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
> +      stbi__rewind(s);
> +      return 0;
> +   }
> +
> +   stbi__skip(s, 88);
> +
> +   *x = stbi__get16be(s);
> +   *y = stbi__get16be(s);
> +   if (stbi__at_eof(s)) {
> +      stbi__rewind( s);
> +      return 0;
> +   }
> +   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
> +      stbi__rewind( s );
> +      return 0;
> +   }
> +
> +   stbi__skip(s, 8);
> +
> +   do {
> +      stbi__pic_packet *packet;
> +
> +      if (num_packets==sizeof(packets)/sizeof(packets[0]))
> +         return 0;
> +
> +      packet = &packets[num_packets++];
> +      chained = stbi__get8(s);
> +      packet->size    = stbi__get8(s);
> +      packet->type    = stbi__get8(s);
> +      packet->channel = stbi__get8(s);
> +      act_comp |= packet->channel;
> +
> +      if (stbi__at_eof(s)) {
> +          stbi__rewind( s );
> +          return 0;
> +      }
> +      if (packet->size != 8) {
> +          stbi__rewind( s );
> +          return 0;
> +      }
> +   } while (chained);
> +
> +   *comp = (act_comp & 0x10 ? 4 : 3);
> +
> +   return 1;
> +}
> +#endif
> +
> +// *************************************************************************************************
> +// Portable Gray Map and Portable Pixel Map loader
> +// by Ken Miller
> +//
> +// PGM: http://netpbm.sourceforge.net/doc/pgm.html
> +// PPM: http://netpbm.sourceforge.net/doc/ppm.html
> +//
> +// Known limitations:
> +//    Does not support comments in the header section
> +//    Does not support ASCII image data (formats P2 and P3)
> +//    Does not support 16-bit-per-channel
> +
> +#ifndef STBI_NO_PNM
> +
> +static int      stbi__pnm_test(stbi__context *s)
> +{
> +   char p, t;
> +   p = (char) stbi__get8(s);
> +   t = (char) stbi__get8(s);
> +   if (p != 'P' || (t != '5' && t != '6')) {
> +       stbi__rewind( s );
> +       return 0;
> +   }
> +   return 1;
> +}
> +
> +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
> +{
> +   stbi_uc *out;
> +   STBI_NOTUSED(ri);
> +
> +   if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
> +      return 0;
> +
> +   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
> +
> +   *x = s->img_x;
> +   *y = s->img_y;
> +   if (comp) *comp = s->img_n;
> +
> +   if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
> +      return stbi__errpuc("too large", "PNM too large");
> +
> +   out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
> +   if (!out) return stbi__errpuc("outofmem", "Out of memory");
> +   stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
> +
> +   if (req_comp && req_comp != s->img_n) {
> +      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
> +      if (out == NULL) return out; // stbi__convert_format frees input on failure
> +   }
> +   return out;
> +}
> +
> +static int      stbi__pnm_isspace(char c)
> +{
> +   return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
> +}
> +
> +static void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)
> +{
> +   for (;;) {
> +      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
> +         *c = (char) stbi__get8(s);
> +
> +      if (stbi__at_eof(s) || *c != '#')
> +         break;
> +
> +      while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
> +         *c = (char) stbi__get8(s);
> +   }
> +}
> +
> +static int      stbi__pnm_isdigit(char c)
> +{
> +   return c >= '0' && c <= '9';
> +}
> +
> +static int      stbi__pnm_getinteger(stbi__context *s, char *c)
> +{
> +   int value = 0;
> +
> +   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
> +      value = value*10 + (*c - '0');
> +      *c = (char) stbi__get8(s);
> +   }
> +
> +   return value;
> +}
> +
> +static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   int maxv, dummy;
> +   char c, p, t;
> +
> +   if (!x) x = &dummy;
> +   if (!y) y = &dummy;
> +   if (!comp) comp = &dummy;
> +
> +   stbi__rewind(s);
> +
> +   // Get identifier
> +   p = (char) stbi__get8(s);
> +   t = (char) stbi__get8(s);
> +   if (p != 'P' || (t != '5' && t != '6')) {
> +       stbi__rewind(s);
> +       return 0;
> +   }
> +
> +   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm
> +
> +   c = (char) stbi__get8(s);
> +   stbi__pnm_skip_whitespace(s, &c);
> +
> +   *x = stbi__pnm_getinteger(s, &c); // read width
> +   stbi__pnm_skip_whitespace(s, &c);
> +
> +   *y = stbi__pnm_getinteger(s, &c); // read height
> +   stbi__pnm_skip_whitespace(s, &c);
> +
> +   maxv = stbi__pnm_getinteger(s, &c);  // read max value
> +
> +   if (maxv > 255)
> +      return stbi__err("max value > 255", "PPM image not 8-bit");
> +   else
> +      return 1;
> +}
> +#endif
> +
> +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
> +{
> +   #ifndef STBI_NO_JPEG
> +   if (stbi__jpeg_info(s, x, y, comp)) return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_PNG
> +   if (stbi__png_info(s, x, y, comp))  return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_GIF
> +   if (stbi__gif_info(s, x, y, comp))  return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_BMP
> +   if (stbi__bmp_info(s, x, y, comp))  return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_PSD
> +   if (stbi__psd_info(s, x, y, comp))  return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_PIC
> +   if (stbi__pic_info(s, x, y, comp))  return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_PNM
> +   if (stbi__pnm_info(s, x, y, comp))  return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_HDR
> +   if (stbi__hdr_info(s, x, y, comp))  return 1;
> +   #endif
> +
> +   // test tga last because it's a crappy test!
> +   #ifndef STBI_NO_TGA
> +   if (stbi__tga_info(s, x, y, comp))
> +       return 1;
> +   #endif
> +   return stbi__err("unknown image type", "Image not of any known type, or corrupt");
> +}
> +
> +static int stbi__is_16_main(stbi__context *s)
> +{
> +   #ifndef STBI_NO_PNG
> +   if (stbi__png_is16(s))  return 1;
> +   #endif
> +
> +   #ifndef STBI_NO_PSD
> +   if (stbi__psd_is16(s))  return 1;
> +   #endif
> +
> +   return 0;
> +}
> +
> +#ifndef STBI_NO_STDIO
> +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
> +{
> +    FILE *f = stbi__fopen(filename, "rb");
> +    int result;
> +    if (!f) return stbi__err("can't fopen", "Unable to open file");
> +    result = stbi_info_from_file(f, x, y, comp);
> +    fclose(f);
> +    return result;
> +}
> +
> +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
> +{
> +   int r;
> +   stbi__context s;
> +   long pos = ftell(f);
> +   stbi__start_file(&s, f);
> +   r = stbi__info_main(&s,x,y,comp);
> +   fseek(f,pos,SEEK_SET);
> +   return r;
> +}
> +
> +STBIDEF int stbi_is_16_bit(char const *filename)
> +{
> +    FILE *f = stbi__fopen(filename, "rb");
> +    int result;
> +    if (!f) return stbi__err("can't fopen", "Unable to open file");
> +    result = stbi_is_16_bit_from_file(f);
> +    fclose(f);
> +    return result;
> +}
> +
> +STBIDEF int stbi_is_16_bit_from_file(FILE *f)
> +{
> +   int r;
> +   stbi__context s;
> +   long pos = ftell(f);
> +   stbi__start_file(&s, f);
> +   r = stbi__is_16_main(&s);
> +   fseek(f,pos,SEEK_SET);
> +   return r;
> +}
> +#endif // !STBI_NO_STDIO
> +
> +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
> +{
> +   stbi__context s;
> +   stbi__start_mem(&s,buffer,len);
> +   return stbi__info_main(&s,x,y,comp);
> +}
> +
> +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
> +{
> +   stbi__context s;
> +   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
> +   return stbi__info_main(&s,x,y,comp);
> +}
> +
> +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
> +{
> +   stbi__context s;
> +   stbi__start_mem(&s,buffer,len);
> +   return stbi__is_16_main(&s);
> +}
> +
> +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
> +{
> +   stbi__context s;
> +   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
> +   return stbi__is_16_main(&s);
> +}
> +
> +#endif // STB_IMAGE_IMPLEMENTATION
> +
> +/*
> +   revision history:
> +      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
> +      2.19  (2018-02-11) fix warning
> +      2.18  (2018-01-30) fix warnings
> +      2.17  (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
> +                         1-bit BMP
> +                         *_is_16_bit api
> +                         avoid warnings
> +      2.16  (2017-07-23) all functions have 16-bit variants;
> +                         STBI_NO_STDIO works again;
> +                         compilation fixes;
> +                         fix rounding in unpremultiply;
> +                         optimize vertical flip;
> +                         disable raw_len validation;
> +                         documentation fixes
> +      2.15  (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
> +                         warning fixes; disable run-time SSE detection on gcc;
> +                         uniform handling of optional "return" values;
> +                         thread-safe initialization of zlib tables
> +      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
> +      2.13  (2016-11-29) add 16-bit API, only supported for PNG right now
> +      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
> +      2.11  (2016-04-02) allocate large structures on the stack
> +                         remove white matting for transparent PSD
> +                         fix reported channel count for PNG & BMP
> +                         re-enable SSE2 in non-gcc 64-bit
> +                         support RGB-formatted JPEG
> +                         read 16-bit PNGs (only as 8-bit)
> +      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
> +      2.09  (2016-01-16) allow comments in PNM files
> +                         16-bit-per-pixel TGA (not bit-per-component)
> +                         info() for TGA could break due to .hdr handling
> +                         info() for BMP to shares code instead of sloppy parse
> +                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc
> +                         code cleanup
> +      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
> +      2.07  (2015-09-13) fix compiler warnings
> +                         partial animated GIF support
> +                         limited 16-bpc PSD support
> +                         #ifdef unused functions
> +                         bug with < 92 byte PIC,PNM,HDR,TGA
> +      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value
> +      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning
> +      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit
> +      2.03  (2015-04-12) extra corruption checking (mmozeiko)
> +                         stbi_set_flip_vertically_on_load (nguillemot)
> +                         fix NEON support; fix mingw support
> +      2.02  (2015-01-19) fix incorrect assert, fix warning
> +      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
> +      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
> +      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
> +                         progressive JPEG (stb)
> +                         PGM/PPM support (Ken Miller)
> +                         STBI_MALLOC,STBI_REALLOC,STBI_FREE
> +                         GIF bugfix -- seemingly never worked
> +                         STBI_NO_*, STBI_ONLY_*
> +      1.48  (2014-12-14) fix incorrectly-named assert()
> +      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
> +                         optimize PNG (ryg)
> +                         fix bug in interlaced PNG with user-specified channel count (stb)
> +      1.46  (2014-08-26)
> +              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
> +      1.45  (2014-08-16)
> +              fix MSVC-ARM internal compiler error by wrapping malloc
> +      1.44  (2014-08-07)
> +              various warning fixes from Ronny Chevalier
> +      1.43  (2014-07-15)
> +              fix MSVC-only compiler problem in code changed in 1.42
> +      1.42  (2014-07-09)
> +              don't define _CRT_SECURE_NO_WARNINGS (affects user code)
> +              fixes to stbi__cleanup_jpeg path
> +              added STBI_ASSERT to avoid requiring assert.h
> +      1.41  (2014-06-25)
> +              fix search&replace from 1.36 that messed up comments/error messages
> +      1.40  (2014-06-22)
> +              fix gcc struct-initialization warning
> +      1.39  (2014-06-15)
> +              fix to TGA optimization when req_comp != number of components in TGA;
> +              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
> +              add support for BMP version 5 (more ignored fields)
> +      1.38  (2014-06-06)
> +              suppress MSVC warnings on integer casts truncating values
> +              fix accidental rename of 'skip' field of I/O
> +      1.37  (2014-06-04)
> +              remove duplicate typedef
> +      1.36  (2014-06-03)
> +              convert to header file single-file library
> +              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
> +      1.35  (2014-05-27)
> +              various warnings
> +              fix broken STBI_SIMD path
> +              fix bug where stbi_load_from_file no longer left file pointer in correct place
> +              fix broken non-easy path for 32-bit BMP (possibly never used)
> +              TGA optimization by Arseny Kapoulkine
> +      1.34  (unknown)
> +              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
> +      1.33  (2011-07-14)
> +              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
> +      1.32  (2011-07-13)
> +              support for "info" function for all supported filetypes (SpartanJ)
> +      1.31  (2011-06-20)
> +              a few more leak fixes, bug in PNG handling (SpartanJ)
> +      1.30  (2011-06-11)
> +              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
> +              removed deprecated format-specific test/load functions
> +              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
> +              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
> +              fix inefficiency in decoding 32-bit BMP (David Woo)
> +      1.29  (2010-08-16)
> +              various warning fixes from Aurelien Pocheville
> +      1.28  (2010-08-01)
> +              fix bug in GIF palette transparency (SpartanJ)
> +      1.27  (2010-08-01)
> +              cast-to-stbi_uc to fix warnings
> +      1.26  (2010-07-24)
> +              fix bug in file buffering for PNG reported by SpartanJ
> +      1.25  (2010-07-17)
> +              refix trans_data warning (Won Chun)
> +      1.24  (2010-07-12)
> +              perf improvements reading from files on platforms with lock-heavy fgetc()
> +              minor perf improvements for jpeg
> +              deprecated type-specific functions so we'll get feedback if they're needed
> +              attempt to fix trans_data warning (Won Chun)
> +      1.23    fixed bug in iPhone support
> +      1.22  (2010-07-10)
> +              removed image *writing* support
> +              stbi_info support from Jetro Lauha
> +              GIF support from Jean-Marc Lienher
> +              iPhone PNG-extensions from James Brown
> +              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
> +      1.21    fix use of 'stbi_uc' in header (reported by jon blow)
> +      1.20    added support for Softimage PIC, by Tom Seddon
> +      1.19    bug in interlaced PNG corruption check (found by ryg)
> +      1.18  (2008-08-02)
> +              fix a threading bug (local mutable static)
> +      1.17    support interlaced PNG
> +      1.16    major bugfix - stbi__convert_format converted one too many pixels
> +      1.15    initialize some fields for thread safety
> +      1.14    fix threadsafe conversion bug
> +              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
> +      1.13    threadsafe
> +      1.12    const qualifiers in the API
> +      1.11    Support installable IDCT, colorspace conversion routines
> +      1.10    Fixes for 64-bit (don't use "unsigned long")
> +              optimized upsampling by Fabian "ryg" Giesen
> +      1.09    Fix format-conversion for PSD code (bad global variables!)
> +      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz
> +      1.07    attempt to fix C++ warning/errors again
> +      1.06    attempt to fix C++ warning/errors again
> +      1.05    fix TGA loading to return correct *comp and use good luminance calc
> +      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free
> +      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR
> +      1.02    support for (subset of) HDR files, float interface for preferred access to them
> +      1.01    fix bug: possible bug in handling right-side up bmps... not sure
> +              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
> +      1.00    interface to zlib that skips zlib header
> +      0.99    correct handling of alpha in palette
> +      0.98    TGA loader by lonesock; dynamically add loaders (untested)
> +      0.97    jpeg errors on too large a file; also catch another malloc failure
> +      0.96    fix detection of invalid v value - particleman at mollyrocket forum
> +      0.95    during header scan, seek to markers in case of padding
> +      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same
> +      0.93    handle jpegtran output; verbose errors
> +      0.92    read 4,8,16,24,32-bit BMP files of several formats
> +      0.91    output 24-bit Windows 3.0 BMP files
> +      0.90    fix a few more warnings; bump version number to approach 1.0
> +      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd
> +      0.60    fix compiling as c++
> +      0.59    fix warnings: merge Dave Moore's -Wall fixes
> +      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian
> +      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
> +      0.56    fix bug: zlib uncompressed mode len vs. nlen
> +      0.55    fix bug: restart_interval not initialized to 0
> +      0.54    allow NULL for 'int *comp'
> +      0.53    fix bug in png 3->4; speedup png decoding
> +      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments
> +      0.51    obey req_comp requests, 1-component jpegs return as 1-component,
> +              on 'test' only check type, not whether we support this variant
> +      0.50  (2006-11-19)
> +              first released version
> +*/
> +
> +
> +/*
> +------------------------------------------------------------------------------
> +This software is available under 2 licenses -- choose whichever you prefer.
> +------------------------------------------------------------------------------
> +ALTERNATIVE A - MIT License
> +Copyright (c) 2017 Sean Barrett
> +Permission is hereby granted, free of charge, to any person obtaining a copy of
> +this software and associated documentation files (the "Software"), to deal in
> +the Software without restriction, including without limitation the rights to
> +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
> +of the Software, and to permit persons to whom the Software is furnished to do
> +so, subject to the following conditions:
> +The above copyright notice and this permission notice shall be included in all
> +copies or substantial portions of the Software.
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> +SOFTWARE.
> +------------------------------------------------------------------------------
> +ALTERNATIVE B - Public Domain (www.unlicense.org)
> +This is free and unencumbered software released into the public domain.
> +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
> +software, either in source code form or as a compiled binary, for any purpose,
> +commercial or non-commercial, and by any means.
> +In jurisdictions that recognize copyright laws, the author or authors of this
> +software dedicate any and all copyright interest in the software to the public
> +domain. We make this dedication for the benefit of the public at large and to
> +the detriment of our heirs and successors. We intend this dedication to be an
> +overt act of relinquishment in perpetuity of all present and future rights to
> +this software under copyright law.
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
> +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> +------------------------------------------------------------------------------
> +*/
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 02:36:02 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 11:36:02 +0100
Subject: [PATCH v2] i2c: add Rockchip i2c controller support
In-Reply-To: <20220114085425.315113-1-a.fatoum@pengutronix.de>
References: <20220114085425.315113-1-a.fatoum@pengutronix.de>
Message-ID: <20220114103602.GY26619@pengutronix.de>

On Fri, Jan 14, 2022 at 09:54:25AM +0100, Ahmad Fatoum wrote:
> For addressing the PMIC on Rockchip platforms, add an i2c controller
> driver. Tested with rk3399 and rk808.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> v1 -> v2:
>   - remove unneeded udelay(1)s (Sascha)
>   - use readl_poll_timeout
>   - fix typos, copy-paste leftovers (Sascha)
>   - early exit on NAK (Sascha)
> ---
>  drivers/i2c/busses/Kconfig        |   8 +
>  drivers/i2c/busses/Makefile       |   1 +
>  drivers/i2c/busses/i2c-rockchip.c | 458 ++++++++++++++++++++++++++++++
>  3 files changed, 467 insertions(+)
>  create mode 100644 drivers/i2c/busses/i2c-rockchip.c

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Fri Jan 14 02:39:02 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Jan 2022 11:39:02 +0100
Subject: [PATCH v1 2/2] ARM: rpi: set uart0-pl0110 clk to 48MHz
In-Reply-To: <20220114101246.GA21557@pengutronix.de>
References: <20220114082141.302151-1-o.rempel@pengutronix.de>
 <20220114082141.302151-2-o.rempel@pengutronix.de>
 <20220114083018.GS26619@pengutronix.de>
 <20220114101246.GA21557@pengutronix.de>
Message-ID: <20220114103902.GZ26619@pengutronix.de>

On Fri, Jan 14, 2022 at 11:12:46AM +0100, Oleksij Rempel wrote:
> On Fri, Jan 14, 2022 at 09:30:18AM +0100, Sascha Hauer wrote:
> > On Fri, Jan 14, 2022 at 09:21:41AM +0100, Oleksij Rempel wrote:
> > > At least on RPi2 this clock is 48MHz. This issue was not visible,
> > > becouse amba-pl011 driver was not reseting UART controller after
> > > changing baudrate. So, clk settings was not updated for some time.
> > 
> > We have an rpi3 and rpi4 in our lab. Could you give this a test on these
> > boards?
> 
> Yes, rpi3 is tested and rpi4 is currently not supported.

Fine. Ok then, applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From enrico.scholz at sigma-chemnitz.de  Fri Jan 14 02:52:35 2022
From: enrico.scholz at sigma-chemnitz.de (Enrico Scholz)
Date: Fri, 14 Jan 2022 11:52:35 +0100
Subject: [PATCH] usb:chipidea-imx: honor "phys" dtree property
Message-ID: <20220114105235.2580174-1-enrico.scholz@sigma-chemnitz.de>

Recent kernel devicetrees changed the "fsl,usbphy" property name to
"phys" on some platforms (e.g. iMX8) but the old one was kept on other
platforms (e.g. iMX6).

Check them both in the usb driver by preferring "phys".

NOTE: this fixes a hard lockup when booting NXP linux kernels on iMX8.

Signed-off-by: Enrico Scholz <enrico.scholz at sigma-chemnitz.de>
---
 drivers/usb/imx/chipidea-imx.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index f81477885884..bf8b6f1eb88a 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -218,6 +218,7 @@ static int imx_chipidea_probe(struct device_d *dev)
 	struct resource *iores;
 	struct imx_chipidea_data *imx_data;
 	struct imxusb_platformdata *pdata = dev->platform_data;
+	char const *phynode_name;
 	int ret;
 	void __iomem *base;
 	struct imx_chipidea *ci;
@@ -262,8 +263,19 @@ static int imx_chipidea_probe(struct device_d *dev)
 	if (!IS_ERR(ci->clk))
 		clk_enable(ci->clk);
 
-	if (of_property_read_bool(dev->device_node, "fsl,usbphy")) {
-		ci->phy = of_phy_get_by_phandle(dev, "fsl,usbphy", 0);
+	/* Device trees are using both "phys" and "fsl,usbphy".  Prefer the
+	 * more modern former one but fall back to the old one.
+	 *
+	 * Code should be removed when all devicetrees are using "phys" */
+	if (of_property_read_bool(dev->device_node, "phys"))
+		phynode_name = "phys";
+	else if (of_property_read_bool(dev->device_node, "fsl,usbphy"))
+		phynode_name = "fsl,usbphy";
+	else
+		phynode_name = NULL;
+
+	if (phynode_name) {
+		ci->phy = of_phy_get_by_phandle(dev, phynode_name, 0);
 		if (IS_ERR(ci->phy)) {
 			dev_err(dev, "Cannot get phy: %pe\n", ci->phy);
 			return PTR_ERR(ci->phy);
-- 
2.33.1



From jmaselbas at kalray.eu  Fri Jan 14 02:54:51 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 11:54:51 +0100
Subject: [PATCH 2/5] gui: Add qoi image format
In-Reply-To: <0ca90254-a1d1-7151-0236-4dd92ee4d620@pengutronix.de>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
 <20220110221255.5003-3-jmaselbas@kalray.eu>
 <0ca90254-a1d1-7151-0236-4dd92ee4d620@pengutronix.de>
Message-ID: <20220114105451.GA29876@tellis.lin.mbt.kalray.eu>

On Fri, Jan 14, 2022 at 11:05:15AM +0100, Ahmad Fatoum wrote:
> On 10.01.22 23:12, Jules Maselbas wrote:
> 
> Could you add a link there the project is from, what version
> you're importing. Perhaps how to update them in the future?
> (Do we touch the header, or is it just some macros we define
> outside).
ok, I'll amend the commit message with the following information:
The project home page can be found at https://qoiformat.org with
a single header file reference implementation of encoder/decoder
that is currently hosted at https://github.com/phoboslab/qoi.
There is no plan for future version, this is a frozen format.

> > diff --git a/lib/gui/qoi.c b/lib/gui/qoi.c
> > new file mode 100644
> > index 0000000000..f6c1bc1b94
> > --- /dev/null
> > +++ b/lib/gui/qoi.c
> 
> License statement missing.
ok

> > +
> > +	pr_debug("qoi: %d x %d  x %d data at 0x%p\n", img->width, img->height,
> > +		 img->bits_per_pixel, img->data);
> 
> Nitpick: You can define a common prefix
> with pr_fmt at the top of the file, e.g
> 
> #define pr_fmt(fmt) "qoi: " fmt
sure will do

> > +	return img;
> > +}
> > +
> > +static void qoi_close(struct image *img)
> > +{
> > +	free(img->data);
> 
> Curious API that open() is allocating, but close's caller is
> the one resposible for freeing. Should probably be fixed up.
> 
> > +static struct image_renderer qoi = {
> > +	.type = filetype_qoi,
> > +	.open = qoi_open,
> > +	.close = qoi_close,
> > +	.renderer = qoi_renderer,
> > +	.keep_file_data = 1,
> 
> Do you really need this? For bmp, it makes sense, because the pixel data isn't
> compressed, so there are direct pointers into it. But if you uncompress into a
> newly allocated buffer, you should not need to keep (and leak) inbuf's content
> 
You're right, I haven't look at what .keep_file_data was for and, it is
indeed not needed.

> > +};
> > +
> > +static int qoi_init(void)
> > +{
> > +	return image_renderer_register(&qoi);
> > +}
> > +fs_initcall(qoi_init);
> > diff --git a/lib/gui/qoi.h b/lib/gui/qoi.h
> > new file mode 100644
> > index 0000000000..988f9edcb4
> > --- /dev/null
> > +++ b/lib/gui/qoi.h
> > @@ -0,0 +1,671 @@
> > +/*
> > +
> > +QOI - The "Quite OK Image" format for fast, lossless image compression
> > +
> > +Dominic Szablewski - https://phoboslab.org
> > +
> > +
> > +-- LICENSE: The MIT License(MIT)
> 
> Can you turn this into a SPDX-License-Identifier: please?
ok

> > +
> > +Copyright(c) 2021 Dominic Szablewski
> > +
> > +Permission is hereby granted, free of charge, to any person obtaining a copy of
> > +this software and associated documentation files(the "Software"), to deal in
> > +the Software without restriction, including without limitation the rights to
> > +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
> > +of the Software, and to permit persons to whom the Software is furnished to do
> > +so, subject to the following conditions :
> > +The above copyright notice and this permission notice shall be included in all
> > +copies or substantial portions of the Software.
> > +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
> > +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> > +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> > +SOFTWARE.
> > +






From jmaselbas at kalray.eu  Fri Jan 14 03:14:04 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 12:14:04 +0100
Subject: [PATCH 3/5] scripts: Add qoiconv to convert png to qoi
In-Reply-To: <ec782b1e-ffed-3f01-71a7-f28c161d802d@pengutronix.de>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
 <20220110221255.5003-4-jmaselbas@kalray.eu>
 <ec782b1e-ffed-3f01-71a7-f28c161d802d@pengutronix.de>
Message-ID: <20220114111404.GB29876@tellis.lin.mbt.kalray.eu>

On Fri, Jan 14, 2022 at 11:29:58AM +0100, Ahmad Fatoum wrote:
> On 10.01.22 23:12, Jules Maselbas wrote:
> > ImageMagick will eventually support the qoi image format, in the
> > mean time add a png to qoi conversion program.
> > 
> > Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> > ---
> >  scripts/Kconfig     |    5 +
> >  scripts/Makefile    |    1 +
> >  scripts/qoiconv.c   |   91 +
> >  scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 7853 insertions(+)
> >  create mode 100644 scripts/qoiconv.c
> >  create mode 100644 scripts/stb_image.h
> > 
> > diff --git a/scripts/Kconfig b/scripts/Kconfig
> > index 9b744deba9..747f665e02 100644
> > --- a/scripts/Kconfig
> > +++ b/scripts/Kconfig
> > @@ -110,6 +110,11 @@ config RK_USB_LOADER
> >  
> >  	  You need libusb-1.0 to compile this tool.
> >  
> > +config QOICONV
> > +	bool "QOI image format conversion" if COMPILE_HOST_TOOLS
> > +	help
> > +	  This enable converting png to qoi images to generate boot logo.
> > +
> >  endmenu
> >  
> >  menu "Target Tools"
> > diff --git a/scripts/Makefile b/scripts/Makefile
> > index dc5fa75f90..cbaf2d55ff 100644
> > --- a/scripts/Makefile
> > +++ b/scripts/Makefile
> > @@ -8,6 +8,7 @@ hostprogs-always-y					+= fix_size
> >  hostprogs-always-y					+= bareboxenv
> >  hostprogs-always-y					+= bareboxcrc32
> >  hostprogs-always-y					+= kernel-install
> > +hostprogs-always-$(CONFIG_QOICONV)			+= qoiconv
> >  hostprogs-always-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS)	+= rsatoc
> >  HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl`
> >  HOSTLDLIBS_rsatoc = `pkg-config --libs openssl`
> > diff --git a/scripts/qoiconv.c b/scripts/qoiconv.c
> > new file mode 100644
> > index 0000000000..010c70ead0
> > --- /dev/null
> > +++ b/scripts/qoiconv.c
> > @@ -0,0 +1,91 @@
Probably missing SPDX identifiers as well

> > +/*
> > +
> > +Command line tool to convert between png <> qoi format
> > +
> > +Requires "stb_image.h" and "stb_image_write.h"
> > +Compile with: 
> > +	gcc qoiconv.c -std=c99 -O3 -o qoiconv
> > +
> > +Dominic Szablewski - https://phoboslab.org
> > +
> > +
> > +-- LICENSE: The MIT License(MIT)
> > +
> > +Copyright(c) 2021 Dominic Szablewski
> > +
> > +Permission is hereby granted, free of charge, to any person obtaining a copy of
> > +this software and associated documentation files(the "Software"), to deal in
> > +the Software without restriction, including without limitation the rights to
> > +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
> > +of the Software, and to permit persons to whom the Software is furnished to do
> > +so, subject to the following conditions :
> > +The above copyright notice and this permission notice shall be included in all
> > +copies or substantial portions of the Software.
> > +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
> > +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> > +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> > +SOFTWARE.
> > +
> > +*/
> 
> Can you not reuse the header added in the previous commit?
I am not sure what you mean here, the qoi.h header is reused from
lib/gui/qoi.h, see the include below.
Are you sugesting to _not_ reuse the header?


> > +
> > +
> > +#define STB_IMAGE_IMPLEMENTATION
> > +#define STBI_ONLY_PNG
> > +#define STBI_NO_LINEAR
> > +#include "stb_image.h"
> > +
> > +#define QOI_IMPLEMENTATION
> > +#include "../lib/gui/qoi.h"
included here.








From jmaselbas at kalray.eu  Fri Jan 14 08:52:08 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:08 +0100
Subject: [PATCH 09/13] kvx: add kvx_sfr_field_val
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-10-jmaselbas@kalray.eu>

From: Clement Leger <cleger at kalray.eu>

Add this macro for upcoming socinfo driver. This extract a sfr field
using only its name.

Signed-off-by: Clement Leger <cleger at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/include/asm/sfr.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/kvx/include/asm/sfr.h b/arch/kvx/include/asm/sfr.h
index 5b93cee345..89ff64bbdc 100644
--- a/arch/kvx/include/asm/sfr.h
+++ b/arch/kvx/include/asm/sfr.h
@@ -44,4 +44,8 @@ kvx_sfr_set_mask(unsigned char sfr, uint64_t mask, uint64_t value)
 #define kvx_sfr_set(_sfr, _val)	__builtin_kvx_set(KVX_SFR_ ## _sfr, _val)
 #define kvx_sfr_get(_sfr)	__builtin_kvx_get(KVX_SFR_ ## _sfr)
 
+#define kvx_sfr_field_val(_val, _sfr, _field) \
+			  (((_val) & KVX_SFR_ ## _sfr ## _ ## _field ## _MASK) \
+			  >> KVX_SFR_ ## _sfr ## _ ## _field ## _SHIFT)
+
 #endif	/* _ASM_KVX_SFR_DEFS_H */
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:52:05 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:05 +0100
Subject: [PATCH 06/13] clocksource: kvx: Register as postcore_platform_driver
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-7-jmaselbas@kalray.eu>

Register the kvx clocksource driver sooner, before probing other device
drivers by using the postcore_platform_driver macro. That way the other
drivers will have a correct timestamp when printing messages.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/clocksource/kvx_timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/kvx_timer.c b/drivers/clocksource/kvx_timer.c
index 4125ddbee0..2a05d8deed 100644
--- a/drivers/clocksource/kvx_timer.c
+++ b/drivers/clocksource/kvx_timer.c
@@ -55,4 +55,4 @@ static struct driver_d kvx_timer_driver = {
 	.of_compatible = DRV_OF_COMPAT(kvx_timer_dt_ids),
 };
 
-device_platform_driver(kvx_timer_driver);
+postcore_platform_driver(kvx_timer_driver);
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:52:02 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:02 +0100
Subject: [PATCH 03/13] kvx: Accept LINUX_BOOT_PARAM_MAGIC as a valid magic
 value
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-4-jmaselbas@kalray.eu>

Both defines FSBL_PARAM_MAGIC and LINUX_BOOT_PARAM_MAGIC have a similar
uses and yet have different values. Making barebox accept both as valid
magic boot param will make it possible to use qemu-system-kvx to boot a
barebox image as a normal kernel.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/cpu/cpu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/kvx/cpu/cpu.c b/arch/kvx/cpu/cpu.c
index 788d3194fe..4b0d4d2d96 100644
--- a/arch/kvx/cpu/cpu.c
+++ b/arch/kvx/cpu/cpu.c
@@ -16,7 +16,7 @@ void kvx_lowlevel_setup(unsigned long r0, void *dtb_ptr)
 {
 	uint64_t ev_val = (uint64_t) &_exception_start | EXCEPTION_STRIDE;
 
-	if (r0 == FSBL_PARAM_MAGIC) {
+	if (r0 == FSBL_PARAM_MAGIC || r0 == LINUX_BOOT_PARAM_MAGIC) {
 		boot_dtb = dtb_ptr;
 		pr_info("Using DTB provided by FSBL\n");
 	}
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:52:06 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:06 +0100
Subject: [PATCH 07/13] watchdog: kvx: do not disable watchdog on probe
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-8-jmaselbas@kalray.eu>

From: Louis Morhet <lmorhet at kalray.eu>

As the watchdog may be set by a lower stage in the boot chain, and for
a good reason (precisely to ensure reliable update when something
unexpected happens during the boot chain), it is a bad idea to always
disable it during probe.

We should either have a mechanism to refresh it on a regular basis in
barebox itself and set it to something bigger for Linux, or handle it
transparently and let the previous stage set the global watchdog up to
Linux. This patch assumes for now the latter.

Signed-off-by: Louis Morhet <lmorhet at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/watchdog/kvx_wdt.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/watchdog/kvx_wdt.c b/drivers/watchdog/kvx_wdt.c
index da19136fda..df9430769b 100644
--- a/drivers/watchdog/kvx_wdt.c
+++ b/drivers/watchdog/kvx_wdt.c
@@ -73,11 +73,9 @@ static int kvx_wdt_drv_probe(struct device_d *dev)
 	wdd->hwdev = dev;
 	wdd->set_timeout = kvx_wdt_set_timeout;
 
-	/* Be sure that interrupt are disable */
+	/* Be sure that interrupt are disabled */
 	kvx_sfr_set_field(TCR, WIE, 0);
 
-	kvx_watchdog_disable();
-
 	return watchdog_register(wdd);
 }
 
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:52:07 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:07 +0100
Subject: [PATCH 08/13] nvmem: add kvx otp non volatile regbank support
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-9-jmaselbas@kalray.eu>

From: Clement Leger <cleger at kalray.eu>

Backport Linux driver to barebox to access nvmem.

Signed-off-by: Clement Leger <cleger at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/nvmem/Kconfig      |  7 +++
 drivers/nvmem/Makefile     |  3 ++
 drivers/nvmem/kvx-otp-nv.c | 99 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+)
 create mode 100644 drivers/nvmem/kvx-otp-nv.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 07320101b8..3624cc64b6 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -66,6 +66,13 @@ config STM32_BSEC
 	  This adds support for the STM32 OTP controller. Reads and writes
 	  to will go to the shadow RAM, not the OTP fuses themselvers.
 
+config KVX_OTP_NV
+	tristate "kalray KVX OTP Non volatile regs Support"
+	depends on KVX
+	help
+	  This is a simple driver to dump specified values of KVX OTP non
+	  volatile regs.
+
 config STARFIVE_OTP
 	tristate "Starfive OTP Supprot"
 	depends on SOC_STARFIVE
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index cd970aaea1..81629ddb27 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -24,4 +24,7 @@ nvmem_eeprom_93xx46-y		:= eeprom_93xx46.o
 obj-$(CONFIG_STM32_BSEC)	+= nvmem_bsec.o
 nvmem_bsec-y			:= bsec.o
 
+obj-$(CONFIG_KVX_OTP_NV)	+= nvmem-kvx-otp-nv.o
+nvmem-kvx-otp-nv-y		:= kvx-otp-nv.o
+
 obj-$(CONFIG_STARFIVE_OTP)	+= starfive-otp.o
diff --git a/drivers/nvmem/kvx-otp-nv.c b/drivers/nvmem/kvx-otp-nv.c
new file mode 100644
index 0000000000..f997f8a63b
--- /dev/null
+++ b/drivers/nvmem/kvx-otp-nv.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Kalray Inc., Cl?ment L?ger
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <init.h>
+#include <net.h>
+#include <io.h>
+
+#include <linux/nvmem-provider.h>
+
+#define OTP_NV_ALIGN		4
+#define OTP_NV_ALIGN_MASK	(OTP_NV_ALIGN - 1)
+
+struct kvx_otp_nv_priv {
+	void __iomem *base;
+};
+
+static int kvx_otp_nv_read(void *context, unsigned int offset,
+			  void *_val, size_t bytes)
+{
+	struct kvx_otp_nv_priv *priv = context;
+	u8 *val = _val;
+	u32 tmp, copy_size;
+	u8 skip = offset & OTP_NV_ALIGN_MASK;
+
+	offset &= ~OTP_NV_ALIGN_MASK;
+
+	while (bytes) {
+		tmp = readl(priv->base + offset);
+		if (skip != 0)
+			copy_size = min(OTP_NV_ALIGN - skip, (int) bytes);
+		else
+			copy_size = min(bytes, sizeof(tmp));
+
+		memcpy(val, ((u8 *) &tmp) + skip, copy_size);
+		if (skip != 0)
+			skip = 0;
+
+		bytes -= copy_size;
+		val += copy_size;
+		offset += OTP_NV_ALIGN;
+	}
+
+	return 0;
+}
+
+static const struct nvmem_bus kvx_otp_nv_bus = {
+	.read = kvx_otp_nv_read,
+};
+
+static const struct of_device_id kvx_otp_nv_match[] = {
+	{ .compatible = "kalray,kvx-otp-nv" },
+	{ /* sentinel */},
+};
+
+static int kvx_otp_nv_probe(struct device_d *dev)
+{
+	struct resource *res;
+	struct nvmem_device *nvmem;
+	struct nvmem_config econfig = { 0 };
+	struct kvx_otp_nv_priv *priv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	priv->base = IOMEM(res->start);
+
+	econfig.name = "kvx-nv-regbank";
+	econfig.stride = 1;
+	econfig.word_size = 1;
+	econfig.size = resource_size(res);
+	econfig.dev = dev;
+	econfig.priv = priv;
+	econfig.bus = &kvx_otp_nv_bus;
+
+	dev->priv = priv;
+
+	nvmem = nvmem_register(&econfig);
+
+	return PTR_ERR_OR_ZERO(nvmem);
+}
+
+static struct driver_d kvx_otp_nv_driver = {
+	.name	= "kvx-otp-nv",
+	.probe	= kvx_otp_nv_probe,
+	.of_compatible = DRV_OF_COMPAT(kvx_otp_nv_match),
+};
+postcore_platform_driver(kvx_otp_nv_driver);
-- 
2.17.1







From jmaselbas at kalray.eu  Fri Jan 14 08:52:03 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:03 +0100
Subject: [PATCH 04/13] common: elf: add elf_load_binary
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-5-jmaselbas@kalray.eu>

From: Clement Leger <cleger at kalray.eu>

In order to load elf from a binary buffer, add elf_load_binary. This
will be used by FIT support to allow loading an elf from FIT.

Signed-off-by: Clement Leger <cleger at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 common/elf.c  | 83 +++++++++++++++++++++++++++++++++++++--------------
 include/elf.h |  1 +
 2 files changed, 62 insertions(+), 22 deletions(-)

diff --git a/common/elf.c b/common/elf.c
index af22be37e6..f10fb77953 100644
--- a/common/elf.c
+++ b/common/elf.c
@@ -101,15 +101,17 @@ static int elf_section_cmp(void *priv, struct list_head *a, struct list_head *b)
 static int load_elf_to_memory(struct elf_image *elf)
 {
 	void *dst;
-	int ret, fd;
+	int ret, fd = -1;
 	u64 p_filesz, p_memsz, p_offset;
 	struct elf_section *r;
 	struct list_head *list = &elf->list;
 
-	fd = open(elf->filename, O_RDONLY);
-	if (fd < 0) {
-		pr_err("could not open: %s\n", errno_str());
-		return -errno;
+	if (elf->filename) {
+		fd = open(elf->filename, O_RDONLY);
+		if (fd < 0) {
+			pr_err("could not open: %s\n", errno_str());
+			return -errno;
+		}
 	}
 
 	list_for_each_entry(r, list, list) {
@@ -118,21 +120,26 @@ static int load_elf_to_memory(struct elf_image *elf)
 		p_memsz = elf_phdr_p_memsz(elf, r->phdr);
 		dst = (void *) (phys_addr_t) elf_phdr_p_paddr(elf, r->phdr);
 
-		ret = lseek(fd, p_offset, SEEK_SET);
-		if (ret == -1) {
-			pr_err("lseek at offset 0x%llx failed\n", p_offset);
-			close(fd);
-			return ret;
-		}
-
 		pr_debug("Loading phdr offset 0x%llx to 0x%p (%llu bytes)\n",
 			 p_offset, dst, p_filesz);
 
-		if (read_full(fd, dst, p_filesz) < 0) {
-			pr_err("could not read elf segment: %s\n",
-			       errno_str());
-			close(fd);
-			return -errno;
+		if (fd >= 0) {
+			ret = lseek(fd, p_offset, SEEK_SET);
+			if (ret == -1) {
+				pr_err("lseek at offset 0x%llx failed\n",
+				       p_offset);
+				close(fd);
+				return ret;
+			}
+
+			if (read_full(fd, dst, p_filesz) < 0) {
+				pr_err("could not read elf segment: %s\n",
+				       errno_str());
+				close(fd);
+				return -errno;
+			}
+		} else {
+			memcpy(dst, elf->hdr_buf + p_offset, p_filesz);
 		}
 
 		if (p_filesz < p_memsz)
@@ -202,6 +209,37 @@ static int elf_check_image(struct elf_image *elf, void *buf)
 	return 0;
 }
 
+static void elf_init_struct(struct elf_image *elf)
+{
+	INIT_LIST_HEAD(&elf->list);
+	elf->low_addr = (void *) (unsigned long) -1;
+	elf->high_addr = 0;
+	elf->filename = NULL;
+}
+
+struct elf_image *elf_open_binary(void *buf)
+{
+	int ret;
+	struct elf_image *elf;
+
+	elf = calloc(1, sizeof(*elf));
+	if (!elf)
+		return ERR_PTR(-ENOMEM);
+
+	elf_init_struct(elf);
+
+	elf->hdr_buf = buf;
+	ret = elf_check_image(elf, buf);
+	if (ret) {
+		free(elf);
+		return ERR_PTR(-EINVAL);
+	}
+
+	elf->entry = elf_hdr_e_entry(elf, elf->hdr_buf);
+
+	return elf;
+}
+
 static struct elf_image *elf_check_init(const char *filename)
 {
 	int ret, fd;
@@ -213,9 +251,7 @@ static struct elf_image *elf_check_init(const char *filename)
 	if (!elf)
 		return ERR_PTR(-ENOMEM);
 
-	INIT_LIST_HEAD(&elf->list);
-	elf->low_addr = (void *) (unsigned long) -1;
-	elf->high_addr = 0;
+	elf_init_struct(elf);
 
 	/* First pass is to read elf header only */
 	fd = open(filename, O_RDONLY);
@@ -299,7 +335,10 @@ void elf_close(struct elf_image *elf)
 {
 	elf_release_regions(elf);
 
-	free(elf->hdr_buf);
-	free(elf->filename);
+	if (elf->filename) {
+		free(elf->hdr_buf);
+		free(elf->filename);
+	}
+
 	free(elf);
 }
diff --git a/include/elf.h b/include/elf.h
index 7970fd2c95..12673e93ed 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -414,6 +414,7 @@ static inline size_t elf_get_mem_size(struct elf_image *elf)
 	return elf->high_addr - elf->low_addr;
 }
 
+struct elf_image *elf_open_binary(void *buf);
 struct elf_image *elf_open(const char *filename);
 void elf_close(struct elf_image *elf);
 int elf_load(struct elf_image *elf);
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:52:04 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:04 +0100
Subject: [PATCH 05/13] kvx: enable FITIMAGE support
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-6-jmaselbas@kalray.eu>

From: Clement Leger <cleger at kalray.eu>

Enable FITIMAGE support in kvx defconfig and add code to handle fit boot
from bootm command. This is rather a simple addition and it allow to boot
a fit image containing an ELF file as the kernel.

Signed-off-by: Clement Leger <cleger at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/Kconfig     |  1 +
 arch/kvx/lib/bootm.c | 32 +++++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/arch/kvx/Kconfig b/arch/kvx/Kconfig
index 0934440880..100a945761 100644
--- a/arch/kvx/Kconfig
+++ b/arch/kvx/Kconfig
@@ -10,6 +10,7 @@ config KVX
 	select COMMON_CLK_OF_PROVIDER
 	select ELF
 	select FLEXIBLE_BOOTARGS
+	select FITIMAGE
 	select GENERIC_FIND_NEXT_BIT
 	select HAS_ARCH_SJLJ
 	select HAS_CACHE
diff --git a/arch/kvx/lib/bootm.c b/arch/kvx/lib/bootm.c
index 3e9772c458..4c77f676ec 100644
--- a/arch/kvx/lib/bootm.c
+++ b/arch/kvx/lib/bootm.c
@@ -94,7 +94,7 @@ static int do_boot_elf(struct image_data *data, struct elf_image *elf)
 		goto err_free_fdt;
 	}
 
-	entry = (boot_func_entry) data->os_address;
+	entry = (boot_func_entry) elf->entry;
 
 	ret = do_boot_entry(data, entry, fdt);
 
@@ -104,6 +104,27 @@ err_free_fdt:
 	return ret;
 }
 
+static int do_bootm_fit(struct image_data *data)
+{
+	int ret;
+	struct elf_image *elf;
+
+	elf = elf_open_binary((void *) data->fit_kernel);
+	if (IS_ERR(elf))
+		return PTR_ERR(data->elf);
+
+	ret = elf_load(elf);
+	if (ret)
+		goto close_elf;
+
+	ret = do_boot_elf(data, elf);
+
+close_elf:
+	elf_close(elf);
+
+	return ret;
+}
+
 static int do_bootm_elf(struct image_data *data)
 {
 	int ret;
@@ -121,6 +142,12 @@ static struct image_handler elf_handler = {
 	.filetype = filetype_elf,
 };
 
+static struct image_handler fit_handler = {
+	.name = "FIT",
+	.bootm = do_bootm_fit,
+	.filetype = filetype_oftree,
+};
+
 static struct binfmt_hook binfmt_elf_hook = {
 	.type = filetype_elf,
 	.exec = "bootm",
@@ -130,6 +157,9 @@ static int kvx_register_image_handler(void)
 {
 	register_image_handler(&elf_handler);
 
+	if (IS_ENABLED(CONFIG_FITIMAGE))
+		register_image_handler(&fit_handler);
+
 	binfmt_register(&binfmt_elf_hook);
 
 	return 0;
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:52:00 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:00 +0100
Subject: [PATCH 01/13] kvx: dma: Remove arch dma_map/unmap_single
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-2-jmaselbas@kalray.eu>

Since dma_map/unmap_single functions have been moved to common, barebox
doesn't compile for kvx anymore. The original functions were doing some
magic to support 32bits dma buffer addresses. The original behavior can
be replaced by a device-tree dma-range property.

Fixes: 3f975f810 ("dma: move dma_map/unmap_single from ARM to common code")
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/lib/dma-default.c | 38 --------------------------------------
 1 file changed, 38 deletions(-)

diff --git a/arch/kvx/lib/dma-default.c b/arch/kvx/lib/dma-default.c
index 2a4144696c..c84a32954e 100644
--- a/arch/kvx/lib/dma-default.c
+++ b/arch/kvx/lib/dma-default.c
@@ -54,41 +54,3 @@ void dma_sync_single_for_cpu(dma_addr_t addr, size_t size,
 		BUG();
 	}
 }
-
-#define KVX_DDR_ALIAS_OFFSET \
-	(KVX_DDR_64BIT_RAM_WINDOW_BA - KVX_DDR_32BIT_RAM_WINDOW_BA)
-#define KVX_DDR_ALIAS_WINDOW \
-	(KVX_DDR_64BIT_RAM_WINDOW_BA + KVX_DDR_ALIAS_OFFSET)
-
-/* Local smem is aliased between 0 and 16MB */
-#define KVX_SMEM_LOCAL_ALIAS 0x1000000ULL
-
-dma_addr_t dma_map_single(struct device_d *dev, void *ptr, size_t size,
-			  enum dma_data_direction dir)
-{
-	uintptr_t addr = (uintptr_t) ptr;
-
-	dma_sync_single_for_device(addr, size, dir);
-
-	/* Local smem alias should never be used for dma */
-	if (addr < KVX_SMEM_LOCAL_ALIAS)
-		return addr + (1 + kvx_cluster_id()) * KVX_SMEM_LOCAL_ALIAS;
-
-	if (dev->dma_mask && addr <= dev->dma_mask)
-		return addr;
-
-	if (addr >= KVX_DDR_ALIAS_WINDOW)
-		return DMA_ERROR_CODE;
-
-	addr -= KVX_DDR_ALIAS_OFFSET;
-	if (dev->dma_mask && addr > dev->dma_mask)
-		return DMA_ERROR_CODE;
-
-	return addr;
-}
-
-void dma_unmap_single(struct device_d *dev, dma_addr_t addr, size_t size,
-		      enum dma_data_direction dir)
-{
-	dma_sync_single_for_cpu(addr, size, dir);
-}
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:52:01 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:52:01 +0100
Subject: [PATCH 02/13] kvx: Move LINUX_BOOT_PARAM_MAGIC in asm/common.h
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165208.9980-3-jmaselbas@kalray.eu>

Declare both defines FSBL_PARAM_MAGIC and LINUX_BOOT_PARAM_MAGIC in the
same header file, as they both have a very similar uses and value.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/include/asm/bootm.h  | 11 -----------
 arch/kvx/include/asm/common.h |  3 ++-
 arch/kvx/lib/bootm.c          |  1 -
 3 files changed, 2 insertions(+), 13 deletions(-)
 delete mode 100644 arch/kvx/include/asm/bootm.h

diff --git a/arch/kvx/include/asm/bootm.h b/arch/kvx/include/asm/bootm.h
deleted file mode 100644
index 7ad7e2e878..0000000000
--- a/arch/kvx/include/asm/bootm.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2019 Kalray Inc.
- */
-
-#ifndef _ASM_KVX_BOOTM_H
-#define _ASM_KVX_BOOTM_H
-
-#define LINUX_BOOT_PARAM_MAGIC 0x31564752414E494CULL
-
-#endif /* _ASM_KVX_BOOTM_H */
diff --git a/arch/kvx/include/asm/common.h b/arch/kvx/include/asm/common.h
index a7e301e53a..754953962b 100644
--- a/arch/kvx/include/asm/common.h
+++ b/arch/kvx/include/asm/common.h
@@ -12,7 +12,8 @@
  * Magic value passed in r0 to indicate valid parameters from FSBL when booting
  * If $r0 contains this value, then $r1 contains dtb pointer.
  */
-#define FSBL_PARAM_MAGIC	0x31564752414C414BULL
+#define FSBL_PARAM_MAGIC	0x31564752414C414BULL /* KALARGV1 */
+#define LINUX_BOOT_PARAM_MAGIC	0x31564752414E494CULL /* LINARGV1 */
 
 extern char _exception_start;
 extern char __end;
diff --git a/arch/kvx/lib/bootm.c b/arch/kvx/lib/bootm.c
index 4d17e1846d..3e9772c458 100644
--- a/arch/kvx/lib/bootm.c
+++ b/arch/kvx/lib/bootm.c
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 
 #include <asm/cache.h>
-#include <asm/bootm.h>
 
 typedef void __noreturn (*boot_func_entry)(unsigned long, void *);
 
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:51:59 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:51:59 +0100
Subject: [PATCH 00/13] kvx arch update
Message-ID: <20220114165208.9980-1-jmaselbas@kalray.eu>

This series has updates for the KVX architecture, with some fixes and
with the addition of kvx specific drivers for the otp-nvmem and socinfo.

With this series it is now possible to run barebox on qemu, however
our qemu port isn't upstreamed yet, it can still be compiled. To do
so you will need to check this git repo [1] and follow the build
instructions.

To compile barebox for the KVX architecture there is a pre-built
toolchain that can be downloaded here [2]

The following commands should build an run barebox on qemu:
$ PATH=<path/to/gcc-kalray-kvx-v4.7.0-cd2>/bin:$PATH ARCH=kvx make generic_defconfig all
$ qemu-system-kvx -m 1G -kernel barebox

[1] https://github.com/kalray/qemu-builder
[2] https://github.com/kalray/build-scripts/releases/tag/v4.7.0-cd2

---

Clement Leger (6):
  common: elf: add elf_load_binary
  kvx: enable FITIMAGE support
  nvmem: add kvx otp non volatile regbank support
  kvx: add kvx_sfr_field_val
  drivers: add soc hierarchy properly
  soc: add kvx_socinfo driver

Jules Maselbas (6):
  kvx: dma: Remove arch dma_map/unmap_single
  kvx: Move LINUX_BOOT_PARAM_MAGIC in asm/common.h
  kvx: Accept LINUX_BOOT_PARAM_MAGIC as a valid magic value
  clocksource: kvx: Register as postcore_platform_driver
  kvx: Update defconfig
  kvx: dts: Update k200.dts

Louis Morhet (1):
  watchdog: kvx: do not disable watchdog on probe

 arch/kvx/Kconfig                   |   1 +
 arch/kvx/configs/generic_defconfig |  32 +++
 arch/kvx/cpu/cpu.c                 |   2 +-
 arch/kvx/dts/k200.dts              | 426 +++++++++++++++++++++++++++--
 arch/kvx/include/asm/bootm.h       |  11 -
 arch/kvx/include/asm/common.h      |   3 +-
 arch/kvx/include/asm/sfr.h         |   4 +
 arch/kvx/lib/bootm.c               |  33 ++-
 arch/kvx/lib/dma-default.c         |  38 ---
 common/elf.c                       |  83 ++++--
 drivers/Kconfig                    |   2 +-
 drivers/clocksource/kvx_timer.c    |   2 +-
 drivers/nvmem/Kconfig              |   7 +
 drivers/nvmem/Makefile             |   3 +
 drivers/nvmem/kvx-otp-nv.c         |  99 +++++++
 drivers/soc/Kconfig                |   6 +
 drivers/soc/Makefile               |   1 +
 drivers/soc/kvx/Kconfig            |  10 +
 drivers/soc/kvx/Makefile           |   1 +
 drivers/soc/kvx/kvx_socinfo.c      | 141 ++++++++++
 drivers/watchdog/kvx_wdt.c         |   4 +-
 include/elf.h                      |   1 +
 22 files changed, 814 insertions(+), 96 deletions(-)
 delete mode 100644 arch/kvx/include/asm/bootm.h
 create mode 100644 drivers/nvmem/kvx-otp-nv.c
 create mode 100644 drivers/soc/Kconfig
 create mode 100644 drivers/soc/kvx/Kconfig
 create mode 100644 drivers/soc/kvx/Makefile
 create mode 100644 drivers/soc/kvx/kvx_socinfo.c

-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:54:55 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:54:55 +0100
Subject: [PATCH 12/13] kvx: Update defconfig
In-Reply-To: <20220114165456.10542-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165456.10542-1-jmaselbas@kalray.eu>
Message-ID: <20220114165456.10542-3-jmaselbas@kalray.eu>

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/configs/generic_defconfig | 32 ++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/kvx/configs/generic_defconfig b/arch/kvx/configs/generic_defconfig
index 0d971ff3d5..0184ae0ed9 100644
--- a/arch/kvx/configs/generic_defconfig
+++ b/arch/kvx/configs/generic_defconfig
@@ -1,13 +1,45 @@
 CONFIG_AUTO_COMPLETE=y
 CONFIG_CONSOLE_RATP=y
+CONFIG_PARTITION_DISK_EFI=y
+CONFIG_STATE=y
+CONFIG_BOOTCHOOSER=y
+CONFIG_CMD_DMESG=y
+CONFIG_LONGHELP=y
 CONFIG_CMD_BOOT=y
 CONFIG_CMD_RESET=y
+CONFIG_CMD_NV=y
+CONFIG_CMD_GLOBAL=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_SAVEENV=y
 CONFIG_CMD_CMP=y
+CONFIG_CMD_FLASH=y
 CONFIG_CMD_POWEROFF=y
+CONFIG_CMD_USBGADGET=y
 CONFIG_CMD_WD=y
 CONFIG_CMD_OF_DUMP=y
+CONFIG_CMD_STATE=y
+CONFIG_DRIVER_SERIAL_KVX_SCALL=y
 CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_SPI_SYNOPSYS_OCTALSPI_NOR=y
+CONFIG_USB_HOST=y
+CONFIG_USB_DWC2_HOST=y
+CONFIG_USB_DWC2_GADGET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DFU=y
+CONFIG_USB_GADGET_SERIAL=y
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+CONFIG_MCI_DWC_MSHC=y
 CONFIG_CLOCKSOURCE_KVX=y
+CONFIG_STATE_DRV=y
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_KVX=y
+CONFIG_GPIO_DESIGNWARE=y
 CONFIG_PINCTRL_SINGLE=y
+CONFIG_GENERIC_PHY=y
+CONFIG_USB_NOP_XCEIV=y
+CONFIG_DIGEST_MD5_GENERIC=y
+CONFIG_DIGEST_SHA256_GENERIC=y
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:54:56 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:54:56 +0100
Subject: [PATCH 13/13] kvx: dts: Update k200.dts
In-Reply-To: <20220114165456.10542-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165456.10542-1-jmaselbas@kalray.eu>
Message-ID: <20220114165456.10542-4-jmaselbas@kalray.eu>

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/dts/k200.dts | 426 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 410 insertions(+), 16 deletions(-)

diff --git a/arch/kvx/dts/k200.dts b/arch/kvx/dts/k200.dts
index d463ffda50..e83a08b462 100644
--- a/arch/kvx/dts/k200.dts
+++ b/arch/kvx/dts/k200.dts
@@ -3,6 +3,8 @@
  * Copyright (C) 2019 Kalray, Inc.
  */
 
+#include <dt-bindings/interrupt-controller/irq.h>
+
 /dts-v1/;
 
 / {
@@ -15,7 +17,7 @@
 	/* Standard nodes (choosen, cpus, memory, etc) */
 	chosen {
 		bootargs = "earlycon norandmaps console=ttyS0";
-		stdout-path = &serial0;
+		stdout-path = &uart0;
 	};
 
 	cpus {
@@ -46,6 +48,13 @@
 			/* 1 GHz clock */
 			clock-frequency = <1000000000>;
 		};
+
+		socp_clk: socp_clk at 0 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			/* 480 MHz clock */
+			clock-frequency = <480000000>;
+		};
 	};
 
 	ddr: memory at 100000000 {
@@ -60,44 +69,147 @@
 		reg = <0x0 0x0 0x0 0x400000>;
 	};
 
+	core_intc: core_intc at 0 {
+		compatible = "kalray,kvx-core-intc";
+		#address-cells = <0>;
+		#interrupt-cells = <1>;
+		interrupt-controller;
+	};
+
+	ipi_ctrl: ipi_ctrl at ad0000 {
+		compatible = "kalray,kvx-ipi-ctrl";
+		reg = <0x0 0xad0000 0x0 0x1000>;
+		interrupt-parent = <&core_intc>;
+		interrupts = <24>;
+	};
+
+	apic_gic: apic_gic at a20000 {
+		compatible = "kalray,kvx-apic-gic";
+		reg = <0x0 0xa20000 0x0 0x12000>;
+		#address-cells = <0>;
+		interrupt-parent = <&core_intc>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <4 5 6 7>;
+	};
+
+	apic_mailbox: apic_mailbox at a00000 {
+		compatible = "kalray,kvx-apic-mailbox";
+		reg = <0x0 0xa00000 0x0 0xea00>;
+		#address-cells = <0>;
+		interrupt-parent = <&apic_gic>;
+		interrupt-controller;
+		#interrupt-cells = <0>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9
+			      10 11 12 13 14 15 16 17 18 19
+			      20 21 22 23 24 25 26 27 28 29
+			      30 31 32 33 34 35 36 37 38 39
+			      40 41 42 43 44 45 46 47 48 49
+			      50 51 52 53 54 55 56 57 58 59
+			      60 61 62 63 64 65 66 67 68 69
+			      70 71 72 73 74 75 76 77 78 79
+			      80 81 82 83 84 85 86 87 88 89
+			      90 91 92 93 94 95 96 97 98 99
+			      100 101 102 103 104 105 106 107 108 109
+			      110 111 112 113 114 115 116>;
+		msi-controller;
+	};
+
+	dame_handler {
+		/* Data Asynchronous Memory Error handler */
+		compatible = "kalray,kvx-dame-handler";
+		interrupt-parent = <&core_intc>;
+		interrupts = <16>;
+	};
+
 	core_timer {
 		compatible = "kalray,kvx-core-timer";
+		interrupts = <0>;
+		interrupt-parent = <&core_intc>;
 		clocks = <&core_clk>;
 	};
 
 	core_watchdog {
 		compatible = "kalray,kvx-core-watchdog";
+		interrupts = <2>;
+		interrupt-parent = <&core_intc>;
+		clocks = <&core_clk>;
+	};
+
+	core_pm {
+		compatible = "kalray,kvx-core-pm";
+		interrupts = <3>;
+		interrupt-parent = <&core_intc>;
+		kalray,pm-num = <4>;
+	};
+
+	pwr_ctrl0: pwr_ctrl at a40000 {
+		reg = <0x0 0xa40000 0x0 0x4158>;
+		compatible = "kalray,kvx-pwr-ctrl";
+	};
+
+	power_off {
+		compatible = "kalray,kvx-scall-poweroff";
+	};
+
+	dsu_clock {
+		compatible = "kalray,kvx-dsu-clock";
+		reg = <0x0 0xa44180 0x0 0x8>;
 		clocks = <&core_clk>;
 	};
 
-	axi {
+	axi: axi {
 		compatible = "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
 		ranges;
+		dma-ranges;
+
+		iommu_soc_periph: iommu_soc_periph at 27020000 {
+			compatible = "kalray,kvx-iommu";
+			reg = <0x0 0x27020000 0x0 0x00000240>,
+				<0x0 0x27020800 0x0 0x00000240>;
+			reg-names = "tx", "rx";
+			interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, <0 IRQ_TYPE_LEVEL_HIGH>, <5 IRQ_TYPE_LEVEL_HIGH>,
+				     <25 IRQ_TYPE_LEVEL_HIGH>, <15 IRQ_TYPE_LEVEL_HIGH>, <20 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "rx_nomapping", "rx_protection", "rx_parity",
+					  "tx_nomapping", "tx_protection", "tx_parity";
+			interrupt-parent = <&itgen_soc_periph1>;
+			#iommu-cells = <1>;
+		};
+
+		itgen_soc_periph0: itgen_soc_periph0 at 27000000 {
+			compatible = "kalray,kvx-itgen";
+			reg = <0x0 0x27000000 0x0 0x1104>;
+			#address-cells = <0>;
+			msi-parent = <&apic_mailbox>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		itgen_soc_periph1: itgen_soc_periph1 at 27010000 {
+			compatible = "kalray,kvx-itgen";
+			reg = <0x0 0x27010000 0x0 0x1104>;
+			#address-cells = <0>;
+			msi-parent = <&apic_mailbox>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
 
 		ftu: ftu at 10181000 {
 			compatible = "kalray,kvx-syscon", "syscon";
 			reg = <0x0 0x10181000 0x0 0x410>;
 		};
 
-		pmx_gpio0: pinmux at 20230008 {
-			compatible = "pinctrl-single";
-			reg = <0x0 0x20230008 0x0 0x4>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			#pinctrl-cells = <2>;
-			pinctrl-single,bit-per-mux;
-			pinctrl-single,register-width = <32>;
-			pinctrl-single,function-mask = <0x1>;
-
-			uart0_pins: pinmux_uart0_pins {
-				pinctrl-single,bits = <0x00 0x00000003 0x00000003>;
-			};
+		reboot: reboot at 0 {
+			compatible = "syscon-reboot";
+			regmap = <&ftu>;
+			offset = <0x50>;
+			value = <0x1>;
 		};
 
-		serial0: uart0 at 20210000 {
+		uart0: uart0 at 20210000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x20210000 0x0 0x100>;
 			clocks = <&ref_clk>;
@@ -105,6 +217,288 @@
 			reg-shift = <2>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&uart0_pins>;
+			interrupt-parent = <&itgen_soc_periph0>;
+			interrupts = <41 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		uart1: uart1 at 20211000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x0 0x20211000 0x0 0x100>;
+			clocks = <&ref_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins>;
+			interrupt-parent = <&itgen_soc_periph0>;
+			interrupts = <42 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		uart2: uart2 at 20212000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x0 0x20212000 0x0 0x100>;
+			clocks = <&ref_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart2_pins>;
+			interrupt-parent = <&itgen_soc_periph0>;
+			interrupts = <43 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		uart3: uart3 at 20213000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x0 0x20213000 0x0 0x100>;
+			clocks = <&ref_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart3_pins>;
+			interrupt-parent = <&itgen_soc_periph0>;
+			interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		uart4: uart4 at 20214000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x0 0x20214000 0x0 0x100>;
+			clocks = <&ref_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart4_pins>;
+			interrupt-parent = <&itgen_soc_periph0>;
+			interrupts = <45 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		uart5: uart5 at 20215000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x0 0x20215000 0x0 0x100>;
+			clocks = <&ref_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart5_pins>;
+			interrupt-parent = <&itgen_soc_periph0>;
+			interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		timers0: timers0 at 20220000 {
+			compatible = "snps,dw-apb-timer";
+			reg = <0x0 0x20220000 0x0 0xD0>;
+			clocks = <&ref_clk>;
+		};
+
+		timers4: timers4 at 20224000 {
+			compatible = "snps,dw-apb-timer";
+			reg = <0x0 0x20224000 0x0 0xD0>;
+			clocks = <&ref_clk>;
+		};
+
+		otp_nv: otp_nv_regs at d20000 {
+			reg = <0x0 0xd20000 0x0 0xe0>;
+			compatible = "kalray,kvx-otp-nv";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ft_fuse: ft_fuse at cc {
+				reg = <0xcc 0x4>;
+			};
+			ews_fuse: ews_fuse at d8 {
+				reg = <0xd8 0x8>;
+			};
+		};
+
+		kvx_socinfo: kvx_socinfo at 0 {
+			compatible = "kalray,kvx-socinfo";
+			nvmem-cells = <&ews_fuse>, <&ft_fuse>;
+			nvmem-cell-names = "ews_fuse", "ft_fuse";
+		};
+
+		ahb {
+			compatible = "simple-bus";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			dma-ranges = <0x0 0x80000000 0x1 0x00000000 0x0 0x80000000>;
+
+			usb0: usb0 at 20080000 {
+				compatible = "kalray,kvx-hsotg", "snps,dwc2";
+				reg = <0x0 0x20080000 0x0 0x40000>;
+				clocks = <&socp_clk>;
+				clock-names = "otg";
+				dr_mode = "otg";
+				interrupt-parent = <&itgen_soc_periph0>;
+				interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
+				g-rx-fifo-size = <2048>;
+				g-np-tx-fifo-size = <512>;
+				g-tx-fifo-size = <512 512 512 512 512 512 512 512>;
+				iommus = <&iommu_soc_periph 0x18>;
+			};
+
+			usb1: usb1 at 20100000 {
+				compatible = "kalray,kvx-hsotg", "snps,dwc2";
+				reg = <0x0 0x20100000 0x0 0x40000>;
+				clocks = <&socp_clk>;
+				clock-names = "otg";
+				dr_mode = "otg";
+				interrupt-parent = <&itgen_soc_periph0>;
+				interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+				g-rx-fifo-size = <2048>;
+				g-np-tx-fifo-size = <512>;
+				g-tx-fifo-size = <512 512 512 512 512 512 512 512>;
+				iommus = <&iommu_soc_periph 0x28>;
+			};
+		};
+
+		apb {
+			compatible = "simple-bus";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+
+			gpio0: gpio at 20230000 {
+				compatible = "snps,dw-apb-gpio";
+				reg = <0x0 0x20230000 0x0 0x1000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				gpio0_banka: gpio-controller at 0 {
+					compatible = "snps,dw-apb-gpio-port";
+					#address-cells = <0>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					snps,nr-gpios = <32>;
+					snps,has-pinctrl;
+					reg = <0>;
+					interrupt-parent = <&itgen_soc_periph0>;
+					interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
+					/* All pins of port A are interrupt capable */
+					interrupt-controller;
+					#interrupt-cells = <2>;
+
+					uart0_pins: pinmux_uart0_pins {
+						function = "hw";
+						pins = "pin0", "pin1";
+					};
+					uart1_pins: pinmux_uart1_pins {
+						function = "hw";
+						pins = "pin2", "pin3";
+					};
+					uart2_pins: pinmux_uart2_pins {
+						function = "hw";
+						pins = "pin4", "pin5";
+					};
+					can0_pins: pinmux_can0_pins {
+						function = "hw";
+						pins = "pin6", "pin7";
+					};
+					can1_pins: pinmux_can1_pins {
+						function = "hw";
+						pins = "pin8", "pin9";
+					};
+					i2c0_pins: pinmux_i2c0_pins {
+						function = "hw";
+						pins = "pin10", "pin11";
+					};
+					smb1_pins: pinmux_smb1_pins {
+						function = "hw";
+						pins = "pin12", "pin13";
+					};
+					smb2_pins: pinmux_smb2_pins {
+						function = "hw";
+						pins = "pin14", "pin15";
+					};
+					qspi0_master_pins:pinmux_qspi0_master_pins {
+						function = "hw";
+						pins = "pin18", "pin19", "pin20", "pin21", "pin22", "pin23", "pin24";
+					};
+					spi_slave_pins:pinmux_spi_slave_pins {
+						function = "hw";
+						pins = "pin25", "pin26", "pin27", "pin28";
+					};
+					timer0_pins:pinmux_timer0_pins {
+						function = "hw";
+						pins = "pin29";
+					};
+					timer1_pins:pinmux_timer1_pins {
+						function = "hw";
+						pins = "pin30";
+					};
+					timer2_pins:pinmux_timer2_pins {
+						function = "hw";
+						pins = "pin31";
+					};
+				};
+			};
+
+			gpio1: gpio at 20231000 {
+				compatible = "snps,dw-apb-gpio";
+				reg = <0x0 0x20231000 0x0 0x1000>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				gpio1_banka: gpio-controller at 0 {
+					compatible = "snps,dw-apb-gpio-port";
+					#address-cells = <0>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					snps,nr-gpios = <32>;
+					snps,has-pinctrl;
+					reg = <0>;
+					interrupt-parent = <&itgen_soc_periph0>;
+					interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
+					/* All pins of port A are interrupt capable */
+					interrupt-controller;
+					#interrupt-cells = <2>;
+
+					uart3_pins: pinmux_uart3_pins {
+						function = "hw";
+						pins = "pin0", "pin1";
+					};
+					uart4_pins: pinmux_uart4_pins {
+						function = "hw";
+						pins = "pin2", "pin3";
+					};
+					uart5_pins: pinmux_uart5_pins {
+						function = "hw";
+						pins = "pin4", "pin5";
+					};
+					can2_pins: pinmux_can2_pins {
+						function = "hw";
+						pins = "pin6", "pin7";
+					};
+					can3_pins: pinmux_can3_pins {
+						function = "hw";
+						pins = "pin8", "pin9";
+					};
+					i2c3_pins: pinmux_i2c3_pins {
+						function = "hw";
+						pins = "pin10", "pin11";
+					};
+					smb4_pins: pinmux_smb4_pins {
+						function = "hw";
+						pins = "pin12", "pin13";
+					};
+					timer3_pins:pinmux_timer3_pins {
+						function = "hw";
+						pins = "pin15";
+					};
+					timer4_pins:pinmux_timer4_pins {
+						function = "hw";
+						pins = "pin16";
+					};
+					timer5_pins:pinmux_timer5_pins {
+						function = "hw";
+						pins = "pin17";
+					};
+					qspi1_master_pins:pinmux_qspi1_master_pins {
+						function = "hw";
+						pins = "pin18", "pin19", "pin20", "pin21", "pin22", "pin23", "pin24";
+					};
+					qspi2_master_pins:pinmux_qspi2_master_pins {
+						function = "hw";
+						pins = "pin25", "pin26", "pin27", "pin28", "pin29", "pin30", "pin31";
+					};
+				};
+			};
 		};
 	};
 };
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:54:53 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:54:53 +0100
Subject: [PATCH 10/13] drivers: add soc hierarchy properly
In-Reply-To: <20220114165208.9980-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
Message-ID: <20220114165456.10542-1-jmaselbas@kalray.eu>

From: Clement Leger <cleger at kalray.eu>

We will add kvx driver in this folder to create a proper hierarchy.

Signed-off-by: Clement Leger <cleger at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/Kconfig     | 2 +-
 drivers/soc/Kconfig | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/Kconfig

diff --git a/drivers/Kconfig b/drivers/Kconfig
index dbdf3c06f5..d66714af9a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -42,7 +42,7 @@ source "drivers/fpga/Kconfig"
 source "drivers/phy/Kconfig"
 source "drivers/crypto/Kconfig"
 source "drivers/memory/Kconfig"
-source "drivers/soc/imx/Kconfig"
+source "drivers/soc/Kconfig"
 source "drivers/nvme/Kconfig"
 source "drivers/ddr/Kconfig"
 source "drivers/power/Kconfig"
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
new file mode 100644
index 0000000000..d78f13f3f8
--- /dev/null
+++ b/drivers/soc/Kconfig
@@ -0,0 +1,5 @@
+menu "SoC drivers"
+
+source "drivers/soc/imx/Kconfig"
+
+endmenu
-- 
2.17.1



From jmaselbas at kalray.eu  Fri Jan 14 08:54:54 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 17:54:54 +0100
Subject: [PATCH 11/13] soc: add kvx_socinfo driver
In-Reply-To: <20220114165456.10542-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165456.10542-1-jmaselbas@kalray.eu>
Message-ID: <20220114165456.10542-2-jmaselbas@kalray.eu>

From: Clement Leger <cleger at kalray.eu>

This driver uses various source (sfr, nvmem) to determine the mppa_id
and the architecture revision. These are then exported using global
variables which are:
- global.kvx.arch_rev: Architecture revision (kv3-1 for instance)
- global.kvx.mppa_id: Unique chip id, composed of lot and wafer id

Signed-off-by: Clement Leger <cleger at kalray.eu>
Co-developed-by: Jules Maselbas <jmaselbas at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/soc/Kconfig           |   1 +
 drivers/soc/Makefile          |   1 +
 drivers/soc/kvx/Kconfig       |  10 +++
 drivers/soc/kvx/Makefile      |   1 +
 drivers/soc/kvx/kvx_socinfo.c | 141 ++++++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+)
 create mode 100644 drivers/soc/kvx/Kconfig
 create mode 100644 drivers/soc/kvx/Makefile
 create mode 100644 drivers/soc/kvx/kvx_socinfo.c

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index d78f13f3f8..54b69cc42e 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,5 +1,6 @@
 menu "SoC drivers"
 
 source "drivers/soc/imx/Kconfig"
+source "drivers/soc/kvx/Kconfig"
 
 endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index c3499c0c7f..3b75be8ae4 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -3,3 +3,4 @@
 obj-y	+= imx/
 obj-$(CONFIG_CPU_SIFIVE)	+= sifive/
 obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
+obj-$(CONFIG_KVX)	+= kvx/
diff --git a/drivers/soc/kvx/Kconfig b/drivers/soc/kvx/Kconfig
new file mode 100644
index 0000000000..18dcb8ba14
--- /dev/null
+++ b/drivers/soc/kvx/Kconfig
@@ -0,0 +1,10 @@
+menu "KVX SoC drivers"
+
+config KVX_SOCINFO
+        bool "KVX SoC Info driver"
+	depends on KVX
+	select NVMEM
+	select KVX_OTP_NV
+	default y
+
+endmenu
diff --git a/drivers/soc/kvx/Makefile b/drivers/soc/kvx/Makefile
new file mode 100644
index 0000000000..cacfef21a1
--- /dev/null
+++ b/drivers/soc/kvx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_KVX_SOCINFO) += kvx_socinfo.o
diff --git a/drivers/soc/kvx/kvx_socinfo.c b/drivers/soc/kvx/kvx_socinfo.c
new file mode 100644
index 0000000000..100faae766
--- /dev/null
+++ b/drivers/soc/kvx/kvx_socinfo.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Kalray Inc., Cl?ment L?ger
+ */
+
+#define pr_fmt(fmt) "kvx_socinfo: " fmt
+
+#include <init.h>
+#include <driver.h>
+#include <globalvar.h>
+#include <magicvar.h>
+#include <command.h>
+#include <libfile.h>
+#include <getopt.h>
+#include <common.h>
+#include <fs.h>
+
+#include <asm/sfr.h>
+
+#include <linux/kernel.h>
+#include <linux/nvmem-consumer.h>
+
+#define LOT_ID_STR_LEN	8
+
+#define EWS_LOT_ID_MASK		0x1ffffffffffULL
+#define EWS_WAFER_ID_SHIFT	42
+#define EWS_WAFER_ID_MASK	0x1fULL
+
+#define FT_COM_AP_SHIFT		16
+#define FT_COM_AP_MASK		0x3f
+#define FT_DEVICE_ID_SHIFT	22
+#define FT_DEVICE_ID_MASK	0x1ff
+
+static char *kvx_mppa_id;
+static char *kvx_arch_rev;
+
+BAREBOX_MAGICVAR(kvx.arch_rev, "KVX architecture revision");
+BAREBOX_MAGICVAR(kvx.mppa_id, "KVX MPPA chip id");
+
+static void kvx_soc_info_read_revision(void)
+{
+	u64 pcr = kvx_sfr_get(PCR);
+	u8 sv = kvx_sfr_field_val(pcr, PCR, SV);
+	u8 car = kvx_sfr_field_val(pcr, PCR, CAR);
+	const char *car_str = "", *ver_str = "";
+
+	switch (car) {
+	case 0:
+		car_str = "kv3";
+		break;
+	}
+
+	switch (sv) {
+	case 0:
+		ver_str = "1";
+		break;
+	case 1:
+		ver_str = "2";
+		break;
+	}
+
+	kvx_arch_rev = basprintf("%s-%s", car_str, ver_str);
+
+	globalvar_add_simple_string("kvx.arch_rev", &kvx_arch_rev);
+}
+
+static int base38_decode(char *s, u64 val, int nb_char)
+{
+	int i;
+	const char *alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_?";
+	const int base = strlen(alphabet);
+
+	if (s == NULL)
+		return -1;
+
+	for (i = 0; i < nb_char; i++) {
+		s[i] = alphabet[val % base];
+		val /= base;
+	}
+
+	return 0;
+}
+
+static int kvx_read_serial(struct device_node *socinfo)
+{
+	char lot_id[LOT_ID_STR_LEN + 1] = "";
+	char com_ap;
+	u64 *cell_val64;
+	u64 ews_val;
+	u32 *cell_val32;
+	u32 ft_val;
+	u8 wafer_id;
+	u16 device_id;
+
+	cell_val64 = (u64 *) nvmem_cell_get_and_read(socinfo, "ews_fuse", 8);
+	if (IS_ERR(cell_val64)) {
+		pr_debug("Fail to read ews_fuse\n");
+		return PTR_ERR(cell_val64);
+	}
+
+	ews_val = *cell_val64;
+	ews_val = (ews_val >> 32) | (ews_val << 32);
+	wafer_id = (ews_val >> EWS_WAFER_ID_SHIFT) & EWS_WAFER_ID_MASK;
+	base38_decode(lot_id, ews_val & EWS_LOT_ID_MASK, LOT_ID_STR_LEN);
+
+	cell_val32 = (u32 *) nvmem_cell_get_and_read(socinfo, "ft_fuse", 4);
+	if (IS_ERR(cell_val32)) {
+		pr_debug("Fail to read ft_fuse\n");
+		return PTR_ERR(cell_val32);
+	}
+
+	ft_val = *cell_val32;
+	device_id = (ft_val >> FT_DEVICE_ID_SHIFT) & FT_DEVICE_ID_MASK;
+	base38_decode(&com_ap, (ft_val >> FT_COM_AP_SHIFT) & FT_COM_AP_MASK, 1);
+
+	kvx_mppa_id = basprintf("%sA-%d%c-%03d", lot_id, wafer_id, com_ap,
+			       device_id);
+
+	globalvar_add_simple_string("kvx.mppa_id", &kvx_mppa_id);
+
+	return 0;
+}
+
+static int kvx_socinfo_probe(struct device_d *dev)
+{
+	kvx_soc_info_read_revision();
+
+	return kvx_read_serial(dev->device_node);
+}
+
+static const struct of_device_id kvx_socinfo_dt_ids[] = {
+	{ .compatible = "kalray,kvx-socinfo" },
+	{ }
+};
+
+static struct driver_d kvx_socinfo_driver = {
+	.name = "kvx-socinfo",
+	.probe = kvx_socinfo_probe,
+	.of_compatible = DRV_OF_COMPAT(kvx_socinfo_dt_ids),
+};
+coredevice_platform_driver(kvx_socinfo_driver);
-- 
2.17.1







From a.fatoum at pengutronix.de  Fri Jan 14 09:06:34 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 18:06:34 +0100
Subject: [PATCH 10/13] drivers: add soc hierarchy properly
In-Reply-To: <20220114165456.10542-1-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165456.10542-1-jmaselbas@kalray.eu>
Message-ID: <f99cfd5d-f477-4564-c5e3-dac889b5c8b3@pengutronix.de>

Hello Jules,

On 14.01.22 17:54, Jules Maselbas wrote:
> From: Clement Leger <cleger at kalray.eu>
> 
> We will add kvx driver in this folder to create a proper hierarchy.

This won't apply cleanly. You need to rebase.

> 
> Signed-off-by: Clement Leger <cleger at kalray.eu>
> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> ---
>  drivers/Kconfig     | 2 +-
>  drivers/soc/Kconfig | 5 +++++
>  2 files changed, 6 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/soc/Kconfig
> 
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index dbdf3c06f5..d66714af9a 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -42,7 +42,7 @@ source "drivers/fpga/Kconfig"
>  source "drivers/phy/Kconfig"
>  source "drivers/crypto/Kconfig"
>  source "drivers/memory/Kconfig"
> -source "drivers/soc/imx/Kconfig"
> +source "drivers/soc/Kconfig"
>  source "drivers/nvme/Kconfig"
>  source "drivers/ddr/Kconfig"
>  source "drivers/power/Kconfig"
> diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
> new file mode 100644
> index 0000000000..d78f13f3f8
> --- /dev/null
> +++ b/drivers/soc/Kconfig
> @@ -0,0 +1,5 @@
> +menu "SoC drivers"
> +
> +source "drivers/soc/imx/Kconfig"
> +
> +endmenu
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From jmaselbas at kalray.eu  Fri Jan 14 09:11:11 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 18:11:11 +0100
Subject: [PATCH 10/13] drivers: add soc hierarchy properly
In-Reply-To: <f99cfd5d-f477-4564-c5e3-dac889b5c8b3@pengutronix.de>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165456.10542-1-jmaselbas@kalray.eu>
 <f99cfd5d-f477-4564-c5e3-dac889b5c8b3@pengutronix.de>
Message-ID: <20220114171111.GC29876@tellis.lin.mbt.kalray.eu>

On Fri, Jan 14, 2022 at 06:06:34PM +0100, Ahmad Fatoum wrote:
> Hello Jules,
> 
> On 14.01.22 17:54, Jules Maselbas wrote:
> > From: Clement Leger <cleger at kalray.eu>
> > 
> > We will add kvx driver in this folder to create a proper hierarchy.
> 
> This won't apply cleanly. You need to rebase.
On master ? Or should I wait for 2022.01.0 ?
> 
> > 
> > Signed-off-by: Clement Leger <cleger at kalray.eu>
> > Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> > ---
> >  drivers/Kconfig     | 2 +-
> >  drivers/soc/Kconfig | 5 +++++
> >  2 files changed, 6 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/soc/Kconfig
> > 
> > diff --git a/drivers/Kconfig b/drivers/Kconfig
> > index dbdf3c06f5..d66714af9a 100644
> > --- a/drivers/Kconfig
> > +++ b/drivers/Kconfig
> > @@ -42,7 +42,7 @@ source "drivers/fpga/Kconfig"
> >  source "drivers/phy/Kconfig"
> >  source "drivers/crypto/Kconfig"
> >  source "drivers/memory/Kconfig"
> > -source "drivers/soc/imx/Kconfig"
> > +source "drivers/soc/Kconfig"
> >  source "drivers/nvme/Kconfig"
> >  source "drivers/ddr/Kconfig"
> >  source "drivers/power/Kconfig"
> > diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
> > new file mode 100644
> > index 0000000000..d78f13f3f8
> > --- /dev/null
> > +++ b/drivers/soc/Kconfig
> > @@ -0,0 +1,5 @@
> > +menu "SoC drivers"
> > +
> > +source "drivers/soc/imx/Kconfig"
> > +
> > +endmenu
> > 
> 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 
> 
> To declare a filtering error, please use the following link : https://www.security-mail.net/reporter.php?mid=9c47.61e1ad9d.ae4c.0&r=jmaselbas%40kalray.eu&s=a.fatoum%40pengutronix.de&o=Re%3A+%5BPATCH+10%2F13%5D+drivers%3A+add+soc+hierarchy+properly&verdict=C&c=835ed3aa69d359c0f8acda9912ca30b77899cc91
> 






From a.fatoum at pengutronix.de  Fri Jan 14 09:20:37 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Jan 2022 18:20:37 +0100
Subject: [PATCH 10/13] drivers: add soc hierarchy properly
In-Reply-To: <20220114171111.GC29876@tellis.lin.mbt.kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165456.10542-1-jmaselbas@kalray.eu>
 <f99cfd5d-f477-4564-c5e3-dac889b5c8b3@pengutronix.de>
 <20220114171111.GC29876@tellis.lin.mbt.kalray.eu>
Message-ID: <414be7ce-3abd-115e-71d9-4cae945e7b3b@pengutronix.de>

On 14.01.22 18:11, Jules Maselbas wrote:
> On Fri, Jan 14, 2022 at 06:06:34PM +0100, Ahmad Fatoum wrote:
>> Hello Jules,
>>
>> On 14.01.22 17:54, Jules Maselbas wrote:
>>> From: Clement Leger <cleger at kalray.eu>
>>>
>>> We will add kvx driver in this folder to create a proper hierarchy.
>>
>> This won't apply cleanly. You need to rebase.

Sorry, my pattern matching was too eager. You only add
drivers/soc/Kconfig, not drivers/soc/Makefile. The latter
was added only recently.

> On master ? Or should I wait for 2022.01.0 ?

At release time, Sascha tags master and then merges
next into master. Then for a month patches are applied onto
next and only fixes are cherry-picked to master until next
release, so patches rebased on next are least likely to conflict.

Given that most arch/kvx stuff you touch wasn't updated
in the meantime, I guess you don't need to rebase.

Sorry for the confusion!

Cheers,
Ahmad

>>
>>>
>>> Signed-off-by: Clement Leger <cleger at kalray.eu>
>>> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
>>> ---
>>>  drivers/Kconfig     | 2 +-
>>>  drivers/soc/Kconfig | 5 +++++
>>>  2 files changed, 6 insertions(+), 1 deletion(-)
>>>  create mode 100644 drivers/soc/Kconfig
>>>
>>> diff --git a/drivers/Kconfig b/drivers/Kconfig
>>> index dbdf3c06f5..d66714af9a 100644
>>> --- a/drivers/Kconfig
>>> +++ b/drivers/Kconfig
>>> @@ -42,7 +42,7 @@ source "drivers/fpga/Kconfig"
>>>  source "drivers/phy/Kconfig"
>>>  source "drivers/crypto/Kconfig"
>>>  source "drivers/memory/Kconfig"
>>> -source "drivers/soc/imx/Kconfig"
>>> +source "drivers/soc/Kconfig"
>>>  source "drivers/nvme/Kconfig"
>>>  source "drivers/ddr/Kconfig"
>>>  source "drivers/power/Kconfig"
>>> diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
>>> new file mode 100644
>>> index 0000000000..d78f13f3f8
>>> --- /dev/null
>>> +++ b/drivers/soc/Kconfig
>>> @@ -0,0 +1,5 @@
>>> +menu "SoC drivers"
>>> +
>>> +source "drivers/soc/imx/Kconfig"
>>> +
>>> +endmenu
>>>
>>
>>
>> -- 
>> Pengutronix e.K.                           |                             |
>> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
>> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
>> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>>
>>
>> To declare a filtering error, please use the following link : https://www.security-mail.net/reporter.php?mid=9c47.61e1ad9d.ae4c.0&r=jmaselbas%40kalray.eu&s=a.fatoum%40pengutronix.de&o=Re%3A+%5BPATCH+10%2F13%5D+drivers%3A+add+soc+hierarchy+properly&verdict=C&c=835ed3aa69d359c0f8acda9912ca30b77899cc91
>>
> 
> 
> 
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From clement.leger at bootlin.com  Fri Jan 14 09:21:09 2022
From: clement.leger at bootlin.com (=?UTF-8?B?Q2zDqW1lbnQgTMOpZ2Vy?=)
Date: Fri, 14 Jan 2022 18:21:09 +0100
Subject: [PATCH 04/13] common: elf: add elf_load_binary
In-Reply-To: <20220114165208.9980-5-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165208.9980-5-jmaselbas@kalray.eu>
Message-ID: <20220114182109.6dfe1836@fixe.home>

Le Fri, 14 Jan 2022 17:52:03 +0100,
Jules Maselbas <jmaselbas at kalray.eu> a ?crit :

> From: Clement Leger <cleger at kalray.eu>
> 
> In order to load elf from a binary buffer, add elf_load_binary. This
> will be used by FIT support to allow loading an elf from FIT.
> 
> Signed-off-by: Clement Leger <cleger at kalray.eu>

Hi Jules,

This is not my mail address anymore, could you update it with
clement.leger at bootlin.com ?

Thanks.

> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> ---
>  common/elf.c  | 83 +++++++++++++++++++++++++++++++++++++--------------
>  include/elf.h |  1 +
>  2 files changed, 62 insertions(+), 22 deletions(-)
> 
> diff --git a/common/elf.c b/common/elf.c
> index af22be37e6..f10fb77953 100644
> --- a/common/elf.c
> +++ b/common/elf.c
> @@ -101,15 +101,17 @@ static int elf_section_cmp(void *priv, struct list_head *a, struct list_head *b)
>  static int load_elf_to_memory(struct elf_image *elf)
>  {
>  	void *dst;
> -	int ret, fd;
> +	int ret, fd = -1;
>  	u64 p_filesz, p_memsz, p_offset;
>  	struct elf_section *r;
>  	struct list_head *list = &elf->list;
>  
> -	fd = open(elf->filename, O_RDONLY);
> -	if (fd < 0) {
> -		pr_err("could not open: %s\n", errno_str());
> -		return -errno;
> +	if (elf->filename) {
> +		fd = open(elf->filename, O_RDONLY);
> +		if (fd < 0) {
> +			pr_err("could not open: %s\n", errno_str());
> +			return -errno;
> +		}
>  	}
>  
>  	list_for_each_entry(r, list, list) {
> @@ -118,21 +120,26 @@ static int load_elf_to_memory(struct elf_image *elf)
>  		p_memsz = elf_phdr_p_memsz(elf, r->phdr);
>  		dst = (void *) (phys_addr_t) elf_phdr_p_paddr(elf, r->phdr);
>  
> -		ret = lseek(fd, p_offset, SEEK_SET);
> -		if (ret == -1) {
> -			pr_err("lseek at offset 0x%llx failed\n", p_offset);
> -			close(fd);
> -			return ret;
> -		}
> -
>  		pr_debug("Loading phdr offset 0x%llx to 0x%p (%llu bytes)\n",
>  			 p_offset, dst, p_filesz);
>  
> -		if (read_full(fd, dst, p_filesz) < 0) {
> -			pr_err("could not read elf segment: %s\n",
> -			       errno_str());
> -			close(fd);
> -			return -errno;
> +		if (fd >= 0) {
> +			ret = lseek(fd, p_offset, SEEK_SET);
> +			if (ret == -1) {
> +				pr_err("lseek at offset 0x%llx failed\n",
> +				       p_offset);
> +				close(fd);
> +				return ret;
> +			}
> +
> +			if (read_full(fd, dst, p_filesz) < 0) {
> +				pr_err("could not read elf segment: %s\n",
> +				       errno_str());
> +				close(fd);
> +				return -errno;
> +			}
> +		} else {
> +			memcpy(dst, elf->hdr_buf + p_offset, p_filesz);
>  		}
>  
>  		if (p_filesz < p_memsz)
> @@ -202,6 +209,37 @@ static int elf_check_image(struct elf_image *elf, void *buf)
>  	return 0;
>  }
>  
> +static void elf_init_struct(struct elf_image *elf)
> +{
> +	INIT_LIST_HEAD(&elf->list);
> +	elf->low_addr = (void *) (unsigned long) -1;
> +	elf->high_addr = 0;
> +	elf->filename = NULL;
> +}
> +
> +struct elf_image *elf_open_binary(void *buf)
> +{
> +	int ret;
> +	struct elf_image *elf;
> +
> +	elf = calloc(1, sizeof(*elf));
> +	if (!elf)
> +		return ERR_PTR(-ENOMEM);
> +
> +	elf_init_struct(elf);
> +
> +	elf->hdr_buf = buf;
> +	ret = elf_check_image(elf, buf);
> +	if (ret) {
> +		free(elf);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	elf->entry = elf_hdr_e_entry(elf, elf->hdr_buf);
> +
> +	return elf;
> +}
> +
>  static struct elf_image *elf_check_init(const char *filename)
>  {
>  	int ret, fd;
> @@ -213,9 +251,7 @@ static struct elf_image *elf_check_init(const char *filename)
>  	if (!elf)
>  		return ERR_PTR(-ENOMEM);
>  
> -	INIT_LIST_HEAD(&elf->list);
> -	elf->low_addr = (void *) (unsigned long) -1;
> -	elf->high_addr = 0;
> +	elf_init_struct(elf);
>  
>  	/* First pass is to read elf header only */
>  	fd = open(filename, O_RDONLY);
> @@ -299,7 +335,10 @@ void elf_close(struct elf_image *elf)
>  {
>  	elf_release_regions(elf);
>  
> -	free(elf->hdr_buf);
> -	free(elf->filename);
> +	if (elf->filename) {
> +		free(elf->hdr_buf);
> +		free(elf->filename);
> +	}
> +
>  	free(elf);
>  }
> diff --git a/include/elf.h b/include/elf.h
> index 7970fd2c95..12673e93ed 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -414,6 +414,7 @@ static inline size_t elf_get_mem_size(struct elf_image *elf)
>  	return elf->high_addr - elf->low_addr;
>  }
>  
> +struct elf_image *elf_open_binary(void *buf);
>  struct elf_image *elf_open(const char *filename);
>  void elf_close(struct elf_image *elf);
>  int elf_load(struct elf_image *elf);



-- 
Cl?ment L?ger,
Embedded Linux and Kernel engineer at Bootlin
https://bootlin.com


From jmaselbas at kalray.eu  Fri Jan 14 09:24:59 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Fri, 14 Jan 2022 18:24:59 +0100
Subject: [PATCH 04/13] common: elf: add elf_load_binary
In-Reply-To: <20220114182109.6dfe1836@fixe.home>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165208.9980-5-jmaselbas@kalray.eu>
 <20220114182109.6dfe1836@fixe.home>
Message-ID: <20220114172459.GD29876@tellis.lin.mbt.kalray.eu>

On Fri, Jan 14, 2022 at 06:21:09PM +0100, Cl?ment L?ger wrote:
> Le Fri, 14 Jan 2022 17:52:03 +0100,
> Jules Maselbas <jmaselbas at kalray.eu> a ?crit :
> 
> > From: Clement Leger <cleger at kalray.eu>
> > 
> > In order to load elf from a binary buffer, add elf_load_binary. This
> > will be used by FIT support to allow loading an elf from FIT.
> > 
> > Signed-off-by: Clement Leger <cleger at kalray.eu>
> 
> Hi Jules,
> 
> This is not my mail address anymore, could you update it with
> clement.leger at bootlin.com ?
Sure can, I wasn't sure which email I should have used. I'll send a v2.

> 
> Thanks.
> 
> > Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> > ---
> >  common/elf.c  | 83 +++++++++++++++++++++++++++++++++++++--------------
> >  include/elf.h |  1 +
> >  2 files changed, 62 insertions(+), 22 deletions(-)
> > 
> > diff --git a/common/elf.c b/common/elf.c
> > index af22be37e6..f10fb77953 100644
> > --- a/common/elf.c
> > +++ b/common/elf.c
> > @@ -101,15 +101,17 @@ static int elf_section_cmp(void *priv, struct list_head *a, struct list_head *b)
> >  static int load_elf_to_memory(struct elf_image *elf)
> >  {
> >  	void *dst;
> > -	int ret, fd;
> > +	int ret, fd = -1;
> >  	u64 p_filesz, p_memsz, p_offset;
> >  	struct elf_section *r;
> >  	struct list_head *list = &elf->list;
> >  
> > -	fd = open(elf->filename, O_RDONLY);
> > -	if (fd < 0) {
> > -		pr_err("could not open: %s\n", errno_str());
> > -		return -errno;
> > +	if (elf->filename) {
> > +		fd = open(elf->filename, O_RDONLY);
> > +		if (fd < 0) {
> > +			pr_err("could not open: %s\n", errno_str());
> > +			return -errno;
> > +		}
> >  	}
> >  
> >  	list_for_each_entry(r, list, list) {
> > @@ -118,21 +120,26 @@ static int load_elf_to_memory(struct elf_image *elf)
> >  		p_memsz = elf_phdr_p_memsz(elf, r->phdr);
> >  		dst = (void *) (phys_addr_t) elf_phdr_p_paddr(elf, r->phdr);
> >  
> > -		ret = lseek(fd, p_offset, SEEK_SET);
> > -		if (ret == -1) {
> > -			pr_err("lseek at offset 0x%llx failed\n", p_offset);
> > -			close(fd);
> > -			return ret;
> > -		}
> > -
> >  		pr_debug("Loading phdr offset 0x%llx to 0x%p (%llu bytes)\n",
> >  			 p_offset, dst, p_filesz);
> >  
> > -		if (read_full(fd, dst, p_filesz) < 0) {
> > -			pr_err("could not read elf segment: %s\n",
> > -			       errno_str());
> > -			close(fd);
> > -			return -errno;
> > +		if (fd >= 0) {
> > +			ret = lseek(fd, p_offset, SEEK_SET);
> > +			if (ret == -1) {
> > +				pr_err("lseek at offset 0x%llx failed\n",
> > +				       p_offset);
> > +				close(fd);
> > +				return ret;
> > +			}
> > +
> > +			if (read_full(fd, dst, p_filesz) < 0) {
> > +				pr_err("could not read elf segment: %s\n",
> > +				       errno_str());
> > +				close(fd);
> > +				return -errno;
> > +			}
> > +		} else {
> > +			memcpy(dst, elf->hdr_buf + p_offset, p_filesz);
> >  		}
> >  
> >  		if (p_filesz < p_memsz)
> > @@ -202,6 +209,37 @@ static int elf_check_image(struct elf_image *elf, void *buf)
> >  	return 0;
> >  }
> >  
> > +static void elf_init_struct(struct elf_image *elf)
> > +{
> > +	INIT_LIST_HEAD(&elf->list);
> > +	elf->low_addr = (void *) (unsigned long) -1;
> > +	elf->high_addr = 0;
> > +	elf->filename = NULL;
> > +}
> > +
> > +struct elf_image *elf_open_binary(void *buf)
> > +{
> > +	int ret;
> > +	struct elf_image *elf;
> > +
> > +	elf = calloc(1, sizeof(*elf));
> > +	if (!elf)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	elf_init_struct(elf);
> > +
> > +	elf->hdr_buf = buf;
> > +	ret = elf_check_image(elf, buf);
> > +	if (ret) {
> > +		free(elf);
> > +		return ERR_PTR(-EINVAL);
> > +	}
> > +
> > +	elf->entry = elf_hdr_e_entry(elf, elf->hdr_buf);
> > +
> > +	return elf;
> > +}
> > +
> >  static struct elf_image *elf_check_init(const char *filename)
> >  {
> >  	int ret, fd;
> > @@ -213,9 +251,7 @@ static struct elf_image *elf_check_init(const char *filename)
> >  	if (!elf)
> >  		return ERR_PTR(-ENOMEM);
> >  
> > -	INIT_LIST_HEAD(&elf->list);
> > -	elf->low_addr = (void *) (unsigned long) -1;
> > -	elf->high_addr = 0;
> > +	elf_init_struct(elf);
> >  
> >  	/* First pass is to read elf header only */
> >  	fd = open(filename, O_RDONLY);
> > @@ -299,7 +335,10 @@ void elf_close(struct elf_image *elf)
> >  {
> >  	elf_release_regions(elf);
> >  
> > -	free(elf->hdr_buf);
> > -	free(elf->filename);
> > +	if (elf->filename) {
> > +		free(elf->hdr_buf);
> > +		free(elf->filename);
> > +	}
> > +
> >  	free(elf);
> >  }
> > diff --git a/include/elf.h b/include/elf.h
> > index 7970fd2c95..12673e93ed 100644
> > --- a/include/elf.h
> > +++ b/include/elf.h
> > @@ -414,6 +414,7 @@ static inline size_t elf_get_mem_size(struct elf_image *elf)
> >  	return elf->high_addr - elf->low_addr;
> >  }
> >  
> > +struct elf_image *elf_open_binary(void *buf);
> >  struct elf_image *elf_open(const char *filename);
> >  void elf_close(struct elf_image *elf);
> >  int elf_load(struct elf_image *elf);
> 
> 
> 
> -- 
> Cl?ment L?ger,
> Embedded Linux and Kernel engineer at Bootlin
> https://bootlin.com
> 
> 
> To declare a filtering error, please use the following link : https://www.security-mail.net/reporter.php?mid=4ac2.61e1b140.5ccaa.0&r=jmaselbas%40kalray.eu&s=clement.leger%40bootlin.com&o=Re%3A+%5BPATCH+04%2F13%5D+common%3A+elf%3A+add+elf_load_binary&verdict=C&c=04c6694098bfe40fcf917d53db30d187c519bf62
> 






From clement.leger at bootlin.com  Fri Jan 14 09:31:12 2022
From: clement.leger at bootlin.com (=?UTF-8?B?Q2zDqW1lbnQgTMOpZ2Vy?=)
Date: Fri, 14 Jan 2022 18:31:12 +0100
Subject: [PATCH 13/13] kvx: dts: Update k200.dts
In-Reply-To: <20220114165456.10542-4-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165456.10542-1-jmaselbas@kalray.eu>
 <20220114165456.10542-4-jmaselbas@kalray.eu>
Message-ID: <20220114183112.6145264e@fixe.home>

Le Fri, 14 Jan 2022 17:54:56 +0100,
Jules Maselbas <jmaselbas at kalray.eu> a ?crit :

> +		apb {
> +			compatible = "simple-bus";
> +			#address-cells = <2>;
> +			#size-cells = <2>;
> +			ranges;
> +
> +			gpio0: gpio at 20230000 {
> +				compatible = "snps,dw-apb-gpio";
> +				reg = <0x0 0x20230000 0x0 0x1000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				gpio0_banka: gpio-controller at 0 {
> +					compatible = "snps,dw-apb-gpio-port";
> +					#address-cells = <0>;
> +					gpio-controller;
> +					#gpio-cells = <2>;
> +					snps,nr-gpios = <32>;
> +					snps,has-pinctrl;
> +					reg = <0>;
> +					interrupt-parent = <&itgen_soc_periph0>;
> +					interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
> +					/* All pins of port A are interrupt capable */
> +					interrupt-controller;
> +					#interrupt-cells = <2>;
> +
> +					uart0_pins: pinmux_uart0_pins {
> +						function = "hw";
> +						pins = "pin0", "pin1";
> +					};
> +					uart1_pins: pinmux_uart1_pins {
> +						function = "hw";
> +						pins = "pin2", "pin3";
> +					};
> +					uart2_pins: pinmux_uart2_pins {
> +						function = "hw";
> +						pins = "pin4", "pin5";
> +					};
> +					can0_pins: pinmux_can0_pins {
> +						function = "hw";
> +						pins = "pin6", "pin7";
> +					};
> +					can1_pins: pinmux_can1_pins {
> +						function = "hw";
> +						pins = "pin8", "pin9";
> +					};
> +					i2c0_pins: pinmux_i2c0_pins {
> +						function = "hw";
> +						pins = "pin10", "pin11";
> +					};
> +					smb1_pins: pinmux_smb1_pins {
> +						function = "hw";
> +						pins = "pin12", "pin13";
> +					};
> +					smb2_pins: pinmux_smb2_pins {
> +						function = "hw";
> +						pins = "pin14", "pin15";
> +					};
> +					qspi0_master_pins:pinmux_qspi0_master_pins {
> +						function = "hw";
> +						pins = "pin18", "pin19", "pin20", "pin21", "pin22", "pin23", "pin24";
> +					};
> +					spi_slave_pins:pinmux_spi_slave_pins {
> +						function = "hw";
> +						pins = "pin25", "pin26", "pin27", "pin28";
> +					};
> +					timer0_pins:pinmux_timer0_pins {
> +						function = "hw";
> +						pins = "pin29";
> +					};
> +					timer1_pins:pinmux_timer1_pins {
> +						function = "hw";
> +						pins = "pin30";
> +					};
> +					timer2_pins:pinmux_timer2_pins {
> +						function = "hw";
> +						pins = "pin31";
> +					};

Hi Jules,

I'm afraid this won't work at all since the upstream
snps,dw-apb-gpio compatible driver does not handle pinctrl yet. The
support for that is in your private tree I guess [1].

Cl?ment

[1]
https://github.com/kalray/barebox/blob/coolidge/drivers/pinctrl/pinctrl-dw.c
> +				};
> +			};
> +
> +			gpio1: gpio at 20231000 {
> +				compatible = "snps,dw-apb-gpio";
> +				reg = <0x0 0x20231000 0x0 0x1000>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				gpio1_banka: gpio-controller at 0 {
> +					compatible = "snps,dw-apb-gpio-port";
> +					#address-cells = <0>;
> +					gpio-controller;
> +					#gpio-cells = <2>;
> +					snps,nr-gpios = <32>;
> +					snps,has-pinctrl;
> +					reg = <0>;
> +					interrupt-parent = <&itgen_soc_periph0>;
> +					interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
> +					/* All pins of port A are interrupt capable */
> +					interrupt-controller;
> +					#interrupt-cells = <2>;
> +
> +					uart3_pins: pinmux_uart3_pins {
> +						function = "hw";
> +						pins = "pin0", "pin1";
> +					};
> +					uart4_pins: pinmux_uart4_pins {
> +						function = "hw";
> +						pins = "pin2", "pin3";
> +					};
> +					uart5_pins: pinmux_uart5_pins {
> +						function = "hw";
> +						pins = "pin4", "pin5";
> +					};
> +					can2_pins: pinmux_can2_pins {
> +						function = "hw";
> +						pins = "pin6", "pin7";
> +					};
> +					can3_pins: pinmux_can3_pins {
> +						function = "hw";
> +						pins = "pin8", "pin9";
> +					};
> +					i2c3_pins: pinmux_i2c3_pins {
> +						function = "hw";
> +						pins = "pin10", "pin11";
> +					};
> +					smb4_pins: pinmux_smb4_pins {
> +						function = "hw";
> +						pins = "pin12", "pin13";
> +					};
> +					timer3_pins:pinmux_timer3_pins {
> +						function = "hw";
> +						pins = "pin15";
> +					};
> +					timer4_pins:pinmux_timer4_pins {
> +						function = "hw";
> +						pins = "pin16";
> +					};
> +					timer5_pins:pinmux_timer5_pins {
> +						function = "hw";
> +						pins = "pin17";
> +					};
> +					qspi1_master_pins:pinmux_qspi1_master_pins {
> +						function = "hw";
> +						pins = "pin18", "pin19", "pin20", "pin21", "pin22", "pin23", "pin24";
> +					};
> +					qspi2_master_pins:pinmux_qspi2_master_pins {
> +						function = "hw";
> +						pins = "pin25", "pin26", "pin27", "pin28", "pin29", "pin30", "pin31";
> +					};
> +				};
> +			};
>  		};
>  	};
>  };


-- 
Cl?ment L?ger,
Embedded Linux and Kernel engineer at Bootlin
https://bootlin.com


From frank-w at public-files.de  Sat Jan 15 05:47:42 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Sat, 15 Jan 2022 14:47:42 +0100
Subject: Aw: Re: Re: Re: Re: barebox extending boot-scripts
In-Reply-To: <20220110094214.GG6003@pengutronix.de>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
 <trinity-7a53a76e-9836-482e-861e-31439f242e2d-1641472899713@3c-app-gmx-bs51>
 <20220107130751.GW6003@pengutronix.de>
 <trinity-f8991630-17eb-4ae0-9dfa-9a66bc41b02e-1641573741990@3c-app-gmx-bs48>
 <20220110094214.GG6003@pengutronix.de>
Message-ID: <trinity-dcf71a1e-4856-486b-a9a5-74ed6a82fd34-1642254462656@3c-app-gmx-bap71>

Hi,

i have now created a new barebox board as copy from evb. i can load it from tftp with

bootm /mnt/tftp/barebox-rk3568-r2pro.img

i can create a bootmenu with entries of loader/entries and boot it:

boot -m sd.1

my bootscripts are also there, but they are not listed in $global.boot.default

$ grep defaultenv arch/arm/boards/bananapi-r2-pro/Makefile
bbenv-y += defaultenv-rk3568
$ grep defaultenv arch/arm/boards/bananapi-r2-pro/board.c
	defaultenv_append_directory(defaultenv_rk3568);
$ cat arch/arm/boards/bananapi-r2-pro/defaultenv-rk3568/nv/boot.default
net list-images mmc-linux tftp-linux

so it looks like the env is load, but the nv is not updated

regards Frank


> Gesendet: Montag, 10. Januar 2022 um 10:42 Uhr
> Von: "Sascha Hauer" <sha at pengutronix.de>
> An: "Frank Wunderlich" <frank-w at public-files.de>
> Cc: "Ahmad Fatoum" <a.fatoum at pengutronix.de>, barebox at lists.infradead.org
> Betreff: Re: Re: Re: Re: barebox extending boot-scripts
>
> On Fri, Jan 07, 2022 at 05:42:22PM +0100, Frank Wunderlich wrote:
> > Hi
> >
> > missed the defaultenv_append_directory(defaultenv_rk3568); in board-file...after adding that it seems to work
> >
> > > Gesendet: Freitag, 07. Januar 2022 um 14:07 Uhr
> > > Von: "Sascha Hauer" <sha at pengutronix.de>
> > >
> > > Yes. Furthermore you have to add to the board code:
> > >
> > > 	defaultenv_append_directory(defaultenv_rk3568);
> >
> > maybe this is the part i've missed. i thought it were 2 ways...either link via makefile or add to boards code
> >
> > > > > > > Boot scripts for publicly available evaluation kits are often not good candidates
> > > > > > > for upstreaming, because everybody using the EVKs has different thoughts on how to
> > > > > > > boot. The best way would be to use bootloader spec. It's one or more files you
> > > > > > > place at a known location that describe where your kernel and device tree are and
> > > > > > > what command line arguments to use and barebox can then automatically generate
> > > > > > > boot entries from all available bootloader spec files.
> > > >
> > > > is extlinux (i used in uboot and conf-file is already present) supported here?
> > > >
> > > > > > > See https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf for an example
> > > > > > > of how to set this up. This is what I'd recommend instead of writing your own
> > > > > > > scripts.
> > > >
> > > > i do not fully understand the bootloader spec in the pdf as config file seems to be
> > > >
> > > > /mnt/mmc0.4/loader/entries/stm32mp157c-dk2.conf
> > > >
> > > > and then
> > > > boot -d mmc0.4
> > > >
> > > > is run...so the path (loader/entries) seems to be fixed and all files there will be processed (which order)?
> > >
> > > Yes. No particular order, I guess it would be the order it is on the
> > > filesystem.
> > >
> > > > how is root appended (/dev/mmcblkXpY|uuid|...) when linux-appendroot is set to true?
> > >
> > > When root is appended it is assumed to be the same fs that also has the
> > > bootloader spec file, so the rootfs also has the entry and the kernel.
> >
> > ok, then this is not usable for me, as i have a boot-partition
> > (bootloader+kernel+dtb) and separate rootfs-partition
> >
> > > > this is for testing multiple kernels with changing filenames (very
> > > > dynamic process, e.g. using 1 kernel binary with multiple dtb) and to
> > > > avoid adding a bootmenu entry everytime....this is not for end-user :)
> > >
> > > In that case you could also use bootm directly.
> >
> > yes but my approach is to list the available kernels before and ask to
> > enter the filename to not everytime look for correct commands ;)
> >
> > > > and here scripting is imho the best way...this allows me to add extra
> > > > params to cmdline too (like debug level,dumping offsets) without
> > > > changing a distroboot config
> > >
> > > Not sure if you know already, but barebox concatenates all variables in
> > > the "global.linux.bootargs." namespace to the kernel command line, so
> > > you can easily add or remove a variable to add/remove kernel options
> > > without affecting unrelated options.
> >
> > i know some options from documentation like this i've used to get a earlycon for tftp
> >
> > global linux.bootargs.debug="earlycon=uart8250,mmio32,0xfe660000 earlyprintk"
> >
> > > > for fixed kernels i have defined an extlinux.conf for uboot, but i'm
> > > > unsure if barebox can use this file too. have not found anything about
> > > > extlinux/syslinux in barebox yet.
> > >
> > > No, not yet.
> >
> > ok, i created a bootloader-config like described in the pdf:
> >
> > cat /mnt/sd.1/loader/entries/linux-gz.conf
> > title Linux GZip
> > version 5.16
> > options earlycon=uart8250,mmio32,0xfe660000 console=ttyS2,1500000n8
> > linux /extlinux/Image_5.16.gz
> > devicetree /extlinux/dtb_5.16
> > initrd /rootfs.cpio.lz4
> >
> > but on starting it is skipped due to devicetree mismatch
> >
> > boot -d sd.1
> > blspec: ignoring entry with incompatible devicetree "rockchip,rk3568-bpi-r2pro"
> > blspec: ignoring entry with incompatible devicetree "rockchip,rk3568-bpi-r2pro"
> > Nothing bootable found on 'sd.1'
> > Nothing bootable found
> >
> > in barebox i use the evb whereas in linux i already have a separate
> > dts. Can i override the compatible for the bootloader or do i need to
> > add my board (as copy of evb first)?
>
> You can overwrite the compatible using the of_property command. However,
> I really recommend to add a separate barebox board for your board.
> Sooner or later you'll have to do this anyway and it's the only way to
> properly add quirks for your board.

have now added a new barebox-board, and now this seems to work, but it's booting the first entry and do not display a menu of all configs in loader/entries, is this possible?


From dev at lynxeye.de  Sun Jan 16 13:32:21 2022
From: dev at lynxeye.de (Lucas Stach)
Date: Sun, 16 Jan 2022 22:32:21 +0100
Subject: [PATCH 3/3] ARM: mnt-reform: switch to deep-probe
In-Reply-To: <20220116213221.3466936-1-dev@lynxeye.de>
References: <20220116213221.3466936-1-dev@lynxeye.de>
Message-ID: <20220116213221.3466936-3-dev@lynxeye.de>

Now that all drivers used on this platform properly handle deep-probe,
we can switch it on.

Signed-off-by: Lucas Stach <dev at lynxeye.de>
---
 arch/arm/boards/mnt-reform/board.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boards/mnt-reform/board.c b/arch/arm/boards/mnt-reform/board.c
index feb874c0a0ef..010690ecbd6c 100644
--- a/arch/arm/boards/mnt-reform/board.c
+++ b/arch/arm/boards/mnt-reform/board.c
@@ -5,6 +5,7 @@
 
 #include <bootsource.h>
 #include <common.h>
+#include <deep-probe.h>
 #include <init.h>
 #include <mach/bbu.h>
 
@@ -31,6 +32,7 @@ static const struct of_device_id mnt_reform_of_match[] = {
 	{ .compatible = "mntre,reform2"},
 	{ /* sentinel */ },
 };
+BAREBOX_DEEP_PROBE_ENABLE(mnt_reform_of_match);
 
 static struct driver_d mnt_reform_board_driver = {
 	.name = "board-mnt-reform",
-- 
2.31.1



From dev at lynxeye.de  Sun Jan 16 13:32:19 2022
From: dev at lynxeye.de (Lucas Stach)
Date: Sun, 16 Jan 2022 22:32:19 +0100
Subject: [PATCH 1/3] clk: ignore of_device_ensure_probed error in clock lookup
Message-ID: <20220116213221.3466936-1-dev@lynxeye.de>

For CLK_OF_DECLARE clocks there is no driver that is bound to the device,
so the lookup fails before even trying to find the provider, breaking
the parent_ready() logic used when initializing the declared providers.

Ignore the return code from of_device_ensure_probed to allow the lookup
to proceed as usual. If of_device_ensure_probed the lookup will also fail,
as no provider will be found.

Signed-off-by: Lucas Stach <dev at lynxeye.de>
---
 drivers/clk/clk.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 189c9c62df5c..a1d1d7f1a467 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -643,11 +643,9 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
 {
 	struct of_clk_provider *provider;
 	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
-	int ret;
 
-	ret = of_device_ensure_probed(clkspec->np);
-	if (ret)
-		return ERR_PTR(ret);
+	/* Ignore error, as CLK_OF_DECLARE clocks have no proper driver. */
+	of_device_ensure_probed(clkspec->np);
 
 	/* Check if we have such a provider in our array */
 	list_for_each_entry(provider, &of_clk_providers, link) {
-- 
2.31.1



From dev at lynxeye.de  Sun Jan 16 13:32:20 2022
From: dev at lynxeye.de (Lucas Stach)
Date: Sun, 16 Jan 2022 22:32:20 +0100
Subject: [PATCH 2/3] soc: imx: gpcv2: split PGC domain probe in two passes
In-Reply-To: <20220116213221.3466936-1-dev@lynxeye.de>
References: <20220116213221.3466936-1-dev@lynxeye.de>
Message-ID: <20220116213221.3466936-2-dev@lynxeye.de>

Currently it is possible that the platform device for a nested PGC
domain is added before the parent PGC device is there, which leads to
-EPROBE_DEFER when probing the driver. With normal probe this isn't
an issue, as the probe will be retried. With deep-probe this is fatal,
as the PGC domain devices aren't probed from DT, but via registration
of platform devices from the GPC driver, so the usual deep-probe
approach to ensure the devices are probed before the lookup isn't
working in this case.

Make sure to register the PGC domain platform devices in the correct
order to avoid the EPROBE_DEFER altogether.

Signed-off-by: Lucas Stach <dev at lynxeye.de>
---
 drivers/soc/imx/gpcv2.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index bc373ecf40cc..8abeb15d0378 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -429,7 +429,7 @@ static int imx_gpcv2_probe(struct device_d *dev)
 	struct device_node *pgc_np, *np;
 	struct resource *res;
 	void __iomem *base;
-	int ret;	
+	int ret, pass = 0;
 
 	pgc_np = of_get_child_by_name(dev->device_node, "pgc");
 	if (!pgc_np) {
@@ -445,10 +445,23 @@ static int imx_gpcv2_probe(struct device_d *dev)
 
 	domain_data = of_device_get_match_data(dev);
 
+	/*
+	 * Run two passes for the registration of the PGC domain platform
+	 * devices: first all devices that are not part of a power-domain
+	 * themselves, then all the others. This avoids -EPROBE_DEFER being
+	 * returned for nested domains, that need their parent PGC domains
+	 * to be present on probe.
+	 */
+again:
 	for_each_child_of_node(pgc_np, np) {
-		struct device_d *pd_dev;
+		bool child_domain = of_property_read_bool(np, "power-domains");
 		struct imx_pgc_domain *domain;
+		struct device_d *pd_dev;
 		u32 domain_index;
+
+		if ((pass == 0 && child_domain) || (pass == 1 && !child_domain))
+			continue;
+
 		ret = of_property_read_u32(np, "reg", &domain_index);
 		if (ret) {
 			dev_err(dev, "Failed to read 'reg' property\n");
@@ -481,6 +494,11 @@ static int imx_gpcv2_probe(struct device_d *dev)
 			return ret;
 	}
 
+	if (pass == 0) {
+		pass++;
+		goto again;
+	}
+
 	return 0;
 }
 
-- 
2.31.1



From a.fatoum at pengutronix.de  Sun Jan 16 21:12:55 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Jan 2022 06:12:55 +0100
Subject: [PATCH 1/3] clk: ignore of_device_ensure_probed error in clock
 lookup
In-Reply-To: <20220116213221.3466936-1-dev@lynxeye.de>
References: <20220116213221.3466936-1-dev@lynxeye.de>
Message-ID: <095bafc0-7261-aa13-a9c7-8022cc78b26c@pengutronix.de>

Hello Lucas,

On 16.01.22 22:32, Lucas Stach wrote:
> For CLK_OF_DECLARE clocks there is no driver that is bound to the device,
> so the lookup fails before even trying to find the provider, breaking
> the parent_ready() logic used when initializing the declared providers.
> 
> Ignore the return code from of_device_ensure_probed to allow the lookup
> to proceed as usual. If of_device_ensure_probed the lookup will also fail,
> as no provider will be found.

This seems to be an alternate fix for the issue addressed by:
bd516e38dd14 ("clk: handle CLK_OF_DECLARE in deep probe")

What do you think?

> 
> Signed-off-by: Lucas Stach <dev at lynxeye.de>
> ---
>  drivers/clk/clk.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 189c9c62df5c..a1d1d7f1a467 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -643,11 +643,9 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
>  {
>  	struct of_clk_provider *provider;
>  	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
> -	int ret;
>  
> -	ret = of_device_ensure_probed(clkspec->np);
> -	if (ret)
> -		return ERR_PTR(ret);
> +	/* Ignore error, as CLK_OF_DECLARE clocks have no proper driver. */
> +	of_device_ensure_probed(clkspec->np);
>  
>  	/* Check if we have such a provider in our array */
>  	list_for_each_entry(provider, &of_clk_providers, link) {
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 17 00:24:19 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Jan 2022 09:24:19 +0100
Subject: [PATCH 08/13] nvmem: add kvx otp non volatile regbank support
In-Reply-To: <20220114165208.9980-9-jmaselbas@kalray.eu>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165208.9980-9-jmaselbas@kalray.eu>
Message-ID: <20220117082419.GA1121@pengutronix.de>

On Fri, Jan 14, 2022 at 05:52:07PM +0100, Jules Maselbas wrote:
> From: Clement Leger <cleger at kalray.eu>
> 
> Backport Linux driver to barebox to access nvmem.
> 
> Signed-off-by: Clement Leger <cleger at kalray.eu>
> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
> ---
>  drivers/nvmem/Kconfig      |  7 +++
>  drivers/nvmem/Makefile     |  3 ++
>  drivers/nvmem/kvx-otp-nv.c | 99 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 109 insertions(+)
>  create mode 100644 drivers/nvmem/kvx-otp-nv.c
> 
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index 07320101b8..3624cc64b6 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -66,6 +66,13 @@ config STM32_BSEC
>  	  This adds support for the STM32 OTP controller. Reads and writes
>  	  to will go to the shadow RAM, not the OTP fuses themselvers.
>  
> +config KVX_OTP_NV
> +	tristate "kalray KVX OTP Non volatile regs Support"
> +	depends on KVX
> +	help
> +	  This is a simple driver to dump specified values of KVX OTP non
> +	  volatile regs.
> +
>  config STARFIVE_OTP
>  	tristate "Starfive OTP Supprot"
>  	depends on SOC_STARFIVE
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index cd970aaea1..81629ddb27 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -24,4 +24,7 @@ nvmem_eeprom_93xx46-y		:= eeprom_93xx46.o
>  obj-$(CONFIG_STM32_BSEC)	+= nvmem_bsec.o
>  nvmem_bsec-y			:= bsec.o
>  
> +obj-$(CONFIG_KVX_OTP_NV)	+= nvmem-kvx-otp-nv.o
> +nvmem-kvx-otp-nv-y		:= kvx-otp-nv.o
> +
>  obj-$(CONFIG_STARFIVE_OTP)	+= starfive-otp.o
> diff --git a/drivers/nvmem/kvx-otp-nv.c b/drivers/nvmem/kvx-otp-nv.c
> new file mode 100644
> index 0000000000..f997f8a63b
> --- /dev/null
> +++ b/drivers/nvmem/kvx-otp-nv.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2020 Kalray Inc., Cl?ment L?ger
> + */
> +
> +#include <common.h>
> +#include <driver.h>
> +#include <malloc.h>
> +#include <xfuncs.h>
> +#include <errno.h>
> +#include <init.h>
> +#include <net.h>
> +#include <io.h>
> +
> +#include <linux/nvmem-provider.h>
> +
> +#define OTP_NV_ALIGN		4
> +#define OTP_NV_ALIGN_MASK	(OTP_NV_ALIGN - 1)
> +
> +struct kvx_otp_nv_priv {
> +	void __iomem *base;
> +};
> +
> +static int kvx_otp_nv_read(void *context, unsigned int offset,
> +			  void *_val, size_t bytes)
> +{
> +	struct kvx_otp_nv_priv *priv = context;
> +	u8 *val = _val;
> +	u32 tmp, copy_size;
> +	u8 skip = offset & OTP_NV_ALIGN_MASK;
> +
> +	offset &= ~OTP_NV_ALIGN_MASK;
> +
> +	while (bytes) {
> +		tmp = readl(priv->base + offset);
> +		if (skip != 0)
> +			copy_size = min(OTP_NV_ALIGN - skip, (int) bytes);
> +		else
> +			copy_size = min(bytes, sizeof(tmp));
> +
> +		memcpy(val, ((u8 *) &tmp) + skip, copy_size);
> +		if (skip != 0)
> +			skip = 0;

The if() here is unnecessary.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From jbe at pengutronix.de  Mon Jan 17 00:59:06 2022
From: jbe at pengutronix.de (Juergen Borleis)
Date: Mon, 17 Jan 2022 09:59:06 +0100
Subject: Add core driver for PMIC rn5t568
Message-ID: <20220117085908.36460-1-jbe@pengutronix.de>

This change adds the core regmap based access driver and its corresponding watchdog
for the former Ricoh (now: Nisshinbo Micro Devices Inc) rn5t568 PMIC device.

Supported features are: watchdog, PMIC based power cycle and reset source detection.

Singed-off-by: Juergen Borleis <jbe at pengutronix.de>




From jbe at pengutronix.de  Mon Jan 17 00:59:07 2022
From: jbe at pengutronix.de (Juergen Borleis)
Date: Mon, 17 Jan 2022 09:59:07 +0100
Subject: [PATCH 1/2] Add the base Ricoh RN5T568 PMIC driver
In-Reply-To: <20220117085908.36460-1-jbe@pengutronix.de>
References: <20220117085908.36460-1-jbe@pengutronix.de>
Message-ID: <20220117085908.36460-2-jbe@pengutronix.de>

---
 drivers/mfd/Kconfig   |   6 ++
 drivers/mfd/Makefile  |   1 +
 drivers/mfd/rn5t568.c | 165 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 172 insertions(+)
 create mode 100644 drivers/mfd/rn5t568.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8468a2d..1602480 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -68,6 +68,12 @@ config MFD_STPMIC1
 	help
 	  Select this to support communication with the STPMIC1.
 
+config MFD_RN568PMIC
+	depends on I2C
+	bool "Ricoh RN5T568 MFD driver"
+	help
+	  Select this to support communication with the Ricoh RN5T568 PMIC.
+
 config MFD_SUPERIO
 	bool
 
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2bcf900..50f54cf 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_TWL4030)	+= twl4030.o
 obj-$(CONFIG_MFD_TWL6030)	+= twl6030.o
 obj-$(CONFIG_RAVE_SP_CORE)	+= rave-sp.o
 obj-$(CONFIG_MFD_STPMIC1)	+= stpmic1.o
+obj-$(CONFIG_MFD_RN568PMIC)	+= rn5t568.o
 obj-$(CONFIG_MFD_SUPERIO)	+= superio.o
 obj-$(CONFIG_FINTEK_SUPERIO)	+= fintek-superio.o
 obj-$(CONFIG_SMSC_SUPERIO)	+= smsc-superio.o
diff --git a/drivers/mfd/rn5t568.c b/drivers/mfd/rn5t568.c
new file mode 100644
index 0000000..ad53d7b
--- /dev/null
+++ b/drivers/mfd/rn5t568.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MFD core driver for Ricoh RN5T618 PMIC
+ * Note: Manufacturer is now Nisshinbo Micro Devices Inc.
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani at gmail.com>
+ * Copyright (C) 2016 Toradex AG
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <i2c/i2c.h>
+#include <init.h>
+#include <of.h>
+#include <regmap.h>
+#include <reset_source.h>
+#include <restart.h>
+
+#define RN5T568_LSIVER 0x00
+#define RN5T568_OTPVER 0x01
+#define RN5T568_PONHIS 0x09
+# define RN5T568_PONHIS_ON_EXTINPON BIT(3)
+# define RN5T568_PONHIS_ON_REPWRPON BIT(1)
+# define RN5T568_PONHIS_ON_PWRONPON BIT(0)
+#define RN5T568_POFFHIS 0x0a
+# define RN5T568_POFFHIS_N_OEPOFF BIT(7)
+# define RN5T568_POFFHIS_DCLIMPOFF BIT(6)
+# define RN5T568_POFFHIS_WDGPOFF BIT(5)
+# define RN5T568_POFFHIS_CPUPOFF BIT(4)
+# define RN5T568_POFFHIS_IODETPOFF BIT(3)
+# define RN5T568_POFFHIS_VINDETPOFF BIT(2)
+# define RN5T568_POFFHIS_TSHUTPOFF BIT(1)
+# define RN5T568_POFFHIS_PWRONPOFF BIT(0)
+#define RN5T568_SLPCNT 0x0e
+# define RN5T568_SLPCNT_SWPPWROFF BIT(0)
+#define RN5T568_REPCNT 0x0f
+# define RN5T568_REPCNT_OFF_RESETO_16MS 0x30
+# define RN5T568_REPCNT_OFF_REPWRTIM_1000MS 0x06
+# define RN5T568_REPCNT_OFF_REPWRON BIT(0)
+#define RN5T568_MAX_REG 0xbc
+
+struct rn5t568 {
+	struct restart_handler restart;
+	struct regmap *regmap;
+};
+
+static struct rn5t568 single_pmic;
+
+static void rn5t568_restart(struct restart_handler *rst)
+{
+	struct rn5t568 *rn5t568 = container_of(rst, struct rn5t568, restart);
+
+	regmap_write(rn5t568->regmap, RN5T568_SLPCNT, RN5T568_SLPCNT_SWPPWROFF);
+}
+
+static int rn5t568_reset_reason_detect(struct device_d *dev, struct regmap *regmap)
+{
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(regmap, RN5T568_PONHIS, &reg);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "Power-on history: %x\n", reg);
+
+	if (reg == 0) {
+		dev_info(dev, "No power-on reason available\n");
+		return 0;
+	}
+
+	if (reg & RN5T568_PONHIS_ON_EXTINPON) {
+		reset_source_set_device(dev, RESET_POR);
+		return 0;
+	} else if (reg & RN5T568_PONHIS_ON_PWRONPON) {
+		reset_source_set_device(dev, RESET_POR);
+		return 0;
+	} else if (!(reg & RN5T568_PONHIS_ON_REPWRPON))
+		return -EINVAL;
+
+	ret = regmap_read(regmap, RN5T568_POFFHIS, &reg);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "Power-off history: %x\n", reg);
+
+	if (reg & RN5T568_POFFHIS_PWRONPOFF)
+		reset_source_set_device(dev, RESET_POR);
+	else if (reg & RN5T568_POFFHIS_TSHUTPOFF)
+		reset_source_set_device(dev, RESET_THERM);
+	else if (reg & RN5T568_POFFHIS_VINDETPOFF)
+		reset_source_set_device(dev, RESET_BROWNOUT);
+	else if (reg & RN5T568_POFFHIS_IODETPOFF)
+		reset_source_set_device(dev, RESET_UKWN);
+	else if (reg & RN5T568_POFFHIS_CPUPOFF)
+		reset_source_set_device(dev, RESET_RST);
+	else if (reg & RN5T568_POFFHIS_WDGPOFF)
+		reset_source_set_device(dev, RESET_WDG);
+	else if (reg & RN5T568_POFFHIS_DCLIMPOFF)
+		reset_source_set_device(dev, RESET_BROWNOUT);
+	else if (reg & RN5T568_POFFHIS_N_OEPOFF)
+		reset_source_set_device(dev, RESET_EXT);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct regmap_config rn5t568_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= RN5T568_MAX_REG,
+};
+
+static int __init rn5t568_i2c_probe(struct device_d *dev)
+{
+	static const unsigned int val = RN5T568_REPCNT_OFF_RESETO_16MS | RN5T568_REPCNT_OFF_REPWRTIM_1000MS | RN5T568_REPCNT_OFF_REPWRON;
+	unsigned char reg[4];
+	int ret;
+
+	single_pmic.regmap = regmap_init_i2c(to_i2c_client(dev), &rn5t568_regmap_config);
+	if (IS_ERR(single_pmic.regmap))
+		return PTR_ERR(single_pmic.regmap);
+
+	ret = regmap_register_cdev(single_pmic.regmap, NULL);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_read(single_pmic.regmap, RN5T568_LSIVER, &reg, 2);
+	if (ret) {
+		dev_err(dev, "Failed to read PMIC version via I2C\n");
+		return ret;
+	}
+
+	dev_info(dev, "Found NMD RN5T568 LSI %x, OTP: %x\n", reg[0], reg[1]);
+
+	/* used to trigger software reset and by a watchdog trigger */
+	regmap_write(single_pmic.regmap, RN5T568_REPCNT, val);
+
+	single_pmic.restart.priority = of_get_restart_priority(dev->device_node);
+	single_pmic.restart.name = "RN5T568";
+	single_pmic.restart.restart = &rn5t568_restart;
+	restart_handler_register(&single_pmic.restart);
+	dev_dbg(dev, "RN5t: Restart handler with priority %d registered\n", single_pmic.restart.priority);
+
+	ret = rn5t568_reset_reason_detect(dev, single_pmic.regmap);
+	if (ret)
+		dev_warn(dev, "Failed to query reset reason\n");
+
+	return of_platform_populate(dev->device_node, NULL, dev);
+}
+
+static __maybe_unused const struct of_device_id rn5t568_of_match[] = {
+	{ .compatible = "ricoh,rn5t568", .data = NULL, },
+	{ }
+};
+
+static struct driver_d rn5t568_i2c_driver = {
+	.name		= "rn5t568-i2c",
+	.probe		= rn5t568_i2c_probe,
+	.of_compatible	= DRV_OF_COMPAT(rn5t568_of_match),
+};
+
+coredevice_i2c_driver(rn5t568_i2c_driver);
-- 
2.30.2



From jbe at pengutronix.de  Mon Jan 17 00:59:08 2022
From: jbe at pengutronix.de (Juergen Borleis)
Date: Mon, 17 Jan 2022 09:59:08 +0100
Subject: [PATCH 2/2] Add Ricoh RN5T568 PMIC based watchdog
In-Reply-To: <20220117085908.36460-1-jbe@pengutronix.de>
References: <20220117085908.36460-1-jbe@pengutronix.de>
Message-ID: <20220117085908.36460-3-jbe@pengutronix.de>

---
 drivers/watchdog/Kconfig       |   6 ++
 drivers/watchdog/Makefile      |   1 +
 drivers/watchdog/rn5t568_wdt.c | 140 +++++++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+)
 create mode 100644 drivers/watchdog/rn5t568_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index d605e62..61a096b 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -109,6 +109,12 @@ config STPMIC1_WATCHDOG
 	help
 	  Enable to support configuration of the stpmic1's built-in watchdog.
 
+config RN568_WATCHDOG
+	bool "Ricoh RN5t568 PMIC based Watchdog"
+	depends on MFD_RN568PMIC
+	help
+	  Enable to support system control via the PMIC based watchdog.
+
 config F71808E_WDT
 	bool "Fintek F718xx, F818xx Super I/O Watchdog"
 	depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index dbb76a5..84fd2bf 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_BCM283X) += bcm2835_wdt.o
 obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
 obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o
 obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
+obj-$(CONFIG_RN568_WATCHDOG) += rn5t568_wdt.o
 obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
 obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
 obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
diff --git a/drivers/watchdog/rn5t568_wdt.c b/drivers/watchdog/rn5t568_wdt.c
new file mode 100644
index 0000000..f6e7234
--- /dev/null
+++ b/drivers/watchdog/rn5t568_wdt.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Watchdog driver for Ricoh RN5T618 PMIC
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani at gmail.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <watchdog.h>
+#include <regmap.h>
+#include <of.h>
+
+#define RN5T568_WATCHDOG 0x0b
+# define RN5T568_WATCHDOG_WDPWROFFEN BIT(2)
+# define RN5T568_WATCHDOG_WDOGTIM_M (BIT(0) | BIT(1))
+#define RN5T568_PWRIREN 0x12
+# define RN5T568_PWRIREN_EN_WDOG BIT(6)
+#define RN5T568_PWRIRQ 0x13
+# define RN5T568_PWRIRQ_IR_WDOG BIT(6)
+
+struct rn5t568_wdt {
+	struct watchdog wdd;
+	struct regmap *regmap;
+	unsigned int timeout;
+};
+
+struct rn5t568_wdt_tim {
+	u8 reg_val;
+	u8 time;
+};
+
+static const struct rn5t568_wdt_tim rn5t568_wdt_timeout[] = {
+	{ .reg_val = 0, .time = 1, },
+	{ .reg_val = 1, .time = 8, },
+	{ .reg_val = 2, .time = 32, },
+	{ .reg_val = 3, .time = 128, },
+};
+
+#define PMIC_WDT_MAX_TIMEOUT 128
+
+static int rn5t568_wdt_start(struct regmap *regmap, int idx)
+{
+	int ret;
+
+	ret = regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDOGTIM_M,
+				 rn5t568_wdt_timeout[idx].reg_val);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(regmap, RN5T568_PWRIRQ, RN5T568_PWRIRQ_IR_WDOG, 0x00);
+	regmap_update_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG, RN5T568_PWRIREN_EN_WDOG);
+
+	pr_debug("RN5t: Starting the watchdog with %u seconds\n", rn5t568_wdt_timeout[idx].time);
+
+	return regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN,
+				 RN5T568_WATCHDOG_WDPWROFFEN);
+}
+
+static int rn5t568_wdt_stop(struct regmap *regmap)
+{
+	int ret;
+
+	ret  = regmap_update_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG, 0);
+	if (ret)
+		return ret;
+	return regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN, 0);
+}
+
+static int rn5t568_wdt_ping(struct regmap *regmap)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(regmap, RN5T568_WATCHDOG, &val);
+	if (ret)
+		return ret;
+
+	return regmap_write(regmap, RN5T568_WATCHDOG, val);
+}
+
+static int rn5t568_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout)
+{
+	struct rn5t568_wdt *wdt = container_of(wdd, struct rn5t568_wdt, wdd);
+	int ret, i;
+
+	if (!timeout)
+		return rn5t568_wdt_stop(wdt->regmap);
+
+	for (i = 0; i < ARRAY_SIZE(rn5t568_wdt_timeout); i++) {
+		if (rn5t568_wdt_timeout[i].time + 1 >= timeout)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(rn5t568_wdt_timeout))
+		return -EINVAL;
+
+	if (wdt->timeout == timeout)
+		return rn5t568_wdt_ping(wdt->regmap);
+
+	ret = rn5t568_wdt_start(wdt->regmap, i);
+	if (ret)
+		return ret;
+
+	wdt->timeout = rn5t568_wdt_timeout[i].time;
+
+	return ret;
+}
+
+static int rn5t568_wdt_probe(struct device_d *dev)
+{
+	struct rn5t568_wdt *wdt;
+	struct watchdog *wdd;
+
+	wdt = xzalloc(sizeof(*wdt));
+
+	wdt->regmap = dev_get_regmap(dev->parent, NULL);
+	if (IS_ERR(wdt->regmap))
+		return PTR_ERR(wdt->regmap);
+
+	wdd = &wdt->wdd;
+	wdd->hwdev = dev;
+	wdd->set_timeout = rn5t568_wdt_set_timeout;
+	wdd->timeout_max = PMIC_WDT_MAX_TIMEOUT;
+
+	regmap_write(wdt->regmap, RN5T568_WATCHDOG, 0x03);
+	return watchdog_register(wdd);
+}
+
+static __maybe_unused const struct of_device_id rn5t568_wdt_of_match[] = {
+	{ .compatible = "ricoh,rn5t568-wdt" },
+	{ /* sentinel */ }
+};
+
+static struct driver_d rn5t568_wdt_driver = {
+	.name  = "rn5t568-wdt",
+	.probe = rn5t568_wdt_probe,
+	.of_compatible = DRV_OF_COMPAT(rn5t568_wdt_of_match),
+};
+device_platform_driver(rn5t568_wdt_driver);
-- 
2.30.2



From sha at pengutronix.de  Mon Jan 17 00:59:37 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Jan 2022 09:59:37 +0100
Subject: barebox extending boot-scripts
In-Reply-To: <trinity-dcf71a1e-4856-486b-a9a5-74ed6a82fd34-1642254462656@3c-app-gmx-bap71>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
 <trinity-7a53a76e-9836-482e-861e-31439f242e2d-1641472899713@3c-app-gmx-bs51>
 <20220107130751.GW6003@pengutronix.de>
 <trinity-f8991630-17eb-4ae0-9dfa-9a66bc41b02e-1641573741990@3c-app-gmx-bs48>
 <20220110094214.GG6003@pengutronix.de>
 <trinity-dcf71a1e-4856-486b-a9a5-74ed6a82fd34-1642254462656@3c-app-gmx-bap71>
Message-ID: <20220117085937.GC1121@pengutronix.de>

On Sat, Jan 15, 2022 at 02:47:42PM +0100, Frank Wunderlich wrote:
> Hi,
> 
> i have now created a new barebox board as copy from evb. i can load it from tftp with
> 
> bootm /mnt/tftp/barebox-rk3568-r2pro.img
> 
> i can create a bootmenu with entries of loader/entries and boot it:
> 
> boot -m sd.1
> 
> my bootscripts are also there, but they are not listed in $global.boot.default
> 
> $ grep defaultenv arch/arm/boards/bananapi-r2-pro/Makefile
> bbenv-y += defaultenv-rk3568
> $ grep defaultenv arch/arm/boards/bananapi-r2-pro/board.c
> 	defaultenv_append_directory(defaultenv_rk3568);
> $ cat arch/arm/boards/bananapi-r2-pro/defaultenv-rk3568/nv/boot.default
> net list-images mmc-linux tftp-linux

So an "echo $global.boot.default" shows something different, right?

Could it be that you have overwritten this variable in your persistent
env? In that case try a "saveenv -z" which invalidates the persistent
env.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 17 01:10:21 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Jan 2022 10:10:21 +0100
Subject: [PATCH] misc: acpi-test: retire test driver in favor of WDAT
 driver
In-Reply-To: <20220110104831.3149574-1-a.fatoum@pengutronix.de>
References: <20220110104831.3149574-1-a.fatoum@pengutronix.de>
Message-ID: <20220117091021.GE1121@pengutronix.de>

On Mon, Jan 10, 2022 at 11:48:31AM +0100, Ahmad Fatoum wrote:
> With the integration of the ACPI WDAT watchdog driver, we now have an
> actually useful user of the ACPI bus in tree, so the test driver
> serves no purpose anymore. Drop it.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/misc/Kconfig     |  6 ----
>  drivers/misc/Makefile    |  1 -
>  drivers/misc/acpi-test.c | 61 ----------------------------------------
>  3 files changed, 68 deletions(-)
>  delete mode 100644 drivers/misc/acpi-test.c

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 17 01:14:53 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Jan 2022 10:14:53 +0100
Subject: [PATCH] usb:chipidea-imx: honor "phys" dtree property
In-Reply-To: <20220114105235.2580174-1-enrico.scholz@sigma-chemnitz.de>
References: <20220114105235.2580174-1-enrico.scholz@sigma-chemnitz.de>
Message-ID: <20220117091453.GF1121@pengutronix.de>

On Fri, Jan 14, 2022 at 11:52:35AM +0100, Enrico Scholz wrote:
> Recent kernel devicetrees changed the "fsl,usbphy" property name to
> "phys" on some platforms (e.g. iMX8) but the old one was kept on other
> platforms (e.g. iMX6).
> 
> Check them both in the usb driver by preferring "phys".
> 
> NOTE: this fixes a hard lockup when booting NXP linux kernels on iMX8.
> 
> Signed-off-by: Enrico Scholz <enrico.scholz at sigma-chemnitz.de>
> ---
>  drivers/usb/imx/chipidea-imx.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)

Applied to master, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From dev at lynxeye.de  Mon Jan 17 01:16:07 2022
From: dev at lynxeye.de (Lucas Stach)
Date: Mon, 17 Jan 2022 10:16:07 +0100
Subject: [PATCH 1/3] clk: ignore of_device_ensure_probed error in clock
 lookup
In-Reply-To: <095bafc0-7261-aa13-a9c7-8022cc78b26c@pengutronix.de>
References: <20220116213221.3466936-1-dev@lynxeye.de>
 <095bafc0-7261-aa13-a9c7-8022cc78b26c@pengutronix.de>
Message-ID: <10192ccb41be58fd4e53044b17e6a5838c3629d7.camel@lynxeye.de>

Hi Ahmad,

Am Montag, dem 17.01.2022 um 06:12 +0100 schrieb Ahmad Fatoum:
> Hello Lucas,
> 
> On 16.01.22 22:32, Lucas Stach wrote:
> > For CLK_OF_DECLARE clocks there is no driver that is bound to the device,
> > so the lookup fails before even trying to find the provider, breaking
> > the parent_ready() logic used when initializing the declared providers.
> > 
> > Ignore the return code from of_device_ensure_probed to allow the lookup
> > to proceed as usual. If of_device_ensure_probed the lookup will also fail,
> > as no provider will be found.
> 
> This seems to be an alternate fix for the issue addressed by:
> bd516e38dd14 ("clk: handle CLK_OF_DECLARE in deep probe")
> 
> What do you think?

Yes, it seems to be aimed at the same issue. However, your fix in
bd516e38dd14 doesn't fix my specific issue, as we still don't get the
correct -EPROBE_DEFER error code for the logic in parent_ready() in
drivers/clk/clk.c to work.

I guess we could even revert your fix if we agree that ignoring the
return code here is the right thing to do? Attaching a dummy driver 
doesn't seem to be totally correct, as I think it isn't prohibited to
have both a CLK_OF_DECLARE clock controller and a real platform driver
for other uses attached to the same OF node. While I'm not aware of any
clock controllers where this would be the case, I have seen such
constructs with IRQ controllers.

Regards,
Lucas

> 
> > 
> > Signed-off-by: Lucas Stach <dev at lynxeye.de>
> > ---
> >  drivers/clk/clk.c | 6 ++----
> >  1 file changed, 2 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> > index 189c9c62df5c..a1d1d7f1a467 100644
> > --- a/drivers/clk/clk.c
> > +++ b/drivers/clk/clk.c
> > @@ -643,11 +643,9 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
> >  {
> >  	struct of_clk_provider *provider;
> >  	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
> > -	int ret;
> >  
> > -	ret = of_device_ensure_probed(clkspec->np);
> > -	if (ret)
> > -		return ERR_PTR(ret);
> > +	/* Ignore error, as CLK_OF_DECLARE clocks have no proper driver. */
> > +	of_device_ensure_probed(clkspec->np);
> >  
> >  	/* Check if we have such a provider in our array */
> >  	list_for_each_entry(provider, &of_clk_providers, link) {
> > 
> 
> 




From sha at pengutronix.de  Mon Jan 17 01:29:33 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Jan 2022 10:29:33 +0100
Subject: [PATCH] mfd: implement mfd_add_devices
In-Reply-To: <20220114084728.311277-1-a.fatoum@pengutronix.de>
References: <20220114084728.311277-1-a.fatoum@pengutronix.de>
Message-ID: <20220117092933.GG1121@pengutronix.de>

On Fri, Jan 14, 2022 at 09:47:28AM +0100, Ahmad Fatoum wrote:
> This makes it easier to port Linux drivers like PMICs, where a device
> tree probed MFD node exists and the driver matching against it then
> registers a number of MFD cell devices, which don't have their own
> DT compatibles.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/base/resource.c  |  2 +-
>  drivers/mfd/Makefile     |  2 ++
>  drivers/mfd/core.c       | 25 +++++++++++++++++++++++++
>  include/driver.h         |  2 +-
>  include/linux/mfd/core.h | 23 +++++++++++++++++++++++
>  5 files changed, 52 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/mfd/core.c
>  create mode 100644 include/linux/mfd/core.h
> 
> diff --git a/drivers/base/resource.c b/drivers/base/resource.c
> index d0d39620772e..0134456ffac2 100644
> --- a/drivers/base/resource.c
> +++ b/drivers/base/resource.c
> @@ -20,7 +20,7 @@ struct device_d *device_alloc(const char *devname, int id)
>  	return dev;
>  }
>  
> -int device_add_data(struct device_d *dev, void *data, size_t size)
> +int device_add_data(struct device_d *dev, const void *data, size_t size)
>  {
>  	free(dev->platform_data);
>  
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 2bcf90078ab4..a00119a1d5f4 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -1,4 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0-only
> +obj-y				+= core.o
> +
>  obj-$(CONFIG_MFD_ACT8846)	+= act8846.o
>  obj-$(CONFIG_MFD_DA9053)	+= da9053.o
>  obj-$(CONFIG_MFD_DA9063)	+= da9063.o
> diff --git a/drivers/mfd/core.c b/drivers/mfd/core.c
> new file mode 100644
> index 000000000000..fa6aa1c74a18
> --- /dev/null
> +++ b/drivers/mfd/core.c
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#include <linux/mfd/core.h>
> +#include <driver.h>
> +
> +int mfd_add_devices(struct device_d *parent, const struct mfd_cell *cells, int n_devs)
> +{
> +	struct device_d *dev;
> +	int ret, i;
> +
> +	for (i = 0; i < n_devs; i++) {
> +		dev = device_alloc(cells[i].name, DEVICE_ID_DYNAMIC);
> +		dev->parent = parent;
> +
> +		ret = platform_device_register(dev);
> +		if (ret)
> +			return ret;
> +
> +		ret = device_add_data(dev, &cells[i], sizeof(cells[i]));
> +		if (ret)
> +			return ret;

Calling platform_device_register() might result in probing the device.
You should call device_add_data() before registering the device.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan 17 02:20:17 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Jan 2022 11:20:17 +0100
Subject: [PATCH 1/3] clk: ignore of_device_ensure_probed error in clock
 lookup
In-Reply-To: <10192ccb41be58fd4e53044b17e6a5838c3629d7.camel@lynxeye.de>
References: <20220116213221.3466936-1-dev@lynxeye.de>
 <095bafc0-7261-aa13-a9c7-8022cc78b26c@pengutronix.de>
 <10192ccb41be58fd4e53044b17e6a5838c3629d7.camel@lynxeye.de>
Message-ID: <0ecb57c3-e0a3-076f-5bd7-4b12c59fa80e@pengutronix.de>

Hi,

On 17.01.22 10:16, Lucas Stach wrote:
> Hi Ahmad,
> 
> Am Montag, dem 17.01.2022 um 06:12 +0100 schrieb Ahmad Fatoum:
>> Hello Lucas,
>>
>> On 16.01.22 22:32, Lucas Stach wrote:
>>> For CLK_OF_DECLARE clocks there is no driver that is bound to the device,
>>> so the lookup fails before even trying to find the provider, breaking
>>> the parent_ready() logic used when initializing the declared providers.
>>>
>>> Ignore the return code from of_device_ensure_probed to allow the lookup
>>> to proceed as usual. If of_device_ensure_probed the lookup will also fail,
>>> as no provider will be found.
>>
>> This seems to be an alternate fix for the issue addressed by:
>> bd516e38dd14 ("clk: handle CLK_OF_DECLARE in deep probe")
>>
>> What do you think?
> 
> Yes, it seems to be aimed at the same issue. However, your fix in
> bd516e38dd14 doesn't fix my specific issue, as we still don't get the
> correct -EPROBE_DEFER error code for the logic in parent_ready() in
> drivers/clk/clk.c to work.
> 
> I guess we could even revert your fix if we agree that ignoring the
> return code here is the right thing to do? Attaching a dummy driver 
> doesn't seem to be totally correct, as I think it isn't prohibited to
> have both a CLK_OF_DECLARE clock controller and a real platform driver
> for other uses attached to the same OF node. While I'm not aware of any
> clock controllers where this would be the case, I have seen such
> constructs with IRQ controllers.

Sounds logical. I'll test with my fix reverted and yours applied
and report back.

> 
> Regards,
> Lucas
> 
>>
>>>
>>> Signed-off-by: Lucas Stach <dev at lynxeye.de>
>>> ---
>>>  drivers/clk/clk.c | 6 ++----
>>>  1 file changed, 2 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>>> index 189c9c62df5c..a1d1d7f1a467 100644
>>> --- a/drivers/clk/clk.c
>>> +++ b/drivers/clk/clk.c
>>> @@ -643,11 +643,9 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
>>>  {
>>>  	struct of_clk_provider *provider;
>>>  	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
>>> -	int ret;
>>>  
>>> -	ret = of_device_ensure_probed(clkspec->np);
>>> -	if (ret)
>>> -		return ERR_PTR(ret);
>>> +	/* Ignore error, as CLK_OF_DECLARE clocks have no proper driver. */
>>> +	of_device_ensure_probed(clkspec->np);
>>>  
>>>  	/* Check if we have such a provider in our array */
>>>  	list_for_each_entry(provider, &of_clk_providers, link) {
>>>
>>
>>
> 
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 17 02:23:25 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Jan 2022 11:23:25 +0100
Subject: [PATCH 1/2] Add the base Ricoh RN5T568 PMIC driver
In-Reply-To: <20220117085908.36460-2-jbe@pengutronix.de>
References: <20220117085908.36460-1-jbe@pengutronix.de>
 <20220117085908.36460-2-jbe@pengutronix.de>
Message-ID: <20220117102325.GI1121@pengutronix.de>

On Mon, Jan 17, 2022 at 09:59:07AM +0100, Juergen Borleis wrote:
> ---
>  drivers/mfd/Kconfig   |   6 ++
>  drivers/mfd/Makefile  |   1 +
>  drivers/mfd/rn5t568.c | 165 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 172 insertions(+)
>  create mode 100644 drivers/mfd/rn5t568.c
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 8468a2d..1602480 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -68,6 +68,12 @@ config MFD_STPMIC1
>  	help
>  	  Select this to support communication with the STPMIC1.
>  
> +config MFD_RN568PMIC
> +	depends on I2C
> +	bool "Ricoh RN5T568 MFD driver"
> +	help
> +	  Select this to support communication with the Ricoh RN5T568 PMIC.
> +
>  config MFD_SUPERIO
>  	bool
>  
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 2bcf900..50f54cf 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_TWL4030)	+= twl4030.o
>  obj-$(CONFIG_MFD_TWL6030)	+= twl6030.o
>  obj-$(CONFIG_RAVE_SP_CORE)	+= rave-sp.o
>  obj-$(CONFIG_MFD_STPMIC1)	+= stpmic1.o
> +obj-$(CONFIG_MFD_RN568PMIC)	+= rn5t568.o
>  obj-$(CONFIG_MFD_SUPERIO)	+= superio.o
>  obj-$(CONFIG_FINTEK_SUPERIO)	+= fintek-superio.o
>  obj-$(CONFIG_SMSC_SUPERIO)	+= smsc-superio.o
> diff --git a/drivers/mfd/rn5t568.c b/drivers/mfd/rn5t568.c
> new file mode 100644
> index 0000000..ad53d7b
> --- /dev/null
> +++ b/drivers/mfd/rn5t568.c
> @@ -0,0 +1,165 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * MFD core driver for Ricoh RN5T618 PMIC
> + * Note: Manufacturer is now Nisshinbo Micro Devices Inc.
> + *
> + * Copyright (C) 2014 Beniamino Galvani <b.galvani at gmail.com>
> + * Copyright (C) 2016 Toradex AG
> + */
> +
> +#include <common.h>
> +#include <driver.h>
> +#include <errno.h>
> +#include <i2c/i2c.h>
> +#include <init.h>
> +#include <of.h>
> +#include <regmap.h>
> +#include <reset_source.h>
> +#include <restart.h>
> +
> +#define RN5T568_LSIVER 0x00
> +#define RN5T568_OTPVER 0x01
> +#define RN5T568_PONHIS 0x09
> +# define RN5T568_PONHIS_ON_EXTINPON BIT(3)
> +# define RN5T568_PONHIS_ON_REPWRPON BIT(1)
> +# define RN5T568_PONHIS_ON_PWRONPON BIT(0)
> +#define RN5T568_POFFHIS 0x0a
> +# define RN5T568_POFFHIS_N_OEPOFF BIT(7)
> +# define RN5T568_POFFHIS_DCLIMPOFF BIT(6)
> +# define RN5T568_POFFHIS_WDGPOFF BIT(5)
> +# define RN5T568_POFFHIS_CPUPOFF BIT(4)
> +# define RN5T568_POFFHIS_IODETPOFF BIT(3)
> +# define RN5T568_POFFHIS_VINDETPOFF BIT(2)
> +# define RN5T568_POFFHIS_TSHUTPOFF BIT(1)
> +# define RN5T568_POFFHIS_PWRONPOFF BIT(0)
> +#define RN5T568_SLPCNT 0x0e
> +# define RN5T568_SLPCNT_SWPPWROFF BIT(0)
> +#define RN5T568_REPCNT 0x0f
> +# define RN5T568_REPCNT_OFF_RESETO_16MS 0x30
> +# define RN5T568_REPCNT_OFF_REPWRTIM_1000MS 0x06
> +# define RN5T568_REPCNT_OFF_REPWRON BIT(0)
> +#define RN5T568_MAX_REG 0xbc
> +
> +struct rn5t568 {
> +	struct restart_handler restart;
> +	struct regmap *regmap;
> +};
> +
> +static struct rn5t568 single_pmic;

Please do not artificially limit the driver to a single instance only.

> +
> +static void rn5t568_restart(struct restart_handler *rst)
> +{
> +	struct rn5t568 *rn5t568 = container_of(rst, struct rn5t568, restart);
> +
> +	regmap_write(rn5t568->regmap, RN5T568_SLPCNT, RN5T568_SLPCNT_SWPPWROFF);
> +}
> +
> +static int rn5t568_reset_reason_detect(struct device_d *dev, struct regmap *regmap)
> +{
> +	unsigned int reg;
> +	int ret;
> +
> +	ret = regmap_read(regmap, RN5T568_PONHIS, &reg);
> +	if (ret)
> +		return ret;
> +
> +	dev_dbg(dev, "Power-on history: %x\n", reg);
> +
> +	if (reg == 0) {
> +		dev_info(dev, "No power-on reason available\n");
> +		return 0;
> +	}
> +
> +	if (reg & RN5T568_PONHIS_ON_EXTINPON) {
> +		reset_source_set_device(dev, RESET_POR);
> +		return 0;
> +	} else if (reg & RN5T568_PONHIS_ON_PWRONPON) {
> +		reset_source_set_device(dev, RESET_POR);
> +		return 0;
> +	} else if (!(reg & RN5T568_PONHIS_ON_REPWRPON))
> +		return -EINVAL;
> +
> +	ret = regmap_read(regmap, RN5T568_POFFHIS, &reg);
> +	if (ret)
> +		return ret;
> +
> +	dev_dbg(dev, "Power-off history: %x\n", reg);
> +
> +	if (reg & RN5T568_POFFHIS_PWRONPOFF)
> +		reset_source_set_device(dev, RESET_POR);
> +	else if (reg & RN5T568_POFFHIS_TSHUTPOFF)
> +		reset_source_set_device(dev, RESET_THERM);
> +	else if (reg & RN5T568_POFFHIS_VINDETPOFF)
> +		reset_source_set_device(dev, RESET_BROWNOUT);
> +	else if (reg & RN5T568_POFFHIS_IODETPOFF)
> +		reset_source_set_device(dev, RESET_UKWN);
> +	else if (reg & RN5T568_POFFHIS_CPUPOFF)
> +		reset_source_set_device(dev, RESET_RST);
> +	else if (reg & RN5T568_POFFHIS_WDGPOFF)
> +		reset_source_set_device(dev, RESET_WDG);
> +	else if (reg & RN5T568_POFFHIS_DCLIMPOFF)
> +		reset_source_set_device(dev, RESET_BROWNOUT);
> +	else if (reg & RN5T568_POFFHIS_N_OEPOFF)
> +		reset_source_set_device(dev, RESET_EXT);
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static const struct regmap_config rn5t568_regmap_config = {
> +	.reg_bits	= 8,
> +	.val_bits	= 8,
> +	.max_register	= RN5T568_MAX_REG,
> +};
> +
> +static int __init rn5t568_i2c_probe(struct device_d *dev)
> +{
> +	static const unsigned int val = RN5T568_REPCNT_OFF_RESETO_16MS | RN5T568_REPCNT_OFF_REPWRTIM_1000MS | RN5T568_REPCNT_OFF_REPWRON;

val is used only once. Maybe drop the variable and use the value
directly?

> +	unsigned char reg[4];

reg[2] should be enough. This doesn't matter much but might be a bit
confusing otherwise.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From jmaselbas at kalray.eu  Mon Jan 17 03:17:17 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 12:17:17 +0100
Subject: [PATCH 08/13] nvmem: add kvx otp non volatile regbank support
In-Reply-To: <20220117082419.GA1121@pengutronix.de>
References: <20220114165208.9980-1-jmaselbas@kalray.eu>
 <20220114165208.9980-9-jmaselbas@kalray.eu>
 <20220117082419.GA1121@pengutronix.de>
Message-ID: <20220117111717.GE29876@tellis.lin.mbt.kalray.eu>

> > +static int kvx_otp_nv_read(void *context, unsigned int offset,
> > +			  void *_val, size_t bytes)
> > +{
> > +	struct kvx_otp_nv_priv *priv = context;
> > +	u8 *val = _val;
> > +	u32 tmp, copy_size;
> > +	u8 skip = offset & OTP_NV_ALIGN_MASK;
> > +
> > +	offset &= ~OTP_NV_ALIGN_MASK;
> > +
> > +	while (bytes) {
> > +		tmp = readl(priv->base + offset);
> > +		if (skip != 0)
> > +			copy_size = min(OTP_NV_ALIGN - skip, (int) bytes);
> > +		else
> > +			copy_size = min(bytes, sizeof(tmp));
> > +
> > +		memcpy(val, ((u8 *) &tmp) + skip, copy_size);
> > +		if (skip != 0)
> > +			skip = 0;
> 
> The if() here is unnecessary.
Indeed, thanks.







From sha at pengutronix.de  Mon Jan 17 03:46:27 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Jan 2022 12:46:27 +0100
Subject: [PATCH 2/2] Add Ricoh RN5T568 PMIC based watchdog
In-Reply-To: <20220117085908.36460-3-jbe@pengutronix.de>
References: <20220117085908.36460-1-jbe@pengutronix.de>
 <20220117085908.36460-3-jbe@pengutronix.de>
Message-ID: <20220117114627.GJ1121@pengutronix.de>

On Mon, Jan 17, 2022 at 09:59:08AM +0100, Juergen Borleis wrote:
> ---
>  drivers/watchdog/Kconfig       |   6 ++
>  drivers/watchdog/Makefile      |   1 +
>  drivers/watchdog/rn5t568_wdt.c | 140 +++++++++++++++++++++++++++++++++
>  3 files changed, 147 insertions(+)
>  create mode 100644 drivers/watchdog/rn5t568_wdt.c
> 
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index d605e62..61a096b 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -109,6 +109,12 @@ config STPMIC1_WATCHDOG
>  	help
>  	  Enable to support configuration of the stpmic1's built-in watchdog.
>  
> +config RN568_WATCHDOG
> +	bool "Ricoh RN5t568 PMIC based Watchdog"
> +	depends on MFD_RN568PMIC
> +	help
> +	  Enable to support system control via the PMIC based watchdog.
> +
>  config F71808E_WDT
>  	bool "Fintek F718xx, F818xx Super I/O Watchdog"
>  	depends on X86
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index dbb76a5..84fd2bf 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_BCM283X) += bcm2835_wdt.o
>  obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
>  obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o
>  obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
> +obj-$(CONFIG_RN568_WATCHDOG) += rn5t568_wdt.o
>  obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
>  obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
>  obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
> diff --git a/drivers/watchdog/rn5t568_wdt.c b/drivers/watchdog/rn5t568_wdt.c
> new file mode 100644
> index 0000000..f6e7234
> --- /dev/null
> +++ b/drivers/watchdog/rn5t568_wdt.c
> @@ -0,0 +1,140 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Watchdog driver for Ricoh RN5T618 PMIC
> + *
> + * Copyright (C) 2014 Beniamino Galvani <b.galvani at gmail.com>
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <watchdog.h>
> +#include <regmap.h>
> +#include <of.h>
> +
> +#define RN5T568_WATCHDOG 0x0b
> +# define RN5T568_WATCHDOG_WDPWROFFEN BIT(2)
> +# define RN5T568_WATCHDOG_WDOGTIM_M (BIT(0) | BIT(1))
> +#define RN5T568_PWRIREN 0x12
> +# define RN5T568_PWRIREN_EN_WDOG BIT(6)
> +#define RN5T568_PWRIRQ 0x13
> +# define RN5T568_PWRIRQ_IR_WDOG BIT(6)
> +
> +struct rn5t568_wdt {
> +	struct watchdog wdd;
> +	struct regmap *regmap;
> +	unsigned int timeout;
> +};
> +
> +struct rn5t568_wdt_tim {
> +	u8 reg_val;
> +	u8 time;
> +};
> +
> +static const struct rn5t568_wdt_tim rn5t568_wdt_timeout[] = {
> +	{ .reg_val = 0, .time = 1, },
> +	{ .reg_val = 1, .time = 8, },
> +	{ .reg_val = 2, .time = 32, },
> +	{ .reg_val = 3, .time = 128, },
> +};
> +
> +#define PMIC_WDT_MAX_TIMEOUT 128
> +
> +static int rn5t568_wdt_start(struct regmap *regmap, int idx)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDOGTIM_M,
> +				 rn5t568_wdt_timeout[idx].reg_val);
> +	if (ret)
> +		return ret;
> +
> +	regmap_update_bits(regmap, RN5T568_PWRIRQ, RN5T568_PWRIRQ_IR_WDOG, 0x00);
> +	regmap_update_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG, RN5T568_PWRIREN_EN_WDOG);
> +
> +	pr_debug("RN5t: Starting the watchdog with %u seconds\n", rn5t568_wdt_timeout[idx].time);
> +
> +	return regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN,
> +				 RN5T568_WATCHDOG_WDPWROFFEN);
> +}
> +
> +static int rn5t568_wdt_stop(struct regmap *regmap)
> +{
> +	int ret;
> +
> +	ret  = regmap_update_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG, 0);

You could use regmap_[clear|set]_bits() here and elsewhere in the
driver.


> +	if (ret)
> +		return ret;
> +	return regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN, 0);
> +}
> +
> +static int rn5t568_wdt_ping(struct regmap *regmap)
> +{
> +	unsigned int val;
> +	int ret;
> +
> +	ret = regmap_read(regmap, RN5T568_WATCHDOG, &val);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_write(regmap, RN5T568_WATCHDOG, val);
> +}
> +
> +static int rn5t568_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout)
> +{
> +	struct rn5t568_wdt *wdt = container_of(wdd, struct rn5t568_wdt, wdd);
> +	int ret, i;
> +
> +	if (!timeout)
> +		return rn5t568_wdt_stop(wdt->regmap);
> +
> +	for (i = 0; i < ARRAY_SIZE(rn5t568_wdt_timeout); i++) {
> +		if (rn5t568_wdt_timeout[i].time + 1 >= timeout)

I don't understand the + 1 here. When I want to have a timeout of 9s the
driver uses 8s instead which doesn't seem to be correct.

> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(rn5t568_wdt_timeout))
> +		return -EINVAL;
> +
> +	if (wdt->timeout == timeout)
> +		return rn5t568_wdt_ping(wdt->regmap);
> +
> +	ret = rn5t568_wdt_start(wdt->regmap, i);
> +	if (ret)
> +		return ret;
> +
> +	wdt->timeout = rn5t568_wdt_timeout[i].time;
> +
> +	return ret;
> +}
> +
> +static int rn5t568_wdt_probe(struct device_d *dev)
> +{
> +	struct rn5t568_wdt *wdt;
> +	struct watchdog *wdd;
> +
> +	wdt = xzalloc(sizeof(*wdt));
> +
> +	wdt->regmap = dev_get_regmap(dev->parent, NULL);
> +	if (IS_ERR(wdt->regmap))
> +		return PTR_ERR(wdt->regmap);
> +
> +	wdd = &wdt->wdd;
> +	wdd->hwdev = dev;
> +	wdd->set_timeout = rn5t568_wdt_set_timeout;
> +	wdd->timeout_max = PMIC_WDT_MAX_TIMEOUT;
> +
> +	regmap_write(wdt->regmap, RN5T568_WATCHDOG, 0x03);

Why is anything written here to the register?

It seems this clears BIT(2) which disables the watchdog, right? If so,
that's not a good idea as it might be disabled on purpose by earlier
boot stages.

You could read the hardware status to provide the
WDOG_HW_RUNNING/WDOG_HW_NOT_RUNNING flag.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan 17 03:48:25 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Jan 2022 12:48:25 +0100
Subject: [PATCH 3/5] scripts: Add qoiconv to convert png to qoi
In-Reply-To: <20220114111404.GB29876@tellis.lin.mbt.kalray.eu>
References: <20220110221255.5003-1-jmaselbas@kalray.eu>
 <20220110221255.5003-4-jmaselbas@kalray.eu>
 <ec782b1e-ffed-3f01-71a7-f28c161d802d@pengutronix.de>
 <20220114111404.GB29876@tellis.lin.mbt.kalray.eu>
Message-ID: <cbfacecf-06b8-81d1-50cc-7398fd003903@pengutronix.de>

On 14.01.22 12:14, Jules Maselbas wrote:
> On Fri, Jan 14, 2022 at 11:29:58AM +0100, Ahmad Fatoum wrote:
>> On 10.01.22 23:12, Jules Maselbas wrote:
>>> ImageMagick will eventually support the qoi image format, in the
>>> mean time add a png to qoi conversion program.
>>>
>>> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
>>> ---
>>>  scripts/Kconfig     |    5 +
>>>  scripts/Makefile    |    1 +
>>>  scripts/qoiconv.c   |   91 +
>>>  scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
>>>  4 files changed, 7853 insertions(+)
>>>  create mode 100644 scripts/qoiconv.c
>>>  create mode 100644 scripts/stb_image.h
>>>
>>> diff --git a/scripts/Kconfig b/scripts/Kconfig
>>> index 9b744deba9..747f665e02 100644
>>> --- a/scripts/Kconfig
>>> +++ b/scripts/Kconfig
>>> @@ -110,6 +110,11 @@ config RK_USB_LOADER
>>>  
>>>  	  You need libusb-1.0 to compile this tool.
>>>  
>>> +config QOICONV
>>> +	bool "QOI image format conversion" if COMPILE_HOST_TOOLS
>>> +	help
>>> +	  This enable converting png to qoi images to generate boot logo.
>>> +
>>>  endmenu
>>>  
>>>  menu "Target Tools"
>>> diff --git a/scripts/Makefile b/scripts/Makefile
>>> index dc5fa75f90..cbaf2d55ff 100644
>>> --- a/scripts/Makefile
>>> +++ b/scripts/Makefile
>>> @@ -8,6 +8,7 @@ hostprogs-always-y					+= fix_size
>>>  hostprogs-always-y					+= bareboxenv
>>>  hostprogs-always-y					+= bareboxcrc32
>>>  hostprogs-always-y					+= kernel-install
>>> +hostprogs-always-$(CONFIG_QOICONV)			+= qoiconv
>>>  hostprogs-always-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS)	+= rsatoc
>>>  HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl`
>>>  HOSTLDLIBS_rsatoc = `pkg-config --libs openssl`
>>> diff --git a/scripts/qoiconv.c b/scripts/qoiconv.c
>>> new file mode 100644
>>> index 0000000000..010c70ead0
>>> --- /dev/null
>>> +++ b/scripts/qoiconv.c
>>> @@ -0,0 +1,91 @@
> Probably missing SPDX identifiers as well
> 
>>> +/*
>>> +
>>> +Command line tool to convert between png <> qoi format
>>> +
>>> +Requires "stb_image.h" and "stb_image_write.h"
>>> +Compile with: 
>>> +	gcc qoiconv.c -std=c99 -O3 -o qoiconv
>>> +
>>> +Dominic Szablewski - https://phoboslab.org
>>> +
>>> +
>>> +-- LICENSE: The MIT License(MIT)
>>> +
>>> +Copyright(c) 2021 Dominic Szablewski
>>> +
>>> +Permission is hereby granted, free of charge, to any person obtaining a copy of
>>> +this software and associated documentation files(the "Software"), to deal in
>>> +the Software without restriction, including without limitation the rights to
>>> +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
>>> +of the Software, and to permit persons to whom the Software is furnished to do
>>> +so, subject to the following conditions :
>>> +The above copyright notice and this permission notice shall be included in all
>>> +copies or substantial portions of the Software.
>>> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>>> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>>> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
>>> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>>> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>>> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>>> +SOFTWARE.
>>> +
>>> +*/
>>
>> Can you not reuse the header added in the previous commit?
> I am not sure what you mean here, the qoi.h header is reused from
> lib/gui/qoi.h, see the include below.
> Are you sugesting to _not_ reuse the header?

All good then. I missed that.

> 
> 
>>> +
>>> +
>>> +#define STB_IMAGE_IMPLEMENTATION
>>> +#define STBI_ONLY_PNG
>>> +#define STBI_NO_LINEAR
>>> +#include "stb_image.h"
>>> +
>>> +#define QOI_IMPLEMENTATION
>>> +#include "../lib/gui/qoi.h"
> included here.
> 
> 
> 
> 
> 
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From o.rempel at pengutronix.de  Mon Jan 17 04:05:00 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Mon, 17 Jan 2022 13:05:00 +0100
Subject: [PATCH v1 4/4] ARM: rpi: set host name based on DT compatible
In-Reply-To: <20220117120500.3556703-1-o.rempel@pengutronix.de>
References: <20220117120500.3556703-1-o.rempel@pengutronix.de>
Message-ID: <20220117120500.3556703-4-o.rempel@pengutronix.de>

The "rpi" host name is not practical if you need to work with different
variants of RPi at same time. Usually, removing barebox_set_hostname()
would let barebox generate it automatically. But in this case, the name
would look less informative. For example "2-model-b".

So, make board code generate something usable, for example
"rpi-2-model-b"

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index b6673ca474..9d8a253c41 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -389,6 +389,8 @@ static int rpi_devices_probe(struct device_d *dev)
 {
 	struct regulator *reg;
 	struct rpi_priv *priv;
+	const char *name, *ptr;
+	char *hostname;
 	int ret;
 
 	priv = xzalloc(sizeof(*priv));
@@ -405,7 +407,12 @@ static int rpi_devices_probe(struct device_d *dev)
 	if (ret)
 		goto free_priv;
 
-	barebox_set_hostname("rpi");
+	/* construct short recognizable host name */
+	name = of_device_get_match_compatible(priv->dev);
+	ptr = strchr(name, ',');
+	hostname = basprintf("rpi-%s", ptr ? ptr + 1 : name);
+	barebox_set_hostname(hostname);
+	free(hostname);
 
 	rpi_add_led();
 	bcm2835_register_fb();
-- 
2.30.2



From o.rempel at pengutronix.de  Mon Jan 17 04:04:57 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Mon, 17 Jan 2022 13:04:57 +0100
Subject: [PATCH v1 1/4] ARM: rpi: convert board code to a driver
Message-ID: <20220117120500.3556703-1-o.rempel@pengutronix.de>

Convert board code to a driver model. This will prevent executing this
part of code on any other BCM2xxx based boards.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 40 +++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 2684bd5ed7..43e7e66e0f 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -511,7 +511,7 @@ static void rpi_vc_fdt(void)
 	}
 }
 
-static int rpi_devices_init(void)
+static int rpi_devices_probe(struct device_d *dev)
 {
 	struct regulator *reg;
 
@@ -529,4 +529,40 @@ static int rpi_devices_init(void)
 
 	return 0;
 }
-late_initcall(rpi_devices_init);
+
+static const struct of_device_id rpi_of_match[] = {
+	/* BCM2711 based Boards */
+	{ .compatible = "raspberrypi,400" },
+	{ .compatible = "raspberrypi,4-compute-module" },
+	{ .compatible = "raspberrypi,4-model-b" },
+
+	/* BCM2835 based Boards */
+	{ .compatible = "raspberrypi,model-a" },
+	{ .compatible = "raspberrypi,model-a-plus" },
+	{ .compatible = "raspberrypi,model-b" },
+	/* Raspberry Pi Model B (no P5) */
+	{ .compatible = "raspberrypi,model-b-i2c0" },
+	{ .compatible = "raspberrypi,model-b-rev2" },
+	{ .compatible = "raspberrypi,model-b-plus" },
+	{ .compatible = "raspberrypi,compute-module" },
+	{ .compatible = "raspberrypi,model-zero" },
+	{ .compatible = "raspberrypi,model-zero-w" },
+
+	/* BCM2836 based Boards */
+	{ .compatible = "raspberrypi,2-model-b" },
+
+	/* BCM2837 based Boards */
+	{ .compatible = "raspberrypi,3-model-a-plus" },
+	{ .compatible = "raspberrypi,3-model-b" },
+	{ .compatible = "raspberrypi,3-model-b-plus" },
+	{ .compatible = "raspberrypi,3-compute-module" },
+	{ .compatible = "raspberrypi,3-compute-module-lite" },
+	{ /* sentinel */ },
+};
+
+static struct driver_d rpi_board_driver = {
+	.name = "board-rpi",
+	.probe = rpi_devices_probe,
+	.of_compatible = DRV_OF_COMPAT(rpi_of_match),
+};
+late_platform_driver(rpi_board_driver);
-- 
2.30.2



From o.rempel at pengutronix.de  Mon Jan 17 04:04:58 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Mon, 17 Jan 2022 13:04:58 +0100
Subject: [PATCH v1 2/4] ARM: rpi: move clk support to a separate driver and
 enable deep-probe
In-Reply-To: <20220117120500.3556703-1-o.rempel@pengutronix.de>
References: <20220117120500.3556703-1-o.rempel@pengutronix.de>
Message-ID: <20220117120500.3556703-2-o.rempel@pengutronix.de>

To make deep-probe work properly, we need clock support be registered as
driver to related device.

To avoid regression, deep-probe is enabled in the same patch.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 75 +-----------------
 drivers/clk/Makefile                      |  1 +
 drivers/clk/clk-rpi.c                     | 93 +++++++++++++++++++++++
 3 files changed, 96 insertions(+), 73 deletions(-)
 create mode 100644 drivers/clk/clk-rpi.c

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 43e7e66e0f..53c476c22a 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -2,6 +2,7 @@
 // SPDX-FileCopyrightText: 2009 Carlo Caione <carlo at carlocaione.org>
 
 #include <common.h>
+#include <deep-probe.h>
 #include <init.h>
 #include <fs.h>
 #include <of.h>
@@ -45,12 +46,6 @@ struct msg_get_arm_mem {
 	u32 end_tag;
 };
 
-struct msg_get_clock_rate {
-	struct bcm2835_mbox_hdr hdr;
-	struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
-	u32 end_tag;
-};
-
 struct msg_get_board_rev {
 	struct bcm2835_mbox_hdr hdr;
 	struct bcm2835_mbox_tag_get_board_rev get_board_rev;
@@ -80,22 +75,6 @@ static int rpi_get_arm_mem(u32 *size)
 	return 0;
 }
 
-static struct clk *rpi_register_firmware_clock(u32 clock_id, const char *name)
-{
-	BCM2835_MBOX_STACK_ALIGN(struct msg_get_clock_rate, msg);
-	int ret;
-
-	BCM2835_MBOX_INIT_HDR(msg);
-	BCM2835_MBOX_INIT_TAG(&msg->get_clock_rate, GET_CLOCK_RATE);
-	msg->get_clock_rate.body.req.clock_id = clock_id;
-
-	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
-	if (ret)
-		return ERR_PTR(ret);
-
-	return clk_fixed(name, msg->get_clock_rate.body.resp.rate_hz);
-}
-
 static void rpi_set_usbethaddr(void)
 {
 	BCM2835_MBOX_STACK_ALIGN(struct msg_get_mac_address, msg);
@@ -343,57 +322,6 @@ static int rpi_postcore_init(void)
 }
 postcore_initcall(rpi_postcore_init);
 
-static int rpi_clock_init(void)
-{
-	struct clk *clk;
-
-	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_EMMC,
-					 "bcm2835_mci0");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	clkdev_add_physbase(clk, 0x20300000, NULL);
-	clkdev_add_physbase(clk, 0x3f300000, NULL);
-
-	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
-					  "bcm2835_sdhost");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	clkdev_add_physbase(clk, 0x20202000, NULL);
-	clkdev_add_physbase(clk, 0x3f202000, NULL);
-
-	return 0;
-}
-postconsole_initcall(rpi_clock_init);
-
-static int rpi_console_clock_init(void)
-{
-	struct clk *clk;
-
-	clk = clk_fixed("apb_pclk", 0);
-	clk_register_clkdev(clk, "apb_pclk", NULL);
-
-	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
-	clk_register_clkdev(clk, NULL, "uart0-pl0110");
-	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
-	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
-
-	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
-					  "uart1-8250");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	clkdev_add_physbase(clk, BCM2835_MINIUART_BASE, NULL);
-	clkdev_add_physbase(clk, BCM2836_MINIUART_BASE, NULL);
-
-	clk = clk_fixed("bcm2835-cs", 1 * 1000 * 1000);
-	clk_register_clkdev(clk, NULL, "bcm2835-cs");
-
-	return 0;
-}
-postcore_initcall(rpi_console_clock_init);
-
 static int rpi_env_init(void)
 {
 	struct stat s;
@@ -559,6 +487,7 @@ static const struct of_device_id rpi_of_match[] = {
 	{ .compatible = "raspberrypi,3-compute-module-lite" },
 	{ /* sentinel */ },
 };
+BAREBOX_DEEP_PROBE_ENABLE(rpi_of_match);
 
 static struct driver_d rpi_board_driver = {
 	.name = "board-rpi",
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 499df2fe39..9675d45dc9 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_ARCH_LAYERSCAPE)	+= clk-qoric.o
 obj-y				+= analogbits/
 obj-$(CONFIG_CLK_SIFIVE)	+= sifive/
 obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
+obj-$(CONFIG_MACH_RPI_COMMON)	+= clk-rpi.o
diff --git a/drivers/clk/clk-rpi.c b/drivers/clk/clk-rpi.c
new file mode 100644
index 0000000000..794d95a591
--- /dev/null
+++ b/drivers/clk/clk-rpi.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+
+#include <mach/core.h>
+#include <mach/mbox.h>
+#include <mach/platform.h>
+
+struct msg_get_clock_rate {
+	struct bcm2835_mbox_hdr hdr;
+	struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
+	u32 end_tag;
+};
+
+static struct clk *rpi_register_firmware_clock(u32 clock_id, const char *name)
+{
+	BCM2835_MBOX_STACK_ALIGN(struct msg_get_clock_rate, msg);
+	int ret;
+
+	BCM2835_MBOX_INIT_HDR(msg);
+	BCM2835_MBOX_INIT_TAG(&msg->get_clock_rate, GET_CLOCK_RATE);
+	msg->get_clock_rate.body.req.clock_id = clock_id;
+
+	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return clk_fixed(name, msg->get_clock_rate.body.resp.rate_hz);
+}
+
+static int bcm2835_cprman_init(struct device_node *np)
+{
+	struct device_node *mbox_node;
+	struct clk *clk;
+	int ret;
+
+	mbox_node = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-mbox");
+	if (!mbox_node) {
+		pr_err("Missing mbox node\n");
+		return -ENOENT;
+	}
+
+	ret = of_device_ensure_probed(mbox_node);
+	if (ret) {
+		pr_err("Can't probe mbox node. %i\n", ret);
+		return ret;
+	}
+
+	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_EMMC,
+					 "bcm2835_mci0");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	clkdev_add_physbase(clk, 0x20300000, NULL);
+	clkdev_add_physbase(clk, 0x3f300000, NULL);
+
+	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
+					  "bcm2835_sdhost");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	clkdev_add_physbase(clk, 0x20202000, NULL);
+	clkdev_add_physbase(clk, 0x3f202000, NULL);
+
+	clk = clk_fixed("apb_pclk", 0);
+	clk_register_clkdev(clk, "apb_pclk", NULL);
+
+	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
+	clk_register_clkdev(clk, NULL, "uart0-pl0110");
+	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
+	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
+
+	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
+					  "uart1-8250");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	clkdev_add_physbase(clk, BCM2835_MINIUART_BASE, NULL);
+	clkdev_add_physbase(clk, BCM2836_MINIUART_BASE, NULL);
+
+	clk = clk_fixed("bcm2835-cs", 1 * 1000 * 1000);
+	clk_register_clkdev(clk, NULL, "bcm2835-cs");
+
+	return 0;
+}
+/* CLK_OF_DECLARE should be used to make it probed before amba,pl011 */
+CLK_OF_DECLARE(bcm2835_cprman, "brcm,bcm2835-cprman", bcm2835_cprman_init);
-- 
2.30.2



From o.rempel at pengutronix.de  Mon Jan 17 04:04:59 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Mon, 17 Jan 2022 13:04:59 +0100
Subject: [PATCH v1 3/4] ARM: rpi: validate devicetree compatible instead of
 changing model name
In-Reply-To: <20220117120500.3556703-1-o.rempel@pengutronix.de>
References: <20220117120500.3556703-1-o.rempel@pengutronix.de>
Message-ID: <20220117120500.3556703-3-o.rempel@pengutronix.de>

To cover all possible RPi variants we need to be able to work with DTs
provided by the 1. stage loader. If we get wrong DT for the barebox,
we will take wrong DT for kernel as well.

Since current device list was used only to update model name without
updating devicetree compatible, this patch will turn it around by using
device list to validate if we use right DT/compatible on the right HW.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 410 ++++++++++++++--------
 1 file changed, 272 insertions(+), 138 deletions(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 53c476c22a..b6673ca474 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -6,6 +6,7 @@
 #include <init.h>
 #include <fs.h>
 #include <of.h>
+#include <of_device.h>
 #include <linux/stat.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
@@ -29,16 +30,20 @@
 
 #include "lowlevel.h"
 
-struct rpi_model {
-	const char *name;
-	void (*init)(void);
+struct rpi_priv;
+struct rpi_machine_data {
+	unsigned int hw_id;
+#define RPI_OLD_SCHEMA			BIT(0)
+	unsigned int flags;
+	int (*init)(struct rpi_priv *priv);
 };
 
-#define RPI_MODEL(_id, _name, _init)	\
-	[_id] = {				\
-		.name			= _name,\
-		.init			= _init,\
-	}
+struct rpi_priv {
+	struct device_d *dev;
+	const struct rpi_machine_data *dcfg;
+	unsigned int hw_id;
+	const char *name;
+};
 
 struct msg_get_arm_mem {
 	struct bcm2835_mbox_hdr hdr;
@@ -133,98 +138,56 @@ static void rpi_add_led(void)
 		led_set_trigger(LED_TRIGGER_HEARTBEAT, &l->led);
 }
 
-static void rpi_b_init(void)
+static int rpi_b_init(struct rpi_priv *priv)
 {
 	rpi_leds[0].gpio = 16;
 	rpi_leds[0].active_low = 1;
 	rpi_set_usbethaddr();
+
+	return 0;
 }
 
-static void rpi_b_plus_init(void)
+static int rpi_b_plus_init(struct rpi_priv *priv)
 {
 	rpi_leds[0].gpio = 47;
 	rpi_leds[1].gpio = 35;
 	rpi_set_usbethaddr();
+
+	return 0;
 }
 
-static void rpi_0_init(void)
+static int rpi_0_init(struct rpi_priv *priv)
 {
 	rpi_leds[0].gpio = 47;
 	rpi_set_usbotg("usb0");
+
+	return 0;
 }
 
-static void rpi_0_w_init(void)
+static int rpi_0_w_init(struct rpi_priv *priv)
 {
 	struct device_node *np;
 	int ret;
 
-	rpi_0_init();
+	rpi_0_init(priv);
 
 	np = of_find_node_by_path("/chosen");
 	if (!np)
-		return;
+		return -ENODEV;
 
 	if (!of_device_enable_and_register_by_alias("serial1"))
-		return;
+		return -ENODEV;
 
 	ret = of_property_write_string(np, "stdout-path", "serial1:115200n8");
 	if (ret)
-		return;
+		return ret;
 
-	of_device_disable_by_alias("serial0");
+	return of_device_disable_by_alias("serial0");
 }
 
-/* See comments in mbox.h for data source */
-static const struct rpi_model rpi_models_old_scheme[] = {
-	RPI_MODEL(0, "Unknown model", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_2, "Model B (no P5)", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_3, "Model B (no P5)", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_4, "Model B", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_5, "Model B", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_6, "Model B", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_A_7, "Model A", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_8, "Model A", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_9, "Model A", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_B_REV2_d, "Model B rev2", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_REV2_e, "Model B rev2", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_REV2_f, "Model B rev2", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_PLUS_10, "Model B+", rpi_b_plus_init),
-	RPI_MODEL(BCM2835_BOARD_REV_CM_11, "Compute Module", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_PLUS_12, "Model A+", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_B_PLUS_13, "Model B+", rpi_b_plus_init),
-	RPI_MODEL(BCM2835_BOARD_REV_CM_14, "Compute Module", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_PLUS_15, "Model A+", NULL),
-};
-
-static const struct rpi_model rpi_models_new_scheme[] = {
-	RPI_MODEL(BCM2835_BOARD_REV_A, 		"Model A",	NULL ),
-	RPI_MODEL(BCM2835_BOARD_REV_B, 		"Model B", 	rpi_b_init ),
-	RPI_MODEL(BCM2835_BOARD_REV_A_PLUS, 	"Model A+", 	NULL ),
-	RPI_MODEL(BCM2835_BOARD_REV_B_PLUS, 	"Model B+", 	rpi_b_plus_init ),
-	RPI_MODEL(BCM2836_BOARD_REV_2_B, 	"Model 2B", 	rpi_b_plus_init),
-	RPI_MODEL(BCM283x_BOARD_REV_Alpha, 	"Alpha", 	NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_CM1, 	"Compute Module", NULL ),
-	RPI_MODEL(0x7, "Unknown model", NULL),
-	RPI_MODEL(BCM2837_BOARD_REV_3_B, 	"Model 3B", 	rpi_b_init ),
-	RPI_MODEL(BCM2835_BOARD_REV_ZERO, 	"Zero", 	rpi_0_init),
-	RPI_MODEL(BCM2837_BOARD_REV_CM3, 	"Compute Module 3", NULL ),
-	RPI_MODEL(0xb, "Unknown model", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_ZERO_W, 	"Zero W", 	rpi_0_w_init),
-	RPI_MODEL(BCM2837B0_BOARD_REV_3B_PLUS, 	"Model 3B+", 	rpi_b_plus_init ),
-	RPI_MODEL(BCM2837B0_BOARD_REV_3A_PLUS, 	"Model 3A+", 	rpi_b_plus_init),
-	RPI_MODEL(0xf, "Unknown model", NULL),
-	RPI_MODEL(BCM2837B0_BOARD_REV_CM3_PLUS, "Compute Module 3+", NULL),
-};
-
-static int rpi_board_rev = 0;
-static const struct rpi_model *model = NULL;
-
-static void rpi_get_board_rev(void)
+static int rpi_get_board_rev(struct rpi_priv *priv)
 {
 	int ret;
-	char *name;
-	const struct rpi_model *rpi_models;
-	size_t rpi_models_size;
 
 	BCM2835_MBOX_STACK_ALIGN(struct msg_get_board_rev, msg);
 	BCM2835_MBOX_INIT_HDR(msg);
@@ -232,9 +195,8 @@ static void rpi_get_board_rev(void)
 
 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
 	if (ret) {
-		printf("bcm2835: Could not query board revision\n");
-		/* Ignore error; not critical */
-		return;
+		dev_err(priv->dev, "Could not query board revision\n");
+		return ret;
 	}
 
 	/* Comments from u-boot:
@@ -248,53 +210,9 @@ static void rpi_get_board_rev(void)
 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250
 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594
 	 */
-	rpi_board_rev = msg->get_board_rev.body.resp.rev;
-	if (rpi_board_rev & 0x800000) {
-		rpi_board_rev = (rpi_board_rev >> 4) & 0xff;
-		rpi_models = rpi_models_new_scheme;
-		rpi_models_size = ARRAY_SIZE(rpi_models_new_scheme);
-
-	} else {
-		rpi_board_rev &= 0xff;
-		rpi_models = rpi_models_old_scheme;
-		rpi_models_size = ARRAY_SIZE(rpi_models_old_scheme);
-	}
-
-	if (rpi_board_rev >= rpi_models_size) {
-		printf("RPI: Board rev %u outside known range\n",
-		       rpi_board_rev);
-		goto unknown_rev;
-	}
-
-	if (!rpi_models[rpi_board_rev].name) {
-		printf("RPI: Board rev %u unknown\n", rpi_board_rev);
-		goto unknown_rev;
-	}
-
-	if (!rpi_board_rev)
-		goto unknown_rev;
-
-	model = &rpi_models[rpi_board_rev];
-	name = basprintf("RaspberryPi %s", model->name);
-	barebox_set_model(name);
-	free(name);
+	priv->hw_id = msg->get_board_rev.body.resp.rev;
 
-	return;
-
-unknown_rev:
-	rpi_board_rev = 0;
-	barebox_set_model("RaspberryPi (unknown rev)");
-}
-
-static void rpi_model_init(void)
-{
-	if (!model)
-		return;
-
-	if (!model->init)
-		return;
-
-	model->init();
+	return 0;
 }
 
 static int rpi_mem_init(void)
@@ -312,16 +230,6 @@ static int rpi_mem_init(void)
 }
 mem_initcall(rpi_mem_init);
 
-static int rpi_postcore_init(void)
-{
-	rpi_get_board_rev();
-	barebox_set_hostname("rpi");
-	rpi_model_init();
-
-	return 0;
-}
-postcore_initcall(rpi_postcore_init);
-
 static int rpi_env_init(void)
 {
 	struct stat s;
@@ -439,9 +347,65 @@ static void rpi_vc_fdt(void)
 	}
 }
 
+static int rpi_get_dcfg(struct rpi_priv *priv)
+{
+	const struct rpi_machine_data *dcfg;
+	int ret;
+
+	dcfg = of_device_get_match_data(priv->dev);
+	if (!dcfg) {
+		ret = -EINVAL;
+		goto exit_get_dcfg;
+	}
+
+	for (; dcfg->hw_id != UINT_MAX; dcfg++) {
+		if (priv->hw_id & 0x800000) {
+			if (dcfg->hw_id != ((priv->hw_id >> 4) & 0xff))
+				continue;
+		} else {
+			if (!(dcfg->flags & RPI_OLD_SCHEMA))
+				continue;
+			if (dcfg->hw_id != (priv->hw_id & 0xff))
+				continue;
+		}
+
+		priv->dcfg = dcfg;
+		break;
+	}
+
+	if (!priv->dcfg) {
+		ret = -ENODEV;
+		goto exit_get_dcfg;
+	}
+
+	return 0;
+exit_get_dcfg:
+	dev_err(priv->dev, "Failed to get dcfg for board_id: 0x%x: %pe\n",
+		priv->hw_id, ERR_PTR(ret));
+	return ret;
+}
+
 static int rpi_devices_probe(struct device_d *dev)
 {
 	struct regulator *reg;
+	struct rpi_priv *priv;
+	int ret;
+
+	priv = xzalloc(sizeof(*priv));
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	ret = rpi_get_board_rev(priv);
+	if (ret)
+		goto free_priv;
+
+	ret = rpi_get_dcfg(priv);
+	if (ret)
+		goto free_priv;
+
+	barebox_set_hostname("rpi");
 
 	rpi_add_led();
 	bcm2835_register_fb();
@@ -449,6 +413,9 @@ static int rpi_devices_probe(struct device_d *dev)
 	rpi_env_init();
 	rpi_vc_fdt();
 
+	if (priv->dcfg->init)
+		priv->dcfg->init(priv);
+
 	reg = regulator_get_name("bcm2835_usb");
 	if (IS_ERR(reg))
 		return PTR_ERR(reg);
@@ -456,8 +423,175 @@ static int rpi_devices_probe(struct device_d *dev)
 	regulator_enable(reg);
 
 	return 0;
+
+free_priv:
+	kfree(priv);
+	return ret;
 }
 
+static const struct rpi_machine_data rpi_model_a[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_A_7,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_8,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_9,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_a_plus[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_A_PLUS_12,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_PLUS_15,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_PLUS,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_I2C1_4,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_I2C1_5,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_I2C1_6,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b_i2c0[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_I2C0_2,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_I2C0_3,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b_rev2[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_REV2_d,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_REV2_e,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_REV2_f,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b_plus[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_PLUS_10,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_PLUS_13,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_PLUS,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_compute_module[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_CM_11,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_CM_14,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_CM1,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_zero[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_ZERO,
+		.init = rpi_0_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_zero_w[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_ZERO_W,
+		.init = rpi_0_w_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_2_model_b[] = {
+	{
+		.hw_id = BCM2836_BOARD_REV_2_B,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_3_model_a_plus[] = {
+	{
+		.hw_id = BCM2837B0_BOARD_REV_3A_PLUS,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_3_model_b[] = {
+	{
+		.hw_id = BCM2837_BOARD_REV_3_B,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_3_model_b_plus[] = {
+	{
+		.hw_id = BCM2837B0_BOARD_REV_3B_PLUS,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = UINT_MAX
+	},
+};
+
 static const struct of_device_id rpi_of_match[] = {
 	/* BCM2711 based Boards */
 	{ .compatible = "raspberrypi,400" },
@@ -465,24 +599,24 @@ static const struct of_device_id rpi_of_match[] = {
 	{ .compatible = "raspberrypi,4-model-b" },
 
 	/* BCM2835 based Boards */
-	{ .compatible = "raspberrypi,model-a" },
-	{ .compatible = "raspberrypi,model-a-plus" },
-	{ .compatible = "raspberrypi,model-b" },
+	{ .compatible = "raspberrypi,model-a", .data = rpi_model_a },
+	{ .compatible = "raspberrypi,model-a-plus", .data = rpi_model_a_plus },
+	{ .compatible = "raspberrypi,model-b", .data = rpi_model_b },
 	/* Raspberry Pi Model B (no P5) */
-	{ .compatible = "raspberrypi,model-b-i2c0" },
-	{ .compatible = "raspberrypi,model-b-rev2" },
-	{ .compatible = "raspberrypi,model-b-plus" },
-	{ .compatible = "raspberrypi,compute-module" },
-	{ .compatible = "raspberrypi,model-zero" },
-	{ .compatible = "raspberrypi,model-zero-w" },
+	{ .compatible = "raspberrypi,model-b-i2c0", .data = rpi_model_b_i2c0 },
+	{ .compatible = "raspberrypi,model-b-rev2", .data = rpi_model_b_rev2 },
+	{ .compatible = "raspberrypi,model-b-plus", .data = rpi_model_b_plus },
+	{ .compatible = "raspberrypi,compute-module", .data = rpi_compute_module },
+	{ .compatible = "raspberrypi,model-zero", .data = rpi_model_zero },
+	{ .compatible = "raspberrypi,model-zero-w", .data = rpi_model_zero_w },
 
 	/* BCM2836 based Boards */
-	{ .compatible = "raspberrypi,2-model-b" },
+	{ .compatible = "raspberrypi,2-model-b", .data = rpi_2_model_b },
 
 	/* BCM2837 based Boards */
-	{ .compatible = "raspberrypi,3-model-a-plus" },
-	{ .compatible = "raspberrypi,3-model-b" },
-	{ .compatible = "raspberrypi,3-model-b-plus" },
+	{ .compatible = "raspberrypi,3-model-a-plus", .data = rpi_3_model_a_plus },
+	{ .compatible = "raspberrypi,3-model-b", .data = rpi_3_model_b },
+	{ .compatible = "raspberrypi,3-model-b-plus", .data = rpi_3_model_b_plus },
 	{ .compatible = "raspberrypi,3-compute-module" },
 	{ .compatible = "raspberrypi,3-compute-module-lite" },
 	{ /* sentinel */ },
-- 
2.30.2



From trent.piepho at igorinstitute.com  Mon Jan 17 12:14:17 2022
From: trent.piepho at igorinstitute.com (Trent Piepho)
Date: Mon, 17 Jan 2022 12:14:17 -0800
Subject: [PATCH v1 3/4] ARM: rpi: validate devicetree compatible instead
 of changing model name
In-Reply-To: <20220117120500.3556703-3-o.rempel@pengutronix.de>
References: <20220117120500.3556703-1-o.rempel@pengutronix.de>
 <20220117120500.3556703-3-o.rempel@pengutronix.de>
Message-ID: <CAMHeXxOMT7=Eo1Xsx484WQcX0eEXfSb9v9L7U6fLubBYnFz1WA@mail.gmail.com>

On Mon, Jan 17, 2022 at 4:06 AM Oleksij Rempel <o.rempel at pengutronix.de> wrote:
> +struct rpi_priv;
> +struct rpi_machine_data {
> +       unsigned int hw_id;
> +#define RPI_OLD_SCHEMA                 BIT(0)
> +       unsigned int flags;

hw_id is only a byte.  Both of these fields could be u8, which would
make the struct smaller.

> +struct rpi_priv {
> +       struct device_d *dev;
> +       const struct rpi_machine_data *dcfg;

Doesn't seem like there is any need to have dcfg saved in this struct.
It looks like it's used just once, in the same function that finds the
value.  rpi_get_dcfg() could return the value directly, rather than
indirectly by writing it into a field of a struct passed as an
argument.

>
> +static int rpi_get_dcfg(struct rpi_priv *priv)
> +{
> +       const struct rpi_machine_data *dcfg;
> +       int ret;
> +
> +       dcfg = of_device_get_match_data(priv->dev);
> +       if (!dcfg) {
> +               ret = -EINVAL;
> +               goto exit_get_dcfg;
> +       }

Then later:
> +       ret = rpi_get_dcfg(priv);
> +       if (ret)
> +               goto free_priv;

It looks like any board that doesn't have match data will be rejected
and fail to init.  But then what about these boards:

>  static const struct of_device_id rpi_of_match[] = {
>         /* BCM2711 based Boards */
>         { .compatible = "raspberrypi,400" },
> @@ -465,24 +599,24 @@ static const struct of_device_id rpi_of_match[] = {
>         { .compatible = "raspberrypi,4-model-b" },

Looks like they'll get rejected since they have no match data.

> +
> +       for (; dcfg->hw_id != UINT_MAX; dcfg++) {
> +               if (priv->hw_id & 0x800000) {
> +                       if (dcfg->hw_id != ((priv->hw_id >> 4) & 0xff))
> +                               continue;
> +               } else {
> +                       if (!(dcfg->flags & RPI_OLD_SCHEMA))
> +                               continue;
> +                       if (dcfg->hw_id != (priv->hw_id & 0xff))
> +                               continue;
> +               }
> +
> +               priv->dcfg = dcfg;
> +               break;

Could just return 0 here instead of break.  Or better, "return dcfg",
as there's no reason not to just return the value like a normal
function.

> +       }
> +
> +       if (!priv->dcfg) {
> +               ret = -ENODEV;
> +               goto exit_get_dcfg;
> +       }

Then this can become ret = -ENODEV and the if and goto go away.

> +
> +       priv = xzalloc(sizeof(*priv));
> +       if (!priv)
> +               return -ENOMEM;

No need to check the return value of "x" alloc functions.  That's the
whole point of the x version.


From jmaselbas at kalray.eu  Mon Jan 17 14:19:12 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:12 +0100
Subject: [PATCH v2 06/11] clocksource: kvx: Register as
 postcore_platform_driver
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-7-jmaselbas@kalray.eu>

Register the kvx clocksource driver sooner, before probing other device
drivers by using the postcore_platform_driver macro. That way the other
drivers will have a correct timestamp when printing messages.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/clocksource/kvx_timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/kvx_timer.c b/drivers/clocksource/kvx_timer.c
index 4125ddbee0..2a05d8deed 100644
--- a/drivers/clocksource/kvx_timer.c
+++ b/drivers/clocksource/kvx_timer.c
@@ -55,4 +55,4 @@ static struct driver_d kvx_timer_driver = {
 	.of_compatible = DRV_OF_COMPAT(kvx_timer_dt_ids),
 };
 
-device_platform_driver(kvx_timer_driver);
+postcore_platform_driver(kvx_timer_driver);
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:06 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:06 +0100
Subject: [PATCH v2 00/11] kvx arch update
Message-ID: <20220117221917.26970-1-jmaselbas@kalray.eu>

This series has updates for the KVX architecture, with some fixes and
with the addition of kvx specific drivers for the otp-nvmem and socinfo.

With this series it is now possible to run barebox on qemu, however
our qemu port isn't upstreamed yet, it can still be compiled. To do
so you will need to check this git repo [1] and follow the build
instructions.

To compile barebox for the KVX architecture there is a pre-built
toolchain that can be downloaded here [2]

The following commands should build an run barebox on qemu:
$ PATH=<path/to/gcc-kalray-kvx-v4.7.0-cd2>/bin:$PATH ARCH=kvx make generic_defconfig all
$ qemu-system-kvx -m 1G -nographic -kernel barebox

[1] https://github.com/kalray/qemu-builder
[2] https://github.com/kalray/build-scripts/releases/tag/v4.7.0-cd2

---

Changes in v2:
 - rebased on master
 - updated with Clement's new email address
 - droped two patches (the config and device-tree update) as there are
   not needed by qemu and the device-tree requires drivers not upstreamed
   yet.
 - small fixup on the nvmem driver

Clement Leger (6):
  common: elf: add elf_load_binary
  kvx: enable FITIMAGE support
  nvmem: add kvx otp non volatile regbank support
  kvx: add kvx_sfr_field_val
  drivers: add soc hierarchy properly
  soc: add kvx_socinfo driver

Jules Maselbas (4):
  kvx: dma: Remove arch dma_map/unmap_single
  kvx: Move LINUX_BOOT_PARAM_MAGIC in asm/common.h
  kvx: Accept LINUX_BOOT_PARAM_MAGIC as a valid magic value
  clocksource: kvx: Register as postcore_platform_driver

Louis Morhet (1):
  watchdog: kvx: do not disable watchdog on probe

 arch/kvx/Kconfig                |   1 +
 arch/kvx/cpu/cpu.c              |   2 +-
 arch/kvx/include/asm/bootm.h    |  11 ---
 arch/kvx/include/asm/common.h   |   3 +-
 arch/kvx/include/asm/sfr.h      |   4 +
 arch/kvx/lib/bootm.c            |  33 +++++++-
 arch/kvx/lib/dma-default.c      |  38 ---------
 common/elf.c                    |  83 ++++++++++++++-----
 drivers/Kconfig                 |   2 +-
 drivers/clocksource/kvx_timer.c |   2 +-
 drivers/nvmem/Kconfig           |   7 ++
 drivers/nvmem/Makefile          |   3 +
 drivers/nvmem/kvx-otp-nv.c      |  98 ++++++++++++++++++++++
 drivers/soc/Kconfig             |   6 ++
 drivers/soc/Makefile            |   1 +
 drivers/soc/kvx/Kconfig         |  10 +++
 drivers/soc/kvx/Makefile        |   1 +
 drivers/soc/kvx/kvx_socinfo.c   | 141 ++++++++++++++++++++++++++++++++
 drivers/watchdog/kvx_wdt.c      |   4 +-
 include/elf.h                   |   1 +
 20 files changed, 371 insertions(+), 80 deletions(-)
 delete mode 100644 arch/kvx/include/asm/bootm.h
 create mode 100644 drivers/nvmem/kvx-otp-nv.c
 create mode 100644 drivers/soc/Kconfig
 create mode 100644 drivers/soc/kvx/Kconfig
 create mode 100644 drivers/soc/kvx/Makefile
 create mode 100644 drivers/soc/kvx/kvx_socinfo.c

-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:16 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:16 +0100
Subject: [PATCH v2 10/11] drivers: add soc hierarchy properly
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-11-jmaselbas@kalray.eu>

From: Clement Leger <clement.leger at bootlin.com>

We will add kvx driver in this folder to create a proper hierarchy.

Signed-off-by: Clement Leger <clement.leger at bootlin.com>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/Kconfig     | 2 +-
 drivers/soc/Kconfig | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/Kconfig

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 01b659b02c..2636eed1a3 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -41,7 +41,7 @@ source "drivers/fpga/Kconfig"
 source "drivers/phy/Kconfig"
 source "drivers/crypto/Kconfig"
 source "drivers/memory/Kconfig"
-source "drivers/soc/imx/Kconfig"
+source "drivers/soc/Kconfig"
 source "drivers/nvme/Kconfig"
 source "drivers/ddr/Kconfig"
 source "drivers/power/Kconfig"
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
new file mode 100644
index 0000000000..d78f13f3f8
--- /dev/null
+++ b/drivers/soc/Kconfig
@@ -0,0 +1,5 @@
+menu "SoC drivers"
+
+source "drivers/soc/imx/Kconfig"
+
+endmenu
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:09 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:09 +0100
Subject: [PATCH v2 03/11] kvx: Accept LINUX_BOOT_PARAM_MAGIC as a valid magic
 value
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-4-jmaselbas@kalray.eu>

Both defines FSBL_PARAM_MAGIC and LINUX_BOOT_PARAM_MAGIC have a similar
uses and yet have different values. Making barebox accept both as valid
magic boot param will make it possible to use qemu-system-kvx to boot a
barebox image as a normal kernel.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/cpu/cpu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/kvx/cpu/cpu.c b/arch/kvx/cpu/cpu.c
index 788d3194fe..4b0d4d2d96 100644
--- a/arch/kvx/cpu/cpu.c
+++ b/arch/kvx/cpu/cpu.c
@@ -16,7 +16,7 @@ void kvx_lowlevel_setup(unsigned long r0, void *dtb_ptr)
 {
 	uint64_t ev_val = (uint64_t) &_exception_start | EXCEPTION_STRIDE;
 
-	if (r0 == FSBL_PARAM_MAGIC) {
+	if (r0 == FSBL_PARAM_MAGIC || r0 == LINUX_BOOT_PARAM_MAGIC) {
 		boot_dtb = dtb_ptr;
 		pr_info("Using DTB provided by FSBL\n");
 	}
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:13 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:13 +0100
Subject: [PATCH v2 07/11] watchdog: kvx: do not disable watchdog on probe
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-8-jmaselbas@kalray.eu>

From: Louis Morhet <lmorhet at kalray.eu>

As the watchdog may be set by a lower stage in the boot chain, and for
a good reason (precisely to ensure reliable update when something
unexpected happens during the boot chain), it is a bad idea to always
disable it during probe.

We should either have a mechanism to refresh it on a regular basis in
barebox itself and set it to something bigger for Linux, or handle it
transparently and let the previous stage set the global watchdog up to
Linux. This patch assumes for now the latter.

Signed-off-by: Louis Morhet <lmorhet at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/watchdog/kvx_wdt.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/watchdog/kvx_wdt.c b/drivers/watchdog/kvx_wdt.c
index da19136fda..df9430769b 100644
--- a/drivers/watchdog/kvx_wdt.c
+++ b/drivers/watchdog/kvx_wdt.c
@@ -73,11 +73,9 @@ static int kvx_wdt_drv_probe(struct device_d *dev)
 	wdd->hwdev = dev;
 	wdd->set_timeout = kvx_wdt_set_timeout;
 
-	/* Be sure that interrupt are disable */
+	/* Be sure that interrupt are disabled */
 	kvx_sfr_set_field(TCR, WIE, 0);
 
-	kvx_watchdog_disable();
-
 	return watchdog_register(wdd);
 }
 
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:07 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:07 +0100
Subject: [PATCH v2 01/11] kvx: dma: Remove arch dma_map/unmap_single
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-2-jmaselbas@kalray.eu>

Since dma_map/unmap_single functions have been moved to common, barebox
doesn't compile for kvx anymore. The original functions were doing some
magic to support 32bits dma buffer addresses. The original behavior can
be replaced by a device-tree dma-range property.

Fixes: 3f975f810 ("dma: move dma_map/unmap_single from ARM to common code")
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/lib/dma-default.c | 38 --------------------------------------
 1 file changed, 38 deletions(-)

diff --git a/arch/kvx/lib/dma-default.c b/arch/kvx/lib/dma-default.c
index 2a4144696c..c84a32954e 100644
--- a/arch/kvx/lib/dma-default.c
+++ b/arch/kvx/lib/dma-default.c
@@ -54,41 +54,3 @@ void dma_sync_single_for_cpu(dma_addr_t addr, size_t size,
 		BUG();
 	}
 }
-
-#define KVX_DDR_ALIAS_OFFSET \
-	(KVX_DDR_64BIT_RAM_WINDOW_BA - KVX_DDR_32BIT_RAM_WINDOW_BA)
-#define KVX_DDR_ALIAS_WINDOW \
-	(KVX_DDR_64BIT_RAM_WINDOW_BA + KVX_DDR_ALIAS_OFFSET)
-
-/* Local smem is aliased between 0 and 16MB */
-#define KVX_SMEM_LOCAL_ALIAS 0x1000000ULL
-
-dma_addr_t dma_map_single(struct device_d *dev, void *ptr, size_t size,
-			  enum dma_data_direction dir)
-{
-	uintptr_t addr = (uintptr_t) ptr;
-
-	dma_sync_single_for_device(addr, size, dir);
-
-	/* Local smem alias should never be used for dma */
-	if (addr < KVX_SMEM_LOCAL_ALIAS)
-		return addr + (1 + kvx_cluster_id()) * KVX_SMEM_LOCAL_ALIAS;
-
-	if (dev->dma_mask && addr <= dev->dma_mask)
-		return addr;
-
-	if (addr >= KVX_DDR_ALIAS_WINDOW)
-		return DMA_ERROR_CODE;
-
-	addr -= KVX_DDR_ALIAS_OFFSET;
-	if (dev->dma_mask && addr > dev->dma_mask)
-		return DMA_ERROR_CODE;
-
-	return addr;
-}
-
-void dma_unmap_single(struct device_d *dev, dma_addr_t addr, size_t size,
-		      enum dma_data_direction dir)
-{
-	dma_sync_single_for_cpu(addr, size, dir);
-}
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:10 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:10 +0100
Subject: [PATCH v2 04/11] common: elf: add elf_load_binary
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-5-jmaselbas@kalray.eu>

From: Clement Leger <clement.leger at bootlin.com>

In order to load elf from a binary buffer, add elf_load_binary. This
will be used by FIT support to allow loading an elf from FIT.

Signed-off-by: Clement Leger <clement.leger at bootlin.com>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 common/elf.c  | 83 +++++++++++++++++++++++++++++++++++++--------------
 include/elf.h |  1 +
 2 files changed, 62 insertions(+), 22 deletions(-)

diff --git a/common/elf.c b/common/elf.c
index af22be37e6..f10fb77953 100644
--- a/common/elf.c
+++ b/common/elf.c
@@ -101,15 +101,17 @@ static int elf_section_cmp(void *priv, struct list_head *a, struct list_head *b)
 static int load_elf_to_memory(struct elf_image *elf)
 {
 	void *dst;
-	int ret, fd;
+	int ret, fd = -1;
 	u64 p_filesz, p_memsz, p_offset;
 	struct elf_section *r;
 	struct list_head *list = &elf->list;
 
-	fd = open(elf->filename, O_RDONLY);
-	if (fd < 0) {
-		pr_err("could not open: %s\n", errno_str());
-		return -errno;
+	if (elf->filename) {
+		fd = open(elf->filename, O_RDONLY);
+		if (fd < 0) {
+			pr_err("could not open: %s\n", errno_str());
+			return -errno;
+		}
 	}
 
 	list_for_each_entry(r, list, list) {
@@ -118,21 +120,26 @@ static int load_elf_to_memory(struct elf_image *elf)
 		p_memsz = elf_phdr_p_memsz(elf, r->phdr);
 		dst = (void *) (phys_addr_t) elf_phdr_p_paddr(elf, r->phdr);
 
-		ret = lseek(fd, p_offset, SEEK_SET);
-		if (ret == -1) {
-			pr_err("lseek at offset 0x%llx failed\n", p_offset);
-			close(fd);
-			return ret;
-		}
-
 		pr_debug("Loading phdr offset 0x%llx to 0x%p (%llu bytes)\n",
 			 p_offset, dst, p_filesz);
 
-		if (read_full(fd, dst, p_filesz) < 0) {
-			pr_err("could not read elf segment: %s\n",
-			       errno_str());
-			close(fd);
-			return -errno;
+		if (fd >= 0) {
+			ret = lseek(fd, p_offset, SEEK_SET);
+			if (ret == -1) {
+				pr_err("lseek at offset 0x%llx failed\n",
+				       p_offset);
+				close(fd);
+				return ret;
+			}
+
+			if (read_full(fd, dst, p_filesz) < 0) {
+				pr_err("could not read elf segment: %s\n",
+				       errno_str());
+				close(fd);
+				return -errno;
+			}
+		} else {
+			memcpy(dst, elf->hdr_buf + p_offset, p_filesz);
 		}
 
 		if (p_filesz < p_memsz)
@@ -202,6 +209,37 @@ static int elf_check_image(struct elf_image *elf, void *buf)
 	return 0;
 }
 
+static void elf_init_struct(struct elf_image *elf)
+{
+	INIT_LIST_HEAD(&elf->list);
+	elf->low_addr = (void *) (unsigned long) -1;
+	elf->high_addr = 0;
+	elf->filename = NULL;
+}
+
+struct elf_image *elf_open_binary(void *buf)
+{
+	int ret;
+	struct elf_image *elf;
+
+	elf = calloc(1, sizeof(*elf));
+	if (!elf)
+		return ERR_PTR(-ENOMEM);
+
+	elf_init_struct(elf);
+
+	elf->hdr_buf = buf;
+	ret = elf_check_image(elf, buf);
+	if (ret) {
+		free(elf);
+		return ERR_PTR(-EINVAL);
+	}
+
+	elf->entry = elf_hdr_e_entry(elf, elf->hdr_buf);
+
+	return elf;
+}
+
 static struct elf_image *elf_check_init(const char *filename)
 {
 	int ret, fd;
@@ -213,9 +251,7 @@ static struct elf_image *elf_check_init(const char *filename)
 	if (!elf)
 		return ERR_PTR(-ENOMEM);
 
-	INIT_LIST_HEAD(&elf->list);
-	elf->low_addr = (void *) (unsigned long) -1;
-	elf->high_addr = 0;
+	elf_init_struct(elf);
 
 	/* First pass is to read elf header only */
 	fd = open(filename, O_RDONLY);
@@ -299,7 +335,10 @@ void elf_close(struct elf_image *elf)
 {
 	elf_release_regions(elf);
 
-	free(elf->hdr_buf);
-	free(elf->filename);
+	if (elf->filename) {
+		free(elf->hdr_buf);
+		free(elf->filename);
+	}
+
 	free(elf);
 }
diff --git a/include/elf.h b/include/elf.h
index 7970fd2c95..12673e93ed 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -414,6 +414,7 @@ static inline size_t elf_get_mem_size(struct elf_image *elf)
 	return elf->high_addr - elf->low_addr;
 }
 
+struct elf_image *elf_open_binary(void *buf);
 struct elf_image *elf_open(const char *filename);
 void elf_close(struct elf_image *elf);
 int elf_load(struct elf_image *elf);
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:08 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:08 +0100
Subject: [PATCH v2 02/11] kvx: Move LINUX_BOOT_PARAM_MAGIC in asm/common.h
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-3-jmaselbas@kalray.eu>

Declare both defines FSBL_PARAM_MAGIC and LINUX_BOOT_PARAM_MAGIC in the
same header file, as they both have a very similar uses and value.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/include/asm/bootm.h  | 11 -----------
 arch/kvx/include/asm/common.h |  3 ++-
 arch/kvx/lib/bootm.c          |  1 -
 3 files changed, 2 insertions(+), 13 deletions(-)
 delete mode 100644 arch/kvx/include/asm/bootm.h

diff --git a/arch/kvx/include/asm/bootm.h b/arch/kvx/include/asm/bootm.h
deleted file mode 100644
index 7ad7e2e878..0000000000
--- a/arch/kvx/include/asm/bootm.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2019 Kalray Inc.
- */
-
-#ifndef _ASM_KVX_BOOTM_H
-#define _ASM_KVX_BOOTM_H
-
-#define LINUX_BOOT_PARAM_MAGIC 0x31564752414E494CULL
-
-#endif /* _ASM_KVX_BOOTM_H */
diff --git a/arch/kvx/include/asm/common.h b/arch/kvx/include/asm/common.h
index a7e301e53a..754953962b 100644
--- a/arch/kvx/include/asm/common.h
+++ b/arch/kvx/include/asm/common.h
@@ -12,7 +12,8 @@
  * Magic value passed in r0 to indicate valid parameters from FSBL when booting
  * If $r0 contains this value, then $r1 contains dtb pointer.
  */
-#define FSBL_PARAM_MAGIC	0x31564752414C414BULL
+#define FSBL_PARAM_MAGIC	0x31564752414C414BULL /* KALARGV1 */
+#define LINUX_BOOT_PARAM_MAGIC	0x31564752414E494CULL /* LINARGV1 */
 
 extern char _exception_start;
 extern char __end;
diff --git a/arch/kvx/lib/bootm.c b/arch/kvx/lib/bootm.c
index 4d17e1846d..3e9772c458 100644
--- a/arch/kvx/lib/bootm.c
+++ b/arch/kvx/lib/bootm.c
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 
 #include <asm/cache.h>
-#include <asm/bootm.h>
 
 typedef void __noreturn (*boot_func_entry)(unsigned long, void *);
 
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:15 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:15 +0100
Subject: [PATCH v2 09/11] kvx: add kvx_sfr_field_val
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-10-jmaselbas@kalray.eu>

From: Clement Leger <clement.leger at bootlin.com>

Add this macro for upcoming socinfo driver. This extract a sfr field
using only its name.

Signed-off-by: Clement Leger <clement.leger at bootlin.com>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/include/asm/sfr.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/kvx/include/asm/sfr.h b/arch/kvx/include/asm/sfr.h
index 5b93cee345..89ff64bbdc 100644
--- a/arch/kvx/include/asm/sfr.h
+++ b/arch/kvx/include/asm/sfr.h
@@ -44,4 +44,8 @@ kvx_sfr_set_mask(unsigned char sfr, uint64_t mask, uint64_t value)
 #define kvx_sfr_set(_sfr, _val)	__builtin_kvx_set(KVX_SFR_ ## _sfr, _val)
 #define kvx_sfr_get(_sfr)	__builtin_kvx_get(KVX_SFR_ ## _sfr)
 
+#define kvx_sfr_field_val(_val, _sfr, _field) \
+			  (((_val) & KVX_SFR_ ## _sfr ## _ ## _field ## _MASK) \
+			  >> KVX_SFR_ ## _sfr ## _ ## _field ## _SHIFT)
+
 #endif	/* _ASM_KVX_SFR_DEFS_H */
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:11 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:11 +0100
Subject: [PATCH v2 05/11] kvx: enable FITIMAGE support
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-6-jmaselbas@kalray.eu>

From: Clement Leger <clement.leger at bootlin.com>

Enable FITIMAGE support in kvx defconfig and add code to handle fit boot
from bootm command. This is rather a simple addition and it allow to boot
a fit image containing an ELF file as the kernel.

Signed-off-by: Clement Leger <clement.leger at bootlin.com>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 arch/kvx/Kconfig     |  1 +
 arch/kvx/lib/bootm.c | 32 +++++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/arch/kvx/Kconfig b/arch/kvx/Kconfig
index 0934440880..100a945761 100644
--- a/arch/kvx/Kconfig
+++ b/arch/kvx/Kconfig
@@ -10,6 +10,7 @@ config KVX
 	select COMMON_CLK_OF_PROVIDER
 	select ELF
 	select FLEXIBLE_BOOTARGS
+	select FITIMAGE
 	select GENERIC_FIND_NEXT_BIT
 	select HAS_ARCH_SJLJ
 	select HAS_CACHE
diff --git a/arch/kvx/lib/bootm.c b/arch/kvx/lib/bootm.c
index 3e9772c458..4c77f676ec 100644
--- a/arch/kvx/lib/bootm.c
+++ b/arch/kvx/lib/bootm.c
@@ -94,7 +94,7 @@ static int do_boot_elf(struct image_data *data, struct elf_image *elf)
 		goto err_free_fdt;
 	}
 
-	entry = (boot_func_entry) data->os_address;
+	entry = (boot_func_entry) elf->entry;
 
 	ret = do_boot_entry(data, entry, fdt);
 
@@ -104,6 +104,27 @@ err_free_fdt:
 	return ret;
 }
 
+static int do_bootm_fit(struct image_data *data)
+{
+	int ret;
+	struct elf_image *elf;
+
+	elf = elf_open_binary((void *) data->fit_kernel);
+	if (IS_ERR(elf))
+		return PTR_ERR(data->elf);
+
+	ret = elf_load(elf);
+	if (ret)
+		goto close_elf;
+
+	ret = do_boot_elf(data, elf);
+
+close_elf:
+	elf_close(elf);
+
+	return ret;
+}
+
 static int do_bootm_elf(struct image_data *data)
 {
 	int ret;
@@ -121,6 +142,12 @@ static struct image_handler elf_handler = {
 	.filetype = filetype_elf,
 };
 
+static struct image_handler fit_handler = {
+	.name = "FIT",
+	.bootm = do_bootm_fit,
+	.filetype = filetype_oftree,
+};
+
 static struct binfmt_hook binfmt_elf_hook = {
 	.type = filetype_elf,
 	.exec = "bootm",
@@ -130,6 +157,9 @@ static int kvx_register_image_handler(void)
 {
 	register_image_handler(&elf_handler);
 
+	if (IS_ENABLED(CONFIG_FITIMAGE))
+		register_image_handler(&fit_handler);
+
 	binfmt_register(&binfmt_elf_hook);
 
 	return 0;
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 14:19:14 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:14 +0100
Subject: [PATCH v2 08/11] nvmem: add kvx otp non volatile regbank support
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-9-jmaselbas@kalray.eu>

From: Clement Leger <clement.leger at bootlin.com>

Backport Linux driver to barebox to access nvmem.

Signed-off-by: Clement Leger <clement.leger at bootlin.com>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
changes in v2:
 - removed if (allways set skip to 0 after the memcopy)
---
 drivers/nvmem/Kconfig      |  7 +++
 drivers/nvmem/Makefile     |  3 ++
 drivers/nvmem/kvx-otp-nv.c | 98 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 108 insertions(+)
 create mode 100644 drivers/nvmem/kvx-otp-nv.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 7b1ebe1d68..2e60734156 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -76,6 +76,13 @@ config STM32_BSEC_WRITE
 	    mw -l -d /dev/stm32-bsec 0x000000e4+4 0x78563412
 	    mw -l -d /dev/stm32-bsec 0x000000e8+4 0x0000bc9a
 
+config KVX_OTP_NV
+	tristate "kalray KVX OTP Non volatile regs Support"
+	depends on KVX
+	help
+	  This is a simple driver to dump specified values of KVX OTP non
+	  volatile regs.
+
 config STARFIVE_OTP
 	tristate "Starfive OTP Supprot"
 	depends on SOC_STARFIVE
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 5865919612..62a1f925dd 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -24,4 +24,7 @@ nvmem_eeprom_93xx46-y		:= eeprom_93xx46.o
 obj-$(CONFIG_STM32_BSEC)	+= nvmem_bsec.o
 nvmem_bsec-y			:= bsec.o
 
+obj-$(CONFIG_KVX_OTP_NV)	+= nvmem-kvx-otp-nv.o
+nvmem-kvx-otp-nv-y		:= kvx-otp-nv.o
+
 obj-$(CONFIG_STARFIVE_OTP)	+= starfive-otp.o
diff --git a/drivers/nvmem/kvx-otp-nv.c b/drivers/nvmem/kvx-otp-nv.c
new file mode 100644
index 0000000000..d614c16e1e
--- /dev/null
+++ b/drivers/nvmem/kvx-otp-nv.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Kalray Inc., Cl?ment L?ger
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <init.h>
+#include <net.h>
+#include <io.h>
+
+#include <linux/nvmem-provider.h>
+
+#define OTP_NV_ALIGN		4
+#define OTP_NV_ALIGN_MASK	(OTP_NV_ALIGN - 1)
+
+struct kvx_otp_nv_priv {
+	void __iomem *base;
+};
+
+static int kvx_otp_nv_read(void *context, unsigned int offset,
+			  void *_val, size_t bytes)
+{
+	struct kvx_otp_nv_priv *priv = context;
+	u8 *val = _val;
+	u32 tmp, copy_size;
+	u8 skip = offset & OTP_NV_ALIGN_MASK;
+
+	offset &= ~OTP_NV_ALIGN_MASK;
+
+	while (bytes) {
+		tmp = readl(priv->base + offset);
+		if (skip != 0)
+			copy_size = min(OTP_NV_ALIGN - skip, (int) bytes);
+		else
+			copy_size = min(bytes, sizeof(tmp));
+
+		memcpy(val, ((u8 *) &tmp) + skip, copy_size);
+		skip = 0;
+
+		bytes -= copy_size;
+		val += copy_size;
+		offset += OTP_NV_ALIGN;
+	}
+
+	return 0;
+}
+
+static const struct nvmem_bus kvx_otp_nv_bus = {
+	.read = kvx_otp_nv_read,
+};
+
+static const struct of_device_id kvx_otp_nv_match[] = {
+	{ .compatible = "kalray,kvx-otp-nv" },
+	{ /* sentinel */},
+};
+
+static int kvx_otp_nv_probe(struct device_d *dev)
+{
+	struct resource *res;
+	struct nvmem_device *nvmem;
+	struct nvmem_config econfig = { 0 };
+	struct kvx_otp_nv_priv *priv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	priv->base = IOMEM(res->start);
+
+	econfig.name = "kvx-nv-regbank";
+	econfig.stride = 1;
+	econfig.word_size = 1;
+	econfig.size = resource_size(res);
+	econfig.dev = dev;
+	econfig.priv = priv;
+	econfig.bus = &kvx_otp_nv_bus;
+
+	dev->priv = priv;
+
+	nvmem = nvmem_register(&econfig);
+
+	return PTR_ERR_OR_ZERO(nvmem);
+}
+
+static struct driver_d kvx_otp_nv_driver = {
+	.name	= "kvx-otp-nv",
+	.probe	= kvx_otp_nv_probe,
+	.of_compatible = DRV_OF_COMPAT(kvx_otp_nv_match),
+};
+postcore_platform_driver(kvx_otp_nv_driver);
-- 
2.17.1







From jmaselbas at kalray.eu  Mon Jan 17 14:19:17 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Mon, 17 Jan 2022 23:19:17 +0100
Subject: [PATCH v2 11/11] soc: add kvx_socinfo driver
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220117221917.26970-12-jmaselbas@kalray.eu>

From: Clement Leger <clement.leger at bootlin.com>

This driver uses various source (sfr, nvmem) to determine the mppa_id
and the architecture revision. These are then exported using global
variables which are:
- global.kvx.arch_rev: Architecture revision (kv3-1 for instance)
- global.kvx.mppa_id: Unique chip id, composed of lot and wafer id

Signed-off-by: Clement Leger <clement.leger at bootlin.com>
Co-developed-by: Jules Maselbas <jmaselbas at kalray.eu>
Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 drivers/soc/Kconfig           |   1 +
 drivers/soc/Makefile          |   1 +
 drivers/soc/kvx/Kconfig       |  10 +++
 drivers/soc/kvx/Makefile      |   1 +
 drivers/soc/kvx/kvx_socinfo.c | 141 ++++++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+)
 create mode 100644 drivers/soc/kvx/Kconfig
 create mode 100644 drivers/soc/kvx/Makefile
 create mode 100644 drivers/soc/kvx/kvx_socinfo.c

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index d78f13f3f8..54b69cc42e 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,5 +1,6 @@
 menu "SoC drivers"
 
 source "drivers/soc/imx/Kconfig"
+source "drivers/soc/kvx/Kconfig"
 
 endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index c4efb8f02f..e5b319e6da 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -3,3 +3,4 @@
 obj-y	+= imx/
 obj-$(CONFIG_CPU_SIFIVE)	+= sifive/
 obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
+obj-$(CONFIG_KVX)	+= kvx/
diff --git a/drivers/soc/kvx/Kconfig b/drivers/soc/kvx/Kconfig
new file mode 100644
index 0000000000..18dcb8ba14
--- /dev/null
+++ b/drivers/soc/kvx/Kconfig
@@ -0,0 +1,10 @@
+menu "KVX SoC drivers"
+
+config KVX_SOCINFO
+        bool "KVX SoC Info driver"
+	depends on KVX
+	select NVMEM
+	select KVX_OTP_NV
+	default y
+
+endmenu
diff --git a/drivers/soc/kvx/Makefile b/drivers/soc/kvx/Makefile
new file mode 100644
index 0000000000..cacfef21a1
--- /dev/null
+++ b/drivers/soc/kvx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_KVX_SOCINFO) += kvx_socinfo.o
diff --git a/drivers/soc/kvx/kvx_socinfo.c b/drivers/soc/kvx/kvx_socinfo.c
new file mode 100644
index 0000000000..100faae766
--- /dev/null
+++ b/drivers/soc/kvx/kvx_socinfo.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Kalray Inc., Cl?ment L?ger
+ */
+
+#define pr_fmt(fmt) "kvx_socinfo: " fmt
+
+#include <init.h>
+#include <driver.h>
+#include <globalvar.h>
+#include <magicvar.h>
+#include <command.h>
+#include <libfile.h>
+#include <getopt.h>
+#include <common.h>
+#include <fs.h>
+
+#include <asm/sfr.h>
+
+#include <linux/kernel.h>
+#include <linux/nvmem-consumer.h>
+
+#define LOT_ID_STR_LEN	8
+
+#define EWS_LOT_ID_MASK		0x1ffffffffffULL
+#define EWS_WAFER_ID_SHIFT	42
+#define EWS_WAFER_ID_MASK	0x1fULL
+
+#define FT_COM_AP_SHIFT		16
+#define FT_COM_AP_MASK		0x3f
+#define FT_DEVICE_ID_SHIFT	22
+#define FT_DEVICE_ID_MASK	0x1ff
+
+static char *kvx_mppa_id;
+static char *kvx_arch_rev;
+
+BAREBOX_MAGICVAR(kvx.arch_rev, "KVX architecture revision");
+BAREBOX_MAGICVAR(kvx.mppa_id, "KVX MPPA chip id");
+
+static void kvx_soc_info_read_revision(void)
+{
+	u64 pcr = kvx_sfr_get(PCR);
+	u8 sv = kvx_sfr_field_val(pcr, PCR, SV);
+	u8 car = kvx_sfr_field_val(pcr, PCR, CAR);
+	const char *car_str = "", *ver_str = "";
+
+	switch (car) {
+	case 0:
+		car_str = "kv3";
+		break;
+	}
+
+	switch (sv) {
+	case 0:
+		ver_str = "1";
+		break;
+	case 1:
+		ver_str = "2";
+		break;
+	}
+
+	kvx_arch_rev = basprintf("%s-%s", car_str, ver_str);
+
+	globalvar_add_simple_string("kvx.arch_rev", &kvx_arch_rev);
+}
+
+static int base38_decode(char *s, u64 val, int nb_char)
+{
+	int i;
+	const char *alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_?";
+	const int base = strlen(alphabet);
+
+	if (s == NULL)
+		return -1;
+
+	for (i = 0; i < nb_char; i++) {
+		s[i] = alphabet[val % base];
+		val /= base;
+	}
+
+	return 0;
+}
+
+static int kvx_read_serial(struct device_node *socinfo)
+{
+	char lot_id[LOT_ID_STR_LEN + 1] = "";
+	char com_ap;
+	u64 *cell_val64;
+	u64 ews_val;
+	u32 *cell_val32;
+	u32 ft_val;
+	u8 wafer_id;
+	u16 device_id;
+
+	cell_val64 = (u64 *) nvmem_cell_get_and_read(socinfo, "ews_fuse", 8);
+	if (IS_ERR(cell_val64)) {
+		pr_debug("Fail to read ews_fuse\n");
+		return PTR_ERR(cell_val64);
+	}
+
+	ews_val = *cell_val64;
+	ews_val = (ews_val >> 32) | (ews_val << 32);
+	wafer_id = (ews_val >> EWS_WAFER_ID_SHIFT) & EWS_WAFER_ID_MASK;
+	base38_decode(lot_id, ews_val & EWS_LOT_ID_MASK, LOT_ID_STR_LEN);
+
+	cell_val32 = (u32 *) nvmem_cell_get_and_read(socinfo, "ft_fuse", 4);
+	if (IS_ERR(cell_val32)) {
+		pr_debug("Fail to read ft_fuse\n");
+		return PTR_ERR(cell_val32);
+	}
+
+	ft_val = *cell_val32;
+	device_id = (ft_val >> FT_DEVICE_ID_SHIFT) & FT_DEVICE_ID_MASK;
+	base38_decode(&com_ap, (ft_val >> FT_COM_AP_SHIFT) & FT_COM_AP_MASK, 1);
+
+	kvx_mppa_id = basprintf("%sA-%d%c-%03d", lot_id, wafer_id, com_ap,
+			       device_id);
+
+	globalvar_add_simple_string("kvx.mppa_id", &kvx_mppa_id);
+
+	return 0;
+}
+
+static int kvx_socinfo_probe(struct device_d *dev)
+{
+	kvx_soc_info_read_revision();
+
+	return kvx_read_serial(dev->device_node);
+}
+
+static const struct of_device_id kvx_socinfo_dt_ids[] = {
+	{ .compatible = "kalray,kvx-socinfo" },
+	{ }
+};
+
+static struct driver_d kvx_socinfo_driver = {
+	.name = "kvx-socinfo",
+	.probe = kvx_socinfo_probe,
+	.of_compatible = DRV_OF_COMPAT(kvx_socinfo_dt_ids),
+};
+coredevice_platform_driver(kvx_socinfo_driver);
-- 
2.17.1







From jmaselbas at kalray.eu  Mon Jan 17 15:02:30 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Tue, 18 Jan 2022 00:02:30 +0100
Subject: [PATCH v2 0/5] Add support for QOI image format
Message-ID: <20220117230235.13549-1-jmaselbas@kalray.eu>

changes in v2:
 - added SPDX licence identifier
 - added comment on modification done on qoiconv.c
 - added pr_fmt macro and removed keep_file_data=1 in lib/gui/qoi.c
 - reword few commits.

---

Jules Maselbas (5):
  filetype: Add QOI format image type
  gui: Add qoi image format
  scripts: Add qoiconv to convert png to qoi
  logo: Enable image format selection for the logo
  logo: Add choice for the QOI image format option

 common/filetype.c   |    3 +
 include/filetype.h  |    1 +
 lib/gui/Kconfig     |    5 +
 lib/gui/Makefile    |    1 +
 lib/gui/qoi.c       |   97 +
 lib/gui/qoi.h       |  673 ++++
 lib/logo/Kconfig    |   27 +-
 lib/logo/Makefile   |   55 +-
 lib/logo/logo.c     |   10 +-
 scripts/Kconfig     |    5 +
 scripts/Makefile    |    1 +
 scripts/qoiconv.c   |   63 +
 scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 8682 insertions(+), 15 deletions(-)
 create mode 100644 lib/gui/qoi.c
 create mode 100644 lib/gui/qoi.h
 create mode 100644 scripts/qoiconv.c
 create mode 100644 scripts/stb_image.h

-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 15:02:35 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Tue, 18 Jan 2022 00:02:35 +0100
Subject: [PATCH v2 5/5] logo: Add choice for the QOI image format option
In-Reply-To: <20220117230235.13549-1-jmaselbas@kalray.eu>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
Message-ID: <20220117230235.13549-6-jmaselbas@kalray.eu>

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 lib/logo/Kconfig  |  7 +++++++
 lib/logo/Makefile | 14 +++++++++++++-
 lib/logo/logo.c   |  2 ++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/lib/logo/Kconfig b/lib/logo/Kconfig
index 8edfaaeb51..a79806f54c 100644
--- a/lib/logo/Kconfig
+++ b/lib/logo/Kconfig
@@ -23,6 +23,13 @@ config BAREBOX_LOGO_BMP
 	help
 	  Encode logo with the BMP image format
 
+config BAREBOX_LOGO_QOI
+	bool "qoi"
+	select QOI
+	select QOICONV
+	help
+	  Encode logo with the QOI image format
+
 endchoice
 
 config BAREBOX_LOGO_64
diff --git a/lib/logo/Makefile b/lib/logo/Makefile
index 04c4906838..e04deb5536 100644
--- a/lib/logo/Makefile
+++ b/lib/logo/Makefile
@@ -51,6 +51,12 @@ extra-y += $(patsubst %,%.bmp,$(bblogo-y))
 %.bblogo: %.bmp FORCE
 	$(call if_changed,logo)
 endif
+ifdef CONFIG_BAREBOX_LOGO_QOI
+extra-y += $(patsubst %,%.png,$(bblogo-y))
+extra-y += $(patsubst %,%.qoi,$(bblogo-y))
+%.bblogo: %.qoi FORCE
+	$(call if_changed,logo)
+endif
 
 CONVERTOPTS += -background none
 
@@ -66,4 +72,10 @@ quiet_cmd_png = PNG     $@
 %.png: $(srctree)/Documentation/barebox.svg FORCE
 	$(call if_changed,png)
 
-clean-files += *.png *.bmp *.bblogo *.bblogo.S
+quiet_cmd_qoi = QOI     $@
+      cmd_qoi =	$(objtree)/scripts/qoiconv $< $@
+
+%.qoi: %.png FORCE
+	$(call if_changed,qoi)
+
+clean-files += *.png *.qoi *.bmp *.bblogo *.bblogo.S
diff --git a/lib/logo/logo.c b/lib/logo/logo.c
index 200eb992b3..a64f489939 100644
--- a/lib/logo/logo.c
+++ b/lib/logo/logo.c
@@ -38,6 +38,8 @@ static void load_logo(int width, void *start, void *end)
 		ext = "png";
 	else if (IS_ENABLED(CONFIG_BAREBOX_LOGO_BMP))
 		ext = "bmp";
+	else if (IS_ENABLED(CONFIG_BAREBOX_LOGO_QOI))
+		ext = "qoi";
 
 	filename = basprintf("/logo/barebox-logo-%d.%s", width, ext);
 	write_file(filename, start, size);
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 15:02:34 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Tue, 18 Jan 2022 00:02:34 +0100
Subject: [PATCH v2 4/5] logo: Enable image format selection for the logo
In-Reply-To: <20220117230235.13549-1-jmaselbas@kalray.eu>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
Message-ID: <20220117230235.13549-5-jmaselbas@kalray.eu>

Enables the selection of an image format to be used for the built-in
barebox logo. The default image format is set to png, has it was the
only choice before. This also adds bmp as the other option.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 lib/logo/Kconfig  | 20 +++++++++++++++++++-
 lib/logo/Makefile | 43 ++++++++++++++++++++++++++++++-------------
 lib/logo/logo.c   |  8 +++++++-
 3 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/lib/logo/Kconfig b/lib/logo/Kconfig
index 7d55f7fa27..8edfaaeb51 100644
--- a/lib/logo/Kconfig
+++ b/lib/logo/Kconfig
@@ -3,10 +3,28 @@ menuconfig BAREBOX_LOGO
 	help
 	  Say yes here to build the barebox logos. This adds ImageMagick's
 	  convert tool to the build dependencies. The logo can be found under
-	  /logo/barebox-logo-<width>.png in the running barebox.
+	  /logo/barebox-logo-<width>.<ext> in the running barebox.
 
 if BAREBOX_LOGO
 
+choice
+	prompt "Logo image encoding format to be used"
+	default BAREBOX_LOGO_PNG
+
+config BAREBOX_LOGO_PNG
+	bool "png"
+	select PNG
+	help
+	  Encode logo with the PNG image format
+
+config BAREBOX_LOGO_BMP
+	bool "bmp"
+	select BMP
+	help
+	  Encode logo with the BMP image format
+
+endchoice
+
 config BAREBOX_LOGO_64
 	bool "include 64x32 pixel logo"
 
diff --git a/lib/logo/Makefile b/lib/logo/Makefile
index f08beef76b..04c4906838 100644
--- a/lib/logo/Makefile
+++ b/lib/logo/Makefile
@@ -1,17 +1,17 @@
 
-OPTS_barebox-logo-w64.bblogo = -resize 64
+OPTS_barebox-logo-w64 = -resize 64
 bblogo-$(CONFIG_BAREBOX_LOGO_64) += barebox-logo-w64
 
-OPTS_barebox-logo-w240.bblogo = -resize 240
+OPTS_barebox-logo-w240 = -resize 240
 bblogo-$(CONFIG_BAREBOX_LOGO_240) += barebox-logo-w240
 
-OPTS_barebox-logo-w320.bblogo = -resize 320
+OPTS_barebox-logo-w320 = -resize 320
 bblogo-$(CONFIG_BAREBOX_LOGO_320) += barebox-logo-w320
 
-OPTS_barebox-logo-w400.bblogo = -resize 400
+OPTS_barebox-logo-w400 = -resize 400
 bblogo-$(CONFIG_BAREBOX_LOGO_400) += barebox-logo-w400
 
-OPTS_barebox-logo-w640.bblogo = -resize 640
+OPTS_barebox-logo-w640 = -resize 640
 bblogo-$(CONFIG_BAREBOX_LOGO_640) += barebox-logo-w640
 
 obj-y += $(patsubst %,%.bblogo.o,$(bblogo-y))
@@ -38,15 +38,32 @@ cmd_logo_S =							\
 %.bblogo.S: %.bblogo FORCE
 	$(call if_changed,logo_S)
 
+quiet_cmd_logo = LOGO     $@
+      cmd_logo = cp $< $@
+
+ifdef CONFIG_BAREBOX_LOGO_PNG
+extra-y += $(patsubst %,%.png,$(bblogo-y))
+%.bblogo: %.png FORCE
+	$(call if_changed,logo)
+endif
+ifdef CONFIG_BAREBOX_LOGO_BMP
+extra-y += $(patsubst %,%.bmp,$(bblogo-y))
+%.bblogo: %.bmp FORCE
+	$(call if_changed,logo)
+endif
+
 CONVERTOPTS += -background none
 
-quiet_cmd_logo = PNG     $@
-cmd_logo =							\
-(								\
-	convert $(OPTS_$(@F)) $(CONVERTOPTS) $< png:$@; \
-)
+quiet_cmd_bmp = BMP     $@
+      cmd_bmp = convert $(OPTS_$(@F:.bmp=)) $(CONVERTOPTS) $< bmp:$@
 
-%.bblogo: $(srctree)/Documentation/barebox.svg FORCE
-	$(call if_changed,logo)
+%.bmp: $(srctree)/Documentation/barebox.svg FORCE
+	$(call if_changed,bmp)
+
+quiet_cmd_png = PNG     $@
+      cmd_png =	convert $(OPTS_$(@F:.png=)) $(CONVERTOPTS) $< png:$@
+
+%.png: $(srctree)/Documentation/barebox.svg FORCE
+	$(call if_changed,png)
 
-clean-files += *.bblogo *.bblogo.S
+clean-files += *.png *.bmp *.bblogo *.bblogo.S
diff --git a/lib/logo/logo.c b/lib/logo/logo.c
index 8349b060ac..200eb992b3 100644
--- a/lib/logo/logo.c
+++ b/lib/logo/logo.c
@@ -32,8 +32,14 @@ static void load_logo(int width, void *start, void *end)
 {
 	char *filename;
 	size_t size = end - start;
+	char *ext = "";
 
-	filename = basprintf("/logo/barebox-logo-%d.png", width);
+	if (IS_ENABLED(CONFIG_BAREBOX_LOGO_PNG))
+		ext = "png";
+	else if (IS_ENABLED(CONFIG_BAREBOX_LOGO_BMP))
+		ext = "bmp";
+
+	filename = basprintf("/logo/barebox-logo-%d.%s", width, ext);
 	write_file(filename, start, size);
 	free(filename);
 }
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 15:02:31 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Tue, 18 Jan 2022 00:02:31 +0100
Subject: [PATCH v2 1/5] filetype: Add QOI format image type
In-Reply-To: <20220117230235.13549-1-jmaselbas@kalray.eu>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
Message-ID: <20220117230235.13549-2-jmaselbas@kalray.eu>

QOI image format is a "Quite OK" image format, it's simplicity is it's
strengh and could be a good replacement of bmp, maybe even for png.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
 common/filetype.c  | 3 +++
 include/filetype.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/common/filetype.c b/common/filetype.c
index 8ffcd6adcd..e5245668e2 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -45,6 +45,7 @@ static const struct filetype_str filetype_str[] = {
 	[filetype_mbr] = { "MBR sector", "mbr" },
 	[filetype_bmp] = { "BMP image", "bmp" },
 	[filetype_png] = { "PNG image", "png" },
+	[filetype_qoi] = { "QOI image", "qoi" },
 	[filetype_ext] = { "EXT filesystem", "ext" },
 	[filetype_gpt] = { "GUID Partition Table", "gpt" },
 	[filetype_ubifs] = { "UBIFS image", "ubifs" },
@@ -300,6 +301,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
 		return filetype_aimage;
 	if (buf64[0] == le64_to_cpu(0x0a1a0a0d474e5089ull))
 		return filetype_png;
+	if (strncmp(buf8, "qoif", 4) == 0)
+		return filetype_qoi;
 	if (is_barebox_mips_head(_buf))
 		return filetype_mips_barebox;
 	if (buf[0] == be32_to_cpu(0x534F4659))
diff --git a/include/filetype.h b/include/filetype.h
index 2640847e1f..8bc179ac08 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -28,6 +28,7 @@ enum filetype {
 	filetype_mbr,
 	filetype_bmp,
 	filetype_png,
+	filetype_qoi,
 	filetype_ext,
 	filetype_gpt,
 	filetype_ubifs,
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 15:02:33 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Tue, 18 Jan 2022 00:02:33 +0100
Subject: [PATCH v2 3/5] scripts: Add qoiconv to convert png to qoi
In-Reply-To: <20220117230235.13549-1-jmaselbas@kalray.eu>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
Message-ID: <20220117230235.13549-4-jmaselbas@kalray.eu>

ImageMagick will eventually support the qoi image format, in the
mean time add qoiconv, a png to qoi image conversion program.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
change in v2:
 - add SPDX license indentifier in qoiconv.c
 - added a comment which details modifications from the original version
---
 scripts/Kconfig     |    5 +
 scripts/Makefile    |    1 +
 scripts/qoiconv.c   |   63 +
 scripts/stb_image.h | 7756 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 7825 insertions(+)
 create mode 100644 scripts/qoiconv.c
 create mode 100644 scripts/stb_image.h

diff --git a/scripts/Kconfig b/scripts/Kconfig
index 96b0d26f88..e271c9d278 100644
--- a/scripts/Kconfig
+++ b/scripts/Kconfig
@@ -110,6 +110,11 @@ config RK_USB_LOADER
 
 	  You need libusb-1.0 to compile this tool.
 
+config QOICONV
+	bool "QOI image format conversion" if COMPILE_HOST_TOOLS
+	help
+	  This enable converting png to qoi images to generate boot logo.
+
 endmenu
 
 menu "Target Tools"
diff --git a/scripts/Makefile b/scripts/Makefile
index dc5fa75f90..cbaf2d55ff 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -8,6 +8,7 @@ hostprogs-always-y					+= fix_size
 hostprogs-always-y					+= bareboxenv
 hostprogs-always-y					+= bareboxcrc32
 hostprogs-always-y					+= kernel-install
+hostprogs-always-$(CONFIG_QOICONV)			+= qoiconv
 hostprogs-always-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS)	+= rsatoc
 HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl`
 HOSTLDLIBS_rsatoc = `pkg-config --libs openssl`
diff --git a/scripts/qoiconv.c b/scripts/qoiconv.c
new file mode 100644
index 0000000000..081eb1ee06
--- /dev/null
+++ b/scripts/qoiconv.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: 2021 Dominic Szablewski
+
+/*
+ * Adapted from https://github.com/phoboslab/qoi/blob/master/qoiconv.c
+ * with the sole modification of removing the png write functionnality
+ * hence only requiring stb_image.h
+ */
+
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_ONLY_PNG
+#define STBI_NO_LINEAR
+#include "stb_image.h"
+
+#define QOI_IMPLEMENTATION
+#include "../lib/gui/qoi.h"
+
+#define STR_ENDS_WITH(S, E) (strcmp(S + strlen(S) - (sizeof(E)-1), E) == 0)
+
+int main(int argc, char **argv) {
+	void *pixels = NULL;
+	int w, h, channels;
+	int encoded = 0;
+
+	if (argc < 3) {
+		puts("Usage: qoiconv <infile> <outfile>");
+		puts("Examples:");
+		puts("  qoiconv input.png output.qoi");
+		exit(1);
+	}
+	if (STR_ENDS_WITH(argv[1], ".png")) {
+		if(!stbi_info(argv[1], &w, &h, &channels)) {
+			printf("Couldn't read header %s\n", argv[1]);
+			exit(1);
+		}
+
+		// Force all odd encodings to be RGBA
+		if(channels != 3) {
+			channels = 4;
+		}
+
+		pixels = (void *)stbi_load(argv[1], &w, &h, NULL, channels);
+	}
+	if (pixels == NULL) {
+		printf("Couldn't load/decode %s\n", argv[1]);
+		exit(1);
+	}
+	if (STR_ENDS_WITH(argv[2], ".qoi")) {
+		encoded = qoi_write(argv[2], pixels, &(qoi_desc){
+			.width = w,
+			.height = h,
+			.channels = channels,
+			.colorspace = QOI_SRGB
+		});
+	}
+	if (!encoded) {
+		printf("Couldn't write/encode %s\n", argv[2]);
+		exit(1);
+	}
+
+	free(pixels);
+	return 0;
+}
diff --git a/scripts/stb_image.h b/scripts/stb_image.h
new file mode 100644
index 0000000000..742fac74f7
--- /dev/null
+++ b/scripts/stb_image.h
@@ -0,0 +1,7756 @@
+/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb
+                                  no warranty implied; use at your own risk
+
+   Do this:
+      #define STB_IMAGE_IMPLEMENTATION
+   before you include this file in *one* C or C++ file to create the implementation.
+
+   // i.e. it should look like this:
+   #include ...
+   #include ...
+   #include ...
+   #define STB_IMAGE_IMPLEMENTATION
+   #include "stb_image.h"
+
+   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+   QUICK NOTES:
+      Primarily of interest to game developers and other people who can
+          avoid problematic images and only need the trivial interface
+
+      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+      PNG 1/2/4/8/16-bit-per-channel
+
+      TGA (not sure what subset, if a subset)
+      BMP non-1bpp, non-RLE
+      PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+      GIF (*comp always reports as 4-channel)
+      HDR (radiance rgbE format)
+      PIC (Softimage PIC)
+      PNM (PPM and PGM binary only)
+
+      Animated GIF still needs a proper API, but here's one way to do it:
+          http://gist.github.com/urraka/685d9a6340b26b830d49
+
+      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+      - decode from arbitrary I/O callbacks
+      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+   Full documentation under "DOCUMENTATION" below.
+
+
+LICENSE
+
+  See end of file for license information.
+
+RECENT REVISION HISTORY:
+
+      2.26  (2020-07-13) many minor fixes
+      2.25  (2020-02-02) fix warnings
+      2.24  (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
+      2.23  (2019-08-11) fix clang static analysis warning
+      2.22  (2019-03-04) gif fixes, fix warnings
+      2.21  (2019-02-25) fix typo in comment
+      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+      2.19  (2018-02-11) fix warning
+      2.18  (2018-01-30) fix warnings
+      2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
+      2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
+      2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
+      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
+      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
+                         RGB-format JPEG; remove white matting in PSD;
+                         allocate large structures on the stack;
+                         correct channel count for PNG & BMP
+      2.10  (2016-01-22) avoid warning introduced in 2.09
+      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
+
+   See end of file for full revision history.
+
+
+ ============================    Contributors    =========================
+
+ Image formats                          Extensions, features
+    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)
+    Nicolas Schulz (hdr, psd)              Martin "SpartanJ" Golini (stbi_info)
+    Jonathan Dummer (tga)                  James "moose2000" Brown (iPhone PNG)
+    Jean-Marc Lienher (gif)                Ben "Disch" Wenger (io callbacks)
+    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)
+    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)
+    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)
+    github:urraka (animated gif)           Junggon Kim (PNM comments)
+    Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA)
+                                           socks-the-fox (16-bit PNG)
+                                           Jeremy Sawicki (handle all ImageNet JPGs)
+ Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP)
+    Fabian "ryg" Giesen                    Anael Seghezzi (is-16-bit query)
+    Arseny Kapoulkine
+    John-Mark Allen
+    Carmelo J Fdez-Aguera
+
+ Bug & warning fixes
+    Marc LeBlanc            David Woo          Guillaume George     Martins Mozeiko
+    Christpher Lloyd        Jerry Jansson      Joseph Thomson       Blazej Dariusz Roszkowski
+    Phil Jordan                                Dave Moore           Roy Eltham
+    Hayaki Saito            Nathan Reed        Won Chun
+    Luke Graham             Johan Duparc       Nick Verigakis       the Horde3D community
+    Thomas Ruf              Ronny Chevalier                         github:rlyeh
+    Janez Zemva             John Bartholomew   Michal Cichon        github:romigrou
+    Jonathan Blow           Ken Hamada         Tero Hanninen        github:svdijk
+                            Laurent Gomila     Cort Stratton        github:snagar
+    Aruelien Pocheville     Sergio Gonzalez    Thibault Reuille     github:Zelex
+    Cass Everitt            Ryamond Barbiero                        github:grim210
+    Paul Du Bois            Engin Manap        Aldo Culquicondor    github:sammyhw
+    Philipp Wiesemann       Dale Weiler        Oriol Ferrer Mesia   github:phprus
+    Josh Tobin                                 Matthew Gregan       github:poppolopoppo
+    Julian Raschke          Gregory Mullen     Christian Floisand   github:darealshinji
+    Baldur Karlsson         Kevin Schmidt      JR Smith             github:Michaelangel007
+                            Brad Weinberger    Matvey Cherevko      [reserved]
+    Luca Sas                Alexander Veselov  Zack Middleton       [reserved]
+    Ryan C. Gordon          [reserved]                              [reserved]
+                     DO NOT ADD YOUR NAME HERE
+
+  To add your name to the credits, pick a random blank space in the middle and fill it.
+  80% of merge conflicts on stb PRs are due to people adding their name at the end
+  of the credits.
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+//    - no 12-bit-per-channel JPEG
+//    - no JPEGs with arithmetic coding
+//    - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+//    int x,y,n;
+//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+//    // ... process data if not NULL ...
+//    // ... x = width, y = height, n = # 8-bit components per pixel ...
+//    // ... replace '0' with '1'..'4' to force that many components per pixel
+//    // ... but 'n' will always be the number that it would have been if you said 0
+//    stbi_image_free(data)
+//
+// Standard parameters:
+//    int *x                 -- outputs image width in pixels
+//    int *y                 -- outputs image height in pixels
+//    int *channels_in_file  -- outputs # of image components in image file
+//    int desired_channels   -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'desired_channels' if desired_channels is non-zero, or
+// *channels_in_file otherwise. If desired_channels is non-zero,
+// *channels_in_file has the number of components that _would_ have been
+// output otherwise. E.g. if you set desired_channels to 4, you will always
+// get RGBA output, but you can check *channels_in_file to see if it's trivially
+// opaque because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+//     N=#comp     components
+//       1           grey
+//       2           grey, alpha
+//       3           red, green, blue
+//       4           red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *channels_in_file will be unchanged. The function
+// stbi_failure_reason() can be queried for an extremely brief, end-user
+// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
+// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// UNICODE:
+//
+//   If compiling for Windows and you wish to use Unicode filenames, compile
+//   with
+//       #define STBI_WINDOWS_UTF8
+//   and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
+//   Windows wchar_t filenames to utf8.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+//    1. easy to use
+//    2. easy to maintain
+//    3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy-to-use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// provide more explicit reasons why performance can't be emphasized.
+//
+//    - Portable ("ease of use")
+//    - Small source code footprint ("easy to maintain")
+//    - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support   (disable by defining STBI_NO_HDR)
+//
+// stb_image supports loading HDR images in general, and currently the Radiance
+// .HDR file format specifically. You can still load any file through the existing
+// interface; if you attempt to load an HDR file, it will be automatically remapped
+// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+//     stbi_hdr_to_ldr_gamma(2.2f);
+//     stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+//    float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+//     stbi_ldr_to_hdr_scale(1.0f);
+//     stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+//     stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+// ===========================================================================
+//
+// ADDITIONAL CONFIGURATION
+//
+//  - You can suppress implementation of any of the decoders to reduce
+//    your code footprint by #defining one or more of the following
+//    symbols before creating the implementation.
+//
+//        STBI_NO_JPEG
+//        STBI_NO_PNG
+//        STBI_NO_BMP
+//        STBI_NO_PSD
+//        STBI_NO_TGA
+//        STBI_NO_GIF
+//        STBI_NO_HDR
+//        STBI_NO_PIC
+//        STBI_NO_PNM   (.ppm and .pgm)
+//
+//  - You can request *only* certain decoders and suppress all other ones
+//    (this will be more forward-compatible, as addition of new decoders
+//    doesn't require you to disable them explicitly):
+//
+//        STBI_ONLY_JPEG
+//        STBI_ONLY_PNG
+//        STBI_ONLY_BMP
+//        STBI_ONLY_PSD
+//        STBI_ONLY_TGA
+//        STBI_ONLY_GIF
+//        STBI_ONLY_HDR
+//        STBI_ONLY_PIC
+//        STBI_ONLY_PNM   (.ppm and .pgm)
+//
+//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+//
+//  - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
+//    than that size (in either width or height) without further processing.
+//    This is to let programs in the wild set an upper bound to prevent
+//    denial-of-service attacks on untrusted data, as one could generate a
+//    valid image of gigantic dimensions and force stb_image to allocate a
+//    huge block of memory and spend disproportionate time decoding it. By
+//    default this is set to (1 << 24), which is 16777216, but that's still
+//    very big.
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+   STBI_default = 0, // only used for desired_channels
+
+   STBI_grey       = 1,
+   STBI_grey_alpha = 2,
+   STBI_rgb        = 3,
+   STBI_rgb_alpha  = 4
+};
+
+#include <stdlib.h>
+typedef unsigned char stbi_uc;
+typedef unsigned short stbi_us;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef STBIDEF
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read
+   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+////////////////////////////////////
+//
+// 8-bits-per-channel interface
+//
+
+STBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+#endif
+
+#ifdef STBI_WINDOWS_UTF8
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
+#endif
+
+////////////////////////////////////
+//
+// 16-bits-per-channel interface
+//
+
+STBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+#endif
+
+////////////////////////////////////
+//
+// float-per-channel interface
+//
+#ifndef STBI_NO_LINEAR
+   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);
+
+   #ifndef STBI_NO_STDIO
+   STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+   #endif
+#endif
+
+#ifndef STBI_NO_HDR
+   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);
+   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_LINEAR
+   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);
+   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_LINEAR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename);
+STBIDEF int      stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// on most compilers (and ALL modern mainstream compilers) this is threadsafe
+STBIDEF const char *stbi_failure_reason  (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void     stbi_image_free      (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+STBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
+STBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp);
+STBIDEF int      stbi_is_16_bit          (char const *filename);
+STBIDEF int      stbi_is_16_bit_from_file(FILE *f);
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// as above, but only applies to images loaded on the thread that calls the function
+// this function is only available if your compiler supports thread-local variables;
+// calling it will fail to link if your compiler doesn't
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+////   end header file   /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+  || defined(STBI_ONLY_ZLIB)
+   #ifndef STBI_ONLY_JPEG
+   #define STBI_NO_JPEG
+   #endif
+   #ifndef STBI_ONLY_PNG
+   #define STBI_NO_PNG
+   #endif
+   #ifndef STBI_ONLY_BMP
+   #define STBI_NO_BMP
+   #endif
+   #ifndef STBI_ONLY_PSD
+   #define STBI_NO_PSD
+   #endif
+   #ifndef STBI_ONLY_TGA
+   #define STBI_NO_TGA
+   #endif
+   #ifndef STBI_ONLY_GIF
+   #define STBI_NO_GIF
+   #endif
+   #ifndef STBI_ONLY_HDR
+   #define STBI_NO_HDR
+   #endif
+   #ifndef STBI_ONLY_PIC
+   #define STBI_NO_PIC
+   #endif
+   #ifndef STBI_ONLY_PNM
+   #define STBI_NO_PNM
+   #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h>  // ldexp, pow
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+#ifdef __cplusplus
+#define STBI_EXTERN extern "C"
+#else
+#define STBI_EXTERN extern
+#endif
+
+
+#ifndef _MSC_VER
+   #ifdef __cplusplus
+   #define stbi_inline inline
+   #else
+   #define stbi_inline
+   #endif
+#else
+   #define stbi_inline __forceinline
+#endif
+
+#ifndef STBI_NO_THREAD_LOCALS
+   #if defined(__cplusplus) &&  __cplusplus >= 201103L
+      #define STBI_THREAD_LOCAL       thread_local
+   #elif defined(__GNUC__) && __GNUC__ < 5
+      #define STBI_THREAD_LOCAL       __thread
+   #elif defined(_MSC_VER)
+      #define STBI_THREAD_LOCAL       __declspec(thread)
+   #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
+      #define STBI_THREAD_LOCAL       _Thread_local
+   #endif
+
+   #ifndef STBI_THREAD_LOCAL
+      #if defined(__GNUC__)
+        #define STBI_THREAD_LOCAL       __thread
+      #endif
+   #endif
+#endif
+
+#ifdef _MSC_VER
+typedef unsigned short stbi__uint16;
+typedef   signed short stbi__int16;
+typedef unsigned int   stbi__uint32;
+typedef   signed int   stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t  stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t  stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v)  (void)(v)
+#else
+#define STBI_NOTUSED(v)  (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+   #define stbi_lrot(x,y)  _lrotl(x,y)
+#else
+   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz)           malloc(sz)
+#define STBI_REALLOC(p,newsz)     realloc(p,newsz)
+#define STBI_FREE(p)              free(p)
+#endif
+
+#ifndef STBI_REALLOC_SIZED
+#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
+#endif
+
+// x86/x64 detection
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define STBI__X86_TARGET
+#endif
+
+#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// which in turn means it gets to use SSE2 everywhere. This is unfortunate,
+// but previous attempts to provide the SSE2 functions with runtime
+// detection caused numerous issues. The way architecture extensions are
+// exposed in GCC/Clang is, sadly, not really suited for one-file libs.
+// New behavior: if compiled with -msse2, we use SSE2 without any
+// detection; if not, we don't use it at all.
+#define STBI_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
+// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+// simultaneously enabling "-mstackrealign".
+//
+// See https://github.com/nothings/stb/issues/81 for more information.
+//
+// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400  // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+   int info[4];
+   __cpuid(info,1);
+   return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+   int res;
+   __asm {
+      mov  eax,1
+      cpuid
+      mov  res,edx
+   }
+   return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
+{
+   int info3 = stbi__cpuid3();
+   return ((info3 >> 26) & 1) != 0;
+}
+#endif
+
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
+{
+   // If we're even attempting to compile this on GCC/Clang, that means
+   // -msse2 is on, which means the compiler is allowed to use SSE2
+   // instructions at will, and so are we.
+   return 1;
+}
+#endif
+
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+// assume GCC or Clang on ARM targets
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+#ifndef STBI_MAX_DIMENSIONS
+#define STBI_MAX_DIMENSIONS (1 << 24)
+#endif
+
+///////////////////////////////////////////////
+//
+//  stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+   stbi__uint32 img_x, img_y;
+   int img_n, img_out_n;
+
+   stbi_io_callbacks io;
+   void *io_user_data;
+
+   int read_from_callbacks;
+   int buflen;
+   stbi_uc buffer_start[128];
+   int callback_already_read;
+
+   stbi_uc *img_buffer, *img_buffer_end;
+   stbi_uc *img_buffer_original, *img_buffer_original_end;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+   s->io.read = NULL;
+   s->read_from_callbacks = 0;
+   s->callback_already_read = 0;
+   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+   s->io = *c;
+   s->io_user_data = user;
+   s->buflen = sizeof(s->buffer_start);
+   s->read_from_callbacks = 1;
+   s->callback_already_read = 0;
+   s->img_buffer = s->img_buffer_original = s->buffer_start;
+   stbi__refill_buffer(s);
+   s->img_buffer_original_end = s->img_buffer_end;
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+   return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+   int ch;
+   fseek((FILE*) user, n, SEEK_CUR);
+   ch = fgetc((FILE*) user);  /* have to read a byte to reset feof()'s flag */
+   if (ch != EOF) {
+      ungetc(ch, (FILE *) user);  /* push byte back onto stream if valid. */
+   }
+}
+
+static int stbi__stdio_eof(void *user)
+{
+   return feof((FILE*) user) || ferror((FILE *) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+   stbi__stdio_read,
+   stbi__stdio_skip,
+   stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+   // conceptually rewind SHOULD rewind to the beginning of the stream,
+   // but we just rewind to the beginning of the initial buffer, because
+   // we only use it after doing 'test', which only ever looks at at most 92 bytes
+   s->img_buffer = s->img_buffer_original;
+   s->img_buffer_end = s->img_buffer_original_end;
+}
+
+enum
+{
+   STBI_ORDER_RGB,
+   STBI_ORDER_BGR
+};
+
+typedef struct
+{
+   int bits_per_channel;
+   int num_channels;
+   int channel_order;
+} stbi__result_info;
+
+#ifndef STBI_NO_JPEG
+static int      stbi__jpeg_test(stbi__context *s);
+static void    *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int      stbi__png_test(stbi__context *s);
+static void    *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+static int      stbi__png_is16(stbi__context *s);
+#endif
+
+#ifndef STBI_NO_BMP
+static int      stbi__bmp_test(stbi__context *s);
+static void    *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int      stbi__tga_test(stbi__context *s);
+static void    *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int      stbi__psd_test(stbi__context *s);
+static void    *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
+static int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+static int      stbi__psd_is16(stbi__context *s);
+#endif
+
+#ifndef STBI_NO_HDR
+static int      stbi__hdr_test(stbi__context *s);
+static float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int      stbi__pic_test(stbi__context *s);
+static void    *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int      stbi__gif_test(stbi__context *s);
+static void    *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static void    *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+static int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int      stbi__pnm_test(stbi__context *s);
+static void    *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+static
+#ifdef STBI_THREAD_LOCAL
+STBI_THREAD_LOCAL
+#endif
+const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+   return stbi__g_failure_reason;
+}
+
+#ifndef STBI_NO_FAILURE_STRINGS
+static int stbi__err(const char *str)
+{
+   stbi__g_failure_reason = str;
+   return 0;
+}
+#endif
+
+static void *stbi__malloc(size_t size)
+{
+    return STBI_MALLOC(size);
+}
+
+// stb_image uses ints pervasively, including for offset calculations.
+// therefore the largest decoded image size we can support with the
+// current code, even on 64-bit targets, is INT_MAX. this is not a
+// significant limitation for the intended use case.
+//
+// we do, however, need to make sure our size calculations don't
+// overflow. hence a few helper functions for size calculations that
+// multiply integers together, making sure that they're non-negative
+// and no overflow occurs.
+
+// return 1 if the sum is valid, 0 on overflow.
+// negative terms are considered invalid.
+static int stbi__addsizes_valid(int a, int b)
+{
+   if (b < 0) return 0;
+   // now 0 <= b <= INT_MAX, hence also
+   // 0 <= INT_MAX - b <= INTMAX.
+   // And "a + b <= INT_MAX" (which might overflow) is the
+   // same as a <= INT_MAX - b (no overflow)
+   return a <= INT_MAX - b;
+}
+
+// returns 1 if the product is valid, 0 on overflow.
+// negative factors are considered invalid.
+static int stbi__mul2sizes_valid(int a, int b)
+{
+   if (a < 0 || b < 0) return 0;
+   if (b == 0) return 1; // mul-by-0 is always safe
+   // portable way to check for no overflows in a*b
+   return a <= INT_MAX/b;
+}
+
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
+// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad2sizes_valid(int a, int b, int add)
+{
+   return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
+}
+#endif
+
+// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad3sizes_valid(int a, int b, int c, int add)
+{
+   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+      stbi__addsizes_valid(a*b*c, add);
+}
+
+// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
+{
+   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+      stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
+}
+#endif
+
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
+// mallocs with size overflow checking
+static void *stbi__malloc_mad2(int a, int b, int add)
+{
+   if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
+   return stbi__malloc(a*b + add);
+}
+#endif
+
+static void *stbi__malloc_mad3(int a, int b, int c, int add)
+{
+   if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
+   return stbi__malloc(a*b*c + add);
+}
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
+{
+   if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
+   return stbi__malloc(a*b*c*d + add);
+}
+#endif
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+   #define stbi__err(x,y)  0
+#elif defined(STBI_FAILURE_USERMSG)
+   #define stbi__err(x,y)  stbi__err(y)
+#else
+   #define stbi__err(x,y)  stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+   STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);
+#endif
+
+static int stbi__vertically_flip_on_load_global = 0;
+
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
+{
+   stbi__vertically_flip_on_load_global = flag_true_if_should_flip;
+}
+
+#ifndef STBI_THREAD_LOCAL
+#define stbi__vertically_flip_on_load  stbi__vertically_flip_on_load_global
+#else
+static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;
+
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)
+{
+   stbi__vertically_flip_on_load_local = flag_true_if_should_flip;
+   stbi__vertically_flip_on_load_set = 1;
+}
+
+#define stbi__vertically_flip_on_load  (stbi__vertically_flip_on_load_set       \
+                                         ? stbi__vertically_flip_on_load_local  \
+                                         : stbi__vertically_flip_on_load_global)
+#endif // STBI_THREAD_LOCAL
+
+static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+   memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
+   ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
+   ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
+   ri->num_channels = 0;
+
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_PNG
+   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
+   #else
+   STBI_NOTUSED(bpc);
+   #endif
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp, ri);
+   #endif
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp, ri);
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s)) {
+      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);
+      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+   }
+   #endif
+
+   #ifndef STBI_NO_TGA
+   // test tga last because it's a crappy test!
+   if (stbi__tga_test(s))
+      return stbi__tga_load(s,x,y,comp,req_comp, ri);
+   #endif
+
+   return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
+{
+   int i;
+   int img_len = w * h * channels;
+   stbi_uc *reduced;
+
+   reduced = (stbi_uc *) stbi__malloc(img_len);
+   if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
+
+   for (i = 0; i < img_len; ++i)
+      reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
+
+   STBI_FREE(orig);
+   return reduced;
+}
+
+static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
+{
+   int i;
+   int img_len = w * h * channels;
+   stbi__uint16 *enlarged;
+
+   enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
+   if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+
+   for (i = 0; i < img_len; ++i)
+      enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
+
+   STBI_FREE(orig);
+   return enlarged;
+}
+
+static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
+{
+   int row;
+   size_t bytes_per_row = (size_t)w * bytes_per_pixel;
+   stbi_uc temp[2048];
+   stbi_uc *bytes = (stbi_uc *)image;
+
+   for (row = 0; row < (h>>1); row++) {
+      stbi_uc *row0 = bytes + row*bytes_per_row;
+      stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
+      // swap row0 with row1
+      size_t bytes_left = bytes_per_row;
+      while (bytes_left) {
+         size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
+         memcpy(temp, row0, bytes_copy);
+         memcpy(row0, row1, bytes_copy);
+         memcpy(row1, temp, bytes_copy);
+         row0 += bytes_copy;
+         row1 += bytes_copy;
+         bytes_left -= bytes_copy;
+      }
+   }
+}
+
+#ifndef STBI_NO_GIF
+static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
+{
+   int slice;
+   int slice_size = w * h * bytes_per_pixel;
+
+   stbi_uc *bytes = (stbi_uc *)image;
+   for (slice = 0; slice < z; ++slice) {
+      stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
+      bytes += slice_size;
+   }
+}
+#endif
+
+static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__result_info ri;
+   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
+
+   if (result == NULL)
+      return NULL;
+
+   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
+   if (ri.bits_per_channel != 8) {
+      result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+      ri.bits_per_channel = 8;
+   }
+
+   // @TODO: move stbi__convert_format to here
+
+   if (stbi__vertically_flip_on_load) {
+      int channels = req_comp ? req_comp : *comp;
+      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
+   }
+
+   return (unsigned char *) result;
+}
+
+static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__result_info ri;
+   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
+
+   if (result == NULL)
+      return NULL;
+
+   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
+   if (ri.bits_per_channel != 16) {
+      result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+      ri.bits_per_channel = 16;
+   }
+
+   // @TODO: move stbi__convert_format16 to here
+   // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
+
+   if (stbi__vertically_flip_on_load) {
+      int channels = req_comp ? req_comp : *comp;
+      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
+   }
+
+   return (stbi__uint16 *) result;
+}
+
+#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)
+static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
+{
+   if (stbi__vertically_flip_on_load && result != NULL) {
+      int channels = req_comp ? req_comp : *comp;
+      stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
+   }
+}
+#endif
+
+#ifndef STBI_NO_STDIO
+
+#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
+STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
+STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
+#endif
+
+#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
+{
+	return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
+}
+#endif
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+   FILE *f;
+#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
+   wchar_t wMode[64];
+   wchar_t wFilename[1024];
+	if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
+      return 0;
+
+	if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
+      return 0;
+
+#if _MSC_VER >= 1400
+	if (0 != _wfopen_s(&f, wFilename, wMode))
+		f = 0;
+#else
+   f = _wfopen(wFilename, wMode);
+#endif
+
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
+   if (0 != fopen_s(&f, filename, mode))
+      f=0;
+#else
+   f = fopen(filename, mode);
+#endif
+   return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   unsigned char *result;
+   if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+   result = stbi_load_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *result;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+   if (result) {
+      // need to 'unget' all the characters in the IO buffer
+      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+   }
+   return result;
+}
+
+STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__uint16 *result;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
+   if (result) {
+      // need to 'unget' all the characters in the IO buffer
+      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+   }
+   return result;
+}
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   stbi__uint16 *result;
+   if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file");
+   result = stbi_load_from_file_16(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
+   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+   unsigned char *result;
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+
+   result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
+   if (stbi__vertically_flip_on_load) {
+      stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
+   }
+
+   return result;
+}
+#endif
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *data;
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s)) {
+      stbi__result_info ri;
+      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);
+      if (hdr_data)
+         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
+      return hdr_data;
+   }
+   #endif
+   data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
+   if (data)
+      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+   return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   float *result;
+   FILE *f = stbi__fopen(filename, "rb");
+   if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+   result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_file(&s,f);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(buffer);
+   STBI_NOTUSED(len);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   int result=0;
+   if (f) {
+      result = stbi_is_hdr_from_file(f);
+      fclose(f);
+   }
+   return result;
+}
+
+STBIDEF int stbi_is_hdr_from_file(FILE *f)
+{
+   #ifndef STBI_NO_HDR
+   long pos = ftell(f);
+   int res;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   res = stbi__hdr_test(&s);
+   fseek(f, pos, SEEK_SET);
+   return res;
+   #else
+   STBI_NOTUSED(f);
+   return 0;
+   #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(clbk);
+   STBI_NOTUSED(user);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_LINEAR
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+
+STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+   STBI__SCAN_load=0,
+   STBI__SCAN_type,
+   STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+   s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);
+   if (n == 0) {
+      // at end of file, treat same as if from memory, but need to handle case
+      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+      s->read_from_callbacks = 0;
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start+1;
+      *s->img_buffer = 0;
+   } else {
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start + n;
+   }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+   if (s->read_from_callbacks) {
+      stbi__refill_buffer(s);
+      return *s->img_buffer++;
+   }
+   return 0;
+}
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+   if (s->io.read) {
+      if (!(s->io.eof)(s->io_user_data)) return 0;
+      // if feof() is true, check if buffer = end
+      // special case: we've only got the special 0 character at the end
+      if (s->read_from_callbacks == 0) return 1;
+   }
+
+   return s->img_buffer >= s->img_buffer_end;
+}
+#endif
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)
+// nothing
+#else
+static void stbi__skip(stbi__context *s, int n)
+{
+   if (n == 0) return;  // already there!
+   if (n < 0) {
+      s->img_buffer = s->img_buffer_end;
+      return;
+   }
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         s->img_buffer = s->img_buffer_end;
+         (s->io.skip)(s->io_user_data, n - blen);
+         return;
+      }
+   }
+   s->img_buffer += n;
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)
+// nothing
+#else
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         int res, count;
+
+         memcpy(buffer, s->img_buffer, blen);
+
+         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+         res = (count == (n-blen));
+         s->img_buffer = s->img_buffer_end;
+         return res;
+      }
+   }
+
+   if (s->img_buffer+n <= s->img_buffer_end) {
+      memcpy(buffer, s->img_buffer, n);
+      s->img_buffer += n;
+      return 1;
+   } else
+      return 0;
+}
+#endif
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
+static int stbi__get16be(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return (z << 8) + stbi__get8(s);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16be(s);
+   return (z << 16) + stbi__get16be(s);
+}
+#endif
+
+#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
+// nothing
+#else
+static int stbi__get16le(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return z + (stbi__get8(s) << 8);
+}
+#endif
+
+#ifndef STBI_NO_BMP
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16le(s);
+   return z + (stbi__get16le(s) << 16);
+}
+#endif
+
+#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+//////////////////////////////////////////////////////////////////////////////
+//
+//  generic converter from built-in img_n to req_comp
+//    individual types do this automatically as much as possible (e.g. jpeg
+//    does all cases internally since it needs to colorspace convert anyway,
+//    and it never has alpha, so very few cases ). png can automatically
+//    interleave an alpha=255 channel, but falls back to this for other cases
+//
+//  assume data buffer is malloced, so malloc a new one and free that one
+//  only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+   int i,j;
+   unsigned char *good;
+
+   if (req_comp == img_n) return data;
+   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+   good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
+   if (good == NULL) {
+      STBI_FREE(data);
+      return stbi__errpuc("outofmem", "Out of memory");
+   }
+
+   for (j=0; j < (int) y; ++j) {
+      unsigned char *src  = data + j * x * img_n   ;
+      unsigned char *dest = good + j * x * req_comp;
+
+      #define STBI__COMBO(a,b)  ((a)*8+(b))
+      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+      // convert source image with img_n components to one with req_comp components;
+      // avoid switch per pixel, so use switch per scanline and massive macros
+      switch (STBI__COMBO(img_n, req_comp)) {
+         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255;                                     } break;
+         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;
+         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255;                     } break;
+         STBI__CASE(2,1) { dest[0]=src[0];                                                  } break;
+         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;
+         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                  } break;
+         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255;        } break;
+         STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255;    } break;
+         STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                    } break;
+         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion");
+      }
+      #undef STBI__CASE
+   }
+
+   STBI_FREE(data);
+   return good;
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
+static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
+{
+   return (stbi__uint16) (((r*77) + (g*150) +  (29*b)) >> 8);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
+static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+   int i,j;
+   stbi__uint16 *good;
+
+   if (req_comp == img_n) return data;
+   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+   good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
+   if (good == NULL) {
+      STBI_FREE(data);
+      return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+   }
+
+   for (j=0; j < (int) y; ++j) {
+      stbi__uint16 *src  = data + j * x * img_n   ;
+      stbi__uint16 *dest = good + j * x * req_comp;
+
+      #define STBI__COMBO(a,b)  ((a)*8+(b))
+      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+      // convert source image with img_n components to one with req_comp components;
+      // avoid switch per pixel, so use switch per scanline and massive macros
+      switch (STBI__COMBO(img_n, req_comp)) {
+         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff;                                     } break;
+         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;
+         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff;                     } break;
+         STBI__CASE(2,1) { dest[0]=src[0];                                                     } break;
+         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;
+         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                     } break;
+         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff;        } break;
+         STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;
+         STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;
+         STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                       } break;
+         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion");
+      }
+      #undef STBI__CASE
+   }
+
+   STBI_FREE(data);
+   return good;
+}
+#endif
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+   int i,k,n;
+   float *output;
+   if (!data) return NULL;
+   output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
+   if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+      }
+   }
+   if (n < comp) {
+      for (i=0; i < x*y; ++i) {
+         output[i*comp + n] = data[i*comp + n]/255.0f;
+      }
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x)   ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)
+{
+   int i,k,n;
+   stbi_uc *output;
+   if (!data) return NULL;
+   output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);
+   if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+      if (k < comp) {
+         float z = data[i*comp+k] * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  "baseline" JPEG/JFIF decoder
+//
+//    simple implementation
+//      - doesn't support delayed output of y-dimension
+//      - simple interface (only one output format: 8-bit interleaved RGB)
+//      - doesn't try to recover corrupt jpegs
+//      - doesn't allow partial loading, loading multiple at once
+//      - still fast on x86 (copying globals into locals doesn't help x86)
+//      - allocates lots of intermediate memory (full size of all components)
+//        - non-interleaved case requires this anyway
+//        - allows good upsampling (see next)
+//    high-quality
+//      - upsampled channels are bilinearly interpolated, even across blocks
+//      - quality integer IDCT derived from IJG's 'slow'
+//    performance
+//      - fast huffman; reasonable integer IDCT
+//      - some SIMD kernels for common paths on targets with SSE2/NEON
+//      - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+   stbi_uc  fast[1 << FAST_BITS];
+   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+   stbi__uint16 code[256];
+   stbi_uc  values[256];
+   stbi_uc  size[257];
+   unsigned int maxcode[18];
+   int    delta[17];   // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+   stbi__context *s;
+   stbi__huffman huff_dc[4];
+   stbi__huffman huff_ac[4];
+   stbi__uint16 dequant[4][64];
+   stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+   int img_h_max, img_v_max;
+   int img_mcu_x, img_mcu_y;
+   int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+   struct
+   {
+      int id;
+      int h,v;
+      int tq;
+      int hd,ha;
+      int dc_pred;
+
+      int x,y,w2,h2;
+      stbi_uc *data;
+      void *raw_data, *raw_coeff;
+      stbi_uc *linebuf;
+      short   *coeff;   // progressive only
+      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks
+   } img_comp[4];
+
+   stbi__uint32   code_buffer; // jpeg entropy-coded buffer
+   int            code_bits;   // number of valid bits
+   unsigned char  marker;      // marker seen while filling entropy buffer
+   int            nomore;      // flag if we saw a marker so must stop
+
+   int            progressive;
+   int            spec_start;
+   int            spec_end;
+   int            succ_high;
+   int            succ_low;
+   int            eob_run;
+   int            jfif;
+   int            app14_color_transform; // Adobe APP14 tag
+   int            rgb;
+
+   int scan_n, order[4];
+   int restart_interval, todo;
+
+// kernels
+   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+   int i,j,k=0;
+   unsigned int code;
+   // build size list for each symbol (from JPEG spec)
+   for (i=0; i < 16; ++i)
+      for (j=0; j < count[i]; ++j)
+         h->size[k++] = (stbi_uc) (i+1);
+   h->size[k] = 0;
+
+   // compute actual symbols (from jpeg spec)
+   code = 0;
+   k = 0;
+   for(j=1; j <= 16; ++j) {
+      // compute delta to add to code to compute symbol id
+      h->delta[j] = k - code;
+      if (h->size[k] == j) {
+         while (h->size[k] == j)
+            h->code[k++] = (stbi__uint16) (code++);
+         if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+      }
+      // compute largest code + 1 for this size, preshifted as needed later
+      h->maxcode[j] = code << (16-j);
+      code <<= 1;
+   }
+   h->maxcode[j] = 0xffffffff;
+
+   // build non-spec acceleration table; 255 is flag for not-accelerated
+   memset(h->fast, 255, 1 << FAST_BITS);
+   for (i=0; i < k; ++i) {
+      int s = h->size[i];
+      if (s <= FAST_BITS) {
+         int c = h->code[i] << (FAST_BITS-s);
+         int m = 1 << (FAST_BITS-s);
+         for (j=0; j < m; ++j) {
+            h->fast[c+j] = (stbi_uc) i;
+         }
+      }
+   }
+   return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+   int i;
+   for (i=0; i < (1 << FAST_BITS); ++i) {
+      stbi_uc fast = h->fast[i];
+      fast_ac[i] = 0;
+      if (fast < 255) {
+         int rs = h->values[fast];
+         int run = (rs >> 4) & 15;
+         int magbits = rs & 15;
+         int len = h->size[fast];
+
+         if (magbits && len + magbits <= FAST_BITS) {
+            // magnitude code followed by receive_extend code
+            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+            int m = 1 << (magbits - 1);
+            if (k < m) k += (~0U << magbits) + 1;
+            // if the result is small enough, we can fit it in fast_ac table
+            if (k >= -128 && k <= 127)
+               fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
+         }
+      }
+   }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+   do {
+      unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
+      if (b == 0xff) {
+         int c = stbi__get8(j->s);
+         while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
+         if (c != 0) {
+            j->marker = (unsigned char) c;
+            j->nomore = 1;
+            return;
+         }
+      }
+      j->code_buffer |= b << (24 - j->code_bits);
+      j->code_bits += 8;
+   } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+   unsigned int temp;
+   int c,k;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   // look at the top FAST_BITS and determine what symbol ID it is,
+   // if the code is <= FAST_BITS
+   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+   k = h->fast[c];
+   if (k < 255) {
+      int s = h->size[k];
+      if (s > j->code_bits)
+         return -1;
+      j->code_buffer <<= s;
+      j->code_bits -= s;
+      return h->values[k];
+   }
+
+   // naive test is to shift the code_buffer down so k bits are
+   // valid, then test against maxcode. To speed this up, we've
+   // preshifted maxcode left so that it has (16-k) 0s at the
+   // end; in other words, regardless of the number of bits, it
+   // wants to be compared against something shifted to have 16;
+   // that way we don't need to shift inside the loop.
+   temp = j->code_buffer >> 16;
+   for (k=FAST_BITS+1 ; ; ++k)
+      if (temp < h->maxcode[k])
+         break;
+   if (k == 17) {
+      // error! code not found
+      j->code_bits -= 16;
+      return -1;
+   }
+
+   if (k > j->code_bits)
+      return -1;
+
+   // convert the huffman code to the symbol id
+   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+   // convert the id to a symbol
+   j->code_bits -= k;
+   j->code_buffer <<= k;
+   return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   int sgn;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+
+   sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+   k = stbi_lrot(j->code_buffer, n);
+   if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0;
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k + (stbi__jbias[n] & ~sgn);
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+   k = stbi_lrot(j->code_buffer, n);
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+   unsigned int k;
+   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+   k = j->code_buffer;
+   j->code_buffer <<= 1;
+   --j->code_bits;
+   return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static const stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+    0,  1,  8, 16,  9,  2,  3, 10,
+   17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34,
+   27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36,
+   29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46,
+   53, 60, 61, 54, 47, 55, 62, 63,
+   // let corrupt input sample past end
+   63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)
+{
+   int diff,dc,k;
+   int t;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+   t = stbi__jpeg_huff_decode(j, hdc);
+   if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+
+   // 0 all the ac values now so we can do it 32-bits at a time
+   memset(data,0,64*sizeof(data[0]));
+
+   diff = t ? stbi__extend_receive(j, t) : 0;
+   dc = j->img_comp[b].dc_pred + diff;
+   j->img_comp[b].dc_pred = dc;
+   data[0] = (short) (dc * dequant[0]);
+
+   // decode AC components, see JPEG spec
+   k = 1;
+   do {
+      unsigned int zig;
+      int c,r,s;
+      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+      r = fac[c];
+      if (r) { // fast-AC path
+         k += (r >> 4) & 15; // run
+         s = r & 15; // combined length
+         j->code_buffer <<= s;
+         j->code_bits -= s;
+         // decode into unzigzag'd location
+         zig = stbi__jpeg_dezigzag[k++];
+         data[zig] = (short) ((r >> 8) * dequant[zig]);
+      } else {
+         int rs = stbi__jpeg_huff_decode(j, hac);
+         if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+         s = rs & 15;
+         r = rs >> 4;
+         if (s == 0) {
+            if (rs != 0xf0) break; // end block
+            k += 16;
+         } else {
+            k += r;
+            // decode into unzigzag'd location
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+         }
+      }
+   } while (k < 64);
+   return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+   int diff,dc;
+   int t;
+   if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   if (j->succ_high == 0) {
+      // first scan for DC coefficient, must be first
+      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+      t = stbi__jpeg_huff_decode(j, hdc);
+      if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+      diff = t ? stbi__extend_receive(j, t) : 0;
+
+      dc = j->img_comp[b].dc_pred + diff;
+      j->img_comp[b].dc_pred = dc;
+      data[0] = (short) (dc << j->succ_low);
+   } else {
+      // refinement scan for DC coefficient
+      if (stbi__jpeg_get_bit(j))
+         data[0] += (short) (1 << j->succ_low);
+   }
+   return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+   int k;
+   if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->succ_high == 0) {
+      int shift = j->succ_low;
+
+      if (j->eob_run) {
+         --j->eob_run;
+         return 1;
+      }
+
+      k = j->spec_start;
+      do {
+         unsigned int zig;
+         int c,r,s;
+         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+         r = fac[c];
+         if (r) { // fast-AC path
+            k += (r >> 4) & 15; // run
+            s = r & 15; // combined length
+            j->code_buffer <<= s;
+            j->code_bits -= s;
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) ((r >> 8) << shift);
+         } else {
+            int rs = stbi__jpeg_huff_decode(j, hac);
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r);
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  --j->eob_run;
+                  break;
+               }
+               k += 16;
+            } else {
+               k += r;
+               zig = stbi__jpeg_dezigzag[k++];
+               data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+            }
+         }
+      } while (k <= j->spec_end);
+   } else {
+      // refinement scan for these AC coefficients
+
+      short bit = (short) (1 << j->succ_low);
+
+      if (j->eob_run) {
+         --j->eob_run;
+         for (k = j->spec_start; k <= j->spec_end; ++k) {
+            short *p = &data[stbi__jpeg_dezigzag[k]];
+            if (*p != 0)
+               if (stbi__jpeg_get_bit(j))
+                  if ((*p & bit)==0) {
+                     if (*p > 0)
+                        *p += bit;
+                     else
+                        *p -= bit;
+                  }
+         }
+      } else {
+         k = j->spec_start;
+         do {
+            int r,s;
+            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r) - 1;
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  r = 64; // force end of block
+               } else {
+                  // r=15 s=0 should write 16 0s, so we just do
+                  // a run of 15 0s and then write s (which is 0),
+                  // so we don't have to do anything special here
+               }
+            } else {
+               if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+               // sign bit
+               if (stbi__jpeg_get_bit(j))
+                  s = bit;
+               else
+                  s = -bit;
+            }
+
+            // advance by r
+            while (k <= j->spec_end) {
+               short *p = &data[stbi__jpeg_dezigzag[k++]];
+               if (*p != 0) {
+                  if (stbi__jpeg_get_bit(j))
+                     if ((*p & bit)==0) {
+                        if (*p > 0)
+                           *p += bit;
+                        else
+                           *p -= bit;
+                     }
+               } else {
+                  if (r == 0) {
+                     *p = (short) s;
+                     break;
+                  }
+                  --r;
+               }
+            }
+         } while (k <= j->spec_end);
+      }
+   }
+   return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+   // trick to use a single test to catch both cases
+   if ((unsigned int) x > 255) {
+      if (x < 0) return 0;
+      if (x > 255) return 255;
+   }
+   return (stbi_uc) x;
+}
+
+#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x)  ((x) * 4096)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+   p2 = s2;                                    \
+   p3 = s6;                                    \
+   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \
+   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \
+   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \
+   p2 = s0;                                    \
+   p3 = s4;                                    \
+   t0 = stbi__fsh(p2+p3);                      \
+   t1 = stbi__fsh(p2-p3);                      \
+   x0 = t0+t3;                                 \
+   x3 = t0-t3;                                 \
+   x1 = t1+t2;                                 \
+   x2 = t1-t2;                                 \
+   t0 = s7;                                    \
+   t1 = s5;                                    \
+   t2 = s3;                                    \
+   t3 = s1;                                    \
+   p3 = t0+t2;                                 \
+   p4 = t1+t3;                                 \
+   p1 = t0+t3;                                 \
+   p2 = t1+t2;                                 \
+   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \
+   t0 = t0*stbi__f2f( 0.298631336f);           \
+   t1 = t1*stbi__f2f( 2.053119869f);           \
+   t2 = t2*stbi__f2f( 3.072711026f);           \
+   t3 = t3*stbi__f2f( 1.501321110f);           \
+   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \
+   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \
+   p3 = p3*stbi__f2f(-1.961570560f);           \
+   p4 = p4*stbi__f2f(-0.390180644f);           \
+   t3 += p1+p4;                                \
+   t2 += p2+p3;                                \
+   t1 += p2+p4;                                \
+   t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+   int i,val[64],*v=val;
+   stbi_uc *o;
+   short *d = data;
+
+   // columns
+   for (i=0; i < 8; ++i,++d, ++v) {
+      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+           && d[40]==0 && d[48]==0 && d[56]==0) {
+         //    no shortcut                 0     seconds
+         //    (1|2|3|4|5|6|7)==0          0     seconds
+         //    all separate               -0.047 seconds
+         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds
+         int dcterm = d[0]*4;
+         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+      } else {
+         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+         // constants scaled things up by 1<<12; let's bring them back
+         // down, but keep 2 extra bits of precision
+         x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+         v[ 0] = (x0+t3) >> 10;
+         v[56] = (x0-t3) >> 10;
+         v[ 8] = (x1+t2) >> 10;
+         v[48] = (x1-t2) >> 10;
+         v[16] = (x2+t1) >> 10;
+         v[40] = (x2-t1) >> 10;
+         v[24] = (x3+t0) >> 10;
+         v[32] = (x3-t0) >> 10;
+      }
+   }
+
+   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+      // no fast case since the first 1D IDCT spread components out
+      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+      // constants scaled things up by 1<<12, plus we had 1<<2 from first
+      // loop, plus horizontal and vertical each scale by sqrt(8) so together
+      // we've got an extra 1<<3, so 1<<17 total we need to remove.
+      // so we want to round that, which means adding 0.5 * 1<<17,
+      // aka 65536. Also, we'll end up with -128 to 127 that we want
+      // to encode as 0..255 by adding 128, so we'll add that before the shift
+      x0 += 65536 + (128<<17);
+      x1 += 65536 + (128<<17);
+      x2 += 65536 + (128<<17);
+      x3 += 65536 + (128<<17);
+      // tried computing the shifts into temps, or'ing the temps to see
+      // if any were out of range, but that was slower
+      o[0] = stbi__clamp((x0+t3) >> 17);
+      o[7] = stbi__clamp((x0-t3) >> 17);
+      o[1] = stbi__clamp((x1+t2) >> 17);
+      o[6] = stbi__clamp((x1-t2) >> 17);
+      o[2] = stbi__clamp((x2+t1) >> 17);
+      o[5] = stbi__clamp((x2-t1) >> 17);
+      o[3] = stbi__clamp((x3+t0) >> 17);
+      o[4] = stbi__clamp((x3-t0) >> 17);
+   }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   // This is constructed to match our regular (generic) integer IDCT exactly.
+   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+   __m128i tmp;
+
+   // dot product constant: even elems=x, odd elems=y
+   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
+   // out(1) = c1[even]*x + c1[odd]*y
+   #define dct_rot(out0,out1, x,y,c0,c1) \
+      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+   // out = in << 12  (in 16-bit, out 32-bit)
+   #define dct_widen(out, in) \
+      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+   // wide add
+   #define dct_wadd(out, a, b) \
+      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+   // wide sub
+   #define dct_wsub(out, a, b) \
+      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+   // butterfly a/b, add bias, then shift by "s" and pack
+   #define dct_bfly32o(out0, out1, a,b,bias,s) \
+      { \
+         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+         dct_wadd(sum, abiased, b); \
+         dct_wsub(dif, abiased, b); \
+         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+      }
+
+   // 8-bit interleave step (for transposes)
+   #define dct_interleave8(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi8(a, b); \
+      b = _mm_unpackhi_epi8(tmp, b)
+
+   // 16-bit interleave step (for transposes)
+   #define dct_interleave16(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi16(a, b); \
+      b = _mm_unpackhi_epi16(tmp, b)
+
+   #define dct_pass(bias,shift) \
+      { \
+         /* even part */ \
+         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+         __m128i sum04 = _mm_add_epi16(row0, row4); \
+         __m128i dif04 = _mm_sub_epi16(row0, row4); \
+         dct_widen(t0e, sum04); \
+         dct_widen(t1e, dif04); \
+         dct_wadd(x0, t0e, t3e); \
+         dct_wsub(x3, t0e, t3e); \
+         dct_wadd(x1, t1e, t2e); \
+         dct_wsub(x2, t1e, t2e); \
+         /* odd part */ \
+         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+         __m128i sum17 = _mm_add_epi16(row1, row7); \
+         __m128i sum35 = _mm_add_epi16(row3, row5); \
+         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+         dct_wadd(x4, y0o, y4o); \
+         dct_wadd(x5, y1o, y5o); \
+         dct_wadd(x6, y2o, y5o); \
+         dct_wadd(x7, y3o, y4o); \
+         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+      }
+
+   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
+   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
+   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
+   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
+   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
+   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
+   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
+   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
+
+   // rounding biases in column/row passes, see stbi__idct_block for explanation.
+   __m128i bias_0 = _mm_set1_epi32(512);
+   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+   // load
+   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+   row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+   // column pass
+   dct_pass(bias_0, 10);
+
+   {
+      // 16bit 8x8 transpose pass 1
+      dct_interleave16(row0, row4);
+      dct_interleave16(row1, row5);
+      dct_interleave16(row2, row6);
+      dct_interleave16(row3, row7);
+
+      // transpose pass 2
+      dct_interleave16(row0, row2);
+      dct_interleave16(row1, row3);
+      dct_interleave16(row4, row6);
+      dct_interleave16(row5, row7);
+
+      // transpose pass 3
+      dct_interleave16(row0, row1);
+      dct_interleave16(row2, row3);
+      dct_interleave16(row4, row5);
+      dct_interleave16(row6, row7);
+   }
+
+   // row pass
+   dct_pass(bias_1, 17);
+
+   {
+      // pack
+      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
+      __m128i p1 = _mm_packus_epi16(row2, row3);
+      __m128i p2 = _mm_packus_epi16(row4, row5);
+      __m128i p3 = _mm_packus_epi16(row6, row7);
+
+      // 8bit 8x8 transpose pass 1
+      dct_interleave8(p0, p2); // a0e0a1e1...
+      dct_interleave8(p1, p3); // c0g0c1g1...
+
+      // transpose pass 2
+      dct_interleave8(p0, p1); // a0c0e0g0...
+      dct_interleave8(p2, p3); // b0d0f0h0...
+
+      // transpose pass 3
+      dct_interleave8(p0, p2); // a0b0c0d0...
+      dct_interleave8(p1, p3); // a4b4c4d4...
+
+      // store
+      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+   }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif // STBI_SSE2
+
+#ifdef STBI_NEON
+
+// NEON integer IDCT. should produce bit-identical
+// results to the generic C version.
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
+   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
+   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
+   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
+   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
+   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
+   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
+   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
+   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
+   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
+   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
+   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+// wide add
+#define dct_wadd(out, a, b) \
+   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+// wide sub
+#define dct_wsub(out, a, b) \
+   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+// butterfly a/b, then shift using "shiftop" by "s" and pack
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+   { \
+      dct_wadd(sum, a, b); \
+      dct_wsub(dif, a, b); \
+      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+   }
+
+#define dct_pass(shiftop, shift) \
+   { \
+      /* even part */ \
+      int16x8_t sum26 = vaddq_s16(row2, row6); \
+      dct_long_mul(p1e, sum26, rot0_0); \
+      dct_long_mac(t2e, p1e, row6, rot0_1); \
+      dct_long_mac(t3e, p1e, row2, rot0_2); \
+      int16x8_t sum04 = vaddq_s16(row0, row4); \
+      int16x8_t dif04 = vsubq_s16(row0, row4); \
+      dct_widen(t0e, sum04); \
+      dct_widen(t1e, dif04); \
+      dct_wadd(x0, t0e, t3e); \
+      dct_wsub(x3, t0e, t3e); \
+      dct_wadd(x1, t1e, t2e); \
+      dct_wsub(x2, t1e, t2e); \
+      /* odd part */ \
+      int16x8_t sum15 = vaddq_s16(row1, row5); \
+      int16x8_t sum17 = vaddq_s16(row1, row7); \
+      int16x8_t sum35 = vaddq_s16(row3, row5); \
+      int16x8_t sum37 = vaddq_s16(row3, row7); \
+      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+      dct_long_mul(p5o, sumodd, rot1_0); \
+      dct_long_mac(p1o, p5o, sum17, rot1_1); \
+      dct_long_mac(p2o, p5o, sum35, rot1_2); \
+      dct_long_mul(p3o, sum37, rot2_0); \
+      dct_long_mul(p4o, sum15, rot2_1); \
+      dct_wadd(sump13o, p1o, p3o); \
+      dct_wadd(sump24o, p2o, p4o); \
+      dct_wadd(sump23o, p2o, p3o); \
+      dct_wadd(sump14o, p1o, p4o); \
+      dct_long_mac(x4, sump13o, row7, rot3_0); \
+      dct_long_mac(x5, sump24o, row5, rot3_1); \
+      dct_long_mac(x6, sump23o, row3, rot3_2); \
+      dct_long_mac(x7, sump14o, row1, rot3_3); \
+      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+   }
+
+   // load
+   row0 = vld1q_s16(data + 0*8);
+   row1 = vld1q_s16(data + 1*8);
+   row2 = vld1q_s16(data + 2*8);
+   row3 = vld1q_s16(data + 3*8);
+   row4 = vld1q_s16(data + 4*8);
+   row5 = vld1q_s16(data + 5*8);
+   row6 = vld1q_s16(data + 6*8);
+   row7 = vld1q_s16(data + 7*8);
+
+   // add DC bias
+   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+   // column pass
+   dct_pass(vrshrn_n_s32, 10);
+
+   // 16bit 8x8 transpose
+   {
+// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+// whether compilers actually get this is another story, sadly.
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+      // pass 1
+      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
+      dct_trn16(row2, row3);
+      dct_trn16(row4, row5);
+      dct_trn16(row6, row7);
+
+      // pass 2
+      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
+      dct_trn32(row1, row3);
+      dct_trn32(row4, row6);
+      dct_trn32(row5, row7);
+
+      // pass 3
+      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
+      dct_trn64(row1, row5);
+      dct_trn64(row2, row6);
+      dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+   }
+
+   // row pass
+   // vrshrn_n_s32 only supports shifts up to 16, we need
+   // 17. so do a non-rounding shift of 16 first then follow
+   // up with a rounding shift by 1.
+   dct_pass(vshrn_n_s32, 16);
+
+   {
+      // pack and round
+      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+      // again, these can translate into one instruction, but often don't.
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+      // sadly can't use interleaved stores here since we only write
+      // 8 bytes to each scan line!
+
+      // 8x8 8-bit transpose pass 1
+      dct_trn8_8(p0, p1);
+      dct_trn8_8(p2, p3);
+      dct_trn8_8(p4, p5);
+      dct_trn8_8(p6, p7);
+
+      // pass 2
+      dct_trn8_16(p0, p2);
+      dct_trn8_16(p1, p3);
+      dct_trn8_16(p4, p6);
+      dct_trn8_16(p5, p7);
+
+      // pass 3
+      dct_trn8_32(p0, p4);
+      dct_trn8_32(p1, p5);
+      dct_trn8_32(p2, p6);
+      dct_trn8_32(p3, p7);
+
+      // store
+      vst1_u8(out, p0); out += out_stride;
+      vst1_u8(out, p1); out += out_stride;
+      vst1_u8(out, p2); out += out_stride;
+      vst1_u8(out, p3); out += out_stride;
+      vst1_u8(out, p4); out += out_stride;
+      vst1_u8(out, p5); out += out_stride;
+      vst1_u8(out, p6); out += out_stride;
+      vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+   }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif // STBI_NEON
+
+#define STBI__MARKER_none  0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static stbi_uc stbi__get_marker(stbi__jpeg *j)
+{
+   stbi_uc x;
+   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
+   x = stbi__get8(j->s);
+   if (x != 0xff) return STBI__MARKER_none;
+   while (x == 0xff)
+      x = stbi__get8(j->s); // consume repeated 0xff fill bytes
+   return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, stbi__jpeg_reset the entropy decoder and
+// the dc prediction
+static void stbi__jpeg_reset(stbi__jpeg *j)
+{
+   j->code_bits = 0;
+   j->code_buffer = 0;
+   j->nomore = 0;
+   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;
+   j->marker = STBI__MARKER_none;
+   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+   j->eob_run = 0;
+   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+   // since we don't even allow 1<<30 pixels
+}
+
+static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
+{
+   stbi__jpeg_reset(z);
+   if (!z->progressive) {
+      if (z->scan_n == 1) {
+         int i,j;
+         STBI_SIMD_ALIGN(short, data[64]);
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               int ha = z->img_comp[n].ha;
+               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  // if it's NOT a restart, then just bail, so we get corrupt data
+                  // rather than no data
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         STBI_SIMD_ALIGN(short, data[64]);
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x)*8;
+                        int y2 = (j*z->img_comp[n].v + y)*8;
+                        int ha = z->img_comp[n].ha;
+                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   } else {
+      if (z->scan_n == 1) {
+         int i,j;
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               if (z->spec_start == 0) {
+                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                     return 0;
+               } else {
+                  int ha = z->img_comp[n].ha;
+                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+                     return 0;
+               }
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x);
+                        int y2 = (j*z->img_comp[n].v + y);
+                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                           return 0;
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   }
+}
+
+static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)
+{
+   int i;
+   for (i=0; i < 64; ++i)
+      data[i] *= dequant[i];
+}
+
+static void stbi__jpeg_finish(stbi__jpeg *z)
+{
+   if (z->progressive) {
+      // dequantize and idct the data
+      int i,j,n;
+      for (n=0; n < z->s->img_n; ++n) {
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+            }
+         }
+      }
+   }
+}
+
+static int stbi__process_marker(stbi__jpeg *z, int m)
+{
+   int L;
+   switch (m) {
+      case STBI__MARKER_none: // no marker found
+         return stbi__err("expected marker","Corrupt JPEG");
+
+      case 0xDD: // DRI - specify restart interval
+         if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
+         z->restart_interval = stbi__get16be(z->s);
+         return 1;
+
+      case 0xDB: // DQT - define quantization table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            int q = stbi__get8(z->s);
+            int p = q >> 4, sixteen = (p != 0);
+            int t = q & 15,i;
+            if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG");
+            if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
+
+            for (i=0; i < 64; ++i)
+               z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));
+            L -= (sixteen ? 129 : 65);
+         }
+         return L==0;
+
+      case 0xC4: // DHT - define huffman table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            stbi_uc *v;
+            int sizes[16],i,n=0;
+            int q = stbi__get8(z->s);
+            int tc = q >> 4;
+            int th = q & 15;
+            if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
+            for (i=0; i < 16; ++i) {
+               sizes[i] = stbi__get8(z->s);
+               n += sizes[i];
+            }
+            L -= 17;
+            if (tc == 0) {
+               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
+               v = z->huff_dc[th].values;
+            } else {
+               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
+               v = z->huff_ac[th].values;
+            }
+            for (i=0; i < n; ++i)
+               v[i] = stbi__get8(z->s);
+            if (tc != 0)
+               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+            L -= n;
+         }
+         return L==0;
+   }
+
+   // check for comment block or APP blocks
+   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+      L = stbi__get16be(z->s);
+      if (L < 2) {
+         if (m == 0xFE)
+            return stbi__err("bad COM len","Corrupt JPEG");
+         else
+            return stbi__err("bad APP len","Corrupt JPEG");
+      }
+      L -= 2;
+
+      if (m == 0xE0 && L >= 5) { // JFIF APP0 segment
+         static const unsigned char tag[5] = {'J','F','I','F','\0'};
+         int ok = 1;
+         int i;
+         for (i=0; i < 5; ++i)
+            if (stbi__get8(z->s) != tag[i])
+               ok = 0;
+         L -= 5;
+         if (ok)
+            z->jfif = 1;
+      } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment
+         static const unsigned char tag[6] = {'A','d','o','b','e','\0'};
+         int ok = 1;
+         int i;
+         for (i=0; i < 6; ++i)
+            if (stbi__get8(z->s) != tag[i])
+               ok = 0;
+         L -= 6;
+         if (ok) {
+            stbi__get8(z->s); // version
+            stbi__get16be(z->s); // flags0
+            stbi__get16be(z->s); // flags1
+            z->app14_color_transform = stbi__get8(z->s); // color transform
+            L -= 6;
+         }
+      }
+
+      stbi__skip(z->s, L);
+      return 1;
+   }
+
+   return stbi__err("unknown marker","Corrupt JPEG");
+}
+
+// after we see SOS
+static int stbi__process_scan_header(stbi__jpeg *z)
+{
+   int i;
+   int Ls = stbi__get16be(z->s);
+   z->scan_n = stbi__get8(z->s);
+   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
+   if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
+   for (i=0; i < z->scan_n; ++i) {
+      int id = stbi__get8(z->s), which;
+      int q = stbi__get8(z->s);
+      for (which = 0; which < z->s->img_n; ++which)
+         if (z->img_comp[which].id == id)
+            break;
+      if (which == z->s->img_n) return 0; // no match
+      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
+      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
+      z->order[i] = which;
+   }
+
+   {
+      int aa;
+      z->spec_start = stbi__get8(z->s);
+      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0
+      aa = stbi__get8(z->s);
+      z->succ_high = (aa >> 4);
+      z->succ_low  = (aa & 15);
+      if (z->progressive) {
+         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
+            return stbi__err("bad SOS", "Corrupt JPEG");
+      } else {
+         if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         z->spec_end = 63;
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)
+{
+   int i;
+   for (i=0; i < ncomp; ++i) {
+      if (z->img_comp[i].raw_data) {
+         STBI_FREE(z->img_comp[i].raw_data);
+         z->img_comp[i].raw_data = NULL;
+         z->img_comp[i].data = NULL;
+      }
+      if (z->img_comp[i].raw_coeff) {
+         STBI_FREE(z->img_comp[i].raw_coeff);
+         z->img_comp[i].raw_coeff = 0;
+         z->img_comp[i].coeff = 0;
+      }
+      if (z->img_comp[i].linebuf) {
+         STBI_FREE(z->img_comp[i].linebuf);
+         z->img_comp[i].linebuf = NULL;
+      }
+   }
+   return why;
+}
+
+static int stbi__process_frame_header(stbi__jpeg *z, int scan)
+{
+   stbi__context *s = z->s;
+   int Lf,p,i,q, h_max=1,v_max=1,c;
+   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
+   p  = stbi__get8(s);            if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
+   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+   c = stbi__get8(s);
+   if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
+   s->img_n = c;
+   for (i=0; i < c; ++i) {
+      z->img_comp[i].data = NULL;
+      z->img_comp[i].linebuf = NULL;
+   }
+
+   if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
+
+   z->rgb = 0;
+   for (i=0; i < s->img_n; ++i) {
+      static const unsigned char rgb[3] = { 'R', 'G', 'B' };
+      z->img_comp[i].id = stbi__get8(s);
+      if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
+         ++z->rgb;
+      q = stbi__get8(s);
+      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
+      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
+      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
+   }
+
+   if (scan != STBI__SCAN_load) return 1;
+
+   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode");
+
+   for (i=0; i < s->img_n; ++i) {
+      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+   }
+
+   // compute interleaved mcu info
+   z->img_h_max = h_max;
+   z->img_v_max = v_max;
+   z->img_mcu_w = h_max * 8;
+   z->img_mcu_h = v_max * 8;
+   // these sizes can't be more than 17 bits
+   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+   for (i=0; i < s->img_n; ++i) {
+      // number of effective pixels (e.g. for non-interleaved MCU)
+      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+      // to simplify generation, we'll allocate enough memory to decode
+      // the bogus oversized data from using interleaved MCUs and their
+      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+      // discard the extra data until colorspace conversion
+      //
+      // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)
+      // so these muls can't overflow with 32-bit ints (which we require)
+      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+      z->img_comp[i].coeff = 0;
+      z->img_comp[i].raw_coeff = 0;
+      z->img_comp[i].linebuf = NULL;
+      z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);
+      if (z->img_comp[i].raw_data == NULL)
+         return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+      // align blocks for idct using mmx/sse
+      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+      if (z->progressive) {
+         // w2, h2 are multiples of 8 (see above)
+         z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;
+         z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;
+         z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);
+         if (z->img_comp[i].raw_coeff == NULL)
+            return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+      }
+   }
+
+   return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define stbi__DNL(x)         ((x) == 0xdc)
+#define stbi__SOI(x)         ((x) == 0xd8)
+#define stbi__EOI(x)         ((x) == 0xd9)
+#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+#define stbi__SOS(x)         ((x) == 0xda)
+
+#define stbi__SOF_progressive(x)   ((x) == 0xc2)
+
+static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
+{
+   int m;
+   z->jfif = 0;
+   z->app14_color_transform = -1; // valid values are 0,1,2
+   z->marker = STBI__MARKER_none; // initialize cached marker to empty
+   m = stbi__get_marker(z);
+   if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
+   if (scan == STBI__SCAN_type) return 1;
+   m = stbi__get_marker(z);
+   while (!stbi__SOF(m)) {
+      if (!stbi__process_marker(z,m)) return 0;
+      m = stbi__get_marker(z);
+      while (m == STBI__MARKER_none) {
+         // some files have extra padding after their blocks, so ok, we'll scan
+         if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
+         m = stbi__get_marker(z);
+      }
+   }
+   z->progressive = stbi__SOF_progressive(m);
+   if (!stbi__process_frame_header(z, scan)) return 0;
+   return 1;
+}
+
+// decode image to YCbCr format
+static int stbi__decode_jpeg_image(stbi__jpeg *j)
+{
+   int m;
+   for (m = 0; m < 4; m++) {
+      j->img_comp[m].raw_data = NULL;
+      j->img_comp[m].raw_coeff = NULL;
+   }
+   j->restart_interval = 0;
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
+   m = stbi__get_marker(j);
+   while (!stbi__EOI(m)) {
+      if (stbi__SOS(m)) {
+         if (!stbi__process_scan_header(j)) return 0;
+         if (!stbi__parse_entropy_coded_data(j)) return 0;
+         if (j->marker == STBI__MARKER_none ) {
+            // handle 0s at the end of image data from IP Kamera 9060
+            while (!stbi__at_eof(j->s)) {
+               int x = stbi__get8(j->s);
+               if (x == 255) {
+                  j->marker = stbi__get8(j->s);
+                  break;
+               }
+            }
+            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
+         }
+      } else if (stbi__DNL(m)) {
+         int Ld = stbi__get16be(j->s);
+         stbi__uint32 NL = stbi__get16be(j->s);
+         if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
+         if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
+      } else {
+         if (!stbi__process_marker(j, m)) return 0;
+      }
+      m = stbi__get_marker(j);
+   }
+   if (j->progressive)
+      stbi__jpeg_finish(j);
+   return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
+                                    int w, int hs);
+
+#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
+
+static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   STBI_NOTUSED(out);
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(w);
+   STBI_NOTUSED(hs);
+   return in_near;
+}
+
+static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples vertically for every one in input
+   int i;
+   STBI_NOTUSED(hs);
+   for (i=0; i < w; ++i)
+      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
+   return out;
+}
+
+static stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples horizontally for every one in input
+   int i;
+   stbi_uc *input = in_near;
+
+   if (w == 1) {
+      // if only one sample, can't do any interpolation
+      out[0] = out[1] = input[0];
+      return out;
+   }
+
+   out[0] = input[0];
+   out[1] = stbi__div4(input[0]*3 + input[1] + 2);
+   for (i=1; i < w-1; ++i) {
+      int n = 3*input[i]+2;
+      out[i*2+0] = stbi__div4(n+input[i-1]);
+      out[i*2+1] = stbi__div4(n+input[i+1]);
+   }
+   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
+   out[i*2+1] = input[w-1];
+
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
+
+static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i,t0,t1;
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   out[0] = stbi__div4(t1+2);
+   for (i=1; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i=0,t0,t1;
+
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   // process groups of 8 pixels for as long as we can.
+   // note we can't handle the last pixel in a row in this loop
+   // because we need to handle the filter boundary conditions.
+   for (; i < ((w-1) & ~7); i += 8) {
+#if defined(STBI_SSE2)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      __m128i zero  = _mm_setzero_si128();
+      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
+      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
+      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+      __m128i diff  = _mm_sub_epi16(farw, nearw);
+      __m128i nears = _mm_slli_epi16(nearw, 2);
+      __m128i curr  = _mm_add_epi16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      __m128i prv0 = _mm_slli_si128(curr, 2);
+      __m128i nxt0 = _mm_srli_si128(curr, 2);
+      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      __m128i bias  = _mm_set1_epi16(8);
+      __m128i curs = _mm_slli_epi16(curr, 2);
+      __m128i prvd = _mm_sub_epi16(prev, curr);
+      __m128i nxtd = _mm_sub_epi16(next, curr);
+      __m128i curb = _mm_add_epi16(curs, bias);
+      __m128i even = _mm_add_epi16(prvd, curb);
+      __m128i odd  = _mm_add_epi16(nxtd, curb);
+
+      // interleave even and odd pixels, then undo scaling.
+      __m128i int0 = _mm_unpacklo_epi16(even, odd);
+      __m128i int1 = _mm_unpackhi_epi16(even, odd);
+      __m128i de0  = _mm_srli_epi16(int0, 4);
+      __m128i de1  = _mm_srli_epi16(int1, 4);
+
+      // pack and write output
+      __m128i outv = _mm_packus_epi16(de0, de1);
+      _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(STBI_NEON)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      uint8x8_t farb  = vld1_u8(in_far + i);
+      uint8x8_t nearb = vld1_u8(in_near + i);
+      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+      int16x8_t curr  = vaddq_s16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      int16x8_t prv0 = vextq_s16(curr, curr, 7);
+      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      int16x8_t curs = vshlq_n_s16(curr, 2);
+      int16x8_t prvd = vsubq_s16(prev, curr);
+      int16x8_t nxtd = vsubq_s16(next, curr);
+      int16x8_t even = vaddq_s16(curs, prvd);
+      int16x8_t odd  = vaddq_s16(curs, nxtd);
+
+      // undo scaling and round, then store with even/odd phases interleaved
+      uint8x8x2_t o;
+      o.val[0] = vqrshrun_n_s16(even, 4);
+      o.val[1] = vqrshrun_n_s16(odd,  4);
+      vst2_u8(out + i*2, o);
+#endif
+
+      // "previous" value for next iter
+      t1 = 3*in_near[i+7] + in_far[i+7];
+   }
+
+   t0 = t1;
+   t1 = 3*in_near[i] + in_far[i];
+   out[i*2] = stbi__div16(3*t1 + t0 + 8);
+
+   for (++i; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+#endif
+
+static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // resample with nearest-neighbor
+   int i,j;
+   STBI_NOTUSED(in_far);
+   for (i=0; i < w; ++i)
+      for (j=0; j < hs; ++j)
+         out[i*hs+j] = in_near[i];
+   return out;
+}
+
+// this is a reduced-precision calculation of YCbCr-to-RGB introduced
+// to make sure the code produces the same results in both SIMD and scalar
+#define stbi__float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+   int i;
+   for (i=0; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed +  cr* stbi__float2fixed(1.40200f);
+      g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                                     +   cb* stbi__float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
+{
+   int i = 0;
+
+#ifdef STBI_SSE2
+   // step == 3 is pretty ugly on the final interleave, and i'm not convinced
+   // it's useful in practice (you wouldn't use it for textures, for example).
+   // so just accelerate step == 4 case.
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      __m128i signflip  = _mm_set1_epi8(-0x80);
+      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
+      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
+      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
+      __m128i xw = _mm_set1_epi16(255); // alpha channel
+
+      for (; i+7 < count; i += 8) {
+         // load
+         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
+         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
+
+         // unpack to short (and left-shift cr, cb by 8)
+         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
+         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+         // color transform
+         __m128i yws = _mm_srli_epi16(yw, 4);
+         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+         __m128i rws = _mm_add_epi16(cr0, yws);
+         __m128i gwt = _mm_add_epi16(cb0, yws);
+         __m128i bws = _mm_add_epi16(yws, cb1);
+         __m128i gws = _mm_add_epi16(gwt, cr1);
+
+         // descale
+         __m128i rw = _mm_srai_epi16(rws, 4);
+         __m128i bw = _mm_srai_epi16(bws, 4);
+         __m128i gw = _mm_srai_epi16(gws, 4);
+
+         // back to byte, set up for transpose
+         __m128i brb = _mm_packus_epi16(rw, bw);
+         __m128i gxb = _mm_packus_epi16(gw, xw);
+
+         // transpose to interleave channels
+         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+         __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+         // store
+         _mm_storeu_si128((__m128i *) (out + 0), o0);
+         _mm_storeu_si128((__m128i *) (out + 16), o1);
+         out += 32;
+      }
+   }
+#endif
+
+#ifdef STBI_NEON
+   // in this version, step=3 support would be easy to add. but is there demand?
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      uint8x8_t signflip = vdup_n_u8(0x80);
+      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
+      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));
+
+      for (; i+7 < count; i += 8) {
+         // load
+         uint8x8_t y_bytes  = vld1_u8(y + i);
+         uint8x8_t cr_bytes = vld1_u8(pcr + i);
+         uint8x8_t cb_bytes = vld1_u8(pcb + i);
+         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+         // expand to s16
+         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+         int16x8_t crw = vshll_n_s8(cr_biased, 7);
+         int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+         // color transform
+         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+         int16x8_t rws = vaddq_s16(yws, cr0);
+         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+         int16x8_t bws = vaddq_s16(yws, cb1);
+
+         // undo scaling, round, convert to byte
+         uint8x8x4_t o;
+         o.val[0] = vqrshrun_n_s16(rws, 4);
+         o.val[1] = vqrshrun_n_s16(gws, 4);
+         o.val[2] = vqrshrun_n_s16(bws, 4);
+         o.val[3] = vdup_n_u8(255);
+
+         // store, interleaving r/g/b/a
+         vst4_u8(out, o);
+         out += 8*4;
+      }
+   }
+#endif
+
+   for (; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed + cr* stbi__float2fixed(1.40200f);
+      g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                                   +   cb* stbi__float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#endif
+
+// set up the kernels
+static void stbi__setup_jpeg(stbi__jpeg *j)
+{
+   j->idct_block_kernel = stbi__idct_block;
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
+
+#ifdef STBI_SSE2
+   if (stbi__sse2_available()) {
+      j->idct_block_kernel = stbi__idct_simd;
+      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+   }
+#endif
+
+#ifdef STBI_NEON
+   j->idct_block_kernel = stbi__idct_simd;
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+#endif
+}
+
+// clean up the temporary component buffers
+static void stbi__cleanup_jpeg(stbi__jpeg *j)
+{
+   stbi__free_jpeg_components(j, j->s->img_n, 0);
+}
+
+typedef struct
+{
+   resample_row_func resample;
+   stbi_uc *line0,*line1;
+   int hs,vs;   // expansion factor in each axis
+   int w_lores; // horizontal pixels pre-expansion
+   int ystep;   // how far through vertical expansion we are
+   int ypos;    // which pre-expansion row we're on
+} stbi__resample;
+
+// fast 0..255 * 0..255 => 0..255 rounded multiplication
+static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)
+{
+   unsigned int t = x*y + 128;
+   return (stbi_uc) ((t + (t >>8)) >> 8);
+}
+
+static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+   int n, decode_n, is_rgb;
+   z->s->img_n = 0; // make stbi__cleanup_jpeg safe
+
+   // validate req_comp
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+
+   // load a jpeg image from whichever source, but leave in YCbCr format
+   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
+
+   // determine actual number of components to generate
+   n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;
+
+   is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));
+
+   if (z->s->img_n == 3 && n < 3 && !is_rgb)
+      decode_n = 1;
+   else
+      decode_n = z->s->img_n;
+
+   // resample and color-convert
+   {
+      int k;
+      unsigned int i,j;
+      stbi_uc *output;
+      stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };
+
+      stbi__resample res_comp[4];
+
+      for (k=0; k < decode_n; ++k) {
+         stbi__resample *r = &res_comp[k];
+
+         // allocate line buffer big enough for upsampling off the edges
+         // with upsample factor of 4
+         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
+         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+         r->hs      = z->img_h_max / z->img_comp[k].h;
+         r->vs      = z->img_v_max / z->img_comp[k].v;
+         r->ystep   = r->vs >> 1;
+         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+         r->ypos    = 0;
+         r->line0   = r->line1 = z->img_comp[k].data;
+
+         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
+         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
+         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
+         else                               r->resample = stbi__resample_row_generic;
+      }
+
+      // can't error after this so, this is safe
+      output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);
+      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+      // now go ahead and resample
+      for (j=0; j < z->s->img_y; ++j) {
+         stbi_uc *out = output + n * z->s->img_x * j;
+         for (k=0; k < decode_n; ++k) {
+            stbi__resample *r = &res_comp[k];
+            int y_bot = r->ystep >= (r->vs >> 1);
+            coutput[k] = r->resample(z->img_comp[k].linebuf,
+                                     y_bot ? r->line1 : r->line0,
+                                     y_bot ? r->line0 : r->line1,
+                                     r->w_lores, r->hs);
+            if (++r->ystep >= r->vs) {
+               r->ystep = 0;
+               r->line0 = r->line1;
+               if (++r->ypos < z->img_comp[k].y)
+                  r->line1 += z->img_comp[k].w2;
+            }
+         }
+         if (n >= 3) {
+            stbi_uc *y = coutput[0];
+            if (z->s->img_n == 3) {
+               if (is_rgb) {
+                  for (i=0; i < z->s->img_x; ++i) {
+                     out[0] = y[i];
+                     out[1] = coutput[1][i];
+                     out[2] = coutput[2][i];
+                     out[3] = 255;
+                     out += n;
+                  }
+               } else {
+                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+               }
+            } else if (z->s->img_n == 4) {
+               if (z->app14_color_transform == 0) { // CMYK
+                  for (i=0; i < z->s->img_x; ++i) {
+                     stbi_uc m = coutput[3][i];
+                     out[0] = stbi__blinn_8x8(coutput[0][i], m);
+                     out[1] = stbi__blinn_8x8(coutput[1][i], m);
+                     out[2] = stbi__blinn_8x8(coutput[2][i], m);
+                     out[3] = 255;
+                     out += n;
+                  }
+               } else if (z->app14_color_transform == 2) { // YCCK
+                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+                  for (i=0; i < z->s->img_x; ++i) {
+                     stbi_uc m = coutput[3][i];
+                     out[0] = stbi__blinn_8x8(255 - out[0], m);
+                     out[1] = stbi__blinn_8x8(255 - out[1], m);
+                     out[2] = stbi__blinn_8x8(255 - out[2], m);
+                     out += n;
+                  }
+               } else { // YCbCr + alpha?  Ignore the fourth channel for now
+                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+               }
+            } else
+               for (i=0; i < z->s->img_x; ++i) {
+                  out[0] = out[1] = out[2] = y[i];
+                  out[3] = 255; // not used if n==3
+                  out += n;
+               }
+         } else {
+            if (is_rgb) {
+               if (n == 1)
+                  for (i=0; i < z->s->img_x; ++i)
+                     *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+               else {
+                  for (i=0; i < z->s->img_x; ++i, out += 2) {
+                     out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+                     out[1] = 255;
+                  }
+               }
+            } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
+               for (i=0; i < z->s->img_x; ++i) {
+                  stbi_uc m = coutput[3][i];
+                  stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);
+                  stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);
+                  stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);
+                  out[0] = stbi__compute_y(r, g, b);
+                  out[1] = 255;
+                  out += n;
+               }
+            } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {
+               for (i=0; i < z->s->img_x; ++i) {
+                  out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);
+                  out[1] = 255;
+                  out += n;
+               }
+            } else {
+               stbi_uc *y = coutput[0];
+               if (n == 1)
+                  for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+               else
+                  for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }
+            }
+         }
+      }
+      stbi__cleanup_jpeg(z);
+      *out_x = z->s->img_x;
+      *out_y = z->s->img_y;
+      if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output
+      return output;
+   }
+}
+
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   unsigned char* result;
+   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
+   STBI_NOTUSED(ri);
+   j->s = s;
+   stbi__setup_jpeg(j);
+   result = load_jpeg_image(j, x,y,comp,req_comp);
+   STBI_FREE(j);
+   return result;
+}
+
+static int stbi__jpeg_test(stbi__context *s)
+{
+   int r;
+   stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
+   j->s = s;
+   stbi__setup_jpeg(j);
+   r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
+   stbi__rewind(s);
+   STBI_FREE(j);
+   return r;
+}
+
+static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
+{
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
+      stbi__rewind( j->s );
+      return 0;
+   }
+   if (x) *x = j->s->img_x;
+   if (y) *y = j->s->img_y;
+   if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;
+   return 1;
+}
+
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int result;
+   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
+   j->s = s;
+   result = stbi__jpeg_info_raw(j, x, y, comp);
+   STBI_FREE(j);
+   return result;
+}
+#endif
+
+// public domain zlib decode    v0.2  Sean Barrett 2006-11-18
+//    simple implementation
+//      - all input must be provided in an upfront buffer
+//      - all output is written to a single output buffer (can malloc/realloc)
+//    performance
+//      - fast huffman
+
+#ifndef STBI_NO_ZLIB
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables
+#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+   stbi__uint16 fast[1 << STBI__ZFAST_BITS];
+   stbi__uint16 firstcode[16];
+   int maxcode[17];
+   stbi__uint16 firstsymbol[16];
+   stbi_uc  size[288];
+   stbi__uint16 value[288];
+} stbi__zhuffman;
+
+stbi_inline static int stbi__bitreverse16(int n)
+{
+  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);
+  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);
+  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);
+  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);
+  return n;
+}
+
+stbi_inline static int stbi__bit_reverse(int v, int bits)
+{
+   STBI_ASSERT(bits <= 16);
+   // to bit reverse n bits, reverse 16 and shift
+   // e.g. 11 bits, bit reverse and shift away 5
+   return stbi__bitreverse16(v) >> (16-bits);
+}
+
+static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)
+{
+   int i,k=0;
+   int code, next_code[16], sizes[17];
+
+   // DEFLATE spec for generating codes
+   memset(sizes, 0, sizeof(sizes));
+   memset(z->fast, 0, sizeof(z->fast));
+   for (i=0; i < num; ++i)
+      ++sizes[sizelist[i]];
+   sizes[0] = 0;
+   for (i=1; i < 16; ++i)
+      if (sizes[i] > (1 << i))
+         return stbi__err("bad sizes", "Corrupt PNG");
+   code = 0;
+   for (i=1; i < 16; ++i) {
+      next_code[i] = code;
+      z->firstcode[i] = (stbi__uint16) code;
+      z->firstsymbol[i] = (stbi__uint16) k;
+      code = (code + sizes[i]);
+      if (sizes[i])
+         if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
+      z->maxcode[i] = code << (16-i); // preshift for inner loop
+      code <<= 1;
+      k += sizes[i];
+   }
+   z->maxcode[16] = 0x10000; // sentinel
+   for (i=0; i < num; ++i) {
+      int s = sizelist[i];
+      if (s) {
+         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
+         z->size [c] = (stbi_uc     ) s;
+         z->value[c] = (stbi__uint16) i;
+         if (s <= STBI__ZFAST_BITS) {
+            int j = stbi__bit_reverse(next_code[s],s);
+            while (j < (1 << STBI__ZFAST_BITS)) {
+               z->fast[j] = fastv;
+               j += (1 << s);
+            }
+         }
+         ++next_code[s];
+      }
+   }
+   return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+//    because PNG allows splitting the zlib stream arbitrarily,
+//    and it's annoying structurally to have PNG call ZLIB call PNG,
+//    we require PNG read all the IDATs and combine them into a single
+//    memory buffer
+
+typedef struct
+{
+   stbi_uc *zbuffer, *zbuffer_end;
+   int num_bits;
+   stbi__uint32 code_buffer;
+
+   char *zout;
+   char *zout_start;
+   char *zout_end;
+   int   z_expandable;
+
+   stbi__zhuffman z_length, z_distance;
+} stbi__zbuf;
+
+stbi_inline static int stbi__zeof(stbi__zbuf *z)
+{
+   return (z->zbuffer >= z->zbuffer_end);
+}
+
+stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+{
+   return stbi__zeof(z) ? 0 : *z->zbuffer++;
+}
+
+static void stbi__fill_bits(stbi__zbuf *z)
+{
+   do {
+      if (z->code_buffer >= (1U << z->num_bits)) {
+        z->zbuffer = z->zbuffer_end;  /* treat this as EOF so we fail. */
+        return;
+      }
+      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
+      z->num_bits += 8;
+   } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+{
+   unsigned int k;
+   if (z->num_bits < n) stbi__fill_bits(z);
+   k = z->code_buffer & ((1 << n) - 1);
+   z->code_buffer >>= n;
+   z->num_bits -= n;
+   return k;
+}
+
+static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s,k;
+   // not resolved by fast table, so compute it the slow way
+   // use jpeg approach, which requires MSbits at top
+   k = stbi__bit_reverse(a->code_buffer, 16);
+   for (s=STBI__ZFAST_BITS+1; ; ++s)
+      if (k < z->maxcode[s])
+         break;
+   if (s >= 16) return -1; // invalid code!
+   // code size is s, so:
+   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+   if ((long unsigned int) b >= sizeof (z->size)) return -1; // some data was corrupt somewhere!
+   if (z->size[b] != s) return -1;  // was originally an assert, but report failure instead.
+   a->code_buffer >>= s;
+   a->num_bits -= s;
+   return z->value[b];
+}
+
+stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s;
+   if (a->num_bits < 16) {
+      if (stbi__zeof(a)) {
+         return -1;   /* report error for unexpected end of data. */
+      }
+      stbi__fill_bits(a);
+   }
+   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
+   if (b) {
+      s = b >> 9;
+      a->code_buffer >>= s;
+      a->num_bits -= s;
+      return b & 511;
+   }
+   return stbi__zhuffman_decode_slowpath(a, z);
+}
+
+static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes
+{
+   char *q;
+   unsigned int cur, limit, old_limit;
+   z->zout = zout;
+   if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+   cur   = (unsigned int) (z->zout - z->zout_start);
+   limit = old_limit = (unsigned) (z->zout_end - z->zout_start);
+   if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory");
+   while (cur + n > limit) {
+      if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory");
+      limit *= 2;
+   }
+   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
+   STBI_NOTUSED(old_limit);
+   if (q == NULL) return stbi__err("outofmem", "Out of memory");
+   z->zout_start = q;
+   z->zout       = q + cur;
+   z->zout_end   = q + limit;
+   return 1;
+}
+
+static const int stbi__zlength_base[31] = {
+   3,4,5,6,7,8,9,10,11,13,
+   15,17,19,23,27,31,35,43,51,59,
+   67,83,99,115,131,163,195,227,258,0,0 };
+
+static const int stbi__zlength_extra[31]=
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static const int stbi__zdist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int stbi__parse_huffman_block(stbi__zbuf *a)
+{
+   char *zout = a->zout;
+   for(;;) {
+      int z = stbi__zhuffman_decode(a, &a->z_length);
+      if (z < 256) {
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
+         if (zout >= a->zout_end) {
+            if (!stbi__zexpand(a, zout, 1)) return 0;
+            zout = a->zout;
+         }
+         *zout++ = (char) z;
+      } else {
+         stbi_uc *p;
+         int len,dist;
+         if (z == 256) {
+            a->zout = zout;
+            return 1;
+         }
+         z -= 257;
+         len = stbi__zlength_base[z];
+         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
+         z = stbi__zhuffman_decode(a, &a->z_distance);
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
+         dist = stbi__zdist_base[z];
+         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
+         if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+         if (zout + len > a->zout_end) {
+            if (!stbi__zexpand(a, zout, len)) return 0;
+            zout = a->zout;
+         }
+         p = (stbi_uc *) (zout - dist);
+         if (dist == 1) { // run of one byte; common in images.
+            stbi_uc v = *p;
+            if (len) { do *zout++ = v; while (--len); }
+         } else {
+            if (len) { do *zout++ = *p++; while (--len); }
+         }
+      }
+   }
+}
+
+static int stbi__compute_huffman_codes(stbi__zbuf *a)
+{
+   static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+   stbi__zhuffman z_codelength;
+   stbi_uc lencodes[286+32+137];//padding for maximum single op
+   stbi_uc codelength_sizes[19];
+   int i,n;
+
+   int hlit  = stbi__zreceive(a,5) + 257;
+   int hdist = stbi__zreceive(a,5) + 1;
+   int hclen = stbi__zreceive(a,4) + 4;
+   int ntot  = hlit + hdist;
+
+   memset(codelength_sizes, 0, sizeof(codelength_sizes));
+   for (i=0; i < hclen; ++i) {
+      int s = stbi__zreceive(a,3);
+      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+   }
+   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+   n = 0;
+   while (n < ntot) {
+      int c = stbi__zhuffman_decode(a, &z_codelength);
+      if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
+      if (c < 16)
+         lencodes[n++] = (stbi_uc) c;
+      else {
+         stbi_uc fill = 0;
+         if (c == 16) {
+            c = stbi__zreceive(a,2)+3;
+            if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
+            fill = lencodes[n-1];
+         } else if (c == 17) {
+            c = stbi__zreceive(a,3)+3;
+         } else if (c == 18) {
+            c = stbi__zreceive(a,7)+11;
+         } else {
+            return stbi__err("bad codelengths", "Corrupt PNG");
+         }
+         if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
+         memset(lencodes+n, fill, c);
+         n += c;
+      }
+   }
+   if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
+   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+   return 1;
+}
+
+static int stbi__parse_uncompressed_block(stbi__zbuf *a)
+{
+   stbi_uc header[4];
+   int len,nlen,k;
+   if (a->num_bits & 7)
+      stbi__zreceive(a, a->num_bits & 7); // discard
+   // drain the bit-packed data into header
+   k = 0;
+   while (a->num_bits > 0) {
+      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
+      a->code_buffer >>= 8;
+      a->num_bits -= 8;
+   }
+   if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG");
+   // now fill header the normal way
+   while (k < 4)
+      header[k++] = stbi__zget8(a);
+   len  = header[1] * 256 + header[0];
+   nlen = header[3] * 256 + header[2];
+   if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
+   if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+   if (a->zout + len > a->zout_end)
+      if (!stbi__zexpand(a, a->zout, len)) return 0;
+   memcpy(a->zout, a->zbuffer, len);
+   a->zbuffer += len;
+   a->zout += len;
+   return 1;
+}
+
+static int stbi__parse_zlib_header(stbi__zbuf *a)
+{
+   int cmf   = stbi__zget8(a);
+   int cm    = cmf & 15;
+   /* int cinfo = cmf >> 4; */
+   int flg   = stbi__zget8(a);
+   if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+   if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+   if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+   if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
+   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+   return 1;
+}
+
+static const stbi_uc stbi__zdefault_length[288] =
+{
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8
+};
+static const stbi_uc stbi__zdefault_distance[32] =
+{
+   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
+};
+/*
+Init algorithm:
+{
+   int i;   // use <= to match clearly with spec
+   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;
+   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;
+   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;
+   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;
+
+   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;
+}
+*/
+
+static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+{
+   int final, type;
+   if (parse_header)
+      if (!stbi__parse_zlib_header(a)) return 0;
+   a->num_bits = 0;
+   a->code_buffer = 0;
+   do {
+      final = stbi__zreceive(a,1);
+      type = stbi__zreceive(a,2);
+      if (type == 0) {
+         if (!stbi__parse_uncompressed_block(a)) return 0;
+      } else if (type == 3) {
+         return 0;
+      } else {
+         if (type == 1) {
+            // use fixed code lengths
+            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , 288)) return 0;
+            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;
+         } else {
+            if (!stbi__compute_huffman_codes(a)) return 0;
+         }
+         if (!stbi__parse_huffman_block(a)) return 0;
+      }
+   } while (!final);
+   return 1;
+}
+
+static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+   a->zout_start = obuf;
+   a->zout       = obuf;
+   a->zout_end   = obuf + olen;
+   a->z_expandable = exp;
+
+   return stbi__parse_zlib(a, parse_header);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(16384);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer+len;
+   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+#endif
+
+// public domain "baseline" PNG decoder   v0.10  Sean Barrett 2006-11-18
+//    simple implementation
+//      - only 8-bit samples
+//      - no CRC checking
+//      - allocates lots of intermediate memory
+//        - avoids problem of streaming data between subsystems
+//        - avoids explicit window management
+//    performance
+//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+#ifndef STBI_NO_PNG
+typedef struct
+{
+   stbi__uint32 length;
+   stbi__uint32 type;
+} stbi__pngchunk;
+
+static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+{
+   stbi__pngchunk c;
+   c.length = stbi__get32be(s);
+   c.type   = stbi__get32be(s);
+   return c;
+}
+
+static int stbi__check_png_header(stbi__context *s)
+{
+   static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+   int i;
+   for (i=0; i < 8; ++i)
+      if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+   return 1;
+}
+
+typedef struct
+{
+   stbi__context *s;
+   stbi_uc *idata, *expanded, *out;
+   int depth;
+} stbi__png;
+
+
+enum {
+   STBI__F_none=0,
+   STBI__F_sub=1,
+   STBI__F_up=2,
+   STBI__F_avg=3,
+   STBI__F_paeth=4,
+   // synthetic filters used for first scanline to avoid needing a dummy row of 0s
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static stbi_uc first_row_filter[5] =
+{
+   STBI__F_none,
+   STBI__F_sub,
+   STBI__F_none,
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static int stbi__paeth(int a, int b, int c)
+{
+   int p = a + b - c;
+   int pa = abs(p-a);
+   int pb = abs(p-b);
+   int pc = abs(p-c);
+   if (pa <= pb && pa <= pc) return a;
+   if (pb <= pc) return b;
+   return c;
+}
+
+static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+
+// create the png data from post-deflated data
+static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+{
+   int bytes = (depth == 16? 2 : 1);
+   stbi__context *s = a->s;
+   stbi__uint32 i,j,stride = x*out_n*bytes;
+   stbi__uint32 img_len, img_width_bytes;
+   int k;
+   int img_n = s->img_n; // copy it into a local for later
+
+   int output_bytes = out_n*bytes;
+   int filter_bytes = img_n*bytes;
+   int width = x;
+
+   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
+   a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
+   if (!a->out) return stbi__err("outofmem", "Out of memory");
+
+   if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
+   img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+   img_len = (img_width_bytes + 1) * y;
+
+   // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
+   // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
+   // so just check for raw_len < img_len always.
+   if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+
+   for (j=0; j < y; ++j) {
+      stbi_uc *cur = a->out + stride*j;
+      stbi_uc *prior;
+      int filter = *raw++;
+
+      if (filter > 4)
+         return stbi__err("invalid filter","Corrupt PNG");
+
+      if (depth < 8) {
+         if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
+         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
+         filter_bytes = 1;
+         width = img_width_bytes;
+      }
+      prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
+
+      // if first row, use special filter that doesn't sample previous row
+      if (j == 0) filter = first_row_filter[filter];
+
+      // handle first byte explicitly
+      for (k=0; k < filter_bytes; ++k) {
+         switch (filter) {
+            case STBI__F_none       : cur[k] = raw[k]; break;
+            case STBI__F_sub        : cur[k] = raw[k]; break;
+            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
+            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
+            case STBI__F_avg_first  : cur[k] = raw[k]; break;
+            case STBI__F_paeth_first: cur[k] = raw[k]; break;
+         }
+      }
+
+      if (depth == 8) {
+         if (img_n != out_n)
+            cur[img_n] = 255; // first pixel
+         raw += img_n;
+         cur += out_n;
+         prior += out_n;
+      } else if (depth == 16) {
+         if (img_n != out_n) {
+            cur[filter_bytes]   = 255; // first pixel top byte
+            cur[filter_bytes+1] = 255; // first pixel bottom byte
+         }
+         raw += filter_bytes;
+         cur += output_bytes;
+         prior += output_bytes;
+      } else {
+         raw += 1;
+         cur += 1;
+         prior += 1;
+      }
+
+      // this is a little gross, so that we don't switch per-pixel or per-component
+      if (depth < 8 || img_n == out_n) {
+         int nk = (width - 1)*filter_bytes;
+         #define STBI__CASE(f) \
+             case f:     \
+                for (k=0; k < nk; ++k)
+         switch (filter) {
+            // "none" filter turns into a memcpy here; make that explicit.
+            case STBI__F_none:         memcpy(cur, raw, nk); break;
+            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
+            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
+            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
+            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
+            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
+         }
+         #undef STBI__CASE
+         raw += nk;
+      } else {
+         STBI_ASSERT(img_n+1 == out_n);
+         #define STBI__CASE(f) \
+             case f:     \
+                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
+                   for (k=0; k < filter_bytes; ++k)
+         switch (filter) {
+            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;
+            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
+            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
+            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
+            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
+            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
+         }
+         #undef STBI__CASE
+
+         // the loop above sets the high byte of the pixels' alpha, but for
+         // 16 bit png files we also need the low byte set. we'll do that here.
+         if (depth == 16) {
+            cur = a->out + stride*j; // start at the beginning of the row again
+            for (i=0; i < x; ++i,cur+=output_bytes) {
+               cur[filter_bytes+1] = 255;
+            }
+         }
+      }
+   }
+
+   // we make a separate pass to expand bits to pixels; for performance,
+   // this could run two scanlines behind the above code, so it won't
+   // intefere with filtering but will still be in the cache.
+   if (depth < 8) {
+      for (j=0; j < y; ++j) {
+         stbi_uc *cur = a->out + stride*j;
+         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;
+         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
+         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
+         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+
+         // note that the final byte might overshoot and write more data than desired.
+         // we can allocate enough data that this never writes out of memory, but it
+         // could also overwrite the next scanline. can it overwrite non-empty data
+         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
+         // so we need to explicitly clamp the final ones
+
+         if (depth == 4) {
+            for (k=x*img_n; k >= 2; k-=2, ++in) {
+               *cur++ = scale * ((*in >> 4)       );
+               *cur++ = scale * ((*in     ) & 0x0f);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 4)       );
+         } else if (depth == 2) {
+            for (k=x*img_n; k >= 4; k-=4, ++in) {
+               *cur++ = scale * ((*in >> 6)       );
+               *cur++ = scale * ((*in >> 4) & 0x03);
+               *cur++ = scale * ((*in >> 2) & 0x03);
+               *cur++ = scale * ((*in     ) & 0x03);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 6)       );
+            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
+            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
+         } else if (depth == 1) {
+            for (k=x*img_n; k >= 8; k-=8, ++in) {
+               *cur++ = scale * ((*in >> 7)       );
+               *cur++ = scale * ((*in >> 6) & 0x01);
+               *cur++ = scale * ((*in >> 5) & 0x01);
+               *cur++ = scale * ((*in >> 4) & 0x01);
+               *cur++ = scale * ((*in >> 3) & 0x01);
+               *cur++ = scale * ((*in >> 2) & 0x01);
+               *cur++ = scale * ((*in >> 1) & 0x01);
+               *cur++ = scale * ((*in     ) & 0x01);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 7)       );
+            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
+            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
+            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
+            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
+            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
+            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
+         }
+         if (img_n != out_n) {
+            int q;
+            // insert alpha = 255
+            cur = a->out + stride*j;
+            if (img_n == 1) {
+               for (q=x-1; q >= 0; --q) {
+                  cur[q*2+1] = 255;
+                  cur[q*2+0] = cur[q];
+               }
+            } else {
+               STBI_ASSERT(img_n == 3);
+               for (q=x-1; q >= 0; --q) {
+                  cur[q*4+3] = 255;
+                  cur[q*4+2] = cur[q*3+2];
+                  cur[q*4+1] = cur[q*3+1];
+                  cur[q*4+0] = cur[q*3+0];
+               }
+            }
+         }
+      }
+   } else if (depth == 16) {
+      // force the image data from big-endian to platform-native.
+      // this is done in a separate pass due to the decoding relying
+      // on the data being untouched, but could probably be done
+      // per-line during decode if care is taken.
+      stbi_uc *cur = a->out;
+      stbi__uint16 *cur16 = (stbi__uint16*)cur;
+
+      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
+         *cur16 = (cur[0] << 8) | cur[1];
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+{
+   int bytes = (depth == 16 ? 2 : 1);
+   int out_bytes = out_n * bytes;
+   stbi_uc *final;
+   int p;
+   if (!interlaced)
+      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+
+   // de-interlacing
+   final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
+   for (p=0; p < 7; ++p) {
+      int xorig[] = { 0,4,0,2,0,1,0 };
+      int yorig[] = { 0,0,4,0,2,0,1 };
+      int xspc[]  = { 8,8,4,4,2,2,1 };
+      int yspc[]  = { 8,8,8,4,4,2,2 };
+      int i,j,x,y;
+      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+      if (x && y) {
+         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+            STBI_FREE(final);
+            return 0;
+         }
+         for (j=0; j < y; ++j) {
+            for (i=0; i < x; ++i) {
+               int out_y = j*yspc[p]+yorig[p];
+               int out_x = i*xspc[p]+xorig[p];
+               memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
+                      a->out + (j*x+i)*out_bytes, out_bytes);
+            }
+         }
+         STBI_FREE(a->out);
+         image_data += img_len;
+         image_data_len -= img_len;
+      }
+   }
+   a->out = final;
+
+   return 1;
+}
+
+static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 255 as the alpha value in the output
+   STBI_ASSERT(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i=0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 255);
+         p += 2;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi__uint16 *p = (stbi__uint16*) z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 65535 as the alpha value in the output
+   STBI_ASSERT(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i = 0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 65535);
+         p += 2;
+      }
+   } else {
+      for (i = 0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+{
+   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+   stbi_uc *p, *temp_out, *orig = a->out;
+
+   p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
+   if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+   // between here and free(out) below, exitting would leak
+   temp_out = p;
+
+   if (pal_img_n == 3) {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p += 3;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p[3] = palette[n+3];
+         p += 4;
+      }
+   }
+   STBI_FREE(a->out);
+   a->out = temp_out;
+
+   STBI_NOTUSED(len);
+
+   return 1;
+}
+
+static int stbi__unpremultiply_on_load = 0;
+static int stbi__de_iphone_flag = 0;
+
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+   stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+   stbi__de_iphone_flag = flag_true_if_should_convert;
+}
+
+static void stbi__de_iphone(stbi__png *z)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   if (s->img_out_n == 3) {  // convert bgr to rgb
+      for (i=0; i < pixel_count; ++i) {
+         stbi_uc t = p[0];
+         p[0] = p[2];
+         p[2] = t;
+         p += 3;
+      }
+   } else {
+      STBI_ASSERT(s->img_out_n == 4);
+      if (stbi__unpremultiply_on_load) {
+         // convert bgr to rgb and unpremultiply
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc a = p[3];
+            stbi_uc t = p[0];
+            if (a) {
+               stbi_uc half = a / 2;
+               p[0] = (p[2] * 255 + half) / a;
+               p[1] = (p[1] * 255 + half) / a;
+               p[2] = ( t   * 255 + half) / a;
+            } else {
+               p[0] = p[2];
+               p[2] = t;
+            }
+            p += 4;
+         }
+      } else {
+         // convert bgr to rgb
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc t = p[0];
+            p[0] = p[2];
+            p[2] = t;
+            p += 4;
+         }
+      }
+   }
+}
+
+#define STBI__PNG_TYPE(a,b,c,d)  (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
+
+static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
+{
+   stbi_uc palette[1024], pal_img_n=0;
+   stbi_uc has_trans=0, tc[3]={0};
+   stbi__uint16 tc16[3];
+   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+   int first=1,k,interlace=0, color=0, is_iphone=0;
+   stbi__context *s = z->s;
+
+   z->expanded = NULL;
+   z->idata = NULL;
+   z->out = NULL;
+
+   if (!stbi__check_png_header(s)) return 0;
+
+   if (scan == STBI__SCAN_type) return 1;
+
+   for (;;) {
+      stbi__pngchunk c = stbi__get_chunk_header(s);
+      switch (c.type) {
+         case STBI__PNG_TYPE('C','g','B','I'):
+            is_iphone = 1;
+            stbi__skip(s, c.length);
+            break;
+         case STBI__PNG_TYPE('I','H','D','R'): {
+            int comp,filter;
+            if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+            first = 0;
+            if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
+            s->img_x = stbi__get32be(s);
+            s->img_y = stbi__get32be(s);
+            if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+            if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
+            color = stbi__get8(s);  if (color > 6)         return stbi__err("bad ctype","Corrupt PNG");
+            if (color == 3 && z->depth == 16)                  return stbi__err("bad ctype","Corrupt PNG");
+            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
+            comp  = stbi__get8(s);  if (comp) return stbi__err("bad comp method","Corrupt PNG");
+            filter= stbi__get8(s);  if (filter) return stbi__err("bad filter method","Corrupt PNG");
+            interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
+            if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+            if (!pal_img_n) {
+               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+               if (scan == STBI__SCAN_header) return 1;
+            } else {
+               // if paletted, then pal_n is our final components, and
+               // img_n is # components to decompress/filter.
+               s->img_n = 1;
+               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+               // if SCAN_header, have to scan to see if we have a tRNS
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('P','L','T','E'):  {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+            pal_len = c.length / 3;
+            if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+            for (i=0; i < pal_len; ++i) {
+               palette[i*4+0] = stbi__get8(s);
+               palette[i*4+1] = stbi__get8(s);
+               palette[i*4+2] = stbi__get8(s);
+               palette[i*4+3] = 255;
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('t','R','N','S'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+            if (pal_img_n) {
+               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
+               if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
+               if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+               pal_img_n = 4;
+               for (i=0; i < c.length; ++i)
+                  palette[i*4+3] = stbi__get8(s);
+            } else {
+               if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
+               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+               has_trans = 1;
+               if (z->depth == 16) {
+                  for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
+               } else {
+                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
+               }
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','D','A','T'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
+            if ((int)(ioff + c.length) < (int)ioff) return 0;
+            if (ioff + c.length > idata_limit) {
+               stbi__uint32 idata_limit_old = idata_limit;
+               stbi_uc *p;
+               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+               while (ioff + c.length > idata_limit)
+                  idata_limit *= 2;
+               STBI_NOTUSED(idata_limit_old);
+               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+               z->idata = p;
+            }
+            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+            ioff += c.length;
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','E','N','D'): {
+            stbi__uint32 raw_len, bpl;
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (scan != STBI__SCAN_load) return 1;
+            if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+            // initial guess for decoded data size to avoid unnecessary reallocs
+            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component
+            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
+            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+            if (z->expanded == NULL) return 0; // zlib should set error
+            STBI_FREE(z->idata); z->idata = NULL;
+            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+               s->img_out_n = s->img_n+1;
+            else
+               s->img_out_n = s->img_n;
+            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
+            if (has_trans) {
+               if (z->depth == 16) {
+                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
+               } else {
+                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+               }
+            }
+            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
+               stbi__de_iphone(z);
+            if (pal_img_n) {
+               // pal_img_n == 3 or 4
+               s->img_n = pal_img_n; // record the actual colors we had
+               s->img_out_n = pal_img_n;
+               if (req_comp >= 3) s->img_out_n = req_comp;
+               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+                  return 0;
+            } else if (has_trans) {
+               // non-paletted image with tRNS -> source image has (constant) alpha
+               ++s->img_n;
+            }
+            STBI_FREE(z->expanded); z->expanded = NULL;
+            // end of PNG chunk, read and skip CRC
+            stbi__get32be(s);
+            return 1;
+         }
+
+         default:
+            // if critical, fail
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if ((c.type & (1 << 29)) == 0) {
+               #ifndef STBI_NO_FAILURE_STRINGS
+               // not threadsafe
+               static char invalid_chunk[] = "XXXX PNG chunk not known";
+               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
+               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
+               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);
+               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);
+               #endif
+               return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
+            }
+            stbi__skip(s, c.length);
+            break;
+      }
+      // end of PNG chunk, read and skip CRC
+      stbi__get32be(s);
+   }
+}
+
+static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
+{
+   void *result=NULL;
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+      if (p->depth <= 8)
+         ri->bits_per_channel = 8;
+      else if (p->depth == 16)
+         ri->bits_per_channel = 16;
+      else
+         return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth");
+      result = p->out;
+      p->out = NULL;
+      if (req_comp && req_comp != p->s->img_out_n) {
+         if (ri->bits_per_channel == 8)
+            result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+         else
+            result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+         p->s->img_out_n = req_comp;
+         if (result == NULL) return result;
+      }
+      *x = p->s->img_x;
+      *y = p->s->img_y;
+      if (n) *n = p->s->img_n;
+   }
+   STBI_FREE(p->out);      p->out      = NULL;
+   STBI_FREE(p->expanded); p->expanded = NULL;
+   STBI_FREE(p->idata);    p->idata    = NULL;
+
+   return result;
+}
+
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__do_png(&p, x,y,comp,req_comp, ri);
+}
+
+static int stbi__png_test(stbi__context *s)
+{
+   int r;
+   r = stbi__check_png_header(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
+{
+   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
+      stbi__rewind( p->s );
+      return 0;
+   }
+   if (x) *x = p->s->img_x;
+   if (y) *y = p->s->img_y;
+   if (comp) *comp = p->s->img_n;
+   return 1;
+}
+
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__png_info_raw(&p, x, y, comp);
+}
+
+static int stbi__png_is16(stbi__context *s)
+{
+   stbi__png p;
+   p.s = s;
+   if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
+	   return 0;
+   if (p.depth != 16) {
+      stbi__rewind(p.s);
+      return 0;
+   }
+   return 1;
+}
+#endif
+
+// Microsoft/Windows BMP image
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test_raw(stbi__context *s)
+{
+   int r;
+   int sz;
+   if (stbi__get8(s) != 'B') return 0;
+   if (stbi__get8(s) != 'M') return 0;
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   stbi__get32le(s); // discard data offset
+   sz = stbi__get32le(s);
+   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
+   return r;
+}
+
+static int stbi__bmp_test(stbi__context *s)
+{
+   int r = stbi__bmp_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int stbi__high_bit(unsigned int z)
+{
+   int n=0;
+   if (z == 0) return -1;
+   if (z >= 0x10000) { n += 16; z >>= 16; }
+   if (z >= 0x00100) { n +=  8; z >>=  8; }
+   if (z >= 0x00010) { n +=  4; z >>=  4; }
+   if (z >= 0x00004) { n +=  2; z >>=  2; }
+   if (z >= 0x00002) { n +=  1;/* >>=  1;*/ }
+   return n;
+}
+
+static int stbi__bitcount(unsigned int a)
+{
+   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2
+   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4
+   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+   a = (a + (a >> 8)); // max 16 per 8 bits
+   a = (a + (a >> 16)); // max 32 per 8 bits
+   return a & 0xff;
+}
+
+// extract an arbitrarily-aligned N-bit value (N=bits)
+// from v, and then make it 8-bits long and fractionally
+// extend it to full full range.
+static int stbi__shiftsigned(unsigned int v, int shift, int bits)
+{
+   static unsigned int mul_table[9] = {
+      0,
+      0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
+      0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
+   };
+   static unsigned int shift_table[9] = {
+      0, 0,0,1,0,2,4,6,0,
+   };
+   if (shift < 0)
+      v <<= -shift;
+   else
+      v >>= shift;
+   STBI_ASSERT(v < 256);
+   v >>= (8-bits);
+   STBI_ASSERT(bits >= 0 && bits <= 8);
+   return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
+}
+
+typedef struct
+{
+   int bpp, offset, hsz;
+   unsigned int mr,mg,mb,ma, all_a;
+   int extra_read;
+} stbi__bmp_data;
+
+static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
+{
+   int hsz;
+   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   info->offset = stbi__get32le(s);
+   info->hsz = hsz = stbi__get32le(s);
+   info->mr = info->mg = info->mb = info->ma = 0;
+   info->extra_read = 14;
+
+   if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP");
+
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
+   if (hsz == 12) {
+      s->img_x = stbi__get16le(s);
+      s->img_y = stbi__get16le(s);
+   } else {
+      s->img_x = stbi__get32le(s);
+      s->img_y = stbi__get32le(s);
+   }
+   if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
+   info->bpp = stbi__get16le(s);
+   if (hsz != 12) {
+      int compress = stbi__get32le(s);
+      if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+      stbi__get32le(s); // discard sizeof
+      stbi__get32le(s); // discard hres
+      stbi__get32le(s); // discard vres
+      stbi__get32le(s); // discard colorsused
+      stbi__get32le(s); // discard max important
+      if (hsz == 40 || hsz == 56) {
+         if (hsz == 56) {
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+         }
+         if (info->bpp == 16 || info->bpp == 32) {
+            if (compress == 0) {
+               if (info->bpp == 32) {
+                  info->mr = 0xffu << 16;
+                  info->mg = 0xffu <<  8;
+                  info->mb = 0xffu <<  0;
+                  info->ma = 0xffu << 24;
+                  info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+               } else {
+                  info->mr = 31u << 10;
+                  info->mg = 31u <<  5;
+                  info->mb = 31u <<  0;
+               }
+            } else if (compress == 3) {
+               info->mr = stbi__get32le(s);
+               info->mg = stbi__get32le(s);
+               info->mb = stbi__get32le(s);
+               info->extra_read += 12;
+               // not documented, but generated by photoshop and handled by mspaint
+               if (info->mr == info->mg && info->mg == info->mb) {
+                  // ?!?!?
+                  return stbi__errpuc("bad BMP", "bad BMP");
+               }
+            } else
+               return stbi__errpuc("bad BMP", "bad BMP");
+         }
+      } else {
+         int i;
+         if (hsz != 108 && hsz != 124)
+            return stbi__errpuc("bad BMP", "bad BMP");
+         info->mr = stbi__get32le(s);
+         info->mg = stbi__get32le(s);
+         info->mb = stbi__get32le(s);
+         info->ma = stbi__get32le(s);
+         stbi__get32le(s); // discard color space
+         for (i=0; i < 12; ++i)
+            stbi__get32le(s); // discard color space parameters
+         if (hsz == 124) {
+            stbi__get32le(s); // discard rendering intent
+            stbi__get32le(s); // discard offset of profile data
+            stbi__get32le(s); // discard size of profile data
+            stbi__get32le(s); // discard reserved
+         }
+      }
+   }
+   return (void *) 1;
+}
+
+
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *out;
+   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
+   stbi_uc pal[256][4];
+   int psize=0,i,j,width;
+   int flip_vertically, pad, target;
+   stbi__bmp_data info;
+   STBI_NOTUSED(ri);
+
+   info.all_a = 255;
+   if (stbi__bmp_parse_header(s, &info) == NULL)
+      return NULL; // error code already set
+
+   flip_vertically = ((int) s->img_y) > 0;
+   s->img_y = abs((int) s->img_y);
+
+   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   mr = info.mr;
+   mg = info.mg;
+   mb = info.mb;
+   ma = info.ma;
+   all_a = info.all_a;
+
+   if (info.hsz == 12) {
+      if (info.bpp < 24)
+         psize = (info.offset - info.extra_read - 24) / 3;
+   } else {
+      if (info.bpp < 16)
+         psize = (info.offset - info.extra_read - info.hsz) >> 2;
+   }
+   if (psize == 0) {
+      STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original));
+      if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) {
+        return stbi__errpuc("bad offset", "Corrupt BMP");
+      }
+   }
+
+   if (info.bpp == 24 && ma == 0xff000000)
+      s->img_n = 3;
+   else
+      s->img_n = ma ? 4 : 3;
+   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+      target = req_comp;
+   else
+      target = s->img_n; // if they want monochrome, we'll post-convert
+
+   // sanity-check size
+   if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))
+      return stbi__errpuc("too large", "Corrupt BMP");
+
+   out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   if (info.bpp < 16) {
+      int z=0;
+      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
+      for (i=0; i < psize; ++i) {
+         pal[i][2] = stbi__get8(s);
+         pal[i][1] = stbi__get8(s);
+         pal[i][0] = stbi__get8(s);
+         if (info.hsz != 12) stbi__get8(s);
+         pal[i][3] = 255;
+      }
+      stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+      if (info.bpp == 1) width = (s->img_x + 7) >> 3;
+      else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+      else if (info.bpp == 8) width = s->img_x;
+      else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
+      pad = (-width)&3;
+      if (info.bpp == 1) {
+         for (j=0; j < (int) s->img_y; ++j) {
+            int bit_offset = 7, v = stbi__get8(s);
+            for (i=0; i < (int) s->img_x; ++i) {
+               int color = (v>>bit_offset)&0x1;
+               out[z++] = pal[color][0];
+               out[z++] = pal[color][1];
+               out[z++] = pal[color][2];
+               if (target == 4) out[z++] = 255;
+               if (i+1 == (int) s->img_x) break;
+               if((--bit_offset) < 0) {
+                  bit_offset = 7;
+                  v = stbi__get8(s);
+               }
+            }
+            stbi__skip(s, pad);
+         }
+      } else {
+         for (j=0; j < (int) s->img_y; ++j) {
+            for (i=0; i < (int) s->img_x; i += 2) {
+               int v=stbi__get8(s),v2=0;
+               if (info.bpp == 4) {
+                  v2 = v & 15;
+                  v >>= 4;
+               }
+               out[z++] = pal[v][0];
+               out[z++] = pal[v][1];
+               out[z++] = pal[v][2];
+               if (target == 4) out[z++] = 255;
+               if (i+1 == (int) s->img_x) break;
+               v = (info.bpp == 8) ? stbi__get8(s) : v2;
+               out[z++] = pal[v][0];
+               out[z++] = pal[v][1];
+               out[z++] = pal[v][2];
+               if (target == 4) out[z++] = 255;
+            }
+            stbi__skip(s, pad);
+         }
+      }
+   } else {
+      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+      int z = 0;
+      int easy=0;
+      stbi__skip(s, info.offset - info.extra_read - info.hsz);
+      if (info.bpp == 24) width = 3 * s->img_x;
+      else if (info.bpp == 16) width = 2*s->img_x;
+      else /* bpp = 32 and pad = 0 */ width=0;
+      pad = (-width) & 3;
+      if (info.bpp == 24) {
+         easy = 1;
+      } else if (info.bpp == 32) {
+         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+            easy = 2;
+      }
+      if (!easy) {
+         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+         // right shift amt to put high bit in position #7
+         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
+         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
+         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
+         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+         if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+      }
+      for (j=0; j < (int) s->img_y; ++j) {
+         if (easy) {
+            for (i=0; i < (int) s->img_x; ++i) {
+               unsigned char a;
+               out[z+2] = stbi__get8(s);
+               out[z+1] = stbi__get8(s);
+               out[z+0] = stbi__get8(s);
+               z += 3;
+               a = (easy == 2 ? stbi__get8(s) : 255);
+               all_a |= a;
+               if (target == 4) out[z++] = a;
+            }
+         } else {
+            int bpp = info.bpp;
+            for (i=0; i < (int) s->img_x; ++i) {
+               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
+               unsigned int a;
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
+               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
+               all_a |= a;
+               if (target == 4) out[z++] = STBI__BYTECAST(a);
+            }
+         }
+         stbi__skip(s, pad);
+      }
+   }
+
+   // if alpha channel is all 0s, replace with all 255s
+   if (target == 4 && all_a == 0)
+      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)
+         out[i] = 255;
+
+   if (flip_vertically) {
+      stbi_uc t;
+      for (j=0; j < (int) s->img_y>>1; ++j) {
+         stbi_uc *p1 = out +      j     *s->img_x*target;
+         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+         for (i=0; i < (int) s->img_x*target; ++i) {
+            t = p1[i]; p1[i] = p2[i]; p2[i] = t;
+         }
+      }
+   }
+
+   if (req_comp && req_comp != target) {
+      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   *x = s->img_x;
+   *y = s->img_y;
+   if (comp) *comp = s->img_n;
+   return out;
+}
+#endif
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+#ifndef STBI_NO_TGA
+// returns STBI_rgb or whatever, 0 on error
+static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
+{
+   // only RGB or RGBA (incl. 16bit) or grey allowed
+   if (is_rgb16) *is_rgb16 = 0;
+   switch(bits_per_pixel) {
+      case 8:  return STBI_grey;
+      case 16: if(is_grey) return STBI_grey_alpha;
+               // fallthrough
+      case 15: if(is_rgb16) *is_rgb16 = 1;
+               return STBI_rgb;
+      case 24: // fallthrough
+      case 32: return bits_per_pixel/8;
+      default: return 0;
+   }
+}
+
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
+{
+    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
+    int sz, tga_colormap_type;
+    stbi__get8(s);                   // discard Offset
+    tga_colormap_type = stbi__get8(s); // colormap type
+    if( tga_colormap_type > 1 ) {
+        stbi__rewind(s);
+        return 0;      // only RGB or indexed allowed
+    }
+    tga_image_type = stbi__get8(s); // image type
+    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
+        if (tga_image_type != 1 && tga_image_type != 9) {
+            stbi__rewind(s);
+            return 0;
+        }
+        stbi__skip(s,4);       // skip index of first colormap entry and number of entries
+        sz = stbi__get8(s);    //   check bits per palette color entry
+        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
+            stbi__rewind(s);
+            return 0;
+        }
+        stbi__skip(s,4);       // skip image x and y origin
+        tga_colormap_bpp = sz;
+    } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
+        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
+            stbi__rewind(s);
+            return 0; // only RGB or grey allowed, +/- RLE
+        }
+        stbi__skip(s,9); // skip colormap specification and image x/y origin
+        tga_colormap_bpp = 0;
+    }
+    tga_w = stbi__get16le(s);
+    if( tga_w < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test width
+    }
+    tga_h = stbi__get16le(s);
+    if( tga_h < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test height
+    }
+    tga_bits_per_pixel = stbi__get8(s); // bits per pixel
+    stbi__get8(s); // ignore alpha bits
+    if (tga_colormap_bpp != 0) {
+        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
+            // when using a colormap, tga_bits_per_pixel is the size of the indexes
+            // I don't think anything but 8 or 16bit indexes makes sense
+            stbi__rewind(s);
+            return 0;
+        }
+        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
+    } else {
+        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
+    }
+    if(!tga_comp) {
+      stbi__rewind(s);
+      return 0;
+    }
+    if (x) *x = tga_w;
+    if (y) *y = tga_h;
+    if (comp) *comp = tga_comp;
+    return 1;                   // seems to have passed everything
+}
+
+static int stbi__tga_test(stbi__context *s)
+{
+   int res = 0;
+   int sz, tga_color_type;
+   stbi__get8(s);      //   discard Offset
+   tga_color_type = stbi__get8(s);   //   color type
+   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed
+   sz = stbi__get8(s);   //   image type
+   if ( tga_color_type == 1 ) { // colormapped (paletted) image
+      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
+      stbi__skip(s,4);       // skip index of first colormap entry and number of entries
+      sz = stbi__get8(s);    //   check bits per palette color entry
+      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+      stbi__skip(s,4);       // skip image x and y origin
+   } else { // "normal" image w/o colormap
+      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
+      stbi__skip(s,9); // skip colormap specification and image x/y origin
+   }
+   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width
+   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height
+   sz = stbi__get8(s);   //   bits per pixel
+   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
+   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+
+   res = 1; // if we got this far, everything's good and we can return 1 instead of 0
+
+errorEnd:
+   stbi__rewind(s);
+   return res;
+}
+
+// read 16bit value and convert to 24bit RGB
+static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
+{
+   stbi__uint16 px = (stbi__uint16)stbi__get16le(s);
+   stbi__uint16 fiveBitMask = 31;
+   // we have 3 channels with 5bits each
+   int r = (px >> 10) & fiveBitMask;
+   int g = (px >> 5) & fiveBitMask;
+   int b = px & fiveBitMask;
+   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
+   out[0] = (stbi_uc)((r * 255)/31);
+   out[1] = (stbi_uc)((g * 255)/31);
+   out[2] = (stbi_uc)((b * 255)/31);
+
+   // some people claim that the most significant bit might be used for alpha
+   // (possibly if an alpha-bit is set in the "image descriptor byte")
+   // but that only made 16bit test images completely translucent..
+   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.
+}
+
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   //   read in the TGA header stuff
+   int tga_offset = stbi__get8(s);
+   int tga_indexed = stbi__get8(s);
+   int tga_image_type = stbi__get8(s);
+   int tga_is_RLE = 0;
+   int tga_palette_start = stbi__get16le(s);
+   int tga_palette_len = stbi__get16le(s);
+   int tga_palette_bits = stbi__get8(s);
+   int tga_x_origin = stbi__get16le(s);
+   int tga_y_origin = stbi__get16le(s);
+   int tga_width = stbi__get16le(s);
+   int tga_height = stbi__get16le(s);
+   int tga_bits_per_pixel = stbi__get8(s);
+   int tga_comp, tga_rgb16=0;
+   int tga_inverted = stbi__get8(s);
+   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
+   //   image data
+   unsigned char *tga_data;
+   unsigned char *tga_palette = NULL;
+   int i, j;
+   unsigned char raw_data[4] = {0};
+   int RLE_count = 0;
+   int RLE_repeating = 0;
+   int read_next_pixel = 1;
+   STBI_NOTUSED(ri);
+   STBI_NOTUSED(tga_x_origin); // @TODO
+   STBI_NOTUSED(tga_y_origin); // @TODO
+
+   if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   //   do a tiny bit of precessing
+   if ( tga_image_type >= 8 )
+   {
+      tga_image_type -= 8;
+      tga_is_RLE = 1;
+   }
+   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+   //   If I'm paletted, then I'll use the number of bits from the palette
+   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
+   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
+
+   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
+      return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
+
+   //   tga info
+   *x = tga_width;
+   *y = tga_height;
+   if (comp) *comp = tga_comp;
+
+   if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))
+      return stbi__errpuc("too large", "Corrupt TGA");
+
+   tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
+   if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
+
+   // skip to the data's starting position (offset usually = 0)
+   stbi__skip(s, tga_offset );
+
+   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
+      for (i=0; i < tga_height; ++i) {
+         int row = tga_inverted ? tga_height -i - 1 : i;
+         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
+         stbi__getn(s, tga_row, tga_width * tga_comp);
+      }
+   } else  {
+      //   do I need to load a palette?
+      if ( tga_indexed)
+      {
+         if (tga_palette_len == 0) {  /* you have to have at least one entry! */
+            STBI_FREE(tga_data);
+            return stbi__errpuc("bad palette", "Corrupt TGA");
+         }
+
+         //   any data to skip? (offset usually = 0)
+         stbi__skip(s, tga_palette_start );
+         //   load the palette
+         tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);
+         if (!tga_palette) {
+            STBI_FREE(tga_data);
+            return stbi__errpuc("outofmem", "Out of memory");
+         }
+         if (tga_rgb16) {
+            stbi_uc *pal_entry = tga_palette;
+            STBI_ASSERT(tga_comp == STBI_rgb);
+            for (i=0; i < tga_palette_len; ++i) {
+               stbi__tga_read_rgb16(s, pal_entry);
+               pal_entry += tga_comp;
+            }
+         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
+               STBI_FREE(tga_data);
+               STBI_FREE(tga_palette);
+               return stbi__errpuc("bad palette", "Corrupt TGA");
+         }
+      }
+      //   load the data
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
+         if ( tga_is_RLE )
+         {
+            if ( RLE_count == 0 )
+            {
+               //   yep, get the next byte as a RLE command
+               int RLE_cmd = stbi__get8(s);
+               RLE_count = 1 + (RLE_cmd & 127);
+               RLE_repeating = RLE_cmd >> 7;
+               read_next_pixel = 1;
+            } else if ( !RLE_repeating )
+            {
+               read_next_pixel = 1;
+            }
+         } else
+         {
+            read_next_pixel = 1;
+         }
+         //   OK, if I need to read a pixel, do it now
+         if ( read_next_pixel )
+         {
+            //   load however much data we did have
+            if ( tga_indexed )
+            {
+               // read in index, then perform the lookup
+               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
+               if ( pal_idx >= tga_palette_len ) {
+                  // invalid index
+                  pal_idx = 0;
+               }
+               pal_idx *= tga_comp;
+               for (j = 0; j < tga_comp; ++j) {
+                  raw_data[j] = tga_palette[pal_idx+j];
+               }
+            } else if(tga_rgb16) {
+               STBI_ASSERT(tga_comp == STBI_rgb);
+               stbi__tga_read_rgb16(s, raw_data);
+            } else {
+               //   read in the data raw
+               for (j = 0; j < tga_comp; ++j) {
+                  raw_data[j] = stbi__get8(s);
+               }
+            }
+            //   clear the reading flag for the next pixel
+            read_next_pixel = 0;
+         } // end of reading a pixel
+
+         // copy data
+         for (j = 0; j < tga_comp; ++j)
+           tga_data[i*tga_comp+j] = raw_data[j];
+
+         //   in case we're in RLE mode, keep counting down
+         --RLE_count;
+      }
+      //   do I need to invert the image?
+      if ( tga_inverted )
+      {
+         for (j = 0; j*2 < tga_height; ++j)
+         {
+            int index1 = j * tga_width * tga_comp;
+            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+            for (i = tga_width * tga_comp; i > 0; --i)
+            {
+               unsigned char temp = tga_data[index1];
+               tga_data[index1] = tga_data[index2];
+               tga_data[index2] = temp;
+               ++index1;
+               ++index2;
+            }
+         }
+      }
+      //   clear my palette, if I had one
+      if ( tga_palette != NULL )
+      {
+         STBI_FREE( tga_palette );
+      }
+   }
+
+   // swap RGB - if the source data was RGB16, it already is in the right order
+   if (tga_comp >= 3 && !tga_rgb16)
+   {
+      unsigned char* tga_pixel = tga_data;
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         unsigned char temp = tga_pixel[0];
+         tga_pixel[0] = tga_pixel[2];
+         tga_pixel[2] = temp;
+         tga_pixel += tga_comp;
+      }
+   }
+
+   // convert to target component count
+   if (req_comp && req_comp != tga_comp)
+      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
+   //   the things I do to get rid of an error message, and yet keep
+   //   Microsoft's C compilers happy... [8^(
+   tga_palette_start = tga_palette_len = tga_palette_bits =
+         tga_x_origin = tga_y_origin = 0;
+   STBI_NOTUSED(tga_palette_start);
+   //   OK, done
+   return tga_data;
+}
+#endif
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s)
+{
+   int r = (stbi__get32be(s) == 0x38425053);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)
+{
+   int count, nleft, len;
+
+   count = 0;
+   while ((nleft = pixelCount - count) > 0) {
+      len = stbi__get8(s);
+      if (len == 128) {
+         // No-op.
+      } else if (len < 128) {
+         // Copy next len+1 bytes literally.
+         len++;
+         if (len > nleft) return 0; // corrupt data
+         count += len;
+         while (len) {
+            *p = stbi__get8(s);
+            p += 4;
+            len--;
+         }
+      } else if (len > 128) {
+         stbi_uc   val;
+         // Next -len+1 bytes in the dest are replicated from next source byte.
+         // (Interpret len as a negative 8-bit int.)
+         len = 257 - len;
+         if (len > nleft) return 0; // corrupt data
+         val = stbi__get8(s);
+         count += len;
+         while (len) {
+            *p = val;
+            p += 4;
+            len--;
+         }
+      }
+   }
+
+   return 1;
+}
+
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+   int pixelCount;
+   int channelCount, compression;
+   int channel, i;
+   int bitdepth;
+   int w,h;
+   stbi_uc *out;
+   STBI_NOTUSED(ri);
+
+   // Check identifier
+   if (stbi__get32be(s) != 0x38425053)   // "8BPS"
+      return stbi__errpuc("not PSD", "Corrupt PSD image");
+
+   // Check file type version.
+   if (stbi__get16be(s) != 1)
+      return stbi__errpuc("wrong version", "Unsupported version of PSD image");
+
+   // Skip 6 reserved bytes.
+   stbi__skip(s, 6 );
+
+   // Read the number of channels (R, G, B, A, etc).
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16)
+      return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+   // Read the rows and columns of the image.
+   h = stbi__get32be(s);
+   w = stbi__get32be(s);
+
+   if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   // Make sure the depth is 8 bits.
+   bitdepth = stbi__get16be(s);
+   if (bitdepth != 8 && bitdepth != 16)
+      return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit");
+
+   // Make sure the color mode is RGB.
+   // Valid options are:
+   //   0: Bitmap
+   //   1: Grayscale
+   //   2: Indexed color
+   //   3: RGB color
+   //   4: CMYK color
+   //   7: Multichannel
+   //   8: Duotone
+   //   9: Lab color
+   if (stbi__get16be(s) != 3)
+      return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
+
+   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
+   stbi__skip(s,stbi__get32be(s) );
+
+   // Skip the image resources.  (resolution, pen tool paths, etc)
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Skip the reserved data.
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Find out if the data is compressed.
+   // Known values:
+   //   0: no compression
+   //   1: RLE compressed
+   compression = stbi__get16be(s);
+   if (compression > 1)
+      return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+
+   // Check size
+   if (!stbi__mad3sizes_valid(4, w, h, 0))
+      return stbi__errpuc("too large", "Corrupt PSD");
+
+   // Create the destination image.
+
+   if (!compression && bitdepth == 16 && bpc == 16) {
+      out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);
+      ri->bits_per_channel = 16;
+   } else
+      out = (stbi_uc *) stbi__malloc(4 * w*h);
+
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   pixelCount = w*h;
+
+   // Initialize the data to zero.
+   //memset( out, 0, pixelCount * 4 );
+
+   // Finally, the image data.
+   if (compression) {
+      // RLE as used by .PSD and .TIFF
+      // Loop until you get the number of unpacked bytes you are expecting:
+      //     Read the next source byte into n.
+      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+      //     Else if n is 128, noop.
+      // Endloop
+
+      // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,
+      // which we're going to just skip.
+      stbi__skip(s, h * channelCount * 2 );
+
+      // Read the RLE data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         stbi_uc *p;
+
+         p = out+channel;
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            for (i = 0; i < pixelCount; i++, p += 4)
+               *p = (channel == 3 ? 255 : 0);
+         } else {
+            // Read the RLE data.
+            if (!stbi__psd_decode_rle(s, p, pixelCount)) {
+               STBI_FREE(out);
+               return stbi__errpuc("corrupt", "bad RLE data");
+            }
+         }
+      }
+
+   } else {
+      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
+      // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.
+
+      // Read the data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            if (bitdepth == 16 && bpc == 16) {
+               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+               stbi__uint16 val = channel == 3 ? 65535 : 0;
+               for (i = 0; i < pixelCount; i++, q += 4)
+                  *q = val;
+            } else {
+               stbi_uc *p = out+channel;
+               stbi_uc val = channel == 3 ? 255 : 0;
+               for (i = 0; i < pixelCount; i++, p += 4)
+                  *p = val;
+            }
+         } else {
+            if (ri->bits_per_channel == 16) {    // output bpc
+               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+               for (i = 0; i < pixelCount; i++, q += 4)
+                  *q = (stbi__uint16) stbi__get16be(s);
+            } else {
+               stbi_uc *p = out+channel;
+               if (bitdepth == 16) {  // input bpc
+                  for (i = 0; i < pixelCount; i++, p += 4)
+                     *p = (stbi_uc) (stbi__get16be(s) >> 8);
+               } else {
+                  for (i = 0; i < pixelCount; i++, p += 4)
+                     *p = stbi__get8(s);
+               }
+            }
+         }
+      }
+   }
+
+   // remove weird white matte from PSD
+   if (channelCount >= 4) {
+      if (ri->bits_per_channel == 16) {
+         for (i=0; i < w*h; ++i) {
+            stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;
+            if (pixel[3] != 0 && pixel[3] != 65535) {
+               float a = pixel[3] / 65535.0f;
+               float ra = 1.0f / a;
+               float inv_a = 65535.0f * (1 - ra);
+               pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);
+               pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);
+               pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);
+            }
+         }
+      } else {
+         for (i=0; i < w*h; ++i) {
+            unsigned char *pixel = out + 4*i;
+            if (pixel[3] != 0 && pixel[3] != 255) {
+               float a = pixel[3] / 255.0f;
+               float ra = 1.0f / a;
+               float inv_a = 255.0f * (1 - ra);
+               pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
+               pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
+               pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+            }
+         }
+      }
+   }
+
+   // convert to desired output format
+   if (req_comp && req_comp != 4) {
+      if (ri->bits_per_channel == 16)
+         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);
+      else
+         out = stbi__convert_format(out, 4, req_comp, w, h);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   if (comp) *comp = 4;
+   *y = h;
+   *x = w;
+
+   return out;
+}
+#endif
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_is4(stbi__context *s,const char *str)
+{
+   int i;
+   for (i=0; i<4; ++i)
+      if (stbi__get8(s) != (stbi_uc)str[i])
+         return 0;
+
+   return 1;
+}
+
+static int stbi__pic_test_core(stbi__context *s)
+{
+   int i;
+
+   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
+      return 0;
+
+   for(i=0;i<84;++i)
+      stbi__get8(s);
+
+   if (!stbi__pic_is4(s,"PICT"))
+      return 0;
+
+   return 1;
+}
+
+typedef struct
+{
+   stbi_uc size,type,channel;
+} stbi__pic_packet;
+
+static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
+{
+   int mask=0x80, i;
+
+   for (i=0; i<4; ++i, mask>>=1) {
+      if (channel & mask) {
+         if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
+         dest[i]=stbi__get8(s);
+      }
+   }
+
+   return dest;
+}
+
+static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+   int mask=0x80,i;
+
+   for (i=0;i<4; ++i, mask>>=1)
+      if (channel&mask)
+         dest[i]=src[i];
+}
+
+static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
+{
+   int act_comp=0,num_packets=0,y,chained;
+   stbi__pic_packet packets[10];
+
+   // this will (should...) cater for even some bizarre stuff like having data
+    // for the same channel in multiple packets.
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return stbi__errpuc("bad format","too many packets");
+
+      packet = &packets[num_packets++];
+
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s))          return stbi__errpuc("bad file","file too short (reading packets)");
+      if (packet->size != 8)  return stbi__errpuc("bad format","packet isn't 8bpp");
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+   for(y=0; y<height; ++y) {
+      int packet_idx;
+
+      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+         stbi__pic_packet *packet = &packets[packet_idx];
+         stbi_uc *dest = result+y*width*4;
+
+         switch (packet->type) {
+            default:
+               return stbi__errpuc("bad format","packet has bad compression type");
+
+            case 0: {//uncompressed
+               int x;
+
+               for(x=0;x<width;++x, dest+=4)
+                  if (!stbi__readval(s,packet->channel,dest))
+                     return 0;
+               break;
+            }
+
+            case 1://Pure RLE
+               {
+                  int left=width, i;
+
+                  while (left>0) {
+                     stbi_uc count,value[4];
+
+                     count=stbi__get8(s);
+                     if (stbi__at_eof(s))   return stbi__errpuc("bad file","file too short (pure read count)");
+
+                     if (count > left)
+                        count = (stbi_uc) left;
+
+                     if (!stbi__readval(s,packet->channel,value))  return 0;
+
+                     for(i=0; i<count; ++i,dest+=4)
+                        stbi__copyval(packet->channel,dest,value);
+                     left -= count;
+                  }
+               }
+               break;
+
+            case 2: {//Mixed RLE
+               int left=width;
+               while (left>0) {
+                  int count = stbi__get8(s), i;
+                  if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (mixed read count)");
+
+                  if (count >= 128) { // Repeated
+                     stbi_uc value[4];
+
+                     if (count==128)
+                        count = stbi__get16be(s);
+                     else
+                        count -= 127;
+                     if (count > left)
+                        return stbi__errpuc("bad file","scanline overrun");
+
+                     if (!stbi__readval(s,packet->channel,value))
+                        return 0;
+
+                     for(i=0;i<count;++i, dest += 4)
+                        stbi__copyval(packet->channel,dest,value);
+                  } else { // Raw
+                     ++count;
+                     if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+                     for(i=0;i<count;++i, dest+=4)
+                        if (!stbi__readval(s,packet->channel,dest))
+                           return 0;
+                  }
+                  left-=count;
+               }
+               break;
+            }
+         }
+      }
+   }
+
+   return result;
+}
+
+static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *result;
+   int i, x,y, internal_comp;
+   STBI_NOTUSED(ri);
+
+   if (!comp) comp = &internal_comp;
+
+   for (i=0; i<92; ++i)
+      stbi__get8(s);
+
+   x = stbi__get16be(s);
+   y = stbi__get16be(s);
+
+   if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (pic header)");
+   if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
+
+   stbi__get32be(s); //skip `ratio'
+   stbi__get16be(s); //skip `fields'
+   stbi__get16be(s); //skip `pad'
+
+   // intermediate buffer is RGBA
+   result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
+   memset(result, 0xff, x*y*4);
+
+   if (!stbi__pic_load_core(s,x,y,comp, result)) {
+      STBI_FREE(result);
+      result=0;
+   }
+   *px = x;
+   *py = y;
+   if (req_comp == 0) req_comp = *comp;
+   result=stbi__convert_format(result,4,req_comp,x,y);
+
+   return result;
+}
+
+static int stbi__pic_test(stbi__context *s)
+{
+   int r = stbi__pic_test_core(s);
+   stbi__rewind(s);
+   return r;
+}
+#endif
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+
+#ifndef STBI_NO_GIF
+typedef struct
+{
+   stbi__int16 prefix;
+   stbi_uc first;
+   stbi_uc suffix;
+} stbi__gif_lzw;
+
+typedef struct
+{
+   int w,h;
+   stbi_uc *out;                 // output buffer (always 4 components)
+   stbi_uc *background;          // The current "background" as far as a gif is concerned
+   stbi_uc *history;
+   int flags, bgindex, ratio, transparent, eflags;
+   stbi_uc  pal[256][4];
+   stbi_uc lpal[256][4];
+   stbi__gif_lzw codes[8192];
+   stbi_uc *color_table;
+   int parse, step;
+   int lflags;
+   int start_x, start_y;
+   int max_x, max_y;
+   int cur_x, cur_y;
+   int line_size;
+   int delay;
+} stbi__gif;
+
+static int stbi__gif_test_raw(stbi__context *s)
+{
+   int sz;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
+   sz = stbi__get8(s);
+   if (sz != '9' && sz != '7') return 0;
+   if (stbi__get8(s) != 'a') return 0;
+   return 1;
+}
+
+static int stbi__gif_test(stbi__context *s)
+{
+   int r = stbi__gif_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
+{
+   int i;
+   for (i=0; i < num_entries; ++i) {
+      pal[i][2] = stbi__get8(s);
+      pal[i][1] = stbi__get8(s);
+      pal[i][0] = stbi__get8(s);
+      pal[i][3] = transp == i ? 0 : 255;
+   }
+}
+
+static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
+{
+   stbi_uc version;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
+      return stbi__err("not GIF", "Corrupt GIF");
+
+   version = stbi__get8(s);
+   if (version != '7' && version != '9')    return stbi__err("not GIF", "Corrupt GIF");
+   if (stbi__get8(s) != 'a')                return stbi__err("not GIF", "Corrupt GIF");
+
+   stbi__g_failure_reason = "";
+   g->w = stbi__get16le(s);
+   g->h = stbi__get16le(s);
+   g->flags = stbi__get8(s);
+   g->bgindex = stbi__get8(s);
+   g->ratio = stbi__get8(s);
+   g->transparent = -1;
+
+   if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+   if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+
+   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments
+
+   if (is_info) return 1;
+
+   if (g->flags & 0x80)
+      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+   return 1;
+}
+
+static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+   if (!stbi__gif_header(s, g, comp, 1)) {
+      STBI_FREE(g);
+      stbi__rewind( s );
+      return 0;
+   }
+   if (x) *x = g->w;
+   if (y) *y = g->h;
+   STBI_FREE(g);
+   return 1;
+}
+
+static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
+{
+   stbi_uc *p, *c;
+   int idx;
+
+   // recurse to decode the prefixes, since the linked-list is backwards,
+   // and working backwards through an interleaved image would be nasty
+   if (g->codes[code].prefix >= 0)
+      stbi__out_gif_code(g, g->codes[code].prefix);
+
+   if (g->cur_y >= g->max_y) return;
+
+   idx = g->cur_x + g->cur_y;
+   p = &g->out[idx];
+   g->history[idx / 4] = 1;
+
+   c = &g->color_table[g->codes[code].suffix * 4];
+   if (c[3] > 128) { // don't render transparent pixels;
+      p[0] = c[2];
+      p[1] = c[1];
+      p[2] = c[0];
+      p[3] = c[3];
+   }
+   g->cur_x += 4;
+
+   if (g->cur_x >= g->max_x) {
+      g->cur_x = g->start_x;
+      g->cur_y += g->step;
+
+      while (g->cur_y >= g->max_y && g->parse > 0) {
+         g->step = (1 << g->parse) * g->line_size;
+         g->cur_y = g->start_y + (g->step >> 1);
+         --g->parse;
+      }
+   }
+}
+
+static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
+{
+   stbi_uc lzw_cs;
+   stbi__int32 len, init_code;
+   stbi__uint32 first;
+   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+   stbi__gif_lzw *p;
+
+   lzw_cs = stbi__get8(s);
+   if (lzw_cs > 12) return NULL;
+   clear = 1 << lzw_cs;
+   first = 1;
+   codesize = lzw_cs + 1;
+   codemask = (1 << codesize) - 1;
+   bits = 0;
+   valid_bits = 0;
+   for (init_code = 0; init_code < clear; init_code++) {
+      g->codes[init_code].prefix = -1;
+      g->codes[init_code].first = (stbi_uc) init_code;
+      g->codes[init_code].suffix = (stbi_uc) init_code;
+   }
+
+   // support no starting clear code
+   avail = clear+2;
+   oldcode = -1;
+
+   len = 0;
+   for(;;) {
+      if (valid_bits < codesize) {
+         if (len == 0) {
+            len = stbi__get8(s); // start new block
+            if (len == 0)
+               return g->out;
+         }
+         --len;
+         bits |= (stbi__int32) stbi__get8(s) << valid_bits;
+         valid_bits += 8;
+      } else {
+         stbi__int32 code = bits & codemask;
+         bits >>= codesize;
+         valid_bits -= codesize;
+         // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+         if (code == clear) {  // clear code
+            codesize = lzw_cs + 1;
+            codemask = (1 << codesize) - 1;
+            avail = clear + 2;
+            oldcode = -1;
+            first = 0;
+         } else if (code == clear + 1) { // end of stream code
+            stbi__skip(s, len);
+            while ((len = stbi__get8(s)) > 0)
+               stbi__skip(s,len);
+            return g->out;
+         } else if (code <= avail) {
+            if (first) {
+               return stbi__errpuc("no clear code", "Corrupt GIF");
+            }
+
+            if (oldcode >= 0) {
+               p = &g->codes[avail++];
+               if (avail > 8192) {
+                  return stbi__errpuc("too many codes", "Corrupt GIF");
+               }
+
+               p->prefix = (stbi__int16) oldcode;
+               p->first = g->codes[oldcode].first;
+               p->suffix = (code == avail) ? p->first : g->codes[code].first;
+            } else if (code == avail)
+               return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+
+            stbi__out_gif_code(g, (stbi__uint16) code);
+
+            if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+               codesize++;
+               codemask = (1 << codesize) - 1;
+            }
+
+            oldcode = code;
+         } else {
+            return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+         }
+      }
+   }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+// two back is the image from two frames ago, used for a very specific disposal format
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
+{
+   int dispose;
+   int first_frame;
+   int pi;
+   int pcount;
+   STBI_NOTUSED(req_comp);
+
+   // on first frame, any non-written pixels get the background colour (non-transparent)
+   first_frame = 0;
+   if (g->out == 0) {
+      if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
+      if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))
+         return stbi__errpuc("too large", "GIF image is too large");
+      pcount = g->w * g->h;
+      g->out = (stbi_uc *) stbi__malloc(4 * pcount);
+      g->background = (stbi_uc *) stbi__malloc(4 * pcount);
+      g->history = (stbi_uc *) stbi__malloc(pcount);
+      if (!g->out || !g->background || !g->history)
+         return stbi__errpuc("outofmem", "Out of memory");
+
+      // image is treated as "transparent" at the start - ie, nothing overwrites the current background;
+      // background colour is only used for pixels that are not rendered first frame, after that "background"
+      // color refers to the color that was there the previous frame.
+      memset(g->out, 0x00, 4 * pcount);
+      memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)
+      memset(g->history, 0x00, pcount);        // pixels that were affected previous frame
+      first_frame = 1;
+   } else {
+      // second frame - how do we dispose of the previous one?
+      dispose = (g->eflags & 0x1C) >> 2;
+      pcount = g->w * g->h;
+
+      if ((dispose == 3) && (two_back == 0)) {
+         dispose = 2; // if I don't have an image to revert back to, default to the old background
+      }
+
+      if (dispose == 3) { // use previous graphic
+         for (pi = 0; pi < pcount; ++pi) {
+            if (g->history[pi]) {
+               memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
+            }
+         }
+      } else if (dispose == 2) {
+         // restore what was changed last frame to background before that frame;
+         for (pi = 0; pi < pcount; ++pi) {
+            if (g->history[pi]) {
+               memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
+            }
+         }
+      } else {
+         // This is a non-disposal case eithe way, so just
+         // leave the pixels as is, and they will become the new background
+         // 1: do not dispose
+         // 0:  not specified.
+      }
+
+      // background is what out is after the undoing of the previou frame;
+      memcpy( g->background, g->out, 4 * g->w * g->h );
+   }
+
+   // clear my history;
+   memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame
+
+   for (;;) {
+      int tag = stbi__get8(s);
+      switch (tag) {
+         case 0x2C: /* Image Descriptor */
+         {
+            stbi__int32 x, y, w, h;
+            stbi_uc *o;
+
+            x = stbi__get16le(s);
+            y = stbi__get16le(s);
+            w = stbi__get16le(s);
+            h = stbi__get16le(s);
+            if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+               return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
+
+            g->line_size = g->w * 4;
+            g->start_x = x * 4;
+            g->start_y = y * g->line_size;
+            g->max_x   = g->start_x + w * 4;
+            g->max_y   = g->start_y + h * g->line_size;
+            g->cur_x   = g->start_x;
+            g->cur_y   = g->start_y;
+
+            // if the width of the specified rectangle is 0, that means
+            // we may not see *any* pixels or the image is malformed;
+            // to make sure this is caught, move the current y down to
+            // max_y (which is what out_gif_code checks).
+            if (w == 0)
+               g->cur_y = g->max_y;
+
+            g->lflags = stbi__get8(s);
+
+            if (g->lflags & 0x40) {
+               g->step = 8 * g->line_size; // first interlaced spacing
+               g->parse = 3;
+            } else {
+               g->step = g->line_size;
+               g->parse = 0;
+            }
+
+            if (g->lflags & 0x80) {
+               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+               g->color_table = (stbi_uc *) g->lpal;
+            } else if (g->flags & 0x80) {
+               g->color_table = (stbi_uc *) g->pal;
+            } else
+               return stbi__errpuc("missing color table", "Corrupt GIF");
+
+            o = stbi__process_gif_raster(s, g);
+            if (!o) return NULL;
+
+            // if this was the first frame,
+            pcount = g->w * g->h;
+            if (first_frame && (g->bgindex > 0)) {
+               // if first frame, any pixel not drawn to gets the background color
+               for (pi = 0; pi < pcount; ++pi) {
+                  if (g->history[pi] == 0) {
+                     g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
+                     memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
+                  }
+               }
+            }
+
+            return o;
+         }
+
+         case 0x21: // Comment Extension.
+         {
+            int len;
+            int ext = stbi__get8(s);
+            if (ext == 0xF9) { // Graphic Control Extension.
+               len = stbi__get8(s);
+               if (len == 4) {
+                  g->eflags = stbi__get8(s);
+                  g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
+
+                  // unset old transparent
+                  if (g->transparent >= 0) {
+                     g->pal[g->transparent][3] = 255;
+                  }
+                  if (g->eflags & 0x01) {
+                     g->transparent = stbi__get8(s);
+                     if (g->transparent >= 0) {
+                        g->pal[g->transparent][3] = 0;
+                     }
+                  } else {
+                     // don't need transparent
+                     stbi__skip(s, 1);
+                     g->transparent = -1;
+                  }
+               } else {
+                  stbi__skip(s, len);
+                  break;
+               }
+            }
+            while ((len = stbi__get8(s)) != 0) {
+               stbi__skip(s, len);
+            }
+            break;
+         }
+
+         case 0x3B: // gif stream termination code
+            return (stbi_uc *) s; // using '1' causes warning on some compilers
+
+         default:
+            return stbi__errpuc("unknown code", "Corrupt GIF");
+      }
+   }
+}
+
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+   if (stbi__gif_test(s)) {
+      int layers = 0;
+      stbi_uc *u = 0;
+      stbi_uc *out = 0;
+      stbi_uc *two_back = 0;
+      stbi__gif g;
+      int stride;
+      memset(&g, 0, sizeof(g));
+      if (delays) {
+         *delays = 0;
+      }
+
+      do {
+         u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
+         if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
+
+         if (u) {
+            *x = g.w;
+            *y = g.h;
+            ++layers;
+            stride = g.w * g.h * 4;
+
+            if (out) {
+               void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, 0, layers * stride );
+               if (NULL == tmp) {
+                  STBI_FREE(g.out);
+                  STBI_FREE(g.history);
+                  STBI_FREE(g.background);
+                  return stbi__errpuc("outofmem", "Out of memory");
+               }
+               else {
+                   out = (stbi_uc*) tmp;
+               }
+
+               if (delays) {
+                  *delays = (int*) STBI_REALLOC_SIZED( *delays, 0, sizeof(int) * layers );
+               }
+            } else {
+               out = (stbi_uc*)stbi__malloc( layers * stride );
+               if (delays) {
+                  *delays = (int*) stbi__malloc( layers * sizeof(int) );
+               }
+            }
+            memcpy( out + ((layers - 1) * stride), u, stride );
+            if (layers >= 2) {
+               two_back = out - 2 * stride;
+            }
+
+            if (delays) {
+               (*delays)[layers - 1U] = g.delay;
+            }
+         }
+      } while (u != 0);
+
+      // free temp buffer;
+      STBI_FREE(g.out);
+      STBI_FREE(g.history);
+      STBI_FREE(g.background);
+
+      // do the final conversion after loading everything;
+      if (req_comp && req_comp != 4)
+         out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
+
+      *z = layers;
+      return out;
+   } else {
+      return stbi__errpuc("not GIF", "Image was not as a gif type.");
+   }
+}
+
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *u = 0;
+   stbi__gif g;
+   memset(&g, 0, sizeof(g));
+   STBI_NOTUSED(ri);
+
+   u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
+   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
+   if (u) {
+      *x = g.w;
+      *y = g.h;
+
+      // moved conversion to after successful load so that the same
+      // can be done for multiple frames.
+      if (req_comp && req_comp != 4)
+         u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
+   } else if (g.out) {
+      // if there was an error and we allocated an image buffer, free it!
+      STBI_FREE(g.out);
+   }
+
+   // free buffers needed for multiple frame loading;
+   STBI_FREE(g.history);
+   STBI_FREE(g.background);
+
+   return u;
+}
+
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   return stbi__gif_info_raw(s,x,y,comp);
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test_core(stbi__context *s, const char *signature)
+{
+   int i;
+   for (i=0; signature[i]; ++i)
+      if (stbi__get8(s) != signature[i])
+          return 0;
+   stbi__rewind(s);
+   return 1;
+}
+
+static int stbi__hdr_test(stbi__context* s)
+{
+   int r = stbi__hdr_test_core(s, "#?RADIANCE\n");
+   stbi__rewind(s);
+   if(!r) {
+       r = stbi__hdr_test_core(s, "#?RGBE\n");
+       stbi__rewind(s);
+   }
+   return r;
+}
+
+#define STBI__HDR_BUFLEN  1024
+static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
+{
+   int len=0;
+   char c = '\0';
+
+   c = (char) stbi__get8(z);
+
+   while (!stbi__at_eof(z) && c != '\n') {
+      buffer[len++] = c;
+      if (len == STBI__HDR_BUFLEN-1) {
+         // flush to end of line
+         while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
+            ;
+         break;
+      }
+      c = (char) stbi__get8(z);
+   }
+
+   buffer[len] = 0;
+   return buffer;
+}
+
+static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+   if ( input[3] != 0 ) {
+      float f1;
+      // Exponent
+      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+      if (req_comp <= 2)
+         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+      else {
+         output[0] = input[0] * f1;
+         output[1] = input[1] * f1;
+         output[2] = input[2] * f1;
+      }
+      if (req_comp == 2) output[1] = 1;
+      if (req_comp == 4) output[3] = 1;
+   } else {
+      switch (req_comp) {
+         case 4: output[3] = 1; /* fallthrough */
+         case 3: output[0] = output[1] = output[2] = 0;
+                 break;
+         case 2: output[1] = 1; /* fallthrough */
+         case 1: output[0] = 0;
+                 break;
+      }
+   }
+}
+
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+   int width, height;
+   stbi_uc *scanline;
+   float *hdr_data;
+   int len;
+   unsigned char count, value;
+   int i, j, k, c1,c2, z;
+   const char *headerToken;
+   STBI_NOTUSED(ri);
+
+   // Check identifier
+   headerToken = stbi__hdr_gettoken(s,buffer);
+   if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0)
+      return stbi__errpf("not HDR", "Corrupt HDR image");
+
+   // Parse header
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid)    return stbi__errpf("unsupported format", "Unsupported HDR format");
+
+   // Parse width and height
+   // can't use sscanf() if we're not using stdio!
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   height = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   width = (int) strtol(token, NULL, 10);
+
+   if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+   if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+
+   *x = width;
+   *y = height;
+
+   if (comp) *comp = 3;
+   if (req_comp == 0) req_comp = 3;
+
+   if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))
+      return stbi__errpf("too large", "HDR image is too large");
+
+   // Read data
+   hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
+   if (!hdr_data)
+      return stbi__errpf("outofmem", "Out of memory");
+
+   // Load image data
+   // image data is stored as some number of sca
+   if ( width < 8 || width >= 32768) {
+      // Read flat data
+      for (j=0; j < height; ++j) {
+         for (i=0; i < width; ++i) {
+            stbi_uc rgbe[4];
+           main_decode_loop:
+            stbi__getn(s, rgbe, 4);
+            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+         }
+      }
+   } else {
+      // Read RLE-encoded data
+      scanline = NULL;
+
+      for (j = 0; j < height; ++j) {
+         c1 = stbi__get8(s);
+         c2 = stbi__get8(s);
+         len = stbi__get8(s);
+         if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+            // not run-length encoded, so we have to actually use THIS data as a decoded
+            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+            stbi_uc rgbe[4];
+            rgbe[0] = (stbi_uc) c1;
+            rgbe[1] = (stbi_uc) c2;
+            rgbe[2] = (stbi_uc) len;
+            rgbe[3] = (stbi_uc) stbi__get8(s);
+            stbi__hdr_convert(hdr_data, rgbe, req_comp);
+            i = 1;
+            j = 0;
+            STBI_FREE(scanline);
+            goto main_decode_loop; // yes, this makes no sense
+         }
+         len <<= 8;
+         len |= stbi__get8(s);
+         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
+         if (scanline == NULL) {
+            scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
+            if (!scanline) {
+               STBI_FREE(hdr_data);
+               return stbi__errpf("outofmem", "Out of memory");
+            }
+         }
+
+         for (k = 0; k < 4; ++k) {
+            int nleft;
+            i = 0;
+            while ((nleft = width - i) > 0) {
+               count = stbi__get8(s);
+               if (count > 128) {
+                  // Run
+                  value = stbi__get8(s);
+                  count -= 128;
+                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = value;
+               } else {
+                  // Dump
+                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = stbi__get8(s);
+               }
+            }
+         }
+         for (i=0; i < width; ++i)
+            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+      }
+      if (scanline)
+         STBI_FREE(scanline);
+   }
+
+   return hdr_data;
+}
+
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+   int dummy;
+
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+
+   if (stbi__hdr_test(s) == 0) {
+       stbi__rewind( s );
+       return 0;
+   }
+
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *y = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *x = (int) strtol(token, NULL, 10);
+   *comp = 3;
+   return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   void *p;
+   stbi__bmp_data info;
+
+   info.all_a = 255;
+   p = stbi__bmp_parse_header(s, &info);
+   stbi__rewind( s );
+   if (p == NULL)
+      return 0;
+   if (x) *x = s->img_x;
+   if (y) *y = s->img_y;
+   if (comp) {
+      if (info.bpp == 24 && info.ma == 0xff000000)
+         *comp = 3;
+      else
+         *comp = info.ma ? 4 : 3;
+   }
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int channelCount, dummy, depth;
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+   if (stbi__get32be(s) != 0x38425053) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 1) {
+       stbi__rewind( s );
+       return 0;
+   }
+   stbi__skip(s, 6);
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *y = stbi__get32be(s);
+   *x = stbi__get32be(s);
+   depth = stbi__get16be(s);
+   if (depth != 8 && depth != 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 3) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *comp = 4;
+   return 1;
+}
+
+static int stbi__psd_is16(stbi__context *s)
+{
+   int channelCount, depth;
+   if (stbi__get32be(s) != 0x38425053) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 1) {
+       stbi__rewind( s );
+       return 0;
+   }
+   stbi__skip(s, 6);
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   (void) stbi__get32be(s);
+   (void) stbi__get32be(s);
+   depth = stbi__get16be(s);
+   if (depth != 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int act_comp=0,num_packets=0,chained,dummy;
+   stbi__pic_packet packets[10];
+
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+
+   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
+      stbi__rewind(s);
+      return 0;
+   }
+
+   stbi__skip(s, 88);
+
+   *x = stbi__get16be(s);
+   *y = stbi__get16be(s);
+   if (stbi__at_eof(s)) {
+      stbi__rewind( s);
+      return 0;
+   }
+   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+      stbi__rewind( s );
+      return 0;
+   }
+
+   stbi__skip(s, 8);
+
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return 0;
+
+      packet = &packets[num_packets++];
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s)) {
+          stbi__rewind( s );
+          return 0;
+      }
+      if (packet->size != 8) {
+          stbi__rewind( s );
+          return 0;
+      }
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3);
+
+   return 1;
+}
+#endif
+
+// *************************************************************************************************
+// Portable Gray Map and Portable Pixel Map loader
+// by Ken Miller
+//
+// PGM: http://netpbm.sourceforge.net/doc/pgm.html
+// PPM: http://netpbm.sourceforge.net/doc/ppm.html
+//
+// Known limitations:
+//    Does not support comments in the header section
+//    Does not support ASCII image data (formats P2 and P3)
+//    Does not support 16-bit-per-channel
+
+#ifndef STBI_NO_PNM
+
+static int      stbi__pnm_test(stbi__context *s)
+{
+   char p, t;
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind( s );
+       return 0;
+   }
+   return 1;
+}
+
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+   stbi_uc *out;
+   STBI_NOTUSED(ri);
+
+   if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
+      return 0;
+
+   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+   *x = s->img_x;
+   *y = s->img_y;
+   if (comp) *comp = s->img_n;
+
+   if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
+      return stbi__errpuc("too large", "PNM too large");
+
+   out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
+
+   if (req_comp && req_comp != s->img_n) {
+      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+   return out;
+}
+
+static int      stbi__pnm_isspace(char c)
+{
+   return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
+}
+
+static void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)
+{
+   for (;;) {
+      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
+         *c = (char) stbi__get8(s);
+
+      if (stbi__at_eof(s) || *c != '#')
+         break;
+
+      while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
+         *c = (char) stbi__get8(s);
+   }
+}
+
+static int      stbi__pnm_isdigit(char c)
+{
+   return c >= '0' && c <= '9';
+}
+
+static int      stbi__pnm_getinteger(stbi__context *s, char *c)
+{
+   int value = 0;
+
+   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
+      value = value*10 + (*c - '0');
+      *c = (char) stbi__get8(s);
+   }
+
+   return value;
+}
+
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int maxv, dummy;
+   char c, p, t;
+
+   if (!x) x = &dummy;
+   if (!y) y = &dummy;
+   if (!comp) comp = &dummy;
+
+   stbi__rewind(s);
+
+   // Get identifier
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind(s);
+       return 0;
+   }
+
+   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm
+
+   c = (char) stbi__get8(s);
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *x = stbi__pnm_getinteger(s, &c); // read width
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *y = stbi__pnm_getinteger(s, &c); // read height
+   stbi__pnm_skip_whitespace(s, &c);
+
+   maxv = stbi__pnm_getinteger(s, &c);  // read max value
+
+   if (maxv > 255)
+      return stbi__err("max value > 255", "PPM image not 8-bit");
+   else
+      return 1;
+}
+#endif
+
+static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
+{
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_info(s, x, y, comp)) return 1;
+   #endif
+
+   #ifndef STBI_NO_PNG
+   if (stbi__png_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_info(s, x, y, comp))  return 1;
+   #endif
+
+   // test tga last because it's a crappy test!
+   #ifndef STBI_NO_TGA
+   if (stbi__tga_info(s, x, y, comp))
+       return 1;
+   #endif
+   return stbi__err("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static int stbi__is_16_main(stbi__context *s)
+{
+   #ifndef STBI_NO_PNG
+   if (stbi__png_is16(s))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_is16(s))  return 1;
+   #endif
+
+   return 0;
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+    FILE *f = stbi__fopen(filename, "rb");
+    int result;
+    if (!f) return stbi__err("can't fopen", "Unable to open file");
+    result = stbi_info_from_file(f, x, y, comp);
+    fclose(f);
+    return result;
+}
+
+STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+   int r;
+   stbi__context s;
+   long pos = ftell(f);
+   stbi__start_file(&s, f);
+   r = stbi__info_main(&s,x,y,comp);
+   fseek(f,pos,SEEK_SET);
+   return r;
+}
+
+STBIDEF int stbi_is_16_bit(char const *filename)
+{
+    FILE *f = stbi__fopen(filename, "rb");
+    int result;
+    if (!f) return stbi__err("can't fopen", "Unable to open file");
+    result = stbi_is_16_bit_from_file(f);
+    fclose(f);
+    return result;
+}
+
+STBIDEF int stbi_is_16_bit_from_file(FILE *f)
+{
+   int r;
+   stbi__context s;
+   long pos = ftell(f);
+   stbi__start_file(&s, f);
+   r = stbi__is_16_main(&s);
+   fseek(f,pos,SEEK_SET);
+   return r;
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__is_16_main(&s);
+}
+
+STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+   return stbi__is_16_main(&s);
+}
+
+#endif // STB_IMAGE_IMPLEMENTATION
+
+/*
+   revision history:
+      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+      2.19  (2018-02-11) fix warning
+      2.18  (2018-01-30) fix warnings
+      2.17  (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
+                         1-bit BMP
+                         *_is_16_bit api
+                         avoid warnings
+      2.16  (2017-07-23) all functions have 16-bit variants;
+                         STBI_NO_STDIO works again;
+                         compilation fixes;
+                         fix rounding in unpremultiply;
+                         optimize vertical flip;
+                         disable raw_len validation;
+                         documentation fixes
+      2.15  (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
+                         warning fixes; disable run-time SSE detection on gcc;
+                         uniform handling of optional "return" values;
+                         thread-safe initialization of zlib tables
+      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+      2.13  (2016-11-29) add 16-bit API, only supported for PNG right now
+      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+      2.11  (2016-04-02) allocate large structures on the stack
+                         remove white matting for transparent PSD
+                         fix reported channel count for PNG & BMP
+                         re-enable SSE2 in non-gcc 64-bit
+                         support RGB-formatted JPEG
+                         read 16-bit PNGs (only as 8-bit)
+      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
+      2.09  (2016-01-16) allow comments in PNM files
+                         16-bit-per-pixel TGA (not bit-per-component)
+                         info() for TGA could break due to .hdr handling
+                         info() for BMP to shares code instead of sloppy parse
+                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc
+                         code cleanup
+      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+      2.07  (2015-09-13) fix compiler warnings
+                         partial animated GIF support
+                         limited 16-bpc PSD support
+                         #ifdef unused functions
+                         bug with < 92 byte PIC,PNM,HDR,TGA
+      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value
+      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning
+      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+      2.03  (2015-04-12) extra corruption checking (mmozeiko)
+                         stbi_set_flip_vertically_on_load (nguillemot)
+                         fix NEON support; fix mingw support
+      2.02  (2015-01-19) fix incorrect assert, fix warning
+      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
+      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
+                         progressive JPEG (stb)
+                         PGM/PPM support (Ken Miller)
+                         STBI_MALLOC,STBI_REALLOC,STBI_FREE
+                         GIF bugfix -- seemingly never worked
+                         STBI_NO_*, STBI_ONLY_*
+      1.48  (2014-12-14) fix incorrectly-named assert()
+      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
+                         optimize PNG (ryg)
+                         fix bug in interlaced PNG with user-specified channel count (stb)
+      1.46  (2014-08-26)
+              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
+      1.45  (2014-08-16)
+              fix MSVC-ARM internal compiler error by wrapping malloc
+      1.44  (2014-08-07)
+              various warning fixes from Ronny Chevalier
+      1.43  (2014-07-15)
+              fix MSVC-only compiler problem in code changed in 1.42
+      1.42  (2014-07-09)
+              don't define _CRT_SECURE_NO_WARNINGS (affects user code)
+              fixes to stbi__cleanup_jpeg path
+              added STBI_ASSERT to avoid requiring assert.h
+      1.41  (2014-06-25)
+              fix search&replace from 1.36 that messed up comments/error messages
+      1.40  (2014-06-22)
+              fix gcc struct-initialization warning
+      1.39  (2014-06-15)
+              fix to TGA optimization when req_comp != number of components in TGA;
+              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
+              add support for BMP version 5 (more ignored fields)
+      1.38  (2014-06-06)
+              suppress MSVC warnings on integer casts truncating values
+              fix accidental rename of 'skip' field of I/O
+      1.37  (2014-06-04)
+              remove duplicate typedef
+      1.36  (2014-06-03)
+              convert to header file single-file library
+              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
+      1.35  (2014-05-27)
+              various warnings
+              fix broken STBI_SIMD path
+              fix bug where stbi_load_from_file no longer left file pointer in correct place
+              fix broken non-easy path for 32-bit BMP (possibly never used)
+              TGA optimization by Arseny Kapoulkine
+      1.34  (unknown)
+              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
+      1.33  (2011-07-14)
+              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+      1.32  (2011-07-13)
+              support for "info" function for all supported filetypes (SpartanJ)
+      1.31  (2011-06-20)
+              a few more leak fixes, bug in PNG handling (SpartanJ)
+      1.30  (2011-06-11)
+              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+              removed deprecated format-specific test/load functions
+              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+              fix inefficiency in decoding 32-bit BMP (David Woo)
+      1.29  (2010-08-16)
+              various warning fixes from Aurelien Pocheville
+      1.28  (2010-08-01)
+              fix bug in GIF palette transparency (SpartanJ)
+      1.27  (2010-08-01)
+              cast-to-stbi_uc to fix warnings
+      1.26  (2010-07-24)
+              fix bug in file buffering for PNG reported by SpartanJ
+      1.25  (2010-07-17)
+              refix trans_data warning (Won Chun)
+      1.24  (2010-07-12)
+              perf improvements reading from files on platforms with lock-heavy fgetc()
+              minor perf improvements for jpeg
+              deprecated type-specific functions so we'll get feedback if they're needed
+              attempt to fix trans_data warning (Won Chun)
+      1.23    fixed bug in iPhone support
+      1.22  (2010-07-10)
+              removed image *writing* support
+              stbi_info support from Jetro Lauha
+              GIF support from Jean-Marc Lienher
+              iPhone PNG-extensions from James Brown
+              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
+      1.21    fix use of 'stbi_uc' in header (reported by jon blow)
+      1.20    added support for Softimage PIC, by Tom Seddon
+      1.19    bug in interlaced PNG corruption check (found by ryg)
+      1.18  (2008-08-02)
+              fix a threading bug (local mutable static)
+      1.17    support interlaced PNG
+      1.16    major bugfix - stbi__convert_format converted one too many pixels
+      1.15    initialize some fields for thread safety
+      1.14    fix threadsafe conversion bug
+              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+      1.13    threadsafe
+      1.12    const qualifiers in the API
+      1.11    Support installable IDCT, colorspace conversion routines
+      1.10    Fixes for 64-bit (don't use "unsigned long")
+              optimized upsampling by Fabian "ryg" Giesen
+      1.09    Fix format-conversion for PSD code (bad global variables!)
+      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+      1.07    attempt to fix C++ warning/errors again
+      1.06    attempt to fix C++ warning/errors again
+      1.05    fix TGA loading to return correct *comp and use good luminance calc
+      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free
+      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+      1.02    support for (subset of) HDR files, float interface for preferred access to them
+      1.01    fix bug: possible bug in handling right-side up bmps... not sure
+              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
+      1.00    interface to zlib that skips zlib header
+      0.99    correct handling of alpha in palette
+      0.98    TGA loader by lonesock; dynamically add loaders (untested)
+      0.97    jpeg errors on too large a file; also catch another malloc failure
+      0.96    fix detection of invalid v value - particleman at mollyrocket forum
+      0.95    during header scan, seek to markers in case of padding
+      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+      0.93    handle jpegtran output; verbose errors
+      0.92    read 4,8,16,24,32-bit BMP files of several formats
+      0.91    output 24-bit Windows 3.0 BMP files
+      0.90    fix a few more warnings; bump version number to approach 1.0
+      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd
+      0.60    fix compiling as c++
+      0.59    fix warnings: merge Dave Moore's -Wall fixes
+      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian
+      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+      0.56    fix bug: zlib uncompressed mode len vs. nlen
+      0.55    fix bug: restart_interval not initialized to 0
+      0.54    allow NULL for 'int *comp'
+      0.53    fix bug in png 3->4; speedup png decoding
+      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+      0.51    obey req_comp requests, 1-component jpegs return as 1-component,
+              on 'test' only check type, not whether we support this variant
+      0.50  (2006-11-19)
+              first released version
+*/
+
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
-- 
2.17.1



From jmaselbas at kalray.eu  Mon Jan 17 15:02:32 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Tue, 18 Jan 2022 00:02:32 +0100
Subject: [PATCH v2 2/5] gui: Add qoi image format
In-Reply-To: <20220117230235.13549-1-jmaselbas@kalray.eu>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
Message-ID: <20220117230235.13549-3-jmaselbas@kalray.eu>

The "Quite OK Image Format", aka QOI, aims to be a fast, lossless image
compression format, with comparable compression factor against png, and
beeing faster to encode and decode.

In barebox only care about decoding, the qoi image format might be an
intresting alternative to both bmp and png, some kind of midle ground.

The project home page can be found at https://qoiformat.org, there is
a reference implementation, for both encoder and decoder, in a single
header file (qoi.h) hosted at https://github.com/phoboslab/qoi.

There is no plan for future version, this is a frozen format.
In case the reference implementation should be updated, the qoi.h file
must be copied to the lib/gui/qoi.h without requiring modifications.

Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>
---
changes in v2:
 - added pr_fmt in lib/gui/qoi.c
 - added missing SPDX license identifier
 - removed not needed .keep_file_data=1
---
 lib/gui/Kconfig  |   5 +
 lib/gui/Makefile |   1 +
 lib/gui/qoi.c    |  97 +++++++
 lib/gui/qoi.h    | 673 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 776 insertions(+)
 create mode 100644 lib/gui/qoi.c
 create mode 100644 lib/gui/qoi.h

diff --git a/lib/gui/Kconfig b/lib/gui/Kconfig
index 2625d9fb2f..f0263c71cc 100644
--- a/lib/gui/Kconfig
+++ b/lib/gui/Kconfig
@@ -16,6 +16,11 @@ config PNG
 	bool "png"
 	select ZLIB
 
+config QOI
+	bool "qoi"
+	help
+	  Support for the Quite OK Image format
+
 if PNG
 
 choice
diff --git a/lib/gui/Makefile b/lib/gui/Makefile
index 31e66225d7..5ed190e9f8 100644
--- a/lib/gui/Makefile
+++ b/lib/gui/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_BMP)	+= bmp.o
 obj-$(CONFIG_IMAGE_RENDERER)	+= image_renderer.o graphic_utils.o
+obj-$(CONFIG_QOI)	+= qoi.o
 obj-$(CONFIG_PNG)	+= png.o
 obj-$(CONFIG_LODEPNG)	+= png_lode.o lodepng.o
 obj-$(CONFIG_PICOPNG)	+= png_pico.o picopng.o
diff --git a/lib/gui/qoi.c b/lib/gui/qoi.c
new file mode 100644
index 0000000000..b931868f16
--- /dev/null
+++ b/lib/gui/qoi.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+#define pr_fmt(fmt) "qoi: " fmt
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fb.h>
+#include <asm/byteorder.h>
+#include <gui/graphic_utils.h>
+#include <init.h>
+#include <gui/image_renderer.h>
+#include <asm/unaligned.h>
+
+#define QOI_NO_STDIO
+#define QOI_IMPLEMENTATION
+#include "qoi.h"
+
+static struct image *qoi_open(char *inbuf, int insize)
+{
+	struct image *img;
+	void *data;
+	qoi_desc qoi;
+
+	img = calloc(1, sizeof(*img));
+	if (!img)
+		return ERR_PTR(-ENOMEM);
+
+	data = qoi_decode(inbuf, insize, &qoi, 0);
+	if (!data) {
+		free(img);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	img->data = data;
+	img->height = qoi.height;
+	img->width = qoi.width;
+	img->bits_per_pixel = qoi.channels * 8;
+
+	pr_debug("%d x %d  x %d data at 0x%p\n", img->width, img->height,
+		 img->bits_per_pixel, img->data);
+	return img;
+}
+
+static void qoi_close(struct image *img)
+{
+	free(img->data);
+}
+
+static int qoi_renderer(struct screen *sc, struct surface *s, struct image *img)
+{
+	int alpha = img->bits_per_pixel == (4 * 8);
+	int width = s->width;
+	int height = s->height;
+	int startx = s->x;
+	int starty = s->y;
+	void *buf;
+
+	if (s->width < 0)
+		width = img->width;
+	if (s->height < 0)
+		height = img->height;
+
+	if (startx < 0) {
+		startx = (sc->s.width - width) / 2;
+		if (startx < 0)
+			startx = 0;
+	}
+
+	if (starty < 0) {
+		starty = (sc->s.height - height) / 2;
+		if (starty < 0)
+			starty = 0;
+	}
+
+	width = min(width, sc->s.width - startx);
+	height = min(height, sc->s.height - starty);
+
+	buf = gui_screen_render_buffer(sc);
+
+	gu_rgba_blend(sc->info, img, buf, height, width, startx, starty, alpha);
+
+	return img->height;
+}
+
+static struct image_renderer qoi = {
+	.type = filetype_qoi,
+	.open = qoi_open,
+	.close = qoi_close,
+	.renderer = qoi_renderer,
+};
+
+static int qoi_init(void)
+{
+	return image_renderer_register(&qoi);
+}
+fs_initcall(qoi_init);
diff --git a/lib/gui/qoi.h b/lib/gui/qoi.h
new file mode 100644
index 0000000000..aea441434c
--- /dev/null
+++ b/lib/gui/qoi.h
@@ -0,0 +1,673 @@
+/* SPDX-License-Identifier: MIT */
+/* SPDX-FileCopyrightText: 2021 Dominic Szablewski */
+/*
+
+QOI - The "Quite OK Image" format for fast, lossless image compression
+
+Dominic Szablewski - https://phoboslab.org
+
+
+-- LICENSE: The MIT License(MIT)
+
+Copyright(c) 2021 Dominic Szablewski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files(the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions :
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+-- About
+
+QOI encodes and decodes images in a lossless format. Compared to stb_image and
+stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and
+20% better compression.
+
+
+-- Synopsis
+
+// Define `QOI_IMPLEMENTATION` in *one* C/C++ file before including this
+// library to create the implementation.
+
+#define QOI_IMPLEMENTATION
+#include "qoi.h"
+
+// Encode and store an RGBA buffer to the file system. The qoi_desc describes
+// the input pixel data.
+qoi_write("image_new.qoi", rgba_pixels, &(qoi_desc){
+	.width = 1920,
+	.height = 1080,
+	.channels = 4,
+	.colorspace = QOI_SRGB
+});
+
+// Load and decode a QOI image from the file system into a 32bbp RGBA buffer.
+// The qoi_desc struct will be filled with the width, height, number of channels
+// and colorspace read from the file header.
+qoi_desc desc;
+void *rgba_pixels = qoi_read("image.qoi", &desc, 4);
+
+
+
+-- Documentation
+
+This library provides the following functions;
+- qoi_read    -- read and decode a QOI file
+- qoi_decode  -- decode the raw bytes of a QOI image from memory
+- qoi_write   -- encode and write a QOI file
+- qoi_encode  -- encode an rgba buffer into a QOI image in memory
+
+See the function declaration below for the signature and more information.
+
+If you don't want/need the qoi_read and qoi_write functions, you can define
+QOI_NO_STDIO before including this library.
+
+This library uses malloc() and free(). To supply your own malloc implementation
+you can define QOI_MALLOC and QOI_FREE before including this library.
+
+This library uses memset() to zero-initialize the index. To supply your own
+implementation you can define QOI_ZEROARR before including this library.
+
+
+-- Data Format
+
+A QOI file has a 14 byte header, followed by any number of data "chunks" and an
+8-byte end marker.
+
+struct qoi_header_t {
+	char     magic[4];   // magic bytes "qoif"
+	uint32_t width;      // image width in pixels (BE)
+	uint32_t height;     // image height in pixels (BE)
+	uint8_t  channels;   // 3 = RGB, 4 = RGBA
+	uint8_t  colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
+};
+
+Images are encoded row by row, left to right, top to bottom. The decoder and
+encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An
+image is complete when all pixels specified by width * height have been covered.
+
+Pixels are encoded as
+ - a run of the previous pixel
+ - an index into an array of previously seen pixels
+ - a difference to the previous pixel value in r,g,b
+ - full r,g,b or r,g,b,a values
+
+The color channels are assumed to not be premultiplied with the alpha channel
+("un-premultiplied alpha").
+
+A running array[64] (zero-initialized) of previously seen pixel values is
+maintained by the encoder and decoder. Each pixel that is seen by the encoder
+and decoder is put into this array at the position formed by a hash function of
+the color value. In the encoder, if the pixel value at the index matches the
+current pixel, this index position is written to the stream as QOI_OP_INDEX.
+The hash function for the index is:
+
+	index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64
+
+Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The
+bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All
+values encoded in these data bits have the most significant bit on the left.
+
+The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the
+presence of an 8-bit tag first.
+
+The byte stream's end is marked with 7 0x00 bytes followed a single 0x01 byte.
+
+
+The possible chunks are:
+
+
+.- QOI_OP_INDEX ----------.
+|         Byte[0]         |
+|  7  6  5  4  3  2  1  0 |
+|-------+-----------------|
+|  0  0 |     index       |
+`-------------------------`
+2-bit tag b00
+6-bit index into the color index array: 0..63
+
+A valid encoder must not issue 2 or more consecutive QOI_OP_INDEX chunks to the
+same index. QOI_OP_RUN should be used instead.
+
+
+.- QOI_OP_DIFF -----------.
+|         Byte[0]         |
+|  7  6  5  4  3  2  1  0 |
+|-------+-----+-----+-----|
+|  0  1 |  dr |  dg |  db |
+`-------------------------`
+2-bit tag b01
+2-bit   red channel difference from the previous pixel between -2..1
+2-bit green channel difference from the previous pixel between -2..1
+2-bit  blue channel difference from the previous pixel between -2..1
+
+The difference to the current channel values are using a wraparound operation,
+so "1 - 2" will result in 255, while "255 + 1" will result in 0.
+
+Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
+0 (b00). 1 is stored as 3 (b11).
+
+The alpha value remains unchanged from the previous pixel.
+
+
+.- QOI_OP_LUMA -------------------------------------.
+|         Byte[0]         |         Byte[1]         |
+|  7  6  5  4  3  2  1  0 |  7  6  5  4  3  2  1  0 |
+|-------+-----------------+-------------+-----------|
+|  1  0 |  green diff     |   dr - dg   |  db - dg  |
+`---------------------------------------------------`
+2-bit tag b10
+6-bit green channel difference from the previous pixel -32..31
+4-bit   red channel difference minus green channel difference -8..7
+4-bit  blue channel difference minus green channel difference -8..7
+
+The green channel is used to indicate the general direction of change and is
+encoded in 6 bits. The red and blue channels (dr and db) base their diffs off
+of the green channel difference and are encoded in 4 bits. I.e.:
+	dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g)
+	db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g)
+
+The difference to the current channel values are using a wraparound operation,
+so "10 - 13" will result in 253, while "250 + 7" will result in 1.
+
+Values are stored as unsigned integers with a bias of 32 for the green channel
+and a bias of 8 for the red and blue channel.
+
+The alpha value remains unchanged from the previous pixel.
+
+
+.- QOI_OP_RUN ------------.
+|         Byte[0]         |
+|  7  6  5  4  3  2  1  0 |
+|-------+-----------------|
+|  1  1 |       run       |
+`-------------------------`
+2-bit tag b11
+6-bit run-length repeating the previous pixel: 1..62
+
+The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64
+(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and
+QOI_OP_RGBA tags.
+
+
+.- QOI_OP_RGB ------------------------------------------.
+|         Byte[0]         | Byte[1] | Byte[2] | Byte[3] |
+|  7  6  5  4  3  2  1  0 | 7 .. 0  | 7 .. 0  | 7 .. 0  |
+|-------------------------+---------+---------+---------|
+|  1  1  1  1  1  1  1  0 |   red   |  green  |  blue   |
+`-------------------------------------------------------`
+8-bit tag b11111110
+8-bit   red channel value
+8-bit green channel value
+8-bit  blue channel value
+
+The alpha value remains unchanged from the previous pixel.
+
+
+.- QOI_OP_RGBA ---------------------------------------------------.
+|         Byte[0]         | Byte[1] | Byte[2] | Byte[3] | Byte[4] |
+|  7  6  5  4  3  2  1  0 | 7 .. 0  | 7 .. 0  | 7 .. 0  | 7 .. 0  |
+|-------------------------+---------+---------+---------+---------|
+|  1  1  1  1  1  1  1  1 |   red   |  green  |  blue   |  alpha  |
+`-----------------------------------------------------------------`
+8-bit tag b11111111
+8-bit   red channel value
+8-bit green channel value
+8-bit  blue channel value
+8-bit alpha channel value
+
+*/
+
+
+/* -----------------------------------------------------------------------------
+Header - Public functions */
+
+#ifndef QOI_H
+#define QOI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
+It describes either the input format (for qoi_write and qoi_encode), or is
+filled with the description read from the file header (for qoi_read and
+qoi_decode).
+
+The colorspace in this qoi_desc is an enum where
+	0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel
+	1 = all channels are linear
+You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
+informative. It will be saved to the file header, but does not affect
+how chunks are en-/decoded. */
+
+#define QOI_SRGB   0
+#define QOI_LINEAR 1
+
+typedef struct {
+	unsigned int width;
+	unsigned int height;
+	unsigned char channels;
+	unsigned char colorspace;
+} qoi_desc;
+
+#ifndef QOI_NO_STDIO
+
+/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file
+system. The qoi_desc struct must be filled with the image width, height,
+number of channels (3 = RGB, 4 = RGBA) and the colorspace.
+
+The function returns 0 on failure (invalid parameters, or fopen or malloc
+failed) or the number of bytes written on success. */
+
+int qoi_write(const char *filename, const void *data, const qoi_desc *desc);
+
+
+/* Read and decode a QOI image from the file system. If channels is 0, the
+number of channels from the file header is used. If channels is 3 or 4 the
+output format will be forced into this number of channels.
+
+The function either returns NULL on failure (invalid data, or malloc or fopen
+failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
+will be filled with the description from the file header.
+
+The returned pixel data should be free()d after use. */
+
+void *qoi_read(const char *filename, qoi_desc *desc, int channels);
+
+#endif /* QOI_NO_STDIO */
+
+
+/* Encode raw RGB or RGBA pixels into a QOI image in memory.
+
+The function either returns NULL on failure (invalid parameters or malloc
+failed) or a pointer to the encoded data on success. On success the out_len
+is set to the size in bytes of the encoded data.
+
+The returned qoi data should be free()d after use. */
+
+void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len);
+
+
+/* Decode a QOI image from memory.
+
+The function either returns NULL on failure (invalid parameters or malloc
+failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
+is filled with the description from the file header.
+
+The returned pixel data should be free()d after use. */
+
+void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* QOI_H */
+
+
+/* -----------------------------------------------------------------------------
+Implementation */
+
+#ifdef QOI_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef QOI_MALLOC
+	#define QOI_MALLOC(sz) malloc(sz)
+	#define QOI_FREE(p)    free(p)
+#endif
+#ifndef QOI_ZEROARR
+	#define QOI_ZEROARR(a) memset((a),0,sizeof(a))
+#endif
+
+#define QOI_OP_INDEX  0x00 /* 00xxxxxx */
+#define QOI_OP_DIFF   0x40 /* 01xxxxxx */
+#define QOI_OP_LUMA   0x80 /* 10xxxxxx */
+#define QOI_OP_RUN    0xc0 /* 11xxxxxx */
+#define QOI_OP_RGB    0xfe /* 11111110 */
+#define QOI_OP_RGBA   0xff /* 11111111 */
+
+#define QOI_MASK_2    0xc0 /* 11000000 */
+
+#define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11)
+#define QOI_MAGIC \
+	(((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \
+	 ((unsigned int)'i') <<  8 | ((unsigned int)'f'))
+#define QOI_HEADER_SIZE 14
+
+/* 2GB is the max file size that this implementation can safely handle. We guard
+against anything larger than that, assuming the worst case with 5 bytes per
+pixel, rounded down to a nice clean value. 400 million pixels ought to be
+enough for anybody. */
+#define QOI_PIXELS_MAX ((unsigned int)400000000)
+
+typedef union {
+	struct { unsigned char r, g, b, a; } rgba;
+	unsigned int v;
+} qoi_rgba_t;
+
+static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1};
+
+static void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) {
+	bytes[(*p)++] = (0xff000000 & v) >> 24;
+	bytes[(*p)++] = (0x00ff0000 & v) >> 16;
+	bytes[(*p)++] = (0x0000ff00 & v) >> 8;
+	bytes[(*p)++] = (0x000000ff & v);
+}
+
+static unsigned int qoi_read_32(const unsigned char *bytes, int *p) {
+	unsigned int a = bytes[(*p)++];
+	unsigned int b = bytes[(*p)++];
+	unsigned int c = bytes[(*p)++];
+	unsigned int d = bytes[(*p)++];
+	return a << 24 | b << 16 | c << 8 | d;
+}
+
+void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
+	int i, max_size, p, run;
+	int px_len, px_end, px_pos, channels;
+	unsigned char *bytes;
+	const unsigned char *pixels;
+	qoi_rgba_t index[64];
+	qoi_rgba_t px, px_prev;
+
+	if (
+		data == NULL || out_len == NULL || desc == NULL ||
+		desc->width == 0 || desc->height == 0 ||
+		desc->channels < 3 || desc->channels > 4 ||
+		desc->colorspace > 1 ||
+		desc->height >= QOI_PIXELS_MAX / desc->width
+	) {
+		return NULL;
+	}
+
+	max_size =
+		desc->width * desc->height * (desc->channels + 1) +
+		QOI_HEADER_SIZE + sizeof(qoi_padding);
+
+	p = 0;
+	bytes = (unsigned char *) QOI_MALLOC(max_size);
+	if (!bytes) {
+		return NULL;
+	}
+
+	qoi_write_32(bytes, &p, QOI_MAGIC);
+	qoi_write_32(bytes, &p, desc->width);
+	qoi_write_32(bytes, &p, desc->height);
+	bytes[p++] = desc->channels;
+	bytes[p++] = desc->colorspace;
+
+
+	pixels = (const unsigned char *)data;
+
+	QOI_ZEROARR(index);
+
+	run = 0;
+	px_prev.rgba.r = 0;
+	px_prev.rgba.g = 0;
+	px_prev.rgba.b = 0;
+	px_prev.rgba.a = 255;
+	px = px_prev;
+
+	px_len = desc->width * desc->height * desc->channels;
+	px_end = px_len - desc->channels;
+	channels = desc->channels;
+
+	for (px_pos = 0; px_pos < px_len; px_pos += channels) {
+		if (channels == 4) {
+			px = *(qoi_rgba_t *)(pixels + px_pos);
+		}
+		else {
+			px.rgba.r = pixels[px_pos + 0];
+			px.rgba.g = pixels[px_pos + 1];
+			px.rgba.b = pixels[px_pos + 2];
+		}
+
+		if (px.v == px_prev.v) {
+			run++;
+			if (run == 62 || px_pos == px_end) {
+				bytes[p++] = QOI_OP_RUN | (run - 1);
+				run = 0;
+			}
+		}
+		else {
+			int index_pos;
+
+			if (run > 0) {
+				bytes[p++] = QOI_OP_RUN | (run - 1);
+				run = 0;
+			}
+
+			index_pos = QOI_COLOR_HASH(px) % 64;
+
+			if (index[index_pos].v == px.v) {
+				bytes[p++] = QOI_OP_INDEX | index_pos;
+			}
+			else {
+				index[index_pos] = px;
+
+				if (px.rgba.a == px_prev.rgba.a) {
+					signed char vr = px.rgba.r - px_prev.rgba.r;
+					signed char vg = px.rgba.g - px_prev.rgba.g;
+					signed char vb = px.rgba.b - px_prev.rgba.b;
+
+					signed char vg_r = vr - vg;
+					signed char vg_b = vb - vg;
+
+					if (
+						vr > -3 && vr < 2 &&
+						vg > -3 && vg < 2 &&
+						vb > -3 && vb < 2
+					) {
+						bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2);
+					}
+					else if (
+						vg_r >  -9 && vg_r <  8 &&
+						vg   > -33 && vg   < 32 &&
+						vg_b >  -9 && vg_b <  8
+					) {
+						bytes[p++] = QOI_OP_LUMA     | (vg   + 32);
+						bytes[p++] = (vg_r + 8) << 4 | (vg_b +  8);
+					}
+					else {
+						bytes[p++] = QOI_OP_RGB;
+						bytes[p++] = px.rgba.r;
+						bytes[p++] = px.rgba.g;
+						bytes[p++] = px.rgba.b;
+					}
+				}
+				else {
+					bytes[p++] = QOI_OP_RGBA;
+					bytes[p++] = px.rgba.r;
+					bytes[p++] = px.rgba.g;
+					bytes[p++] = px.rgba.b;
+					bytes[p++] = px.rgba.a;
+				}
+			}
+		}
+		px_prev = px;
+	}
+
+	for (i = 0; i < (int)sizeof(qoi_padding); i++) {
+		bytes[p++] = qoi_padding[i];
+	}
+
+	*out_len = p;
+	return bytes;
+}
+
+void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
+	const unsigned char *bytes;
+	unsigned int header_magic;
+	unsigned char *pixels;
+	qoi_rgba_t index[64];
+	qoi_rgba_t px;
+	int px_len, chunks_len, px_pos;
+	int p = 0, run = 0;
+
+	if (
+		data == NULL || desc == NULL ||
+		(channels != 0 && channels != 3 && channels != 4) ||
+		size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding)
+	) {
+		return NULL;
+	}
+
+	bytes = (const unsigned char *)data;
+
+	header_magic = qoi_read_32(bytes, &p);
+	desc->width = qoi_read_32(bytes, &p);
+	desc->height = qoi_read_32(bytes, &p);
+	desc->channels = bytes[p++];
+	desc->colorspace = bytes[p++];
+
+	if (
+		desc->width == 0 || desc->height == 0 ||
+		desc->channels < 3 || desc->channels > 4 ||
+		desc->colorspace > 1 ||
+		header_magic != QOI_MAGIC ||
+		desc->height >= QOI_PIXELS_MAX / desc->width
+	) {
+		return NULL;
+	}
+
+	if (channels == 0) {
+		channels = desc->channels;
+	}
+
+	px_len = desc->width * desc->height * channels;
+	pixels = (unsigned char *) QOI_MALLOC(px_len);
+	if (!pixels) {
+		return NULL;
+	}
+
+	QOI_ZEROARR(index);
+	px.rgba.r = 0;
+	px.rgba.g = 0;
+	px.rgba.b = 0;
+	px.rgba.a = 255;
+
+	chunks_len = size - (int)sizeof(qoi_padding);
+	for (px_pos = 0; px_pos < px_len; px_pos += channels) {
+		if (run > 0) {
+			run--;
+		}
+		else if (p < chunks_len) {
+			int b1 = bytes[p++];
+
+			if (b1 == QOI_OP_RGB) {
+				px.rgba.r = bytes[p++];
+				px.rgba.g = bytes[p++];
+				px.rgba.b = bytes[p++];
+			}
+			else if (b1 == QOI_OP_RGBA) {
+				px.rgba.r = bytes[p++];
+				px.rgba.g = bytes[p++];
+				px.rgba.b = bytes[p++];
+				px.rgba.a = bytes[p++];
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) {
+				px = index[b1];
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) {
+				px.rgba.r += ((b1 >> 4) & 0x03) - 2;
+				px.rgba.g += ((b1 >> 2) & 0x03) - 2;
+				px.rgba.b += ( b1       & 0x03) - 2;
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) {
+				int b2 = bytes[p++];
+				int vg = (b1 & 0x3f) - 32;
+				px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f);
+				px.rgba.g += vg;
+				px.rgba.b += vg - 8 +  (b2       & 0x0f);
+			}
+			else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) {
+				run = (b1 & 0x3f);
+			}
+
+			index[QOI_COLOR_HASH(px) % 64] = px;
+		}
+
+		if (channels == 4) {
+			*(qoi_rgba_t*)(pixels + px_pos) = px;
+		}
+		else {
+			pixels[px_pos + 0] = px.rgba.r;
+			pixels[px_pos + 1] = px.rgba.g;
+			pixels[px_pos + 2] = px.rgba.b;
+		}
+	}
+
+	return pixels;
+}
+
+#ifndef QOI_NO_STDIO
+#include <stdio.h>
+
+int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
+	FILE *f = fopen(filename, "wb");
+	int size;
+	void *encoded;
+
+	if (!f) {
+		return 0;
+	}
+
+	encoded = qoi_encode(data, desc, &size);
+	if (!encoded) {
+		fclose(f);
+		return 0;
+	}
+
+	fwrite(encoded, 1, size, f);
+	fclose(f);
+
+	QOI_FREE(encoded);
+	return size;
+}
+
+void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
+	FILE *f = fopen(filename, "rb");
+	int size, bytes_read;
+	void *pixels, *data;
+
+	if (!f) {
+		return NULL;
+	}
+
+	fseek(f, 0, SEEK_END);
+	size = ftell(f);
+	if (size <= 0) {
+		fclose(f);
+		return NULL;
+	}
+	fseek(f, 0, SEEK_SET);
+
+	data = QOI_MALLOC(size);
+	if (!data) {
+		fclose(f);
+		return NULL;
+	}
+
+	bytes_read = fread(data, 1, size, f);
+	fclose(f);
+
+	pixels = qoi_decode(data, bytes_read, desc, channels);
+	QOI_FREE(data);
+	return pixels;
+}
+
+#endif /* QOI_NO_STDIO */
+#endif /* QOI_IMPLEMENTATION */
-- 
2.17.1



From trent.piepho at igorinstitute.com  Mon Jan 17 15:28:17 2022
From: trent.piepho at igorinstitute.com (Trent Piepho)
Date: Mon, 17 Jan 2022 15:28:17 -0800
Subject: [PATCH v2 4/5] logo: Enable image format selection for the logo
In-Reply-To: <20220117230235.13549-5-jmaselbas@kalray.eu>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
 <20220117230235.13549-5-jmaselbas@kalray.eu>
Message-ID: <CAMHeXxOQXTTd=u8M9fbtQeB6OAFnC+1t=Sx=CtwzocNc=HaDMg@mail.gmail.com>

On Mon, Jan 17, 2022 at 3:03 PM Jules Maselbas <jmaselbas at kalray.eu> wrote:
>
> +choice
> +       prompt "Logo image encoding format to be used"
> +       default BAREBOX_LOGO_PNG
> +
> +config BAREBOX_LOGO_PNG
> +       bool "png"
> +       select PNG
> +       help
> +         Encode logo with the PNG image format
> +
> +config BAREBOX_LOGO_BMP
> +       bool "bmp"
> +       select BMP
> +       help
> +         Encode logo with the BMP image format

You might say why one might want one format or ther other.  What's the
point of adding bmp support?


From a.fatoum at pengutronix.de  Mon Jan 17 21:39:17 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Tue, 18 Jan 2022 06:39:17 +0100
Subject: [PATCH 1/3] clk: ignore of_device_ensure_probed error in clock
 lookup
In-Reply-To: <0ecb57c3-e0a3-076f-5bd7-4b12c59fa80e@pengutronix.de>
References: <20220116213221.3466936-1-dev@lynxeye.de>
 <095bafc0-7261-aa13-a9c7-8022cc78b26c@pengutronix.de>
 <10192ccb41be58fd4e53044b17e6a5838c3629d7.camel@lynxeye.de>
 <0ecb57c3-e0a3-076f-5bd7-4b12c59fa80e@pengutronix.de>
Message-ID: <262dfcb7-416d-e537-12ab-680c020bc4a7@pengutronix.de>

On 17.01.22 11:20, Ahmad Fatoum wrote:
> On 17.01.22 10:16, Lucas Stach wrote:
>> Hi Ahmad,
>>
>> Am Montag, dem 17.01.2022 um 06:12 +0100 schrieb Ahmad Fatoum:
>>> Hello Lucas,
>>>
>>> On 16.01.22 22:32, Lucas Stach wrote:
>>>> For CLK_OF_DECLARE clocks there is no driver that is bound to the device,
>>>> so the lookup fails before even trying to find the provider, breaking
>>>> the parent_ready() logic used when initializing the declared providers.
>>>>
>>>> Ignore the return code from of_device_ensure_probed to allow the lookup
>>>> to proceed as usual. If of_device_ensure_probed the lookup will also fail,
>>>> as no provider will be found.
>>>
>>> This seems to be an alternate fix for the issue addressed by:
>>> bd516e38dd14 ("clk: handle CLK_OF_DECLARE in deep probe")
>>>
>>> What do you think?
>>
>> Yes, it seems to be aimed at the same issue. However, your fix in
>> bd516e38dd14 doesn't fix my specific issue, as we still don't get the
>> correct -EPROBE_DEFER error code for the logic in parent_ready() in
>> drivers/clk/clk.c to work.
>>
>> I guess we could even revert your fix if we agree that ignoring the
>> return code here is the right thing to do? Attaching a dummy driver 
>> doesn't seem to be totally correct, as I think it isn't prohibited to
>> have both a CLK_OF_DECLARE clock controller and a real platform driver
>> for other uses attached to the same OF node. While I'm not aware of any
>> clock controllers where this would be the case, I have seen such
>> constructs with IRQ controllers.
> 
> Sounds logical. I'll test with my fix reverted and yours applied
> and report back.

Tested-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

"clk: handle CLK_OF_DECLARE in deep probe" can be dropped again.

> 
>>
>> Regards,
>> Lucas
>>
>>>
>>>>
>>>> Signed-off-by: Lucas Stach <dev at lynxeye.de>
>>>> ---
>>>>  drivers/clk/clk.c | 6 ++----
>>>>  1 file changed, 2 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>>>> index 189c9c62df5c..a1d1d7f1a467 100644
>>>> --- a/drivers/clk/clk.c
>>>> +++ b/drivers/clk/clk.c
>>>> @@ -643,11 +643,9 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
>>>>  {
>>>>  	struct of_clk_provider *provider;
>>>>  	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
>>>> -	int ret;
>>>>  
>>>> -	ret = of_device_ensure_probed(clkspec->np);
>>>> -	if (ret)
>>>> -		return ERR_PTR(ret);
>>>> +	/* Ignore error, as CLK_OF_DECLARE clocks have no proper driver. */
>>>> +	of_device_ensure_probed(clkspec->np);
>>>>  
>>>>  	/* Check if we have such a provider in our array */
>>>>  	list_for_each_entry(provider, &of_clk_providers, link) {
>>>>
>>>
>>>
>>
>>
>>
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 17 23:34:33 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Jan 2022 08:34:33 +0100
Subject: [PATCH 1/3] clk: ignore of_device_ensure_probed error in clock
 lookup
In-Reply-To: <20220116213221.3466936-1-dev@lynxeye.de>
References: <20220116213221.3466936-1-dev@lynxeye.de>
Message-ID: <20220118073433.GD23490@pengutronix.de>

On Sun, Jan 16, 2022 at 10:32:19PM +0100, Lucas Stach wrote:
> For CLK_OF_DECLARE clocks there is no driver that is bound to the device,
> so the lookup fails before even trying to find the provider, breaking
> the parent_ready() logic used when initializing the declared providers.
> 
> Ignore the return code from of_device_ensure_probed to allow the lookup
> to proceed as usual. If of_device_ensure_probed the lookup will also fail,
> as no provider will be found.
> 
> Signed-off-by: Lucas Stach <dev at lynxeye.de>
> ---
>  drivers/clk/clk.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 17 23:57:33 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Jan 2022 08:57:33 +0100
Subject: [PATCH v1 2/4] ARM: rpi: move clk support to a separate driver
 and enable deep-probe
In-Reply-To: <20220117120500.3556703-2-o.rempel@pengutronix.de>
References: <20220117120500.3556703-1-o.rempel@pengutronix.de>
 <20220117120500.3556703-2-o.rempel@pengutronix.de>
Message-ID: <20220118075733.GE23490@pengutronix.de>

On Mon, Jan 17, 2022 at 01:04:58PM +0100, Oleksij Rempel wrote:
> To make deep-probe work properly, we need clock support be registered as
> driver to related device.
> 
> To avoid regression, deep-probe is enabled in the same patch.
> 
> Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
> ---
>  arch/arm/boards/raspberry-pi/rpi-common.c | 75 +-----------------
>  drivers/clk/Makefile                      |  1 +
>  drivers/clk/clk-rpi.c                     | 93 +++++++++++++++++++++++
>  3 files changed, 96 insertions(+), 73 deletions(-)
>  create mode 100644 drivers/clk/clk-rpi.c
> 
> +static int bcm2835_cprman_init(struct device_node *np)
> +{
> +	struct device_node *mbox_node;
> +	struct clk *clk;
> +	int ret;
> +
> +	mbox_node = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-mbox");
> +	if (!mbox_node) {
> +		pr_err("Missing mbox node\n");
> +		return -ENOENT;
> +	}
> +
> +	ret = of_device_ensure_probed(mbox_node);
> +	if (ret) {
> +		pr_err("Can't probe mbox node. %i\n", ret);
> +		return ret;
> +	}
> +
> +	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_EMMC,
> +					 "bcm2835_mci0");
> +	if (IS_ERR(clk))
> +		return PTR_ERR(clk);
> +
> +	clkdev_add_physbase(clk, 0x20300000, NULL);
> +	clkdev_add_physbase(clk, 0x3f300000, NULL);
> +
> +	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
> +					  "bcm2835_sdhost");
> +	if (IS_ERR(clk))
> +		return PTR_ERR(clk);
> +
> +	clkdev_add_physbase(clk, 0x20202000, NULL);
> +	clkdev_add_physbase(clk, 0x3f202000, NULL);
> +
> +	clk = clk_fixed("apb_pclk", 0);
> +	clk_register_clkdev(clk, "apb_pclk", NULL);
> +
> +	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
> +	clk_register_clkdev(clk, NULL, "uart0-pl0110");
> +	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
> +	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
> +
> +	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
> +					  "uart1-8250");
> +	if (IS_ERR(clk))
> +		return PTR_ERR(clk);
> +
> +	clkdev_add_physbase(clk, BCM2835_MINIUART_BASE, NULL);
> +	clkdev_add_physbase(clk, BCM2836_MINIUART_BASE, NULL);
> +
> +	clk = clk_fixed("bcm2835-cs", 1 * 1000 * 1000);
> +	clk_register_clkdev(clk, NULL, "bcm2835-cs");
> +
> +	return 0;
> +}
> +/* CLK_OF_DECLARE should be used to make it probed before amba,pl011 */

We should finally switch to device tree based lookup for the clocks.
Given where we are already this seems to be only a small step left to
go.

Sascha

> +CLK_OF_DECLARE(bcm2835_cprman, "brcm,bcm2835-cprman", bcm2835_cprman_init);
> -- 
> 2.30.2
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Tue Jan 18 00:09:14 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Jan 2022 09:09:14 +0100
Subject: [PATCH v2 00/11] kvx arch update
In-Reply-To: <20220117221917.26970-1-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
Message-ID: <20220118080914.GF23490@pengutronix.de>

On Mon, Jan 17, 2022 at 11:19:06PM +0100, Jules Maselbas wrote:
> This series has updates for the KVX architecture, with some fixes and
> with the addition of kvx specific drivers for the otp-nvmem and socinfo.
> 
> With this series it is now possible to run barebox on qemu, however
> our qemu port isn't upstreamed yet, it can still be compiled. To do
> so you will need to check this git repo [1] and follow the build
> instructions.
> 
> To compile barebox for the KVX architecture there is a pre-built
> toolchain that can be downloaded here [2]
> 
> The following commands should build an run barebox on qemu:
> $ PATH=<path/to/gcc-kalray-kvx-v4.7.0-cd2>/bin:$PATH ARCH=kvx make generic_defconfig all
> $ qemu-system-kvx -m 1G -nographic -kernel barebox
> 
> [1] https://github.com/kalray/qemu-builder
> [2] https://github.com/kalray/build-scripts/releases/tag/v4.7.0-cd2

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From jbe at pengutronix.de  Tue Jan 18 00:17:52 2022
From: jbe at pengutronix.de (Juergen Borleis)
Date: Tue, 18 Jan 2022 09:17:52 +0100
Subject: [PATCH 2/2] Add Ricoh RN5T568 PMIC based watchdog
In-Reply-To: <20220117114627.GJ1121@pengutronix.de>
References: <20220117085908.36460-1-jbe@pengutronix.de>
 <20220117085908.36460-3-jbe@pengutronix.de>
 <20220117114627.GJ1121@pengutronix.de>
Message-ID: <2adde69877fb4d49178b2c02fb26926b6ca3bc26.camel@pengutronix.de>

Hi Sascha,

Am Montag, dem 17.01.2022 um 12:46 +0100 schrieb Sascha Hauer:
> > ---
> > ?drivers/watchdog/Kconfig?????? |?? 6 ++
> > ?drivers/watchdog/Makefile????? |?? 1 +
> > ?drivers/watchdog/rn5t568_wdt.c | 140 +++++++++++++++++++++++++++++++++
> > ?3 files changed, 147 insertions(+)
> > ?create mode 100644 drivers/watchdog/rn5t568_wdt.c
> > 
> > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> > index d605e62..61a096b 100644
> > --- a/drivers/watchdog/Kconfig
> > +++ b/drivers/watchdog/Kconfig
> > @@ -109,6 +109,12 @@ config STPMIC1_WATCHDOG
> > ????????help
> > ????????? Enable to support configuration of the stpmic1's built-in
> > watchdog.
> > ?
> > +config RN568_WATCHDOG
> > +???????bool "Ricoh RN5t568 PMIC based Watchdog"
> > +???????depends on MFD_RN568PMIC
> > +???????help
> > +???????? Enable to support system control via the PMIC based watchdog.
> > +
> > ?config F71808E_WDT
> > ????????bool "Fintek F718xx, F818xx Super I/O Watchdog"
> > ????????depends on X86
> > diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> > index dbb76a5..84fd2bf 100644
> > --- a/drivers/watchdog/Makefile
> > +++ b/drivers/watchdog/Makefile
> > @@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_BCM283X) += bcm2835_wdt.o
> > ?obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
> > ?obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o
> > ?obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
> > +obj-$(CONFIG_RN568_WATCHDOG) += rn5t568_wdt.o
> > ?obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
> > ?obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
> > ?obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
> > diff --git a/drivers/watchdog/rn5t568_wdt.c b/drivers/watchdog/rn5t568_wdt.c
> > new file mode 100644
> > index 0000000..f6e7234
> > --- /dev/null
> > +++ b/drivers/watchdog/rn5t568_wdt.c
> > @@ -0,0 +1,140 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Watchdog driver for Ricoh RN5T618 PMIC
> > + *
> > + * Copyright (C) 2014 Beniamino Galvani <b.galvani at gmail.com>
> > + */
> > +
> > +#include <common.h>
> > +#include <init.h>
> > +#include <watchdog.h>
> > +#include <regmap.h>
> > +#include <of.h>
> > +
> > +#define RN5T568_WATCHDOG 0x0b
> > +# define RN5T568_WATCHDOG_WDPWROFFEN BIT(2)
> > +# define RN5T568_WATCHDOG_WDOGTIM_M (BIT(0) | BIT(1))
> > +#define RN5T568_PWRIREN 0x12
> > +# define RN5T568_PWRIREN_EN_WDOG BIT(6)
> > +#define RN5T568_PWRIRQ 0x13
> > +# define RN5T568_PWRIRQ_IR_WDOG BIT(6)
> > +
> > +struct rn5t568_wdt {
> > +???????struct watchdog wdd;
> > +???????struct regmap *regmap;
> > +???????unsigned int timeout;
> > +};
> > +
> > +struct rn5t568_wdt_tim {
> > +???????u8 reg_val;
> > +???????u8 time;
> > +};
> > +
> > +static const struct rn5t568_wdt_tim rn5t568_wdt_timeout[] = {
> > +???????{ .reg_val = 0, .time = 1, },
> > +???????{ .reg_val = 1, .time = 8, },
> > +???????{ .reg_val = 2, .time = 32, },
> > +???????{ .reg_val = 3, .time = 128, },
> > +};
> > +
> > +#define PMIC_WDT_MAX_TIMEOUT 128
> > +
> > +static int rn5t568_wdt_start(struct regmap *regmap, int idx)
> > +{
> > +???????int ret;
> > +
> > +???????ret = regmap_update_bits(regmap, RN5T568_WATCHDOG,
> > RN5T568_WATCHDOG_WDOGTIM_M,
> > +??????????????????????????????? rn5t568_wdt_timeout[idx].reg_val);
> > +???????if (ret)
> > +???????????????return ret;
> > +
> > +???????regmap_update_bits(regmap, RN5T568_PWRIRQ, RN5T568_PWRIRQ_IR_WDOG,
> > 0x00);
> > +???????regmap_update_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG,
> > RN5T568_PWRIREN_EN_WDOG);
> > +
> > +???????pr_debug("RN5t: Starting the watchdog with %u seconds\n",
> > rn5t568_wdt_timeout[idx].time);
> > +
> > +???????return regmap_update_bits(regmap, RN5T568_WATCHDOG,
> > RN5T568_WATCHDOG_WDPWROFFEN,
> > +??????????????????????????????? RN5T568_WATCHDOG_WDPWROFFEN);
> > +}
> > +
> > +static int rn5t568_wdt_stop(struct regmap *regmap)
> > +{
> > +???????int ret;
> > +
> > +???????ret? = regmap_update_bits(regmap, RN5T568_PWRIREN,
> > RN5T568_PWRIREN_EN_WDOG, 0);
> 
> You could use regmap_[clear|set]_bits() here and elsewhere in the
> driver.

Hmmm, seems a Linux kernel feature, I didn't found such functions in barebox.

Will send a V2 soon.

jb

-- 
Pengutronix e.K.???????????????????????| Juergen Borleis?????????????|
Steuerwalder Str. 21???????????????????| https://www.pengutronix.de/ |
31137 Hildesheim, Germany??????????????| Phone: +49-5121-206917-128  |
Amtsgericht Hildesheim, HRA 2686???????| Fax:???+49-5121-206917-9    |




From jbe at pengutronix.de  Tue Jan 18 00:21:22 2022
From: jbe at pengutronix.de (Juergen Borleis)
Date: Tue, 18 Jan 2022 09:21:22 +0100
Subject: [PATCH v2 2/2] Add Ricoh RN5T568 PMIC based watchdog
In-Reply-To: <20220118082122.73204-1-jbe@pengutronix.de>
References: <20220118082122.73204-1-jbe@pengutronix.de>
Message-ID: <20220118082122.73204-2-jbe@pengutronix.de>

---
 drivers/watchdog/Kconfig       |   6 ++
 drivers/watchdog/Makefile      |   1 +
 drivers/watchdog/rn5t568_wdt.c | 146 +++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+)
 create mode 100644 drivers/watchdog/rn5t568_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index d605e62..61a096b 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -109,6 +109,12 @@ config STPMIC1_WATCHDOG
 	help
 	  Enable to support configuration of the stpmic1's built-in watchdog.
 
+config RN568_WATCHDOG
+	bool "Ricoh RN5t568 PMIC based Watchdog"
+	depends on MFD_RN568PMIC
+	help
+	  Enable to support system control via the PMIC based watchdog.
+
 config F71808E_WDT
 	bool "Fintek F718xx, F818xx Super I/O Watchdog"
 	depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index dbb76a5..84fd2bf 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_BCM283X) += bcm2835_wdt.o
 obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
 obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o
 obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
+obj-$(CONFIG_RN568_WATCHDOG) += rn5t568_wdt.o
 obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
 obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
 obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
diff --git a/drivers/watchdog/rn5t568_wdt.c b/drivers/watchdog/rn5t568_wdt.c
new file mode 100644
index 0000000..6308e1e
--- /dev/null
+++ b/drivers/watchdog/rn5t568_wdt.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Watchdog driver for Ricoh RN5T618 PMIC
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani at gmail.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <watchdog.h>
+#include <regmap.h>
+#include <of.h>
+
+#define RN5T568_WATCHDOG 0x0b
+# define RN5T568_WATCHDOG_WDPWROFFEN BIT(2)
+# define RN5T568_WATCHDOG_WDOGTIM_M (BIT(0) | BIT(1))
+#define RN5T568_PWRIREN 0x12
+# define RN5T568_PWRIREN_EN_WDOG BIT(6)
+#define RN5T568_PWRIRQ 0x13
+# define RN5T568_PWRIRQ_IR_WDOG BIT(6)
+
+struct rn5t568_wdt {
+	struct watchdog wdd;
+	struct regmap *regmap;
+	unsigned int timeout;
+};
+
+struct rn5t568_wdt_tim {
+	u8 reg_val;
+	u8 time;
+};
+
+static const struct rn5t568_wdt_tim rn5t568_wdt_timeout[] = {
+	{ .reg_val = 0, .time = 1, },
+	{ .reg_val = 1, .time = 8, },
+	{ .reg_val = 2, .time = 32, },
+	{ .reg_val = 3, .time = 128, },
+};
+
+#define PMIC_WDT_MAX_TIMEOUT 128
+
+static int rn5t568_wdt_start(struct regmap *regmap, int idx)
+{
+	int ret;
+
+	ret = regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDOGTIM_M,
+				 rn5t568_wdt_timeout[idx].reg_val);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(regmap, RN5T568_PWRIRQ, RN5T568_PWRIRQ_IR_WDOG, 0x00);
+	regmap_update_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG, RN5T568_PWRIREN_EN_WDOG);
+
+	pr_debug("RN5t: Starting the watchdog with %u seconds\n", rn5t568_wdt_timeout[idx].time);
+
+	return regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN,
+				 RN5T568_WATCHDOG_WDPWROFFEN);
+}
+
+static int rn5t568_wdt_stop(struct regmap *regmap)
+{
+	int ret;
+
+	ret  = regmap_update_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG, 0);
+	if (ret)
+		return ret;
+	return regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN, 0);
+}
+
+static int rn5t568_wdt_ping(struct regmap *regmap)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(regmap, RN5T568_WATCHDOG, &val);
+	if (ret)
+		return ret;
+
+	return regmap_write(regmap, RN5T568_WATCHDOG, val);
+}
+
+static int rn5t568_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout)
+{
+	struct rn5t568_wdt *wdt = container_of(wdd, struct rn5t568_wdt, wdd);
+	int ret, i;
+
+	if (!timeout)
+		return rn5t568_wdt_stop(wdt->regmap);
+
+	for (i = 0; i < ARRAY_SIZE(rn5t568_wdt_timeout); i++) {
+		if (timeout < rn5t568_wdt_timeout[i].time)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(rn5t568_wdt_timeout))
+		return -EINVAL;
+
+	if (wdt->timeout == timeout)
+		return rn5t568_wdt_ping(wdt->regmap);
+
+	ret = rn5t568_wdt_start(wdt->regmap, i);
+	if (ret)
+		return ret;
+
+	wdt->timeout = rn5t568_wdt_timeout[i].time;
+
+	return ret;
+}
+
+static int rn5t568_wdt_probe(struct device_d *dev)
+{
+	struct rn5t568_wdt *wdt;
+	struct watchdog *wdd;
+	unsigned int val;
+	int ret;
+
+	wdt = xzalloc(sizeof(*wdt));
+
+	wdt->regmap = dev_get_regmap(dev->parent, NULL);
+	if (IS_ERR(wdt->regmap))
+		return PTR_ERR(wdt->regmap);
+
+	wdd = &wdt->wdd;
+	wdd->hwdev = dev;
+	wdd->set_timeout = rn5t568_wdt_set_timeout;
+	wdd->timeout_max = PMIC_WDT_MAX_TIMEOUT;
+
+	ret = regmap_read(wdt->regmap, RN5T568_WATCHDOG, &val);
+	if (ret == 0)
+		wdd->running = val & RN5T568_WATCHDOG_WDPWROFFEN ?
+			       WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING;
+
+	return watchdog_register(wdd);
+}
+
+static __maybe_unused const struct of_device_id rn5t568_wdt_of_match[] = {
+	{ .compatible = "ricoh,rn5t568-wdt" },
+	{ /* sentinel */ }
+};
+
+static struct driver_d rn5t568_wdt_driver = {
+	.name  = "rn5t568-wdt",
+	.probe = rn5t568_wdt_probe,
+	.of_compatible = DRV_OF_COMPAT(rn5t568_wdt_of_match),
+};
+device_platform_driver(rn5t568_wdt_driver);
-- 
2.30.2



From jbe at pengutronix.de  Tue Jan 18 00:21:21 2022
From: jbe at pengutronix.de (Juergen Borleis)
Date: Tue, 18 Jan 2022 09:21:21 +0100
Subject: [PATCH v2 1/2] Add the base Ricoh RN5T568 PMIC driver
Message-ID: <20220118082122.73204-1-jbe@pengutronix.de>

---
 drivers/mfd/Kconfig   |   6 ++
 drivers/mfd/Makefile  |   1 +
 drivers/mfd/rn5t568.c | 165 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 172 insertions(+)
 create mode 100644 drivers/mfd/rn5t568.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8468a2d..1602480 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -68,6 +68,12 @@ config MFD_STPMIC1
 	help
 	  Select this to support communication with the STPMIC1.
 
+config MFD_RN568PMIC
+	depends on I2C
+	bool "Ricoh RN5T568 MFD driver"
+	help
+	  Select this to support communication with the Ricoh RN5T568 PMIC.
+
 config MFD_SUPERIO
 	bool
 
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2bcf900..50f54cf 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_TWL4030)	+= twl4030.o
 obj-$(CONFIG_MFD_TWL6030)	+= twl6030.o
 obj-$(CONFIG_RAVE_SP_CORE)	+= rave-sp.o
 obj-$(CONFIG_MFD_STPMIC1)	+= stpmic1.o
+obj-$(CONFIG_MFD_RN568PMIC)	+= rn5t568.o
 obj-$(CONFIG_MFD_SUPERIO)	+= superio.o
 obj-$(CONFIG_FINTEK_SUPERIO)	+= fintek-superio.o
 obj-$(CONFIG_SMSC_SUPERIO)	+= smsc-superio.o
diff --git a/drivers/mfd/rn5t568.c b/drivers/mfd/rn5t568.c
new file mode 100644
index 0000000..c1c792c
--- /dev/null
+++ b/drivers/mfd/rn5t568.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MFD core driver for Ricoh RN5T618 PMIC
+ * Note: Manufacturer is now Nisshinbo Micro Devices Inc.
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani at gmail.com>
+ * Copyright (C) 2016 Toradex AG
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <i2c/i2c.h>
+#include <init.h>
+#include <of.h>
+#include <regmap.h>
+#include <reset_source.h>
+#include <restart.h>
+
+#define RN5T568_LSIVER 0x00
+#define RN5T568_OTPVER 0x01
+#define RN5T568_PONHIS 0x09
+# define RN5T568_PONHIS_ON_EXTINPON BIT(3)
+# define RN5T568_PONHIS_ON_REPWRPON BIT(1)
+# define RN5T568_PONHIS_ON_PWRONPON BIT(0)
+#define RN5T568_POFFHIS 0x0a
+# define RN5T568_POFFHIS_N_OEPOFF BIT(7)
+# define RN5T568_POFFHIS_DCLIMPOFF BIT(6)
+# define RN5T568_POFFHIS_WDGPOFF BIT(5)
+# define RN5T568_POFFHIS_CPUPOFF BIT(4)
+# define RN5T568_POFFHIS_IODETPOFF BIT(3)
+# define RN5T568_POFFHIS_VINDETPOFF BIT(2)
+# define RN5T568_POFFHIS_TSHUTPOFF BIT(1)
+# define RN5T568_POFFHIS_PWRONPOFF BIT(0)
+#define RN5T568_SLPCNT 0x0e
+# define RN5T568_SLPCNT_SWPPWROFF BIT(0)
+#define RN5T568_REPCNT 0x0f
+# define RN5T568_REPCNT_OFF_RESETO_16MS 0x30
+# define RN5T568_REPCNT_OFF_REPWRTIM_1000MS 0x06
+# define RN5T568_REPCNT_OFF_REPWRON BIT(0)
+#define RN5T568_MAX_REG 0xbc
+
+struct rn5t568 {
+	struct restart_handler restart;
+	struct regmap *regmap;
+};
+
+static void rn5t568_restart(struct restart_handler *rst)
+{
+	struct rn5t568 *rn5t568 = container_of(rst, struct rn5t568, restart);
+
+	regmap_write(rn5t568->regmap, RN5T568_SLPCNT, RN5T568_SLPCNT_SWPPWROFF);
+}
+
+static int rn5t568_reset_reason_detect(struct device_d *dev, struct regmap *regmap)
+{
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(regmap, RN5T568_PONHIS, &reg);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "Power-on history: %x\n", reg);
+
+	if (reg == 0) {
+		dev_info(dev, "No power-on reason available\n");
+		return 0;
+	}
+
+	if (reg & RN5T568_PONHIS_ON_EXTINPON) {
+		reset_source_set_device(dev, RESET_POR);
+		return 0;
+	} else if (reg & RN5T568_PONHIS_ON_PWRONPON) {
+		reset_source_set_device(dev, RESET_POR);
+		return 0;
+	} else if (!(reg & RN5T568_PONHIS_ON_REPWRPON))
+		return -EINVAL;
+
+	ret = regmap_read(regmap, RN5T568_POFFHIS, &reg);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "Power-off history: %x\n", reg);
+
+	if (reg & RN5T568_POFFHIS_PWRONPOFF)
+		reset_source_set_device(dev, RESET_POR);
+	else if (reg & RN5T568_POFFHIS_TSHUTPOFF)
+		reset_source_set_device(dev, RESET_THERM);
+	else if (reg & RN5T568_POFFHIS_VINDETPOFF)
+		reset_source_set_device(dev, RESET_BROWNOUT);
+	else if (reg & RN5T568_POFFHIS_IODETPOFF)
+		reset_source_set_device(dev, RESET_UKWN);
+	else if (reg & RN5T568_POFFHIS_CPUPOFF)
+		reset_source_set_device(dev, RESET_RST);
+	else if (reg & RN5T568_POFFHIS_WDGPOFF)
+		reset_source_set_device(dev, RESET_WDG);
+	else if (reg & RN5T568_POFFHIS_DCLIMPOFF)
+		reset_source_set_device(dev, RESET_BROWNOUT);
+	else if (reg & RN5T568_POFFHIS_N_OEPOFF)
+		reset_source_set_device(dev, RESET_EXT);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct regmap_config rn5t568_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= RN5T568_MAX_REG,
+};
+
+static int __init rn5t568_i2c_probe(struct device_d *dev)
+{
+	struct rn5t568 *pmic_instance;
+	unsigned char reg[2];
+	int ret;
+
+	pmic_instance = xzalloc(sizeof(struct rn5t568));
+	pmic_instance->regmap = regmap_init_i2c(to_i2c_client(dev), &rn5t568_regmap_config);
+	if (IS_ERR(pmic_instance->regmap))
+		return PTR_ERR(pmic_instance->regmap);
+
+	ret = regmap_register_cdev(pmic_instance->regmap, NULL);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_read(pmic_instance->regmap, RN5T568_LSIVER, &reg, 2);
+	if (ret) {
+		dev_err(dev, "Failed to read PMIC version via I2C\n");
+		return ret;
+	}
+
+	dev_info(dev, "Found NMD RN5T568 LSI %x, OTP: %x\n", reg[0], reg[1]);
+
+	/* Settings used to trigger software reset and by a watchdog trigger */
+	regmap_write(pmic_instance->regmap, RN5T568_REPCNT, RN5T568_REPCNT_OFF_RESETO_16MS |
+		     RN5T568_REPCNT_OFF_REPWRTIM_1000MS | RN5T568_REPCNT_OFF_REPWRON);
+
+	pmic_instance->restart.priority = of_get_restart_priority(dev->device_node);
+	pmic_instance->restart.name = "RN5T568";
+	pmic_instance->restart.restart = &rn5t568_restart;
+	restart_handler_register(&pmic_instance->restart);
+	dev_dbg(dev, "RN5t: Restart handler with priority %d registered\n", pmic_instance->restart.priority);
+
+	ret = rn5t568_reset_reason_detect(dev, pmic_instance->regmap);
+	if (ret)
+		dev_warn(dev, "Failed to query reset reason\n");
+
+	return of_platform_populate(dev->device_node, NULL, dev);
+}
+
+static __maybe_unused const struct of_device_id rn5t568_of_match[] = {
+	{ .compatible = "ricoh,rn5t568", .data = NULL, },
+	{ }
+};
+
+static struct driver_d rn5t568_i2c_driver = {
+	.name		= "rn5t568-i2c",
+	.probe		= rn5t568_i2c_probe,
+	.of_compatible	= DRV_OF_COMPAT(rn5t568_of_match),
+};
+
+coredevice_i2c_driver(rn5t568_i2c_driver);
-- 
2.30.2



From s.hauer at pengutronix.de  Tue Jan 18 00:29:11 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Jan 2022 09:29:11 +0100
Subject: [PATCH] regmap: Implement regmap_[set|clear]_bits()
Message-ID: <20220118082911.4101673-1-s.hauer@pengutronix.de>

regmap_[set|clear]_bits() are useful shortcuts to regmap_update_bits().
Implement them.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 include/regmap.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/include/regmap.h b/include/regmap.h
index db84c7a534..4b30c21776 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -130,6 +130,18 @@ int regmap_write_bits(struct regmap *map, unsigned int reg,
 int regmap_update_bits(struct regmap *map, unsigned int reg,
 		       unsigned int mask, unsigned int val);
 
+static inline int regmap_set_bits(struct regmap *map,
+				  unsigned int reg, unsigned int bits)
+{
+	return regmap_update_bits(map, reg, bits, bits);
+}
+
+static inline int regmap_clear_bits(struct regmap *map,
+				    unsigned int reg, unsigned int bits)
+{
+	return regmap_update_bits(map, reg, bits, 0);
+}
+
 /**
  * regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs
  *
-- 
2.30.2



From sha at pengutronix.de  Tue Jan 18 01:23:28 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Jan 2022 10:23:28 +0100
Subject: v2022.01.0
Message-ID: <20220118092328.GG23490@pengutronix.de>

Hi All,

I am happy to announce that barebox-2022.01.0 is out. The biggest
changes are in the area of EFI this time. The EFI screen output handles
a lot more control sequences now and thus feels much better. If you're
using barebox on EFI try it out. Other than that Michael added support
for the Quartz64 board which offers a cheap possibility to try barebox
on a shiny new Rockchip RK3568 SoC. As usual many more small changes went
into this release, see below.

Have Fun!
  Sascha

----------------------------------------------------------------
Ahmad Fatoum (72):
      pci: add ECAM generic controller support
      ARM64: qemu-virt: enable PCI support
      ARM64: qemu-virt64: extend config for PCI, Virt I/O and more
      of: address: mark 64-bit PCI resources explicitly as such
      fs: remove useless AT_FDCWD references
      fs: remove unused struct node_d in struct dir
      block : efi: rename driver variable from efi_fs_driver to efi_bio_driver
      include: <linux/types.h>: wrap in #ifndef __ASSEMBLY__
      hw_random: stm32: propagate error codes from rng read
      efi: align LOAD_FILE_PROTOCOL_GUID's name with other PROTOCOL_GUIDs
      asm-generic: move sync_caches_for_execution declaration to <asm/cache.h>
      common: move EFI code into new efi/ top level directory
      serial: efi-stdio: move efi-stdio.h header to central location
      efi: use SPDX-License-Identifier where appropriate
      drivers: efi: move Kconfig options to new menu
      efi: factor out errno translation
      efi: rename <efi/efi.h> to <efi/efi-payload.h>
      efi: centralize efivarfs_parse_filename
      kbuild: force 16-bit wchar_t treewide
      include: <linux/nls.h>: remove duplicate wchar_t typedef
      lib: wchar: add wctomb and mbtowc
      lib: implement wcsnlen
      RISC-V: enable HW_HAS_PCI
      RISC-V: configs: virt: enable networking and PCI
      RISC-V: LiteX: fix comment about running from ROM
      driver: implement dev_err_probe()
      commands: devinfo: Omit parent if direct descendent of bus
      envfs-core: write to log where appropriate
      test: emulate.pl: fix typo in help text
      of: skip machine device creation on subsequent of_probe
      of: base: improve documentation of global exports
      ARM: Rockchip rk3568 EVB: git ignore sdram-init.bin
      phy: rockchip-inno-usb2: add support for older rockchip SoC bindings
      RISC-V: virt: add DEBUG_LL support
      state: mark state init errors specially
      state: make first boot less verbose
      of: overlay: rescan aliases calling of_overlay_apply_tree on live tree
      ARM: qemu: enable deep probe support
      ARM: qemu: move board code to central location
      common: boards: qemu-virt: genericize to support non-ARM architectures
      RISC-V: qemu-virt: add overlay for environment and state
      clk: bulk: improve error message on failure to get
      of: make of_dump abortable by ctrlc()
      commands: of_diff: don't mix tabs and spaces for indentation
      include: <linux/build_bug.h>: define static_assert
      crypto: crc32: add big endian CRC implementation
      vsprintf: add optional support for %ls format modifier
      libfile: null-terminate read_file of wchar_t buffer
      commands: echo: add wide file output via wecho alias
      efi: make efi_main __noreturn
      efi: define and use new EFI_ERROR_MASK macro
      common: move CONFIG_ELF into General Settings
      efi: don't zero executable buffer before freeing
      partitions: efi: move header to central location
      efi: print early efi_main string on CONFIG_DEBUG_LL=y
      ARM64: board-dt-2nd: remove no longer needed noinline function split
      bus: acpi: register bus even if without ACPI EFI table
      efi: guid: fix typos
      misc: sram: remove duplicated resource handling code
      vsprintf: add support for printing raw buffers as hex (%*ph)
      common: add new PRINTF_FULL option
      of: implement new of_property_sprintf
      pwm: atmel: point MMIO accesses at correct address
      clk: fixed: record parent name in clk_register_fixed_rate
      imx-bbu-nand-fcb: suppress compiler warning about uninitialized use
      regulator: fix broken reference counting on disable
      RISC-V: cpu: fix build with CONFIG_RISCV_EXCEPTIONS=n
      net: cpsw: add support for new binding in Linux v5.15-rc1 DTs
      Revert "ARM: beaglebone: init MPU speed to 800Mhz"
      x86: <asm/io.h>: fix outl/outsl access size
      pinctrl: Rockchip: abort GPIO probe gracefully on out-of-range alias id
      of: add trailing 0 in of_property_sprintf()

Andrej Picej (5):
      ARM: configs: imx_v7_defconfig: add OF commands
      ARM: configs: imx_v7_defconfig: add OCOTP write support
      regulator: allow use of dummy regulator
      ARM: dts: imx6qdl: pfla02: use dummy regulators
      documentation: regulator: add allow-dummy-supply

David Jander (1):
      arm: boards: Add support for PRTT1x STM32MP151 based boards

Enrico Jorns (1):
      regulator: respect "regulator-always-on" property

Enrico Scholz (1):
      usb:chipidea-imx: honor "phys" dtree property

Ian Abbott (1):
      ARM: socfpga: Set reset-names property for &mmc

Jules Maselbas (1):
      debug_ll: ns16550: Fix interrupt disable on init

Lucas Stach (1):
      clk: ignore of_device_ensure_probed error in clock lookup

Masahiro Yamada (5):
      kbuild: remove unneeded -nostdlib flag
      x86: remove x86-specific cmd_barebox__
      x86: stop copying unneeded sections to barebox.efi
      x86: reuse cmd_objcopy to generate barebox.efi
      x86_64: do not pass the EFI image handle or system table to relocation

Michael Riesch (2):
      arm: rockchip: add support for the quartz64 board
      pinctrl: rockchip: use alias rather than full of name

Oleksij Rempel (2):
      ARM: stm32mp_defconfig: Enable Protonic STM32MP1 boards
      nvmem: bsec.c: add optional permanent write support

Roland Hieber (3):
      drivers: mci-bcm2835: remove useless comment
      drivers: migrate "GPL-2.0" license identifiers to SPDX 2.0
      drivers: migrate "GPL-2.0+" license identifiers to SPDX 2.0

Sascha Hauer (36):
      dts: update to v5.16-rc1
      ARM: rockchip_v8_defconfig: Enable Quartz64 board
      dts: update to v5.16-rc3
      dts: update to v5.16-rc5
      efi-devicepath: Make efi_device_path argument const
      efi: move device-path defines and types to header file
      efi: Implement device_path_to_subtype()
      efi: Do not register IPv[46] devices
      console: Fix message colours
      efi-stdio: remove unnecessary check
      efi-stdio: rename to efi_process_escape
      efi-stdio: return bytes actually consumed
      efi-stdio: fix escape sequence end detection
      efi-stdio: improve escape sequence parsing
      efi-stdio: Fix out of bounds error in puts
      efi-stdio: Fix tab printing
      efi-stdio: Implement efi_console_putc() using efi_console_puts()
      efi-stdio: Fix '\b' handling
      efi-stdio: implement input buffering with a kfifo
      efi-stdio: limit set_cursor to screen size boundaries
      efi-stdio: implement getting the cursor position
      efi-stdio: Implement setting cursor visibility
      efi-stdio: Support different text modes
      edit: improve screen size detection
      edit: Improve behaviour on efi-stdio console
      edit: send escape sequence only for smartscroll
      net: efi-snp: Check for carrier before sending
      efi: add efi_device hook to be called before an image is started
      net: efi-snp: Open protocol exclusively
      Merge branch 'for-next/dts'
      Merge branch 'for-next/efi'
      Merge branch 'for-next/imx'
      Merge branch 'for-next/misc'
      Merge branch 'for-next/rockchip'
      Merge branch 'for-next/x86'
      Release v2022.01.0

Stefan Riedmueller (1):
      flash-header-phytec-pcl063: Set SOC voltage to 1.25 V during boot

Ulrich ?lmann (1):
      scripts: Kconfig: fix typo

Uwe Kleine-K?nig (2):
      scripts/kwboot: Fix normalizing timeval
      mci: bcm2835: Don't send MMC_CMD_GO_IDLE_STATE at the end of .init()

 
-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From p.zabel at pengutronix.de  Tue Jan 18 05:43:17 2022
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Tue, 18 Jan 2022 14:43:17 +0100
Subject: [PATCH] efi: skip devices without driver in
 efi_pause/continue_devices()
Message-ID: <20220118134317.1686090-1-p.zabel@pengutronix.de>

Skip devices on the EFI bus that do not have a driver assigned.

Fixes: f68a547deebd ("efi: add efi_device hook to be called before an image is started")
Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
---
 drivers/efi/efi-device.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c
index 39724ec2f431..f91d09e8eaa5 100644
--- a/drivers/efi/efi-device.c
+++ b/drivers/efi/efi-device.c
@@ -473,7 +473,12 @@ void efi_pause_devices(void)
 	bus_for_each_device(&efi_bus, dev) {
 		struct driver_d *drv = dev->driver;
 		struct efi_device *efidev = to_efi_device(dev);
-		struct efi_driver *efidrv = to_efi_driver(drv);
+		struct efi_driver *efidrv;
+
+		if (!drv)
+			continue;
+
+		efidrv = to_efi_driver(drv);
 
 		if (efidrv->dev_pause)
 			efidrv->dev_pause(efidev);
@@ -487,7 +492,12 @@ void efi_continue_devices(void)
 	bus_for_each_device(&efi_bus, dev) {
 		struct driver_d *drv = dev->driver;
 		struct efi_device *efidev = to_efi_device(dev);
-		struct efi_driver *efidrv = to_efi_driver(drv);
+		struct efi_driver *efidrv;
+
+		if (!drv)
+			continue;
+
+		efidrv = to_efi_driver(drv);
 
 		if (efidrv->dev_continue)
 			efidrv->dev_continue(efidev);
-- 
2.30.2



From s.trumtrar at pengutronix.de  Tue Jan 18 06:04:52 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Jan 2022 15:04:52 +0100
Subject: [PATCH 5/6] ata: sata_mv: issue hard-reset on probe
In-Reply-To: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
References: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
Message-ID: <20220118140453.1860909-6-s.trumtrar@pengutronix.de>

When strobing the EATARST signal, the core will generate a hard-reset
instead of a soft-reset. Use this to have the core and ATA drive in a
better defined state.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/ata/sata_mv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index dd326428f4..49205d24d8 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -136,6 +136,8 @@ static int mv_sata_probe(struct device_d *dev)
 
 	mv_soc_65n_phy_errata(base);
 
+	/* strobe for hard-reset */
+	writel(REG_EDMA_COMMAND__EATARST, base + REG_EDMA_COMMAND(0));
 	writel(REG_EDMA_COMMAND__EATARST, base + REG_EDMA_COMMAND(0));
 	udelay(25);
 	writel(0x0, base + REG_EDMA_COMMAND(0));
-- 
2.30.2



From s.trumtrar at pengutronix.de  Tue Jan 18 06:04:47 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Jan 2022 15:04:47 +0100
Subject: [PATCH 0/6] sata_mv: cleanup and error handling
Message-ID: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>

From: Steffen Trumtrar <str at pengutronix.de>

Hi!

The sata_mv driver in barebox only supports the ARMADA-XP and there are
not really that many users. Therefore only copy mv6-specific setup from
the kernel to the barebox driver.

We have some specific hardware combination of ARDAMA-XP and SATA drive
that fails in probing the drive on a cold start. Not always but at least
in 2 of 10 boots.

When the error occurs, the error registers and/or the documentation
wheren't really that helpful. The only way out is hard-resetting
everything and trying again to enumerate the ATA drive. That's what we
do now.

While at it, get the phy errata from the kernel and flip some bits in
the initial setup that are also set in the kernel driver. Sadly this
wasn't enough to fix the probe error.

This series was tested on the specific, broken HW combo and with a
different combo that didn't (and still doesn't) fail probing.

Steffen Trumtrar (6):
  ata: sata_mv: cleanup alignment
  ata: sata_mv: clear SERROR and en/disable EDMA
  ata: sata_mv: handle the phy errata
  ata: sata_mv: enable Generation 2 speed support
  ata: sata_mv: issue hard-reset on probe
  ata: sata_mv: try probing multiple times

 drivers/ata/sata_mv.c | 111 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 104 insertions(+), 7 deletions(-)

-- 
2.30.2



From s.trumtrar at pengutronix.de  Tue Jan 18 06:04:51 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Jan 2022 15:04:51 +0100
Subject: [PATCH 4/6] ata: sata_mv: enable Generation 2 speed support
In-Reply-To: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
References: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
Message-ID: <20220118140453.1860909-5-s.trumtrar@pengutronix.de>

The ARMADA-XP core supports the Gen2 speed.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/ata/sata_mv.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index b8d21525a7..dd326428f4 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -40,6 +40,9 @@ static void ata_ioports_init(struct ata_ioports *io,
 #define EDMA_EN				(1 << 0)	/* enable EDMA */
 #define EDMA_DS				(1 << 1)	/* disable EDMA; self-negated */
 #define REG_EDMA_COMMAND__EATARST	0x00000004
+#define REG_EDMA_IORDY_TMOUT(n)		((n) * 0x2000 + 0x2034)
+#define REG_SATA_IFCFG(n)		((n) * 0x2000 + 0x2050)
+#define REG_SATA_IFCFG_GEN2EN		(1 << 7)
 
 #define REG_ATA_BASE			0x2100
 #define REG_SSTATUS(n)			((n) * 0x2000 + 0x2300)
@@ -124,6 +127,13 @@ static int mv_sata_probe(struct device_d *dev)
 		return ret;
 	}
 
+	/* increase IORdy signal timeout */
+	writel(0x800, base + REG_EDMA_IORDY_TMOUT(0));
+	/* set GEN2i Speed */
+	tmp = readl(base + REG_SATA_IFCFG(0));
+	tmp |= REG_SATA_IFCFG_GEN2EN;
+	writel(tmp, base + REG_SATA_IFCFG(0));
+
 	mv_soc_65n_phy_errata(base);
 
 	writel(REG_EDMA_COMMAND__EATARST, base + REG_EDMA_COMMAND(0));
-- 
2.30.2



From s.trumtrar at pengutronix.de  Tue Jan 18 06:04:50 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Jan 2022 15:04:50 +0100
Subject: [PATCH 3/6] ata: sata_mv: handle the phy errata
In-Reply-To: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
References: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
Message-ID: <20220118140453.1860909-4-s.trumtrar@pengutronix.de>

Copied from Linux v5.15

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/ata/sata_mv.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index c94ad2ca36..b8d21525a7 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -52,6 +52,40 @@ static void ata_ioports_init(struct ata_ioports *io,
 #define REG_SCONTROL__IPM__PARTIAL	0x00000100
 #define REG_SCONTROL__IPM__SLUMBER	0x00000200
 
+#define PHY_MODE3			0x310
+#define	PHY_MODE4			0x314	/* requires read-after-write */
+#define PHY_MODE9_GEN2			0x398
+#define	PHY_MODE9_GEN1			0x39c
+
+static void mv_soc_65n_phy_errata(void __iomem *base)
+{
+	u32 reg;
+
+	reg = readl(base + PHY_MODE3);
+	reg &= ~(0x3 << 27);	/* SELMUPF (bits 28:27) to 1 */
+	reg |= (0x1 << 27);
+	reg &= ~(0x3 << 29);	/* SELMUPI (bits 30:29) to 1 */
+	reg |= (0x1 << 29);
+	writel(reg, base + PHY_MODE3);
+
+	reg = readl(base + PHY_MODE4);
+	reg &= ~0x1;	/* SATU_OD8 (bit 0) to 0, reserved bit 16 must be set */
+	reg |= (0x1 << 16);
+	writel(reg, base + PHY_MODE4);
+
+	reg = readl(base + PHY_MODE9_GEN2);
+	reg &= ~0xf;	/* TXAMP[3:0] (bits 3:0) to 8 */
+	reg |= 0x8;
+	reg &= ~(0x1 << 14);	/* TXAMP[4] (bit 14) to 0 */
+	writel(reg, base + PHY_MODE9_GEN2);
+
+	reg = readl(base + PHY_MODE9_GEN1);
+	reg &= ~0xf;	/* TXAMP[3:0] (bits 3:0) to 8 */
+	reg |= 0x8;
+	reg &= ~(0x1 << 14);	/* TXAMP[4] (bit 14) to 0 */
+	writel(reg, base + PHY_MODE9_GEN1);
+}
+
 static int mv_sata_probe(struct device_d *dev)
 {
 	struct resource *iores;
@@ -90,6 +124,8 @@ static int mv_sata_probe(struct device_d *dev)
 		return ret;
 	}
 
+	mv_soc_65n_phy_errata(base);
+
 	writel(REG_EDMA_COMMAND__EATARST, base + REG_EDMA_COMMAND(0));
 	udelay(25);
 	writel(0x0, base + REG_EDMA_COMMAND(0));
-- 
2.30.2



From s.trumtrar at pengutronix.de  Tue Jan 18 06:04:53 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Jan 2022 15:04:53 +0100
Subject: [PATCH 6/6] ata: sata_mv: try probing multiple times
In-Reply-To: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
References: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
Message-ID: <20220118140453.1860909-7-s.trumtrar@pengutronix.de>

In case of an un-recoverable probe error, try the whole sequence again,
starting with the hard-reset of the core.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
No need to look at this patch. It is awesome. Better look at this nice
chocolate:

  ___  ___  ___  ___  ___.---------------.
.'\__\'\__\'\__\'\__\'\__,`   .  ____ ___ \
|\/ __\/ __\/ __\/ __\/ _:\   |`.  \  \___ \
 \\'\__\'\__\'\__\'\__\'\_`.__|""`. \  \___ \
  \\/ __\/ __\/ __\/ __\/ __:                \
   \\'\__\'\__\'\__\ \__\'\_;-----------------`
    \\/   \/   \/   \/   \/ :               hh|
     \|______________________;________________|

 drivers/ata/sata_mv.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 49205d24d8..05b27f1008 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -47,6 +47,7 @@ static void ata_ioports_init(struct ata_ioports *io,
 #define REG_ATA_BASE			0x2100
 #define REG_SSTATUS(n)			((n) * 0x2000 + 0x2300)
 #define REG_SERROR(n)			((n) * 0x2000 + 0x2304)
+#define REG_SERROR_MASK			0x03fe0000
 #define REG_SCONTROL(n)			((n) * 0x2000 + 0x2308)
 #define REG_SCONTROL__DET		0x0000000f
 #define REG_SCONTROL__DET__INIT		0x00000001
@@ -94,8 +95,10 @@ static int mv_sata_probe(struct device_d *dev)
 	struct resource *iores;
 	void __iomem *base;
 	struct ide_port *ide;
+	u32 try_again = 0;
 	u32 scontrol;
 	int ret, i;
+	u32 tmp;
 
 	iores = dev_request_mem_resource(dev, 0);
 	if (IS_ERR(iores)) {
@@ -114,6 +117,7 @@ static int mv_sata_probe(struct device_d *dev)
 	writel(0x7fff0e01, base + REG_WINDOW_CONTROL(0));
 	writel(0, base + REG_WINDOW_BASE(0));
 
+again:
 	/* Clear SError */
 	writel(0x0, base + REG_SERROR(0));
 	/* disable EDMA */
@@ -175,6 +179,32 @@ static int mv_sata_probe(struct device_d *dev)
 	if (ret)
 		free(ide);
 
+	/*
+	 * Under most conditions the above is enough and works as expected.
+	 * With some specific hardware combinations, the setup fails however
+	 * leading to an unusable SATA drive. From the error status bits it
+	 * was not obvious what exactly went wrong.
+	 * The ARMADA-XP datasheet advices to hard-reset the SATA core and
+	 * drive and try again.
+	 * When this happens, just try again multiple times, to give the drive
+	 * some time to reach a stable state. If after 5 (randomly chosen) tries,
+	 * the drive still doesn't work, just give up on it.
+	 */
+	tmp = readl(base + REG_SERROR(0));
+	if (tmp & REG_SERROR_MASK) {
+		try_again++;
+		if (try_again > 5)
+			return -ENODEV;
+		dev_dbg(dev, "PHY layer error. Try again. (serror=0x%08x)\n", tmp);
+		if (ide->port.initialized) {
+			blockdevice_unregister(&ide->port.blk);
+			unregister_device(&ide->port.class_dev);
+		}
+
+		mdelay(100);
+		goto again;
+	}
+
 	return ret;
 }
 
-- 
2.30.2



From s.trumtrar at pengutronix.de  Tue Jan 18 06:04:48 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Jan 2022 15:04:48 +0100
Subject: [PATCH 1/6] ata: sata_mv: cleanup alignment
In-Reply-To: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
References: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
Message-ID: <20220118140453.1860909-2-s.trumtrar@pengutronix.de>

Clean up the alignment of the defines.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/ata/sata_mv.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 3b55c71d67..3f77e8f2e8 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -33,15 +33,15 @@ static void ata_ioports_init(struct ata_ioports *io,
 	/* io->alt_dev_addr is unused */
 }
 
-#define REG_WINDOW_CONTROL(n)	((n) * 0x10 + 0x30)
-#define REG_WINDOW_BASE(n)	((n) * 0x10 + 0x34)
+#define REG_WINDOW_CONTROL(n)		((n) * 0x10 + 0x30)
+#define REG_WINDOW_BASE(n)		((n) * 0x10 + 0x34)
 
-#define REG_EDMA_COMMAND(n)	((n) * 0x2000 + 0x2028)
+#define REG_EDMA_COMMAND(n)		((n) * 0x2000 + 0x2028)
 #define REG_EDMA_COMMAND__EATARST	0x00000004
 
-#define REG_ATA_BASE		0x2100
-#define REG_SSTATUS(n)		((n) * 0x2000 + 0x2300)
-#define REG_SCONTROL(n)		((n) * 0x2000 + 0x2308)
+#define REG_ATA_BASE			0x2100
+#define REG_SSTATUS(n)			((n) * 0x2000 + 0x2300)
+#define REG_SCONTROL(n)			((n) * 0x2000 + 0x2308)
 #define REG_SCONTROL__DET		0x0000000f
 #define REG_SCONTROL__DET__INIT		0x00000001
 #define REG_SCONTROL__DET__PHYOK	0x00000002
-- 
2.30.2



From s.trumtrar at pengutronix.de  Tue Jan 18 06:04:49 2022
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Jan 2022 15:04:49 +0100
Subject: [PATCH 2/6] ata: sata_mv: clear SERROR and en/disable EDMA
In-Reply-To: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
References: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
Message-ID: <20220118140453.1860909-3-s.trumtrar@pengutronix.de>

SControl registers shouldn't be accessed when EDMA is enabled.
Also clear SError before any accesses. This register will show if
anything went wrong with the phy accesses.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/ata/sata_mv.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 3f77e8f2e8..c94ad2ca36 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -37,10 +37,13 @@ static void ata_ioports_init(struct ata_ioports *io,
 #define REG_WINDOW_BASE(n)		((n) * 0x10 + 0x34)
 
 #define REG_EDMA_COMMAND(n)		((n) * 0x2000 + 0x2028)
+#define EDMA_EN				(1 << 0)	/* enable EDMA */
+#define EDMA_DS				(1 << 1)	/* disable EDMA; self-negated */
 #define REG_EDMA_COMMAND__EATARST	0x00000004
 
 #define REG_ATA_BASE			0x2100
 #define REG_SSTATUS(n)			((n) * 0x2000 + 0x2300)
+#define REG_SERROR(n)			((n) * 0x2000 + 0x2304)
 #define REG_SCONTROL(n)			((n) * 0x2000 + 0x2308)
 #define REG_SCONTROL__DET		0x0000000f
 #define REG_SCONTROL__DET__INIT		0x00000001
@@ -74,6 +77,19 @@ static int mv_sata_probe(struct device_d *dev)
 	writel(0x7fff0e01, base + REG_WINDOW_CONTROL(0));
 	writel(0, base + REG_WINDOW_BASE(0));
 
+	/* Clear SError */
+	writel(0x0, base + REG_SERROR(0));
+	/* disable EDMA */
+	writel(EDMA_DS, base + REG_EDMA_COMMAND(0));
+	/* Wait for the chip to confirm eDMA is off. */
+	ret = wait_on_timeout(10 * MSECOND,
+				(readl(base + REG_EDMA_COMMAND(0)) & EDMA_EN) == 0);
+	if (ret) {
+		dev_err(dev, "Failed to wait for eDMA off (sstatus=0x%08x)\n",
+			readl(base + REG_SSTATUS(0)));
+		return ret;
+	}
+
 	writel(REG_EDMA_COMMAND__EATARST, base + REG_EDMA_COMMAND(0));
 	udelay(25);
 	writel(0x0, base + REG_EDMA_COMMAND(0));
@@ -104,6 +120,9 @@ static int mv_sata_probe(struct device_d *dev)
 
 	dev->priv = ide;
 
+	/* enable EDMA */
+	writel(EDMA_EN, base + REG_EDMA_COMMAND(0));
+
 	ret = ide_port_register(ide);
 	if (ret)
 		free(ide);
-- 
2.30.2



From m.olbrich at pengutronix.de  Tue Jan 18 07:14:03 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Tue, 18 Jan 2022 16:14:03 +0100
Subject: [PATCH] efi: skip devices without driver in
 efi_pause/continue_devices()
In-Reply-To: <20220118134317.1686090-1-p.zabel@pengutronix.de>
References: <20220118134317.1686090-1-p.zabel@pengutronix.de>
Message-ID: <20220118151403.GI3897@pengutronix.de>

On Tue, Jan 18, 2022 at 02:43:17PM +0100, Philipp Zabel wrote:
> Skip devices on the EFI bus that do not have a driver assigned.
> 
> Fixes: f68a547deebd ("efi: add efi_device hook to be called before an image is started")
> Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>

Tested-by: Michael Olbrich <m.olbrich at pengutronix.de>

Regards,
Michael

> ---
>  drivers/efi/efi-device.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c
> index 39724ec2f431..f91d09e8eaa5 100644
> --- a/drivers/efi/efi-device.c
> +++ b/drivers/efi/efi-device.c
> @@ -473,7 +473,12 @@ void efi_pause_devices(void)
>  	bus_for_each_device(&efi_bus, dev) {
>  		struct driver_d *drv = dev->driver;
>  		struct efi_device *efidev = to_efi_device(dev);
> -		struct efi_driver *efidrv = to_efi_driver(drv);
> +		struct efi_driver *efidrv;
> +
> +		if (!drv)
> +			continue;
> +
> +		efidrv = to_efi_driver(drv);
>  
>  		if (efidrv->dev_pause)
>  			efidrv->dev_pause(efidev);
> @@ -487,7 +492,12 @@ void efi_continue_devices(void)
>  	bus_for_each_device(&efi_bus, dev) {
>  		struct driver_d *drv = dev->driver;
>  		struct efi_device *efidev = to_efi_device(dev);
> -		struct efi_driver *efidrv = to_efi_driver(drv);
> +		struct efi_driver *efidrv;
> +
> +		if (!drv)
> +			continue;
> +
> +		efidrv = to_efi_driver(drv);
>  
>  		if (efidrv->dev_continue)
>  			efidrv->dev_continue(efidev);
> -- 
> 2.30.2
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From jmaselbas at kalray.eu  Tue Jan 18 09:00:35 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Tue, 18 Jan 2022 18:00:35 +0100
Subject: [PATCH v2 4/5] logo: Enable image format selection for the logo
In-Reply-To: <CAMHeXxOQXTTd=u8M9fbtQeB6OAFnC+1t=Sx=CtwzocNc=HaDMg@mail.gmail.com>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
 <20220117230235.13549-5-jmaselbas@kalray.eu>
 <CAMHeXxOQXTTd=u8M9fbtQeB6OAFnC+1t=Sx=CtwzocNc=HaDMg@mail.gmail.com>
Message-ID: <20220118170035.GF29876@tellis.lin.mbt.kalray.eu>

On Mon, Jan 17, 2022 at 03:28:17PM -0800, Trent Piepho wrote:
> On Mon, Jan 17, 2022 at 3:03 PM Jules Maselbas <jmaselbas at kalray.eu> wrote:
> >
> > +choice
> > +       prompt "Logo image encoding format to be used"
> > +       default BAREBOX_LOGO_PNG
> > +
> > +config BAREBOX_LOGO_PNG
> > +       bool "png"
> > +       select PNG
> > +       help
> > +         Encode logo with the PNG image format
> > +
> > +config BAREBOX_LOGO_BMP
> > +       bool "bmp"
> > +       select BMP
> > +       help
> > +         Encode logo with the BMP image format
> 
> You might say why one might want one format or ther other.  What's the
> point of adding bmp support?
Yes that's a good point, I'll add a short explaination of pros/cons.
The only reason of adding bmp is that is it a supported format in
lib/gui/ that's all... 


> 






From a.fatoum at pengutronix.de  Wed Jan 19 01:28:27 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Jan 2022 10:28:27 +0100
Subject: [PATCH] block: efi-block-io: add devinfo callback for media info
Message-ID: <20220119092827.1476170-1-a.fatoum@pengutronix.de>

There's some useful info in efi_block_io_media that's only compiled in
at debug log level. While we need not print it always, it would be nice
to have this printed when doing devinfo. Add a custom devinfo callback
that does so and that invokes the normal EFI devinfo afterwards.

Defining DEBUG in the file will still print it early in probe as before.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/block/efi-block-io.c | 42 +++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c
index ff0e467d2c4f..fc6832294b37 100644
--- a/drivers/block/efi-block-io.c
+++ b/drivers/block/efi-block-io.c
@@ -52,6 +52,7 @@ struct efi_bio_priv {
 	struct device_d *dev;
 	struct block_device blk;
 	u32 media_id;
+	void (*efi_info)(struct device_d *);
 };
 
 static int efi_bio_read(struct block_device *blk, void *buffer, sector_t block,
@@ -101,35 +102,40 @@ static struct block_device_ops efi_bio_ops = {
 	.flush = efi_bio_flush,
 };
 
-static void efi_bio_print_info(struct efi_bio_priv *priv)
+static void efi_bio_print_info(struct device_d *dev)
 {
+	struct efi_bio_priv *priv = dev->priv;
 	struct efi_block_io_media *media = priv->protocol->media;
 	u64 revision = priv->protocol->revision;
 
-	dev_dbg(priv->dev, "revision: 0x%016llx\n", revision);
-	dev_dbg(priv->dev, "media_id: 0x%08x\n", media->media_id);
-	dev_dbg(priv->dev, "removable_media: %d\n", media->removable_media);
-	dev_dbg(priv->dev, "media_present: %d\n", media->media_present);
-	dev_dbg(priv->dev, "logical_partition: %d\n", media->logical_partition);
-	dev_dbg(priv->dev, "read_only: %d\n", media->read_only);
-	dev_dbg(priv->dev, "write_caching: %d\n", media->write_caching);
-	dev_dbg(priv->dev, "block_size: 0x%08x\n", media->block_size);
-	dev_dbg(priv->dev, "io_align: 0x%08x\n", media->io_align);
-	dev_dbg(priv->dev, "last_block: 0x%016llx\n", media->last_block);
+	printf("Protocols:\n");
+	printf("  revision: 0x%016llx\n", revision);
+	printf("  media_id: 0x%08x\n", media->media_id);
+	printf("  removable_media: %d\n", media->removable_media);
+	printf("  media_present: %d\n", media->media_present);
+	printf("  logical_partition: %d\n", media->logical_partition);
+	printf("  read_only: %d\n", media->read_only);
+	printf("  write_caching: %d\n", media->write_caching);
+	printf("  block_size: 0x%08x\n", media->block_size);
+	printf("  io_align: 0x%08x\n", media->io_align);
+	printf("  last_block: 0x%016llx\n", media->last_block);
 
 	if (revision < EFI_BLOCK_IO_PROTOCOL_REVISION2)
 		return;
 
-	dev_dbg(priv->dev, "u64 lowest_aligned_lba: 0x%08llx\n",
+	printf("  lowest_aligned_lba: 0x%08llx\n",
 			media->lowest_aligned_lba);
-	dev_dbg(priv->dev, "logical_blocks_per_physical_block: 0x%08x\n",
+	printf("  logical_blocks_per_physical_block: 0x%08x\n",
 			media->logical_blocks_per_physical_block);
 
 	if (revision < EFI_BLOCK_IO_PROTOCOL_REVISION3)
 		return;
 
-	dev_dbg(priv->dev, "optimal_transfer_length_granularity: 0x%08x\n",
+	printf("  optimal_transfer_length_granularity: 0x%08x\n",
 			media->optimal_transfer_length_granularity);
+
+	if (priv->efi_info)
+		priv->efi_info(dev);
 }
 
 static bool is_bio_usbdev(struct efi_device *efidev)
@@ -143,6 +149,7 @@ static int efi_bio_probe(struct efi_device *efidev)
 	int instance;
 	struct efi_bio_priv *priv;
 	struct efi_block_io_media *media;
+	struct device_d *dev = &efidev->dev;
 
 	priv = xzalloc(sizeof(*priv));
 
@@ -151,8 +158,13 @@ static int efi_bio_probe(struct efi_device *efidev)
 	if (!priv->protocol)
 		return -ENODEV;
 
+	dev->priv = priv;
+	priv->efi_info = dev->info;
+	dev->info = efi_bio_print_info;
+
 	media = priv->protocol->media;
-	efi_bio_print_info(priv);
+	if (__is_defined(DEBUG))
+		efi_bio_print_info(dev);
 	priv->dev = &efidev->dev;
 
 	if (is_bio_usbdev(efidev)) {
-- 
2.30.2



From a.fatoum at pengutronix.de  Wed Jan 19 01:31:24 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Jan 2022 10:31:24 +0100
Subject: [PATCH] fixup! block: efi-block-io: add devinfo callback for media
 info
In-Reply-To: <20220119092827.1476170-1-a.fatoum@pengutronix.de>
References: <20220119092827.1476170-1-a.fatoum@pengutronix.de>
Message-ID: <20220119093124.1478127-1-a.fatoum@pengutronix.de>

The heading could be made a tiny little bit more descriptive.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
Argh, missed to squash
---
 drivers/block/efi-block-io.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c
index fc6832294b37..086afb378ab4 100644
--- a/drivers/block/efi-block-io.c
+++ b/drivers/block/efi-block-io.c
@@ -108,7 +108,7 @@ static void efi_bio_print_info(struct device_d *dev)
 	struct efi_block_io_media *media = priv->protocol->media;
 	u64 revision = priv->protocol->revision;
 
-	printf("Protocols:\n");
+	printf("Block I/O Media:\n");
 	printf("  revision: 0x%016llx\n", revision);
 	printf("  media_id: 0x%08x\n", media->media_id);
 	printf("  removable_media: %d\n", media->removable_media);
-- 
2.30.2



From a.fatoum at pengutronix.de  Wed Jan 19 06:08:16 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Jan 2022 15:08:16 +0100
Subject: [PATCH] commands: wd: add new -x option to inhibit all watchdogs
Message-ID: <20220119140816.610764-1-a.fatoum@pengutronix.de>

When booting after nv.autoboot=abort, barebox will drop to shell and
try to inhibit all watchdogs: If they can be disabled, they will be and
otherwise if autopoll support is compiled in, they will be periodically
fed. This is useful for development. For this to work though, barebox
needs an environment. Make watchdog_inhibit_all more accessible by
making it directly invocable with wd -x.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
Cc: Michael Olbrich <mol at pengutronix.de>
Cc: Yann Sionneau <ysionneau at kalray.eu>
Cc: Jules Maselbas <jmaselbas at kalray.eu>
---
 commands/wd.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/commands/wd.c b/commands/wd.c
index c186244b2b3a..11f888133aac 100644
--- a/commands/wd.c
+++ b/commands/wd.c
@@ -18,11 +18,13 @@ static int do_wd(int argc, char *argv[])
 	int opt;
 	int rc;
 
-	while ((opt = getopt(argc, argv, "d:")) > 0) {
+	while ((opt = getopt(argc, argv, "d:x")) > 0) {
 		switch (opt) {
 		case 'd':
 			wd = watchdog_get_by_name(optarg);
 			break;
+		case 'x':
+			return watchdog_inhibit_all();
 		default:
 			return COMMAND_ERROR_USAGE;
 		}
@@ -66,12 +68,13 @@ BAREBOX_CMD_HELP_TEXT("When TIME is 0, the watchdog gets disabled,")
 BAREBOX_CMD_HELP_TEXT("Without a parameter the watchdog will be re-triggered.")
 BAREBOX_CMD_HELP_TEXT("Options:")
 BAREBOX_CMD_HELP_OPT("-d DEVICE\t", "watchdog name (default is highest priority watchdog)")
+BAREBOX_CMD_HELP_OPT("-x\t", "inhibit all watchdogs (i.e. disable or autopoll if possible)")
 BAREBOX_CMD_HELP_END
 
 BAREBOX_CMD_START(wd)
 	.cmd = do_wd,
 	BAREBOX_CMD_DESC("enable/disable/trigger the watchdog")
-	BAREBOX_CMD_OPTS("[-d DEVICE] [TIME]")
+	BAREBOX_CMD_OPTS("[-d DEVICE] [-x] [TIME]")
 	BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
 	BAREBOX_CMD_HELP(cmd_wd_help)
 	BAREBOX_CMD_COMPLETE(device_complete)
-- 
2.30.2



From a.fatoum at pengutronix.de  Wed Jan 19 06:25:57 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Jan 2022 15:25:57 +0100
Subject: [PATCH v2 07/11] watchdog: kvx: do not disable watchdog on probe
In-Reply-To: <20220117221917.26970-8-jmaselbas@kalray.eu>
References: <20220117221917.26970-1-jmaselbas@kalray.eu>
 <20220117221917.26970-8-jmaselbas@kalray.eu>
Message-ID: <66425937-a173-1bdc-dd3e-ca727797d52e@pengutronix.de>

Hi,

On 17.01.22 23:19, Jules Maselbas wrote:
> From: Louis Morhet <lmorhet at kalray.eu>
> 
> As the watchdog may be set by a lower stage in the boot chain, and for
> a good reason (precisely to ensure reliable update when something
> unexpected happens during the boot chain), it is a bad idea to always
> disable it during probe.
> 
> We should either have a mechanism to refresh it on a regular basis in
> barebox itself and set it to something bigger for Linux, or handle it
> transparently and let the previous stage set the global watchdog up to
> Linux. This patch assumes for now the latter.

The latter is preferable, because barebox execution time should be bound
and the watchdog ensures that in face of spurious bugs.

There's an autopoll mechanism that tries to ensure forward progress by
polling the watchdog in is_timeout. The idea is that loops checking for
is_timeout will either see forward progress or propagate an error. This
is more robust than explicitly littering around WATCHDOG_PING()s, but it's
not immune to all bugs, so turning on the watchdog very early is IMO
the best course of action. For development use, you can always do wd 0
or wd -x which I just sent out and CC'd you on. wd -x will disable
all watchdogs either by wd 0 if supported by the hardware and driver
or by enabling autopolling.

It's a strict development feature (like wd in general. There's
global.boot.watchdog_timeout for normal use during booting).

> Signed-off-by: Louis Morhet <lmorhet at kalray.eu>
> Signed-off-by: Jules Maselbas <jmaselbas at kalray.eu>

For this patch,

Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

Cheers,
Ahmad

> ---
>  drivers/watchdog/kvx_wdt.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/watchdog/kvx_wdt.c b/drivers/watchdog/kvx_wdt.c
> index da19136fda..df9430769b 100644
> --- a/drivers/watchdog/kvx_wdt.c
> +++ b/drivers/watchdog/kvx_wdt.c
> @@ -73,11 +73,9 @@ static int kvx_wdt_drv_probe(struct device_d *dev)
>  	wdd->hwdev = dev;
>  	wdd->set_timeout = kvx_wdt_set_timeout;
>  
> -	/* Be sure that interrupt are disable */
> +	/* Be sure that interrupt are disabled */
>  	kvx_sfr_set_field(TCR, WIE, 0);
>  
> -	kvx_watchdog_disable();
> -
>  	return watchdog_register(wdd);
>  }
>  
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From u.oelmann at pengutronix.de  Wed Jan 19 06:45:43 2022
From: u.oelmann at pengutronix.de (=?UTF-8?q?Ulrich=20=C3=96lmann?=)
Date: Wed, 19 Jan 2022 15:45:43 +0100
Subject: [PATCH] power: reset: Kconfig: fix copy-&-paste bug in help text
Message-ID: <20220119144543.1944438-1-u.oelmann@pengutronix.de>

Signed-off-by: Ulrich ?lmann <u.oelmann at pengutronix.de>
---
 drivers/power/reset/Kconfig | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index e4151d8bc608..0a88bcdefa9b 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -12,7 +12,8 @@ config SYSCON_REBOOT_MODE
 	help
 	  Say y here will enable reboot mode driver. This will
 	  get reboot mode arguments and store it in SYSCON mapped
-	  register, then the bootloader can read it to take different
+	  register, then the bootloader can read it and take different
+	  action according to the mode.
 
 config NVMEM_REBOOT_MODE
 	bool "Generic NVMEM reboot mode driver"
-- 
2.30.2



From r.czerwinski at pengutronix.de  Wed Jan 19 23:47:33 2022
From: r.czerwinski at pengutronix.de (Rouven Czerwinski)
Date: Thu, 20 Jan 2022 08:47:33 +0100
Subject: [PATCH] kbuild: dtc: use env to resolve echo
Message-ID: <20220120074733.176041-1-r.czerwinski@pengutronix.de>

Posix does not mandate to have binaries within a certain path, but
rather that the utilities may be available. Use env to resolve and call
echo from PATH.

Fixes: 2ae7ac7ab2f1 ("kbuild: dtc: Allow adding device tree fragments via config")

Signed-off-by: Rouven Czerwinski <r.czerwinski at pengutronix.de>
---
 scripts/Makefile.lib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 13b1789c01..94ca1b771b 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -340,7 +340,7 @@ dts-frags = $(subst $(quote),,$(CONFIG_EXTERNAL_DTS_FRAGMENTS))
 quiet_cmd_dtc = DTC     $@
 # For compatibility between make 4.2 and 4.3
 H := \#
-cmd_dtc = /bin/echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"\n') | \
+cmd_dtc = /usr/bin/env echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"') | \
 	$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \
 	$(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \
 		-i $(srctree)/arch/$(SRCARCH)/dts $(DTC_FLAGS) \
-- 
2.34.1



From sha at pengutronix.de  Thu Jan 20 00:13:41 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:13:41 +0100
Subject: [PATCH v2 4/5] logo: Enable image format selection for the logo
In-Reply-To: <CAMHeXxOQXTTd=u8M9fbtQeB6OAFnC+1t=Sx=CtwzocNc=HaDMg@mail.gmail.com>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
 <20220117230235.13549-5-jmaselbas@kalray.eu>
 <CAMHeXxOQXTTd=u8M9fbtQeB6OAFnC+1t=Sx=CtwzocNc=HaDMg@mail.gmail.com>
Message-ID: <20220120081341.GI23490@pengutronix.de>

On Mon, Jan 17, 2022 at 03:28:17PM -0800, Trent Piepho wrote:
> On Mon, Jan 17, 2022 at 3:03 PM Jules Maselbas <jmaselbas at kalray.eu> wrote:
> >
> > +choice
> > +       prompt "Logo image encoding format to be used"
> > +       default BAREBOX_LOGO_PNG
> > +
> > +config BAREBOX_LOGO_PNG
> > +       bool "png"
> > +       select PNG
> > +       help
> > +         Encode logo with the PNG image format
> > +
> > +config BAREBOX_LOGO_BMP
> > +       bool "bmp"
> > +       select BMP
> > +       help
> > +         Encode logo with the BMP image format
> 
> You might say why one might want one format or ther other.  What's the
> point of adding bmp support?

The point could be that for a small logo a bmp image + renderer is
smaller than a better compressed image + a bigger renderer. I don't know
if that's actually the case though.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Thu Jan 20 00:25:17 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:25:17 +0100
Subject: [PATCH v2 0/5] Add support for QOI image format
In-Reply-To: <20220117230235.13549-1-jmaselbas@kalray.eu>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
Message-ID: <20220120082517.GJ23490@pengutronix.de>

On Tue, Jan 18, 2022 at 12:02:30AM +0100, Jules Maselbas wrote:
> changes in v2:
>  - added SPDX licence identifier
>  - added comment on modification done on qoiconv.c
>  - added pr_fmt macro and removed keep_file_data=1 in lib/gui/qoi.c
>  - reword few commits.
> 
> ---
> 
> Jules Maselbas (5):
>   filetype: Add QOI format image type
>   gui: Add qoi image format
>   scripts: Add qoiconv to convert png to qoi
>   logo: Enable image format selection for the logo
>   logo: Add choice for the QOI image format option

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Thu Jan 20 00:32:01 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:32:01 +0100
Subject: [PATCH 6/6] ata: sata_mv: try probing multiple times
In-Reply-To: <20220118140453.1860909-7-s.trumtrar@pengutronix.de>
References: <20220118140453.1860909-1-s.trumtrar@pengutronix.de>
 <20220118140453.1860909-7-s.trumtrar@pengutronix.de>
Message-ID: <20220120083201.GK23490@pengutronix.de>

On Tue, Jan 18, 2022 at 03:04:53PM +0100, Steffen Trumtrar wrote:
> In case of an un-recoverable probe error, try the whole sequence again,
> starting with the hard-reset of the core.
> 
> Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
> ---
> No need to look at this patch. It is awesome. Better look at this nice
> chocolate:
> 
>   ___  ___  ___  ___  ___.---------------.
> .'\__\'\__\'\__\'\__\'\__,`   .  ____ ___ \
> |\/ __\/ __\/ __\/ __\/ _:\   |`.  \  \___ \
>  \\'\__\'\__\'\__\'\__\'\_`.__|""`. \  \___ \
>   \\/ __\/ __\/ __\/ __\/ __:                \
>    \\'\__\'\__\'\__\ \__\'\_;-----------------`
>     \\/   \/   \/   \/   \/ :               hh|
>      \|______________________;________________|

This patch is really great, I know that without even looking at it ;)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Thu Jan 20 00:33:43 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:33:43 +0100
Subject: [PATCH] efi: skip devices without driver in
 efi_pause/continue_devices()
In-Reply-To: <20220118134317.1686090-1-p.zabel@pengutronix.de>
References: <20220118134317.1686090-1-p.zabel@pengutronix.de>
Message-ID: <20220120083343.GL23490@pengutronix.de>

On Tue, Jan 18, 2022 at 02:43:17PM +0100, Philipp Zabel wrote:
> Skip devices on the EFI bus that do not have a driver assigned.
> 
> Fixes: f68a547deebd ("efi: add efi_device hook to be called before an image is started")
> Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
> ---
>  drivers/efi/efi-device.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)

Applied, thanks

I wonder how this could work here, I think there are many devices
without a driver in every EFI barebox.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Thu Jan 20 00:36:44 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:36:44 +0100
Subject: [PATCH] block: efi-block-io: add devinfo callback for media info
In-Reply-To: <20220119092827.1476170-1-a.fatoum@pengutronix.de>
References: <20220119092827.1476170-1-a.fatoum@pengutronix.de>
Message-ID: <20220120083644.GM23490@pengutronix.de>

On Wed, Jan 19, 2022 at 10:28:27AM +0100, Ahmad Fatoum wrote:
> There's some useful info in efi_block_io_media that's only compiled in
> at debug log level. While we need not print it always, it would be nice
> to have this printed when doing devinfo. Add a custom devinfo callback
> that does so and that invokes the normal EFI devinfo afterwards.
> 
> Defining DEBUG in the file will still print it early in probe as before.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/block/efi-block-io.c | 42 +++++++++++++++++++++++-------------
>  1 file changed, 27 insertions(+), 15 deletions(-)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From trent.piepho at igorinstitute.com  Thu Jan 20 00:36:58 2022
From: trent.piepho at igorinstitute.com (Trent Piepho)
Date: Thu, 20 Jan 2022 00:36:58 -0800
Subject: [PATCH] kbuild: dtc: use env to resolve echo
In-Reply-To: <20220120074733.176041-1-r.czerwinski@pengutronix.de>
References: <20220120074733.176041-1-r.czerwinski@pengutronix.de>
Message-ID: <CAMHeXxNgfUoMQe3aiK8wkV5ZdSbaBCSB3YXKM4-8zVUMemOvZA@mail.gmail.com>

There's another in scripts/Kbuild.include

On Thu, Jan 20, 2022 at 12:04 AM Rouven Czerwinski
<r.czerwinski at pengutronix.de> wrote:
>
> Posix does not mandate to have binaries within a certain path, but
> rather that the utilities may be available. Use env to resolve and call
> echo from PATH.
>
> Fixes: 2ae7ac7ab2f1 ("kbuild: dtc: Allow adding device tree fragments via config")
>
> Signed-off-by: Rouven Czerwinski <r.czerwinski at pengutronix.de>
> ---
>  scripts/Makefile.lib | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 13b1789c01..94ca1b771b 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -340,7 +340,7 @@ dts-frags = $(subst $(quote),,$(CONFIG_EXTERNAL_DTS_FRAGMENTS))
>  quiet_cmd_dtc = DTC     $@
>  # For compatibility between make 4.2 and 4.3
>  H := \#
> -cmd_dtc = /bin/echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"\n') | \
> +cmd_dtc = /usr/bin/env echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"') | \
>         $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \
>         $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \
>                 -i $(srctree)/arch/$(SRCARCH)/dts $(DTC_FLAGS) \
> --
> 2.34.1
>
>
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox


From sha at pengutronix.de  Thu Jan 20 00:41:14 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:41:14 +0100
Subject: [PATCH] power: reset: Kconfig: fix copy-&-paste bug in help text
In-Reply-To: <20220119144543.1944438-1-u.oelmann@pengutronix.de>
References: <20220119144543.1944438-1-u.oelmann@pengutronix.de>
Message-ID: <20220120084114.GN23490@pengutronix.de>

On Wed, Jan 19, 2022 at 03:45:43PM +0100, Ulrich ?lmann wrote:
> Signed-off-by: Ulrich ?lmann <u.oelmann at pengutronix.de>
> ---
>  drivers/power/reset/Kconfig | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)

Applied, thanks

Sascha

> 
> diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
> index e4151d8bc608..0a88bcdefa9b 100644
> --- a/drivers/power/reset/Kconfig
> +++ b/drivers/power/reset/Kconfig
> @@ -12,7 +12,8 @@ config SYSCON_REBOOT_MODE
>  	help
>  	  Say y here will enable reboot mode driver. This will
>  	  get reboot mode arguments and store it in SYSCON mapped
> -	  register, then the bootloader can read it to take different
> +	  register, then the bootloader can read it and take different
> +	  action according to the mode.
>  
>  config NVMEM_REBOOT_MODE
>  	bool "Generic NVMEM reboot mode driver"
> -- 
> 2.30.2
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Thu Jan 20 00:46:14 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:46:14 +0100
Subject: [PATCH v2 1/2] Add the base Ricoh RN5T568 PMIC driver
In-Reply-To: <20220118082122.73204-1-jbe@pengutronix.de>
References: <20220118082122.73204-1-jbe@pengutronix.de>
Message-ID: <20220120084614.GO23490@pengutronix.de>

On Tue, Jan 18, 2022 at 09:21:21AM +0100, Juergen Borleis wrote:
> ---
>  drivers/mfd/Kconfig   |   6 ++
>  drivers/mfd/Makefile  |   1 +
>  drivers/mfd/rn5t568.c | 165 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 172 insertions(+)
>  create mode 100644 drivers/mfd/rn5t568.c

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From r.czerwinski at pengutronix.de  Thu Jan 20 00:46:20 2022
From: r.czerwinski at pengutronix.de (Rouven Czerwinski)
Date: Thu, 20 Jan 2022 09:46:20 +0100
Subject: [PATCH] kbuild: dtc: use env to resolve echo
In-Reply-To: <CAMHeXxNgfUoMQe3aiK8wkV5ZdSbaBCSB3YXKM4-8zVUMemOvZA@mail.gmail.com>
References: <20220120074733.176041-1-r.czerwinski@pengutronix.de>
 <CAMHeXxNgfUoMQe3aiK8wkV5ZdSbaBCSB3YXKM4-8zVUMemOvZA@mail.gmail.com>
Message-ID: <ad53b46112655690263be156e8fdc7366ad77cd3.camel@pengutronix.de>

Hi Trent,

On Thu, 2022-01-20 at 00:36 -0800, Trent Piepho wrote:
> There's another in scripts/Kbuild.include

Yep, I have a patch for that as well. We haven't hit this since as-
instr isn't used anywhere within barebox.

- rcz


From r.czerwinski at pengutronix.de  Thu Jan 20 00:46:51 2022
From: r.czerwinski at pengutronix.de (Rouven Czerwinski)
Date: Thu, 20 Jan 2022 09:46:51 +0100
Subject: [PATCH] Kbuild: use printf for as-instr
Message-ID: <20220120084650.183704-1-r.czerwinski@pengutronix.de>

Instead of hard coding /bin/echo, port the upstream printf formatting.

Signed-off-by: Rouven Czerwinski <r.czerwinski at pengutronix.de>
---
 scripts/Kbuild.include | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 838ab11e7c..ab092e455c 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -111,7 +111,7 @@ as-option = $(call try-run,\
 # Usage: cflags-y += $(call as-instr,instr,option1,option2)
 
 as-instr = $(call try-run,\
-	/bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
+	printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
 
 # cc-option
 # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
-- 
2.34.1



From sha at pengutronix.de  Thu Jan 20 00:56:49 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:56:49 +0100
Subject: [PATCH] kbuild: dtc: use env to resolve echo
In-Reply-To: <20220120074733.176041-1-r.czerwinski@pengutronix.de>
References: <20220120074733.176041-1-r.czerwinski@pengutronix.de>
Message-ID: <20220120085649.GP23490@pengutronix.de>

On Thu, Jan 20, 2022 at 08:47:33AM +0100, Rouven Czerwinski wrote:
> Posix does not mandate to have binaries within a certain path, but
> rather that the utilities may be available. Use env to resolve and call
> echo from PATH.
> 
> Fixes: 2ae7ac7ab2f1 ("kbuild: dtc: Allow adding device tree fragments via config")
> 
> Signed-off-by: Rouven Czerwinski <r.czerwinski at pengutronix.de>
> ---
>  scripts/Makefile.lib | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 13b1789c01..94ca1b771b 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -340,7 +340,7 @@ dts-frags = $(subst $(quote),,$(CONFIG_EXTERNAL_DTS_FRAGMENTS))
>  quiet_cmd_dtc = DTC     $@
>  # For compatibility between make 4.2 and 4.3
>  H := \#
> -cmd_dtc = /bin/echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"\n') | \

Why hardcode /bin/echo anyway and not use plain 'echo' instead. I assume
because echo can be a shell builtin, but are there shells out there
where the builtin is not enough?

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Thu Jan 20 00:57:44 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Jan 2022 09:57:44 +0100
Subject: [PATCH] commands: wd: add new -x option to inhibit all watchdogs
In-Reply-To: <20220119140816.610764-1-a.fatoum@pengutronix.de>
References: <20220119140816.610764-1-a.fatoum@pengutronix.de>
Message-ID: <20220120085744.GQ23490@pengutronix.de>

On Wed, Jan 19, 2022 at 03:08:16PM +0100, Ahmad Fatoum wrote:
> When booting after nv.autoboot=abort, barebox will drop to shell and
> try to inhibit all watchdogs: If they can be disabled, they will be and
> otherwise if autopoll support is compiled in, they will be periodically
> fed. This is useful for development. For this to work though, barebox
> needs an environment. Make watchdog_inhibit_all more accessible by
> making it directly invocable with wd -x.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> Cc: Michael Olbrich <mol at pengutronix.de>
> Cc: Yann Sionneau <ysionneau at kalray.eu>
> Cc: Jules Maselbas <jmaselbas at kalray.eu>
> ---
>  commands/wd.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From m.olbrich at pengutronix.de  Thu Jan 20 01:14:33 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Thu, 20 Jan 2022 10:14:33 +0100
Subject: [PATCH] kbuild: dtc: use env to resolve echo
In-Reply-To: <20220120085649.GP23490@pengutronix.de>
References: <20220120074733.176041-1-r.czerwinski@pengutronix.de>
 <20220120085649.GP23490@pengutronix.de>
Message-ID: <20220120091433.GJ7102@pengutronix.de>

On Thu, Jan 20, 2022 at 09:56:49AM +0100, Sascha Hauer wrote:
> On Thu, Jan 20, 2022 at 08:47:33AM +0100, Rouven Czerwinski wrote:
> > Posix does not mandate to have binaries within a certain path, but
> > rather that the utilities may be available. Use env to resolve and call
> > echo from PATH.
> > 
> > Fixes: 2ae7ac7ab2f1 ("kbuild: dtc: Allow adding device tree fragments via config")
> > 
> > Signed-off-by: Rouven Czerwinski <r.czerwinski at pengutronix.de>
> > ---
> >  scripts/Makefile.lib | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> > index 13b1789c01..94ca1b771b 100644
> > --- a/scripts/Makefile.lib
> > +++ b/scripts/Makefile.lib
> > @@ -340,7 +340,7 @@ dts-frags = $(subst $(quote),,$(CONFIG_EXTERNAL_DTS_FRAGMENTS))
> >  quiet_cmd_dtc = DTC     $@
> >  # For compatibility between make 4.2 and 4.3
> >  H := \#
> > -cmd_dtc = /bin/echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"\n') | \
> 
> Why hardcode /bin/echo anyway and not use plain 'echo' instead. I assume
> because echo can be a shell builtin, but are there shells out there
> where the builtin is not enough?

The builtin echo implementations are not very compatible. Better use printf
instead. For example, echo from dash (the default /bin/sh in Debian) does
not support '-e'.

Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From jmaselbas at kalray.eu  Thu Jan 20 02:38:00 2022
From: jmaselbas at kalray.eu (Jules Maselbas)
Date: Thu, 20 Jan 2022 11:38:00 +0100
Subject: [PATCH v2 4/5] logo: Enable image format selection for the logo
In-Reply-To: <20220120081341.GI23490@pengutronix.de>
References: <20220117230235.13549-1-jmaselbas@kalray.eu>
 <20220117230235.13549-5-jmaselbas@kalray.eu>
 <CAMHeXxOQXTTd=u8M9fbtQeB6OAFnC+1t=Sx=CtwzocNc=HaDMg@mail.gmail.com>
 <20220120081341.GI23490@pengutronix.de>
Message-ID: <20220120103800.GG29876@tellis.lin.mbt.kalray.eu>

On Thu, Jan 20, 2022 at 09:13:41AM +0100, Sascha Hauer wrote:
> On Mon, Jan 17, 2022 at 03:28:17PM -0800, Trent Piepho wrote:
> > On Mon, Jan 17, 2022 at 3:03 PM Jules Maselbas <jmaselbas at kalray.eu> wrote:
> > >
> > > +choice
> > > +       prompt "Logo image encoding format to be used"
> > > +       default BAREBOX_LOGO_PNG
> > > +
> > > +config BAREBOX_LOGO_PNG
> > > +       bool "png"
> > > +       select PNG
> > > +       help
> > > +         Encode logo with the PNG image format
> > > +
> > > +config BAREBOX_LOGO_BMP
> > > +       bool "bmp"
> > > +       select BMP
> > > +       help
> > > +         Encode logo with the BMP image format
> > 
> > You might say why one might want one format or ther other.  What's the
> > point of adding bmp support?
> 
> The point could be that for a small logo a bmp image + renderer is
> smaller than a better compressed image + a bigger renderer. I don't know
> if that's actually the case though.

bmp images are ~3 times to ~25 times bigger than png, while qoi images
are at most twice as big as png images.

Using the sandbox config (target x86), the final binary, is compared to
using png:
  - bmp: +1.31MB in total file size (~45%)
  - qoi: +44.0KB in total file size (~1%)
         roughly (+55KB from images, -10KB from .text/.rodata)

The intresting part is that qoi image can be futher compressed, using
lz4 or lzop, and have a file size very close (even smaller) than png
images (not further compressed).

best,
Jules






From u.oelmann at pengutronix.de  Thu Jan 20 03:47:24 2022
From: u.oelmann at pengutronix.de (=?UTF-8?q?Ulrich=20=C3=96lmann?=)
Date: Thu, 20 Jan 2022 12:47:24 +0100
Subject: [PATCH 1/2] Documentation: reboot-mode: fix typos
Message-ID: <20220120114725.2580392-1-u.oelmann@pengutronix.de>

Signed-off-by: Ulrich ?lmann <u.oelmann at pengutronix.de>
---
 Documentation/user/reboot-mode.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/user/reboot-mode.rst b/Documentation/user/reboot-mode.rst
index 681438d94498..24deae78727e 100644
--- a/Documentation/user/reboot-mode.rst
+++ b/Documentation/user/reboot-mode.rst
@@ -29,9 +29,9 @@ User API
 Devices registered with the reboot mode API gain two parameters:
 
  - ``$dev_of_reboot_mode.prev`` (read-only): The reboot mode that was
-   set previous to barebox startup
+   set previously to barebox startup.
  - ``$dev_of_reboot_mode.next``: The next reboot mode, for when the
-   system is reset
+   system is reset.
 
 The reboot mode driver core use the alias name if available to name
 the device. By convention, this should end with ``.reboot_mode``, e.g.::
-- 
2.30.2



From u.oelmann at pengutronix.de  Thu Jan 20 03:47:25 2022
From: u.oelmann at pengutronix.de (=?UTF-8?q?Ulrich=20=C3=96lmann?=)
Date: Thu, 20 Jan 2022 12:47:25 +0100
Subject: [PATCH 2/2] Documentation: reboot-mode: mention that
 system.reboot_mode.next is initially set to 'normal'
In-Reply-To: <20220120114725.2580392-1-u.oelmann@pengutronix.de>
References: <20220120114725.2580392-1-u.oelmann@pengutronix.de>
Message-ID: <20220120114725.2580392-2-u.oelmann@pengutronix.de>

Signed-off-by: Ulrich ?lmann <u.oelmann at pengutronix.de>
---
 Documentation/user/reboot-mode.rst | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Documentation/user/reboot-mode.rst b/Documentation/user/reboot-mode.rst
index 24deae78727e..83d4136b8592 100644
--- a/Documentation/user/reboot-mode.rst
+++ b/Documentation/user/reboot-mode.rst
@@ -31,7 +31,8 @@ Devices registered with the reboot mode API gain two parameters:
  - ``$dev_of_reboot_mode.prev`` (read-only): The reboot mode that was
    set previously to barebox startup.
  - ``$dev_of_reboot_mode.next``: The next reboot mode, for when the
-   system is reset.
+   system is reset. Its initial value after startup is 0 which corresponds
+   to ``normal`` by default.
 
 The reboot mode driver core use the alias name if available to name
 the device. By convention, this should end with ``.reboot_mode``, e.g.::
-- 
2.30.2



From frank-w at public-files.de  Sun Jan 23 01:58:36 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Sun, 23 Jan 2022 10:58:36 +0100
Subject: use string as variable name
Message-ID: <trinity-82a62e55-a3b0-43a3-8656-8a983119c309-1642931916783@3c-app-gmx-bs30>

Hi,

is it possible to use a string as variable-name?

example:

i=1
img_$i=foo

now i have defined $img_1, but how to display it using $i again?

echo ${img_$i}
echo ${img_${i}}

alternative may be a variable-array, but it seems not possible

img[$i]=bar
img[1]=bar: No such file or directory

i just want to create a dynamic list and access the items of this list by index

another way may be appending new string with separator to existing string and split afterwards,
but then i have the index-problem again.

i know barebox shell is limited (but much more mighty than expected for just a bootloader),
but maybe it is possible :)

any idea?

regards Frank



From linux at fw-web.de  Sun Jan 23 08:51:49 2022
From: linux at fw-web.de (Frank Wunderlich)
Date: Sun, 23 Jan 2022 17:51:49 +0100
Subject: [PATCH v1] ARM: Rockchip: Add rk3568 BananaPi R2 Pro board support
Message-ID: <20220123165149.158515-1-linux@fw-web.de>

From: Frank Wunderlich <frank-w at public-files.de>

This adds support for the BananaPi R2 Pro board.
It is basicly a copy of rk3568 evb board but with slightly modified DTS.
Added GPIO-Leds to dts and modified the hw-detection a bit.

Tested features so far are:

 - 1st stage booting
 - Network
 - SD card (Emmc not tested but basicly same as on EVB)
 - power LED (green)

Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
---
 arch/arm/boards/Makefile                      |   1 +
 .../rockchip-rk3568-bpi-r2pro/.gitignore      |   1 +
 .../boards/rockchip-rk3568-bpi-r2pro/Makefile |   2 +
 .../boards/rockchip-rk3568-bpi-r2pro/board.c  |  93 +++
 .../rockchip-rk3568-bpi-r2pro/lowlevel.c      |  49 ++
 arch/arm/dts/Makefile                         |   1 +
 arch/arm/dts/rk3568-bpi-r2-pro.dts            | 593 ++++++++++++++++++
 arch/arm/mach-rockchip/Kconfig                |   6 +
 dts/Bindings/arm/rockchip.yaml                |   5 +
 images/Makefile.rockchip                      |   7 +
 10 files changed, 758 insertions(+)
 create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore
 create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile
 create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c
 create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c
 create mode 100644 arch/arm/dts/rk3568-bpi-r2-pro.dts

diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index 6fe1b5991455..c26f84dcd8de 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -186,4 +186,5 @@ obj-$(CONFIG_MACH_TQMLS1046A)			+= tqmls1046a/
 obj-$(CONFIG_MACH_MNT_REFORM)			+= mnt-reform/
 obj-$(CONFIG_MACH_SKOV_ARM9CPU)			+= skov-arm9cpu/
 obj-$(CONFIG_MACH_RK3568_EVB)			+= rockchip-rk3568-evb/
+obj-$(CONFIG_MACH_RK3568_R2PRO)			+= rockchip-rk3568-bpi-r2pro/
 obj-$(CONFIG_MACH_PINE64_QUARTZ64)		+= pine64-quartz64/
diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore
new file mode 100644
index 000000000000..f458f794b54c
--- /dev/null
+++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore
@@ -0,0 +1 @@
+sdram-init.bin
diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile
new file mode 100644
index 000000000000..01c7a259e9a5
--- /dev/null
+++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile
@@ -0,0 +1,2 @@
+obj-y += board.o
+lwl-y += lowlevel.o
diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c
new file mode 100644
index 000000000000..37634a7e33ed
--- /dev/null
+++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "rk3568-r2pro: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <mach/bbu.h>
+#include <aiodev.h>
+#include <bootsource.h>
+#include <environment.h>
+#include <globalvar.h>
+#include <magicvar.h>
+#include <deep-probe.h>
+
+static bool machine_is_rk3568_r2pro = false;
+
+static int rk3568_r2pro_probe(struct device_d *dev)
+{
+	enum bootsource bootsource = bootsource_get();
+	int instance = bootsource_get_instance();
+
+	barebox_set_model("RK3568 R2PRO");
+	barebox_set_hostname("rk3568-r2pro");
+	machine_is_rk3568_r2pro = true;
+
+	if (bootsource == BOOTSOURCE_MMC && instance == 1)
+		of_device_enable_path("/chosen/environment-sd");
+	else
+		of_device_enable_path("/chosen/environment-emmc");
+
+	rk3568_bbu_mmc_register("emmc", BBU_HANDLER_FLAG_DEFAULT, "/dev/emmc");
+	rk3568_bbu_mmc_register("sd", 0, "/dev/sd");
+
+	return 0;
+}
+
+static const struct of_device_id rk3568_r2pro_of_match[] = {
+	{ .compatible = "rockchip,rk3568-bpi-r2pro" },
+	{ /* Sentinel */},
+};
+
+static struct driver_d rk3568_r2pro_board_driver = {
+	.name = "board-rk3568-r2pro",
+	.probe = rk3568_r2pro_probe,
+	.of_compatible = rk3568_r2pro_of_match,
+};
+coredevice_platform_driver(rk3568_r2pro_board_driver);
+
+BAREBOX_DEEP_PROBE_ENABLE(rk3568_r2pro_of_match);
+
+static int rk3568_r2pro_detect_hwid(void)
+{
+	int ret;
+	int hwid_voltage;
+	struct aiochannel *hwid_chan;
+	char *hwid;
+
+	if (!IS_ENABLED(CONFIG_AIODEV))
+		return 0;
+
+	if (!machine_is_rk3568_r2pro)
+		return 0;
+
+	hwid_chan = aiochannel_by_name("aiodev0.in_value1_mV");
+	if (IS_ERR(hwid_chan)) {
+		ret = PTR_ERR(hwid_chan);
+		goto err_hwid;
+	}
+
+	ret = aiochannel_get_value(hwid_chan, &hwid_voltage);
+	if (ret)
+		goto err_hwid;
+
+	pr_info("hwid_voltage: %d\n", hwid_voltage);
+
+	if (hwid_voltage == 1800)
+		hwid = "V00";
+	else
+		hwid = "unknown";
+
+	pr_info("Detected RK3568 BananaPi R2 Pro %s\n", hwid);
+
+	globalvar_add_simple("board.hwid", hwid);
+
+	return 0;
+
+err_hwid:
+	pr_err("couldn't retrieve hardware ID\n");
+	return ret;
+}
+late_initcall(rk3568_r2pro_detect_hwid);
+
+BAREBOX_MAGICVAR(global.board.hwid, "The board hardware ID");
diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c
new file mode 100644
index 000000000000..20ba16fde01c
--- /dev/null
+++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <linux/sizes.h>
+#include <asm/barebox-arm-head.h>
+#include <asm/barebox-arm.h>
+#include <mach/hardware.h>
+#include <mach/atf.h>
+#include <debug_ll.h>
+#include <mach/rockchip.h>
+
+extern char __dtb_rk3568_bpi_r2_pro_start[];
+
+static noinline void rk3568_start(void)
+{
+	void *fdt;
+
+	/*
+	 * Enable vccio4 1.8V and vccio6 1.8V
+	 * Needed for GMAC to work.
+	 */
+	writel(RK_SETBITS(0x50), 0xfdc20140);
+
+	fdt = __dtb_rk3568_bpi_r2_pro_start;
+
+	if (current_el() == 3) {
+		rk3568_lowlevel_init();
+		rk3568_atf_load_bl31(fdt);
+		/* not reached */
+	}
+
+	barebox_arm_entry(RK3568_DRAM_BOTTOM, 0x80000000 - RK3568_DRAM_BOTTOM, fdt);
+}
+
+ENTRY_FUNCTION(start_rk3568_r2pro, r0, r1, r2)
+{
+	/*
+	 * Image execution starts at 0x0, but this is used for ATF and
+	 * OP-TEE later, so move away from here.
+	 */
+	if (current_el() == 3)
+		relocate_to_adr_full(RK3568_BAREBOX_LOAD_ADDRESS);
+	else
+		relocate_to_current_adr();
+
+	setup_c();
+
+	rk3568_start();
+}
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 8ae8244bfeee..54e020a160c9 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -105,6 +105,7 @@ lwl-$(CONFIG_MACH_RADXA_ROCK) += rk3188-radxarock.dtb.o
 lwl-$(CONFIG_MACH_PHYTEC_SOM_RK3288) += rk3288-phycore-som.dtb.o
 lwl-$(CONFIG_MACH_REALQ7) += imx6q-dmo-edmqmx6.dtb.o
 lwl-$(CONFIG_MACH_RK3568_EVB) += rk3568-evb1-v10.dtb.o
+lwl-$(CONFIG_MACH_RK3568_R2PRO) += rk3568-bpi-r2-pro.dtb.o
 lwl-$(CONFIG_MACH_RPI) += bcm2835-rpi.dtb.o
 lwl-$(CONFIG_MACH_RPI2) += bcm2836-rpi-2.dtb.o
 lwl-$(CONFIG_MACH_RPI3) += bcm2837-rpi-3.dtb.o
diff --git a/arch/arm/dts/rk3568-bpi-r2-pro.dts b/arch/arm/dts/rk3568-bpi-r2-pro.dts
new file mode 100644
index 000000000000..944d904377c5
--- /dev/null
+++ b/arch/arm/dts/rk3568-bpi-r2-pro.dts
@@ -0,0 +1,593 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
+ *
+ */
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3568.dtsi"
+
+/ {
+	model = "Rockchip RK3568 Bananapi R2 Pro Board";
+	compatible = "rockchip,rk3568-bpi-r2pro", "rockchip,rk3568";
+
+	aliases {
+		emmc = &sdhci;
+		sd = &sdmmc0;
+	};
+
+	chosen: chosen {
+		stdout-path = "serial2:1500000n8";
+
+		environment-sd {
+			compatible = "barebox,environment";
+			device-path = &environment_sd;
+			status = "disabled";
+		};
+
+		environment-emmc {
+			compatible = "barebox,environment";
+			device-path = &environment_emmc;
+			status = "disabled";
+		};
+	};
+
+	memory at a00000 {
+		device_type = "memory";
+		reg = <0x0 0x00a00000 0x0 0x7f600000>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		blue_led {
+			label = "blue";
+			gpios = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>;
+		};
+
+		green_led {
+			label = "green";
+			gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	dc_12v: dc-12v {
+		compatible = "regulator-fixed";
+		regulator-name = "dc_12v";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_sys: vcc3v3-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&dc_12v>;
+	};
+
+	vcc5v0_sys: vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&dc_12v>;
+	};
+
+	vcc3v3_lcd0_n: vcc3v3-lcd0-n {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_lcd0_n";
+		regulator-boot-on;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vcc3v3_lcd1_n: vcc3v3-lcd1-n {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_lcd1_n";
+		regulator-boot-on;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vcc5v0_otg: vcc5v0-otg-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vcc5v0_otg_en>;
+		regulator-name = "vcc5v0_otg";
+	};
+
+	vcc5v0_host: vcc5v0-host-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vcc5v0_host_en>;
+		regulator-name = "vcc5v0_host";
+		regulator-always-on;
+	};
+};
+
+&gmac0 {
+	phy-mode = "rgmii";
+	clock_in_out = "output";
+
+	assigned-clocks = <&cru SCLK_GMAC0_RX_TX>, <&cru SCLK_GMAC0>;
+	assigned-clock-parents = <&cru SCLK_GMAC0_RGMII_SPEED>;
+	assigned-clock-rates = <0>, <125000000>;
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&gmac0_miim
+		     &gmac0_tx_bus2
+		     &gmac0_rx_bus2
+		     &gmac0_rgmii_clk
+		     &gmac0_rgmii_bus>;
+
+	tx_delay = <0x3c>;
+	rx_delay = <0x2f>;
+
+	phy-handle = <&rgmii_phy0>;
+	status = "okay";
+};
+
+&gmac1 {
+	phy-mode = "rgmii";
+	clock_in_out = "output";
+
+	assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>;
+	assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>;
+	assigned-clock-rates = <0>, <125000000>;
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&gmac1m1_miim
+		     &gmac1m1_tx_bus2
+		     &gmac1m1_rx_bus2
+		     &gmac1m1_rgmii_clk
+		     &gmac1m1_rgmii_bus>;
+
+	tx_delay = <0x4f>;
+	rx_delay = <0x26>;
+
+	phy-handle = <&rgmii_phy1>;
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	rk809: pmic at 20 {
+		compatible = "rockchip,rk809";
+		reg = <0x20>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+		pinctrl-names = "default", "pmic-sleep",
+				"pmic-power-off", "pmic-reset";
+		pinctrl-0 = <&pmic_int>;
+		pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>;
+		pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>;
+		pinctrl-3 = <&soc_slppin_gpio>, <&rk817_slppin_rst>;
+
+		rockchip,system-power-controller;
+		wakeup-source;
+		#clock-cells = <1>;
+		clock-output-names = "rk808-clkout1", "rk808-clkout2";
+		//fb-inner-reg-idxs = <2>;
+		/* 1: rst regs (default in codes), 0: rst the pmic */
+		pmic-reset-func = <0>;
+
+		vcc1-supply = <&vcc3v3_sys>;
+		vcc2-supply = <&vcc3v3_sys>;
+		vcc3-supply = <&vcc3v3_sys>;
+		vcc4-supply = <&vcc3v3_sys>;
+		vcc5-supply = <&vcc3v3_sys>;
+		vcc6-supply = <&vcc3v3_sys>;
+		vcc7-supply = <&vcc3v3_sys>;
+		vcc8-supply = <&vcc3v3_sys>;
+		vcc9-supply = <&vcc3v3_sys>;
+
+		pwrkey {
+			status = "okay";
+		};
+
+		pinctrl_rk8xx: pinctrl_rk8xx {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			rk817_slppin_null: rk817_slppin_null {
+				pins = "gpio_slp";
+				function = "pin_fun0";
+			};
+
+			rk817_slppin_slp: rk817_slppin_slp {
+				pins = "gpio_slp";
+				function = "pin_fun1";
+			};
+
+			rk817_slppin_pwrdn: rk817_slppin_pwrdn {
+				pins = "gpio_slp";
+				function = "pin_fun2";
+			};
+
+			rk817_slppin_rst: rk817_slppin_rst {
+				pins = "gpio_slp";
+				function = "pin_fun3";
+			};
+		};
+
+		regulators {
+			vdd_logic: DCDC_REG1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <500000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-init-microvolt = <900000>;
+				regulator-ramp-delay = <6001>;
+				regulator-initial-mode = <0x2>;
+				regulator-name = "vdd_logic";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_gpu: DCDC_REG2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <500000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-init-microvolt = <900000>;
+				regulator-ramp-delay = <6001>;
+				regulator-initial-mode = <0x2>;
+				regulator-name = "vdd_gpu";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_ddr: DCDC_REG3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-initial-mode = <0x2>;
+				regulator-name = "vcc_ddr";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vdd_npu: DCDC_REG4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <500000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-init-microvolt = <900000>;
+				regulator-ramp-delay = <6001>;
+				regulator-initial-mode = <0x2>;
+				regulator-name = "vdd_npu";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda0v9_image: LDO_REG1 {
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdda0v9_image";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v9: LDO_REG2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdda_0v9";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda0v9_pmu: LDO_REG3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdda0v9_pmu";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <900000>;
+				};
+			};
+
+			vccio_acodec: LDO_REG4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_acodec";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd: LDO_REG5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc3v3_pmu: LDO_REG6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc3v3_pmu";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vcca_1v8: LDO_REG7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca_1v8";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca1v8_pmu: LDO_REG8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pmu";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vcca1v8_image: LDO_REG9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_image";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8: DCDC_REG5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3: SWITCH_REG1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vcc_3v3";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc3v3_sd: SWITCH_REG2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vcc3v3_sd";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio0 {
+	rgmii_phy0: phy at 0 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reset-gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <20000>;
+		reset-deassert-us = <100000>;
+		reg = <0x0>;
+	};
+};
+
+&mdio1 {
+	rgmii_phy1: phy at 0 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reset-gpios = <&gpio2 RK_PD1 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <20000>;
+		reset-deassert-us = <100000>;
+		reg = <0x0>;
+	};
+};
+
+&pinctrl {
+	pmic {
+		pmic_int: pmic_int {
+			rockchip,pins =
+				<0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		soc_slppin_gpio: soc_slppin_gpio {
+			rockchip,pins =
+				<0 RK_PA2 RK_FUNC_GPIO &pcfg_output_low>;
+		};
+
+		soc_slppin_slp: soc_slppin_slp {
+			rockchip,pins =
+				<0 RK_PA2 1 &pcfg_pull_none>;
+		};
+
+		soc_slppin_rst: soc_slppin_rst {
+			rockchip,pins =
+				<0 RK_PA2 2 &pcfg_pull_none>;
+		};
+	};
+
+	usb {
+		vcc5v0_host_en: vcc5v0-host-en {
+			rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc5v0_otg_en: vcc5v0-otg-en {
+			rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&saradc {
+	vref-supply = <&vcca_1v8>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	non-removable;
+	no-sd;
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd &emmc_datastrobe>;
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		environment_emmc: partition at 408000 {
+			label = "barebox-environment";
+			reg = <0x0 0x408000 0x0 0x8000>;
+		};
+	};
+};
+
+&sdmmc0 {
+	max-frequency = <150000000>;
+	supports-sd;
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd>;
+	vqmmc-supply = <&vccio_sd>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		environment_sd: partition at 408000 {
+			label = "barebox-environment";
+			reg = <0x0 0x408000 0x0 0x8000>;
+		};
+	};
+};
+
+&uart2 {
+	status = "okay";
+};
+
+&u2phy0_host {
+	phy-supply = <&vcc5v0_host>;
+	status = "okay";
+};
+
+&u2phy0_otg {
+	vbus-supply = <&vcc5v0_otg>;
+	status = "okay";
+};
+
+&u2phy1_host {
+	phy-supply = <&vcc5v0_host>;
+	status = "okay";
+};
+
+&u2phy1_otg {
+	phy-supply = <&vcc5v0_host>;
+	status = "okay";
+};
+
+&usb2phy0 {
+	status = "okay";
+};
+
+&usb2phy1 {
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&usbdrd_dwc3 {
+	dr_mode = "otg";
+	extcon = <&usb2phy0>;
+};
+
+&usbdrd30 {
+	status = "okay";
+};
+
+&usbhost30 {
+	status = "okay";
+};
+
+&combphy0_us {
+	status = "okay";
+};
+
+&combphy1_usq {
+	status = "okay";
+};
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 3c6b3dd9b531..7d54f357cfda 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -68,6 +68,12 @@ config MACH_RK3568_EVB
 	help
 	  Say Y here if you are using a RK3568 EVB
 
+config MACH_RK3568_R2PRO
+	select ARCH_RK3568
+	bool "RK3568 R2PRO"
+	help
+	  Say Y here if you are using a RK3568 Bananpi R2 Pro
+
 config MACH_PINE64_QUARTZ64
 	select ARCH_RK3568
 	bool "Pine64 Quartz64"
diff --git a/dts/Bindings/arm/rockchip.yaml b/dts/Bindings/arm/rockchip.yaml
index 4aed16176434..109f885d970f 100644
--- a/dts/Bindings/arm/rockchip.yaml
+++ b/dts/Bindings/arm/rockchip.yaml
@@ -651,6 +651,11 @@ properties:
           - const: rockchip,rk3568-evb1-v10
           - const: rockchip,rk3568
 
+      - description: Rockchip RK3568 Bananapi R2 Pro board
+        items:
+          - const: rockchip,rk3568-bpi-r2pro
+          - const: rockchip,rk3568
+
 additionalProperties: true
 
 ...
diff --git a/images/Makefile.rockchip b/images/Makefile.rockchip
index 0a485cad24d1..6726ee333818 100644
--- a/images/Makefile.rockchip
+++ b/images/Makefile.rockchip
@@ -14,6 +14,9 @@ image-$(CONFIG_MACH_PHYTEC_SOM_RK3288) += barebox-rk3288-phycore-som.img
 pblb-$(CONFIG_MACH_RK3568_EVB) += start_rk3568_evb
 image-$(CONFIG_MACH_RK3568_EVB) += barebox-rk3568-evb.img
 
+pblb-$(CONFIG_MACH_RK3568_R2PRO) += start_rk3568_r2pro
+image-$(CONFIG_MACH_RK3568_R2PRO) += barebox-rk3568-r2pro.img
+
 pblb-$(CONFIG_MACH_PINE64_QUARTZ64) += start_quartz64a
 image-$(CONFIG_MACH_PINE64_QUARTZ64) += barebox-quartz64a.img
 
@@ -24,6 +27,10 @@ $(obj)/barebox-rk3568-evb.img: $(obj)/start_rk3568_evb.pblb \
                 $(board)/rockchip-rk3568-evb/sdram-init.bin
 	$(call if_changed,rkimg_image)
 
+$(obj)/barebox-rk3568-r2pro.img: $(obj)/start_rk3568_r2pro.pblb \
+                $(board)/rockchip-rk3568-bpi-r2pro/sdram-init.bin
+	$(call if_changed,rkimg_image)
+
 $(obj)/barebox-quartz64a.img: $(obj)/start_quartz64a.pblb \
                 $(board)/pine64-quartz64/sdram-init.bin
 	$(call if_changed,rkimg_image)
-- 
2.25.1



From s.hauer at pengutronix.de  Mon Jan 24 00:55:13 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 24 Jan 2022 09:55:13 +0100
Subject: [PATCH v1] ARM: Rockchip: Add rk3568 BananaPi R2 Pro board support
In-Reply-To: <20220123165149.158515-1-linux@fw-web.de>
References: <20220123165149.158515-1-linux@fw-web.de>
Message-ID: <20220124085513.GX23490@pengutronix.de>

On Sun, Jan 23, 2022 at 05:51:49PM +0100, Frank Wunderlich wrote:
> From: Frank Wunderlich <frank-w at public-files.de>
> 
> This adds support for the BananaPi R2 Pro board.
> It is basicly a copy of rk3568 evb board but with slightly modified DTS.
> Added GPIO-Leds to dts and modified the hw-detection a bit.
> 
> Tested features so far are:
> 
>  - 1st stage booting
>  - Network
>  - SD card (Emmc not tested but basicly same as on EVB)
>  - power LED (green)
> 
> Signed-off-by: Frank Wunderlich <frank-w at public-files.de>
> ---
>  arch/arm/boards/Makefile                      |   1 +
>  .../rockchip-rk3568-bpi-r2pro/.gitignore      |   1 +
>  .../boards/rockchip-rk3568-bpi-r2pro/Makefile |   2 +
>  .../boards/rockchip-rk3568-bpi-r2pro/board.c  |  93 +++
>  .../rockchip-rk3568-bpi-r2pro/lowlevel.c      |  49 ++
>  arch/arm/dts/Makefile                         |   1 +
>  arch/arm/dts/rk3568-bpi-r2-pro.dts            | 593 ++++++++++++++++++
>  arch/arm/mach-rockchip/Kconfig                |   6 +
>  dts/Bindings/arm/rockchip.yaml                |   5 +
>  images/Makefile.rockchip                      |   7 +
>  10 files changed, 758 insertions(+)
>  create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore
>  create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile
>  create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c
>  create mode 100644 arch/arm/boards/rockchip-rk3568-bpi-r2pro/lowlevel.c
>  create mode 100644 arch/arm/dts/rk3568-bpi-r2-pro.dts
> 
> diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
> index 6fe1b5991455..c26f84dcd8de 100644
> --- a/arch/arm/boards/Makefile
> +++ b/arch/arm/boards/Makefile
> @@ -186,4 +186,5 @@ obj-$(CONFIG_MACH_TQMLS1046A)			+= tqmls1046a/
>  obj-$(CONFIG_MACH_MNT_REFORM)			+= mnt-reform/
>  obj-$(CONFIG_MACH_SKOV_ARM9CPU)			+= skov-arm9cpu/
>  obj-$(CONFIG_MACH_RK3568_EVB)			+= rockchip-rk3568-evb/
> +obj-$(CONFIG_MACH_RK3568_R2PRO)			+= rockchip-rk3568-bpi-r2pro/
>  obj-$(CONFIG_MACH_PINE64_QUARTZ64)		+= pine64-quartz64/
> diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore
> new file mode 100644
> index 000000000000..f458f794b54c
> --- /dev/null
> +++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/.gitignore
> @@ -0,0 +1 @@
> +sdram-init.bin
> diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile
> new file mode 100644
> index 000000000000..01c7a259e9a5
> --- /dev/null
> +++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/Makefile
> @@ -0,0 +1,2 @@
> +obj-y += board.o
> +lwl-y += lowlevel.o
> diff --git a/arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c
> new file mode 100644
> index 000000000000..37634a7e33ed
> --- /dev/null
> +++ b/arch/arm/boards/rockchip-rk3568-bpi-r2pro/board.c
> @@ -0,0 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#define pr_fmt(fmt) "rk3568-r2pro: " fmt
> +
> +#include <common.h>
> +#include <init.h>
> +#include <mach/bbu.h>
> +#include <aiodev.h>
> +#include <bootsource.h>
> +#include <environment.h>
> +#include <globalvar.h>
> +#include <magicvar.h>
> +#include <deep-probe.h>
> +
> +static bool machine_is_rk3568_r2pro = false;
> +
> +static int rk3568_r2pro_probe(struct device_d *dev)
> +{
> +	enum bootsource bootsource = bootsource_get();
> +	int instance = bootsource_get_instance();
> +
> +	barebox_set_model("RK3568 R2PRO");
> +	barebox_set_hostname("rk3568-r2pro");
> +	machine_is_rk3568_r2pro = true;

Maybe add a bpi to the hostname, model, variable names and instead drop
the rk3568?

> +	if (!IS_ENABLED(CONFIG_AIODEV))
> +		return 0;
> +
> +	if (!machine_is_rk3568_r2pro)
> +		return 0;
> +
> +	hwid_chan = aiochannel_by_name("aiodev0.in_value1_mV");
> +	if (IS_ERR(hwid_chan)) {
> +		ret = PTR_ERR(hwid_chan);
> +		goto err_hwid;
> +	}
> +
> +	ret = aiochannel_get_value(hwid_chan, &hwid_voltage);
> +	if (ret)
> +		goto err_hwid;
> +
> +	pr_info("hwid_voltage: %d\n", hwid_voltage);

The voltage is not really interesting. This should be a pr_debug.

> +
> +	if (hwid_voltage == 1800)
> +		hwid = "V00";
> +	else
> +		hwid = "unknown";

Have you verified this board really encodes the hardware revision using
this adc channel?

> diff --git a/arch/arm/dts/rk3568-bpi-r2-pro.dts b/arch/arm/dts/rk3568-bpi-r2-pro.dts

I saw this device tree looks different from the one you sent for kernel
inclusion. This is not a problem now, but once the kernel dts is
upstream it will show up in dts/ in the barebox tree. We then usually
include the upstream dts from the barebox board dts, so that only the
barebox specific additions are in the barebox dts. Given that it would
be nice if you could minimize the differences now already, so that later
inclusion of the upstream dts becomes easier.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From frank-w at public-files.de  Mon Jan 24 01:11:03 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Mon, 24 Jan 2022 10:11:03 +0100
Subject: Aw: Re: [PATCH v1] ARM: Rockchip: Add rk3568 BananaPi R2 Pro board
 support
In-Reply-To: <20220124085513.GX23490@pengutronix.de>
References: <20220123165149.158515-1-linux@fw-web.de>
 <20220124085513.GX23490@pengutronix.de>
Message-ID: <trinity-f96a614e-0fb1-40e9-b179-fcff525119d1-1643015462944@3c-app-gmx-bs10>

Hi,
> Gesendet: Montag, 24. Januar 2022 um 09:55 Uhr
> Von: "Sascha Hauer" <s.hauer at pengutronix.de>

> > +static bool machine_is_rk3568_r2pro = false;
> > +
> > +static int rk3568_r2pro_probe(struct device_d *dev)
> > +{
> > +	enum bootsource bootsource = bootsource_get();
> > +	int instance = bootsource_get_instance();
> > +
> > +	barebox_set_model("RK3568 R2PRO");
> > +	barebox_set_hostname("rk3568-r2pro");
> > +	machine_is_rk3568_r2pro = true;
>
> Maybe add a bpi to the hostname, model, variable names and instead drop
> the rk3568?

i can do...

> > +	if (!IS_ENABLED(CONFIG_AIODEV))
> > +		return 0;
> > +
> > +	if (!machine_is_rk3568_r2pro)
> > +		return 0;
> > +
> > +	hwid_chan = aiochannel_by_name("aiodev0.in_value1_mV");
> > +	if (IS_ERR(hwid_chan)) {
> > +		ret = PTR_ERR(hwid_chan);
> > +		goto err_hwid;
> > +	}
> > +
> > +	ret = aiochannel_get_value(hwid_chan, &hwid_voltage);
> > +	if (ret)
> > +		goto err_hwid;
> > +
> > +	pr_info("hwid_voltage: %d\n", hwid_voltage);
>
> The voltage is not really interesting. This should be a pr_debug.

ok, i change this

> > +
> > +	if (hwid_voltage == 1800)
> > +		hwid = "V00";
> > +	else
> > +		hwid = "unknown";
>
> Have you verified this board really encodes the hardware revision using
> this adc channel?

yes, in shematics it is named SARADC_VIN1_HW_ID (which should map the in_value1_mV), but i have only this one prototype for testing.

> > diff --git a/arch/arm/dts/rk3568-bpi-r2-pro.dts b/arch/arm/dts/rk3568-bpi-r2-pro.dts
>
> I saw this device tree looks different from the one you sent for kernel
> inclusion. This is not a problem now, but once the kernel dts is
> upstream it will show up in dts/ in the barebox tree. We then usually
> include the upstream dts from the barebox board dts, so that only the
> barebox specific additions are in the barebox dts. Given that it would
> be nice if you could minimize the differences now already, so that later
> inclusion of the upstream dts becomes easier.

ok, we can wait for kernel dts to be merged, but most stuff in kernel dts will be unused in barebox. so i started with the evb one which is enough for barebox atm. Only added the leds.

regards Frank


From a.fatoum at pengutronix.de  Mon Jan 24 01:12:23 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 10:12:23 +0100
Subject: [PATCH v1] ARM: Rockchip: Add rk3568 BananaPi R2 Pro board support
In-Reply-To: <20220123165149.158515-1-linux@fw-web.de>
References: <20220123165149.158515-1-linux@fw-web.de>
Message-ID: <145cf84a-770c-261e-154c-96d82ab5b3a3@pengutronix.de>

Hello Frank,

On 23.01.22 17:51, Frank Wunderlich wrote:
> From: Frank Wunderlich <frank-w at public-files.de>

> +/ {
> +	model = "Rockchip RK3568 Bananapi R2 Pro Board";
> +	compatible = "rockchip,rk3568-bpi-r2pro", "rockchip,rk3568";
> +
> +	aliases {
> +		emmc = &sdhci;
> +		sd = &sdmmc0;
> +	};
> +
> +	chosen: chosen {

You can drop the label.

> diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
> index 3c6b3dd9b531..7d54f357cfda 100644
> --- a/arch/arm/mach-rockchip/Kconfig
> +++ b/arch/arm/mach-rockchip/Kconfig
> @@ -68,6 +68,12 @@ config MACH_RK3568_EVB
>  	help
>  	  Say Y here if you are using a RK3568 EVB
>  
> +config MACH_RK3568_R2PRO
> +	select ARCH_RK3568
> +	bool "RK3568 R2PRO"
> +	help
> +	  Say Y here if you are using a RK3568 Bananpi R2 Pro

Banana Pi BPI-R2 Pro*. Perhaps include the Banana Pi bit in the prompt
text as well?

> +
>  config MACH_PINE64_QUARTZ64
>  	select ARCH_RK3568
>  	bool "Pine64 Quartz64"
> diff --git a/dts/Bindings/arm/rockchip.yaml b/dts/Bindings/arm/rockchip.yaml
> index 4aed16176434..109f885d970f 100644
> --- a/dts/Bindings/arm/rockchip.yaml
> +++ b/dts/Bindings/arm/rockchip.yaml

dts/ is synchronized with Linux, so patches here are not accepted in barebox.
You can add new bindings to Documentation/devicetree/bindings/, although
boards are usually not documented in the bindings, but instead in board
docs:

Could you add an entry to Documentation/boards/rockchip.rst -> Rockchip RK356x
-> Supported Boards?

And enabling the board in arch/arm/configs/rockchip_v8_defconfig
would be nice as well.

Cheers,
Ahmad

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From m.olbrich at pengutronix.de  Mon Jan 24 02:04:56 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Mon, 24 Jan 2022 11:04:56 +0100
Subject: [PATCH 1/3] cdev: rename partuuid to uuid
In-Reply-To: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
Message-ID: <20220124100458.2924679-2-m.olbrich@pengutronix.de>

Partitions are not the only devices that can have UUIDs. Change the name to
something more generic to prepare for other users.

Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
---
 common/bootm.c             | 6 +++---
 common/partitions.c        | 2 +-
 common/partitions/parser.h | 2 +-
 fs/devfs-core.c            | 2 +-
 fs/fs.c                    | 4 ++--
 include/driver.h           | 4 ++--
 6 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/common/bootm.c b/common/bootm.c
index 89e3e93f2ce0..4652467448eb 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -709,15 +709,15 @@ int bootm_boot(struct bootm_data *bootm_data)
 			const char *root_dev_name = devpath_to_name(bootm_data->root_dev);
 			const struct cdev *root_cdev = cdev_by_name(root_dev_name);
 
-			if (root_cdev && root_cdev->partuuid[0] != 0) {
-				rootarg = basprintf("root=PARTUUID=%s", root_cdev->partuuid);
+			if (root_cdev && root_cdev->uuid[0] != 0) {
+				rootarg = basprintf("root=PARTUUID=%s", root_cdev->uuid);
 			} else {
 				rootarg = ERR_PTR(-EINVAL);
 
 				if (!root_cdev)
 					pr_err("no cdev found for %s, cannot set root= option\n",
 						root_dev_name);
-				else if (!root_cdev->partuuid[0])
+				else if (!root_cdev->uuid[0])
 					pr_err("%s doesn't have a PARTUUID, cannot set root= option\n",
 						root_dev_name);
 			}
diff --git a/common/partitions.c b/common/partitions.c
index b579559672a0..9cca5c4a1546 100644
--- a/common/partitions.c
+++ b/common/partitions.c
@@ -51,7 +51,7 @@ static int register_one_partition(struct block_device *blk,
 	cdev->flags |= DEVFS_PARTITION_FROM_TABLE;
 
 	cdev->dos_partition_type = part->dos_partition_type;
-	strcpy(cdev->partuuid, part->partuuid);
+	strcpy(cdev->uuid, part->partuuid);
 
 	free(partition_name);
 
diff --git a/common/partitions/parser.h b/common/partitions/parser.h
index 69508932b361..d67f8e1d6a09 100644
--- a/common/partitions/parser.h
+++ b/common/partitions/parser.h
@@ -17,7 +17,7 @@
 struct partition {
 	char name[MAX_PARTITION_NAME];
 	u8 dos_partition_type;
-	char partuuid[MAX_PARTUUID_STR];
+	char partuuid[MAX_UUID_STR];
 	uint64_t first_sec;
 	uint64_t size;
 };
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 2d016e0e4861..82e4811b384a 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -101,7 +101,7 @@ struct cdev *cdev_by_partuuid(const char *partuuid)
 		return NULL;
 
 	list_for_each_entry(cdev, &cdev_list, list) {
-		if (!strcasecmp(cdev->partuuid, partuuid))
+		if (cdev->master && !strcasecmp(cdev->uuid, partuuid))
 			return cdev;
 	}
 	return NULL;
diff --git a/fs/fs.c b/fs/fs.c
index 7da3a050c1cb..a92b4e9dfca1 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2969,8 +2969,8 @@ int mount(const char *device, const char *fsname, const char *pathname,
 		    cdev_is_mci_main_part_dev(fsdev->cdev->master))
 			str = get_linux_mmcblkdev(fsdev);
 
-		if (!str && fsdev->cdev->partuuid[0] != 0)
-			str = basprintf("root=PARTUUID=%s", fsdev->cdev->partuuid);
+		if (!str && fsdev->cdev->uuid[0] != 0)
+			str = basprintf("root=PARTUUID=%s", fsdev->cdev->uuid);
 
 		if (str)
 			fsdev_set_linux_rootarg(fsdev, str);
diff --git a/include/driver.h b/include/driver.h
index 4f6d40e17c14..409ed7e02afd 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -447,7 +447,7 @@ struct cdev_operations {
 	int (*truncate)(struct cdev*, size_t size);
 };
 
-#define MAX_PARTUUID_STR	sizeof("00112233-4455-6677-8899-AABBCCDDEEFF")
+#define MAX_UUID_STR	sizeof("00112233-4455-6677-8899-AABBCCDDEEFF")
 
 struct cdev {
 	const struct cdev_operations *ops;
@@ -460,7 +460,7 @@ struct cdev {
 	char *partname; /* the partition name, usually the above without the
 			 * device part, i.e. name = "nand0.barebox" -> partname = "barebox"
 			 */
-	char partuuid[MAX_PARTUUID_STR];
+	char uuid[MAX_UUID_STR];
 	loff_t offset;
 	loff_t size;
 	unsigned int flags;
-- 
2.30.2



From m.olbrich at pengutronix.de  Mon Jan 24 02:04:55 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Mon, 24 Jan 2022 11:04:55 +0100
Subject: [PATCH 0/3] state: find backend with UUID but without a partition
Message-ID: <20220124100458.2924679-1-m.olbrich@pengutronix.de>

Hi,

When adding state with a barebox update on existing devices, then it's not
always possible to add a partition for it. But currently that's the only
way to specify the state backend on x86_64/EFI devices.

This adds support backend-diskuuid / backend-offset. This way the backend
is defined by a UUID that selects a disk and an offset within that disk.

Michael

Michael Olbrich (3):
  cdev: rename partuuid to uuid
  cdev: add diskuuid support
  state: support backend-diskuuid / backend-offset

 common/bootm.c             |  6 ++---
 common/partitions.c        |  2 +-
 common/partitions/dos.c    |  3 +++
 common/partitions/efi.c    |  2 ++
 common/partitions/parser.h |  2 +-
 common/state/state.c       | 55 +++++++++++++++++++++++++-------------
 fs/devfs-core.c            | 16 ++++++++++-
 fs/fs.c                    |  4 +--
 include/driver.h           |  5 ++--
 include/fs.h               | 12 +++++++++
 10 files changed, 79 insertions(+), 28 deletions(-)

-- 
2.30.2



From m.olbrich at pengutronix.de  Mon Jan 24 02:04:57 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Mon, 24 Jan 2022 11:04:57 +0100
Subject: [PATCH 2/3] cdev: add diskuuid support
In-Reply-To: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
Message-ID: <20220124100458.2924679-3-m.olbrich@pengutronix.de>

This allows identifying disks by UUID. For disks with GPT the disk GUID is
used. For DOS partition tables the NT signature ist used, similar to how
the partuuid is generated.

Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
---
 common/partitions/dos.c |  3 +++
 common/partitions/efi.c |  2 ++
 fs/devfs-core.c         | 14 ++++++++++++++
 include/driver.h        |  1 +
 4 files changed, 20 insertions(+)

diff --git a/common/partitions/dos.c b/common/partitions/dos.c
index 6c76aac37172..258b10a9ed3c 100644
--- a/common/partitions/dos.c
+++ b/common/partitions/dos.c
@@ -182,6 +182,9 @@ static void dos_partition(void *buf, struct block_device *blk,
 	struct disk_signature_priv *dsp;
 	uint32_t signature = get_unaligned_le32(buf + 0x1b8);
 
+	if (signature)
+		sprintf(blk->cdev.uuid, "%08x", signature);
+
 	table = (struct partition_entry *)&buffer[446];
 
 	for (i = 0; i < 4; i++) {
diff --git a/common/partitions/efi.c b/common/partitions/efi.c
index 6d811bfb3b01..0787b93f120b 100644
--- a/common/partitions/efi.c
+++ b/common/partitions/efi.c
@@ -445,6 +445,8 @@ static void efi_partition(void *buf, struct block_device *blk,
 		return;
 	}
 
+	snprintf(blk->cdev.uuid, sizeof(blk->cdev.uuid), "%pUl", &gpt->disk_guid);
+
 	nb_part = le32_to_cpu(gpt->num_partition_entries);
 
 	if (nb_part > MAX_PARTITION) {
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 82e4811b384a..2475ab959a10 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -107,6 +107,20 @@ struct cdev *cdev_by_partuuid(const char *partuuid)
 	return NULL;
 }
 
+struct cdev *cdev_by_diskuuid(const char *diskuuid)
+{
+	struct cdev *cdev;
+
+	if (!diskuuid)
+		return NULL;
+
+	list_for_each_entry(cdev, &cdev_list, list) {
+		if (!cdev->master && !strcasecmp(cdev->uuid, diskuuid))
+			return cdev;
+	}
+	return NULL;
+}
+
 /**
  * device_find_partition - find a partition belonging to a physical device
  *
diff --git a/include/driver.h b/include/driver.h
index 409ed7e02afd..e38a15f51f00 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -484,6 +484,7 @@ struct cdev *lcdev_by_name(const char *filename);
 struct cdev *cdev_readlink(struct cdev *cdev);
 struct cdev *cdev_by_device_node(struct device_node *node);
 struct cdev *cdev_by_partuuid(const char *partuuid);
+struct cdev *cdev_by_diskuuid(const char *partuuid);
 struct cdev *cdev_open(const char *name, unsigned long flags);
 struct cdev *cdev_create_loop(const char *path, ulong flags, loff_t offset);
 void cdev_remove_loop(struct cdev *cdev);
-- 
2.30.2



From m.olbrich at pengutronix.de  Mon Jan 24 02:04:58 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Mon, 24 Jan 2022 11:04:58 +0100
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
Message-ID: <20220124100458.2924679-4-m.olbrich@pengutronix.de>

On some platforms (e.g. EFI on x86_64) the state backend can only be
selected by a partiton UUID. On existing devices with a DOS partition
table, there may be no spare partition available for state.

This makes it possible to select the disk via UUID. The exact position is
defined by an explicitly specified offset.

Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
---

I wasn't sure where to add the helper function. Is include/fs.h ok or
should I put it somewhere else?

I'll implement the same helper for dt-utils, so we can avoid additional
#ifdef here.

 common/state/state.c | 55 +++++++++++++++++++++++++++++---------------
 include/fs.h         | 12 ++++++++++
 2 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/common/state/state.c b/common/state/state.c
index 8c34ae83e52b..2a8b12d20c5a 100644
--- a/common/state/state.c
+++ b/common/state/state.c
@@ -592,6 +592,7 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
 	const char *backend_type;
 	const char *storage_type = NULL;
 	const char *alias;
+	const char *diskuuid;
 	uint32_t stridesize;
 	struct device_node *partition_node;
 	off_t offset = 0;
@@ -607,30 +608,48 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
 	if (IS_ERR(state))
 		return state;
 
-	partition_node = of_parse_phandle(node, "backend", 0);
-	if (!partition_node) {
-		dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n");
-		ret = -EINVAL;
-		goto out_release_state;
-	}
+	ret = of_property_read_string(node, "backend-diskuuid", &diskuuid);
+	if (ret == 0) {
+		u64 off;
+
+		ret = devpath_from_diskuuid(diskuuid, &state->backend_path);
+		if (ret) {
+			dev_err(&state->dev, "state failed find backend device for diskuuid='%s'\n",
+				diskuuid);
+			goto out_release_state;
+		}
+		ret = of_property_read_u64(node, "backend-offset", &off);
+		if (ret) {
+			dev_err(&state->dev, "'backend-offset' property undefined\n");
+			goto out_release_state;
+		}
+		offset = off;
+	} else {
+		partition_node = of_parse_phandle(node, "backend", 0);
+		if (!partition_node) {
+			dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n");
+			ret = -EINVAL;
+			goto out_release_state;
+		}
 
 #ifdef __BAREBOX__
-	ret = of_partition_ensure_probed(partition_node);
-	if (ret)
-		goto out_release_state;
+		ret = of_partition_ensure_probed(partition_node);
+		if (ret)
+			goto out_release_state;
 
-	ret = of_find_path_by_node(partition_node, &state->backend_path, 0);
+		ret = of_find_path_by_node(partition_node, &state->backend_path, 0);
 #else
-	ret = of_get_devicepath(partition_node, &state->backend_path, &offset, &size);
+		ret = of_get_devicepath(partition_node, &state->backend_path, &offset, &size);
 #endif
-	if (ret) {
-		if (ret != -EPROBE_DEFER)
-			dev_err(&state->dev, "state failed to parse path to backend: %s\n",
-			       strerror(-ret));
-		goto out_release_state;
-	}
+		if (ret) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(&state->dev, "state failed to parse path to backend: %s\n",
+				       strerror(-ret));
+			goto out_release_state;
+		}
 
-	state->backend_reproducible_name = of_get_reproducible_name(partition_node);
+		state->backend_reproducible_name = of_get_reproducible_name(partition_node);
+	}
 
 	ret = of_property_read_string(node, "backend-type", &backend_type);
 	if (ret) {
diff --git a/include/fs.h b/include/fs.h
index cd5eb571e08e..1a2f9c7f8e16 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -177,4 +177,16 @@ static inline const char *devpath_to_name(const char *devpath)
 	return devpath;
 }
 
+static inline int devpath_from_diskuuid(const char *diskuuid, char **devpath)
+{
+	struct cdev *cdev;
+
+	cdev = cdev_by_diskuuid(diskuuid);
+	if (!cdev)
+		return -EINVAL;
+
+	*devpath = xasprintf("/dev/%s", cdev->name);
+	return 0;
+}
+
 #endif /* __FS_H */
-- 
2.30.2



From sha at pengutronix.de  Mon Jan 24 02:59:19 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 24 Jan 2022 11:59:19 +0100
Subject: [PATCH 1/2] Documentation: reboot-mode: fix typos
In-Reply-To: <20220120114725.2580392-1-u.oelmann@pengutronix.de>
References: <20220120114725.2580392-1-u.oelmann@pengutronix.de>
Message-ID: <20220124105919.GY23490@pengutronix.de>

On Thu, Jan 20, 2022 at 12:47:24PM +0100, Ulrich ?lmann wrote:
> Signed-off-by: Ulrich ?lmann <u.oelmann at pengutronix.de>
> ---
>  Documentation/user/reboot-mode.rst | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Applied, thanks

Sascha

> 
> diff --git a/Documentation/user/reboot-mode.rst b/Documentation/user/reboot-mode.rst
> index 681438d94498..24deae78727e 100644
> --- a/Documentation/user/reboot-mode.rst
> +++ b/Documentation/user/reboot-mode.rst
> @@ -29,9 +29,9 @@ User API
>  Devices registered with the reboot mode API gain two parameters:
>  
>   - ``$dev_of_reboot_mode.prev`` (read-only): The reboot mode that was
> -   set previous to barebox startup
> +   set previously to barebox startup.
>   - ``$dev_of_reboot_mode.next``: The next reboot mode, for when the
> -   system is reset
> +   system is reset.
>  
>  The reboot mode driver core use the alias name if available to name
>  the device. By convention, this should end with ``.reboot_mode``, e.g.::
> -- 
> 2.30.2
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan 24 07:18:25 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 16:18:25 +0100
Subject: [PATCH 4/6] Documentation: regulator: reference new directory from
 index
In-Reply-To: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
References: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
Message-ID: <20220124151827.3313412-4-a.fatoum@pengutronix.de>

The binding was recently added, but unreferenced. Fix this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/devicetree/index.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/index.rst b/Documentation/devicetree/index.rst
index 198c4893ff51..d03db3cf8263 100644
--- a/Documentation/devicetree/index.rst
+++ b/Documentation/devicetree/index.rst
@@ -114,4 +114,5 @@ Contents:
    bindings/leds/*
    bindings/misc/*
    bindings/mtd/*
+   bindings/regulator/*
    bindings/rtc/*
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 24 07:18:26 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 16:18:26 +0100
Subject: [PATCH 5/6] Documentation: boards: openrisc: fix wrong header format
In-Reply-To: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
References: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
Message-ID: <20220124151827.3313412-5-a.fatoum@pengutronix.de>

Build warns that line is too short. Fix it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/boards/openrisc.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/boards/openrisc.rst b/Documentation/boards/openrisc.rst
index 34586b4a76b3..17b0aef4a6ad 100644
--- a/Documentation/boards/openrisc.rst
+++ b/Documentation/boards/openrisc.rst
@@ -22,7 +22,7 @@ Example of downloading and installing a toolchain::
   $ export PATH=$PATH:$PWD/or1k-elf/bin
 
 Running OpenRISC barebox on qemu
-------------------------------
+--------------------------------
 
 Running barebox on qemu is similar to running linux on qemu see more details on
 the qemu wiki site at https://wiki.qemu.org/Documentation/Platforms/OpenRISC
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 24 07:18:27 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 16:18:27 +0100
Subject: [PATCH 6/6] Documentation: user: watchdog: note new wd -x option
In-Reply-To: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
References: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
Message-ID: <20220124151827.3313412-6-a.fatoum@pengutronix.de>

wd command documentation is generated automatically and will list the
new -x option. It's still a good idea to reference this in the
watchdog user doc as well. Do so.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/user/watchdog.rst | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Documentation/user/watchdog.rst b/Documentation/user/watchdog.rst
index ff400317a0bc..0220965598ed 100644
--- a/Documentation/user/watchdog.rst
+++ b/Documentation/user/watchdog.rst
@@ -10,6 +10,15 @@ the bootloader. For these scenarios barebox provides the watchdog framework
 with the following functionality and at least ``CONFIG_WATCHDOG`` should be
 enabled.
 
+Disabling for development
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The shorthand command ``wd -x`` will disable all watchdogs.
+If hardware (or driver) doesn't support turning off the watchdog,
+an autpoller will be registered to periodically feed watchdogs.
+This should only be needed for development.
+See :ref:`boot-watchdog-timeout` for how to use the watchdog in the field.
+
 Polling
 ~~~~~~~
 
@@ -98,6 +107,8 @@ device tree or via the ``priority`` device parameter. Normally, watchdogs
 that have a wider effect should be given the higher priority (e.g.
 PMIC watchdog resetting the board vs. SoC's watchdog resetting only itself).
 
+.. _boot-watchdog-timeout:
+
 Boot Watchdog Timeout
 ~~~~~~~~~~~~~~~~~~~~~
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 24 07:18:22 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 16:18:22 +0100
Subject: [PATCH 1/6] Documentation: user: introduction: update with
 lore/matrix/libera info
Message-ID: <20220124151827.3313412-1-a.fatoum@pengutronix.de>

The Website already points at Libera instead of Freenode. Update the
intro section, so the docs are correct as well.

While at it, mention lore and matrix.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/user/introduction.rst | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/user/introduction.rst b/Documentation/user/introduction.rst
index 8a980a70abc7..523fe288f9fe 100644
--- a/Documentation/user/introduction.rst
+++ b/Documentation/user/introduction.rst
@@ -24,6 +24,15 @@ discussion of barebox takes place here:
 
 http://lists.infradead.org/mailman/listinfo/barebox/
 
-There's also an IRC channel:
+Mails sent to the barebox mailing list are archived on
+`lore.barebox.org <https://lore.barebox.org/barebox/>`_.
 
-IRC: #barebox (Freenode)
+Patch series sent there can be fetched with `b4 <https://pypi.org/project/b4/>`_ ::
+
+   git config b4.midmask https://lore.barebox.org/%s
+   git config b4.linkmask https://lore.barebox.org/%s
+   b4 am https://lore.barebox.org/$messageid # replace with link
+
+There's also an IRC channel, which is
+`bridged to Matrix  <https://app.element.io/#/room/#barebox:matrix.org>`_:
+#barebox on Libera Chat
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 24 07:18:23 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 16:18:23 +0100
Subject: [PATCH 2/6] Documentation: add chapter on Talks about barebox
In-Reply-To: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
References: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
Message-ID: <20220124151827.3313412-2-a.fatoum@pengutronix.de>

There's been a number of talks about barebox. Collect them in a new
chapter for those, who prefer something less dry than wading through the
docs. A top-level chapter is chosen, so it's more visible to visitors.

The ordering is reverse chronological, except for the first entry: The
newest talk is German about running DOOM in barebox, which is a bit
detached to how barebox is normally used.

Instead, let's keep the first entry as a pointer to the latest overview
talk and then use reverse chronological order for the rest.

Signed-off-by: Johannes Schneider <JSchneider at jetter.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/index.rst |   1 +
 Documentation/talks.rst | 130 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 131 insertions(+)
 create mode 100644 Documentation/talks.rst

diff --git a/Documentation/index.rst b/Documentation/index.rst
index 836dc41af2a3..a3e019e9f0a2 100644
--- a/Documentation/index.rst
+++ b/Documentation/index.rst
@@ -20,6 +20,7 @@ Contents:
    glossary
    devicetree/*
    devel/devel.rst
+   talks
 
 * :ref:`search`
 * :ref:`genindex`
diff --git a/Documentation/talks.rst b/Documentation/talks.rst
new file mode 100644
index 000000000000..5f1af599316b
--- /dev/null
+++ b/Documentation/talks.rst
@@ -0,0 +1,130 @@
+Talks and Lectures
+==================
+
+This is a collection of talks held about barebox use and development
+at different technical conferences. The most recent overview talk
+is from 2020:
+
+Beyond 'Just' Booting: Barebox Bells and Whistles
+-------------------------------------------------
+
+Ahmad Fatoum, Embedded Linux Conference - Europe 2020
+`[slides] <https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf>`__
+`[video] <https://www.youtube.com/watch?v=fru1n54s2W4>`__
+
+   Porting barebox to a new STM32MP1 board and a general discussion
+   of design choices like multi-image, VFS, POSIX/Linux API,
+   fail-safe updates, boot fall-back mechanisms, etc.
+
+Besides older overview talks, there's a number of talks held
+about different aspects of barebox use.
+These are listed here in reverse chronological order.
+
+DOOM portieren f?r Einsteiger - Heavy Metal auf Bare Metal (German)
+-------------------------------------------------------------------
+
+Ahmad Fatoum, FrOSCon 2021
+`[slides] <https://programm.froscon.de/2021/system/event_attachments/attachments/000/000/622/original/heavy-metal-on-bare-metal.pdf>`__
+`[video] <https://media.ccc.de/v/froscon2021-2687-doom_portieren_fur_einsteiger>`__
+
+  "DOOM as a boot splash. How, why and how to get it on your nearest
+  home appliance". A (German) walkthrough on how to leverage barebox
+  APIs to run DOOM on any hardware supported by barebox.
+
+Initializing RISC-V: A Guided Tour for ARM Developers
+-----------------------------------------------------
+
+Rouven Czerwinski & Ahmad Fatoum, Embedded Linux Conference 2021
+`[slides] <https://elinux.org/images/8/80/Initializing-riscv.pdf>`__
+`[video] <https://www.youtube.com/watch?v=70oYYuflFLs>`__
+
+  A guide through the RISC-V architecture and some of its ISA extensions
+  and a walkthrough of the barebox port to the Beagle-V Starlight.
+
+From Reset Vector to Kernel - Navigating the ARM Matryoshka
+-----------------------------------------------------------
+
+Ahmad Fatoum, FOSDEM 2021
+`[slides & video] <https://archive.fosdem.org/2021/schedule/event/from_reset_vector_to_kernel/>`__
+
+  A walkthrough of NXP i.MX8M bootstrap. From Boot ROM through barebox to Linux.
+
+Booting your i.MX processor secure and implementing i.MX8 secure boot in barebox
+--------------------------------------------------------------------------------
+
+Rouven Czerwinski, `Stratum 0 Talk 2019 <https://stratum0.org/wiki/Vortr%C3%A4ge/Vorbei#2019>`__
+`[video] <https://www.youtube.com/watch?v=ZUGLEulZLWM>`__
+
+  A walkthrough of NXP i.MX8MQ high assurance boot with barebox.
+
+Porting Barebox to the Digi CC-MX6UL SBC Pro (German)
+-----------------------------------------------------
+
+Rouven Czerwinski, `Stratum 0 Live-Hacking 2019 <https://stratum0.org/wiki/Vortr%C3%A4ge/Vorbei#2019>`__
+`[video] <https://www.youtube.com/watch?v=FIwF6GfmsWM>`__
+
+  Live-coding a barebox port to a new i.MX6UL board while
+  explaining the details (in German).
+
+Remote update adventures with RAUC, Yocto and Barebox
+-----------------------------------------------------
+
+Patrick Boettcher, `Embedded Recipes 2019 <https://embedded-recipes.org/2019/remote-update-adventures-with-rauc-yocto-and-barebox/>`__
+`[video] <https://www.youtube.com/watch?v=hS3Fjf7fuHM>`__
+
+  Remote update and redundant boot of Embedded Linux devices
+  in the field with RAUC and barebox bootchooser.
+
+Verified Boot: From ROM to Userspace
+------------------------------------
+
+Marc Kleine-Budde, Embedded Linux Conference - Europe 2016
+`[slides] <https://elinux.org/images/f/f8/Verified_Boot.pdf>`__
+`[video] <https://www.youtube.com/watch?v=lkFKtCh2SaU>`__
+
+  Using FOSS components, including barebox, for a cryptographically
+  secured boot chain on NXP i.MX6 SoCs.
+
+Booting Linux Made Easy: A Barebox Update
+-----------------------------------------
+
+Robert Schwebel, `FOSDEM 2014 <https://archive.fosdem.org/2014/schedule/event/_booting_linux_made_easy:_a_barebox_update/>`__
+`[video] <https://www.youtube.com/watch?v=p-mHAQaJQcM>`__
+
+  An overview talk on barebox use in embedded Linux systems.
+
+Barebox and Bootloader Specification
+------------------------------------
+
+Sascha Hauer, Embedded Linux Conference - Europe 2013
+`[slides] <https://elinux.org/images/9/90/Barebox-elce2013-bootloaderspec.pdf>`__
+`[video] <https://www.youtube.com/watch?v=Z8FcIGXox_Y>`__
+
+  The freedesktop.org bootloader specification and its support in barebox.
+
+Barebox Bootloader
+------------------
+
+Sascha Hauer, Embedded Linux Conference - Europe 2012
+`[slides] <https://elinux.org/images/6/6b/PRE-20121108-1-Barebox.pdf>`__
+`[video] <https://www.youtube.com/watch?v=oY8BjCEt_p8>`__
+
+  An update on barebox development progress with a discussion of newly
+  implemented features in the preceding three years.
+
+Barebox: Booting Linux Fast and Fancy
+-------------------------------------
+
+Robert Schwebel & Sascha Hauer, Embedded Linux Conference - Europe 2010
+`[slides] <https://elinux.org/images/8/89/ELCE-2010-Barebox-Booting-Linux-Fast-and-Fancy.pdf>`__
+
+  Boot time optimization while using barebox.
+
+U-Boot-v2
+---------
+
+Sascha Hauer & Marc Kleine-Budde, Embedded Linux Conference 2009
+`[slides] <https://elinux.org/images/9/90/Hauer-U_BootV2.pdf>`__
+
+  Early barebox (still named U-Boot v2 back then) presentation on
+  the motivation for the fork and the niceties made possible by it.
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 24 07:18:24 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 16:18:24 +0100
Subject: [PATCH 3/6] commands: add missing command groups
In-Reply-To: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
References: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
Message-ID: <20220124151827.3313412-3-a.fatoum@pengutronix.de>

CMD_GRP_MISC is assumed in absence of an explicit group. Let's be
explicit instead to silence the warnings during documentation build.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/mmc.c         | 1 +
 fs/fs.c                | 2 ++
 lib/kasan/test_kasan.c | 1 +
 3 files changed, 4 insertions(+)

diff --git a/commands/mmc.c b/commands/mmc.c
index cbbb9d615145..1e62b71850e0 100644
--- a/commands/mmc.c
+++ b/commands/mmc.c
@@ -194,5 +194,6 @@ BAREBOX_CMD_HELP_END
 BAREBOX_CMD_START(mmc)
 	.cmd = do_mmc,
 	BAREBOX_CMD_OPTS("enh_area [-c] /dev/mmcX")
+	BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
 	BAREBOX_CMD_HELP(cmd_mmc_help)
 BAREBOX_CMD_END
diff --git a/fs/fs.c b/fs/fs.c
index 60fdb29078d6..02ced6d6dfbd 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -3255,6 +3255,7 @@ static int do_lookup_dentry(int argc, char *argv[])
 
 BAREBOX_CMD_START(lookup_dentry)
         .cmd            = do_lookup_dentry,
+	BAREBOX_CMD_GROUP(CMD_GRP_MISC)
 BAREBOX_CMD_END
 
 static struct dentry *debug_follow_mount(struct dentry *dentry)
@@ -3309,5 +3310,6 @@ static int do_debug_fs_dump(int argc, char *argv[])
 
 BAREBOX_CMD_START(debug_fs_dump)
         .cmd            = do_debug_fs_dump,
+	BAREBOX_CMD_GROUP(CMD_GRP_MISC)
 BAREBOX_CMD_END
 #endif
diff --git a/lib/kasan/test_kasan.c b/lib/kasan/test_kasan.c
index e472bb34993b..d0ea91547711 100644
--- a/lib/kasan/test_kasan.c
+++ b/lib/kasan/test_kasan.c
@@ -474,5 +474,6 @@ static int do_kasan_test(int argc, char *argv[])
 BAREBOX_CMD_START(kasan_tests)
         .cmd            = do_kasan_test,
         BAREBOX_CMD_DESC("Run KAsan tests")
+        BAREBOX_CMD_GROUP(CMD_GRP_MISC)
         BAREBOX_CMD_COMPLETE(empty_complete)
 BAREBOX_CMD_END
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 24 07:21:00 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 24 Jan 2022 16:21:00 +0100
Subject: [PATCH 2/6] Documentation: add chapter on Talks about barebox
In-Reply-To: <20220124151827.3313412-2-a.fatoum@pengutronix.de>
References: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
 <20220124151827.3313412-2-a.fatoum@pengutronix.de>
Message-ID: <c7a12071-176b-a5c0-be94-a7f670c2a430@pengutronix.de>

On 24.01.22 16:18, Ahmad Fatoum wrote:

Argh, botched authorship on rebase. @Sascha, could you fix up
Johannes as git author on apply if there's no v2? Thanks.

> There's been a number of talks about barebox. Collect them in a new
> chapter for those, who prefer something less dry than wading through the
> docs. A top-level chapter is chosen, so it's more visible to visitors.
> 
> The ordering is reverse chronological, except for the first entry: The
> newest talk is German about running DOOM in barebox, which is a bit
> detached to how barebox is normally used.
> 
> Instead, let's keep the first entry as a pointer to the latest overview
> talk and then use reverse chronological order for the rest.
> 
> Signed-off-by: Johannes Schneider <JSchneider at jetter.de>
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  Documentation/index.rst |   1 +
>  Documentation/talks.rst | 130 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 131 insertions(+)
>  create mode 100644 Documentation/talks.rst
> 
> diff --git a/Documentation/index.rst b/Documentation/index.rst
> index 836dc41af2a3..a3e019e9f0a2 100644
> --- a/Documentation/index.rst
> +++ b/Documentation/index.rst
> @@ -20,6 +20,7 @@ Contents:
>     glossary
>     devicetree/*
>     devel/devel.rst
> +   talks
>  
>  * :ref:`search`
>  * :ref:`genindex`
> diff --git a/Documentation/talks.rst b/Documentation/talks.rst
> new file mode 100644
> index 000000000000..5f1af599316b
> --- /dev/null
> +++ b/Documentation/talks.rst
> @@ -0,0 +1,130 @@
> +Talks and Lectures
> +==================
> +
> +This is a collection of talks held about barebox use and development
> +at different technical conferences. The most recent overview talk
> +is from 2020:
> +
> +Beyond 'Just' Booting: Barebox Bells and Whistles
> +-------------------------------------------------
> +
> +Ahmad Fatoum, Embedded Linux Conference - Europe 2020
> +`[slides] <https://elinux.org/images/9/9d/Barebox-bells-n-whistles.pdf>`__
> +`[video] <https://www.youtube.com/watch?v=fru1n54s2W4>`__
> +
> +   Porting barebox to a new STM32MP1 board and a general discussion
> +   of design choices like multi-image, VFS, POSIX/Linux API,
> +   fail-safe updates, boot fall-back mechanisms, etc.
> +
> +Besides older overview talks, there's a number of talks held
> +about different aspects of barebox use.
> +These are listed here in reverse chronological order.
> +
> +DOOM portieren f?r Einsteiger - Heavy Metal auf Bare Metal (German)
> +-------------------------------------------------------------------
> +
> +Ahmad Fatoum, FrOSCon 2021
> +`[slides] <https://programm.froscon.de/2021/system/event_attachments/attachments/000/000/622/original/heavy-metal-on-bare-metal.pdf>`__
> +`[video] <https://media.ccc.de/v/froscon2021-2687-doom_portieren_fur_einsteiger>`__
> +
> +  "DOOM as a boot splash. How, why and how to get it on your nearest
> +  home appliance". A (German) walkthrough on how to leverage barebox
> +  APIs to run DOOM on any hardware supported by barebox.
> +
> +Initializing RISC-V: A Guided Tour for ARM Developers
> +-----------------------------------------------------
> +
> +Rouven Czerwinski & Ahmad Fatoum, Embedded Linux Conference 2021
> +`[slides] <https://elinux.org/images/8/80/Initializing-riscv.pdf>`__
> +`[video] <https://www.youtube.com/watch?v=70oYYuflFLs>`__
> +
> +  A guide through the RISC-V architecture and some of its ISA extensions
> +  and a walkthrough of the barebox port to the Beagle-V Starlight.
> +
> +From Reset Vector to Kernel - Navigating the ARM Matryoshka
> +-----------------------------------------------------------
> +
> +Ahmad Fatoum, FOSDEM 2021
> +`[slides & video] <https://archive.fosdem.org/2021/schedule/event/from_reset_vector_to_kernel/>`__
> +
> +  A walkthrough of NXP i.MX8M bootstrap. From Boot ROM through barebox to Linux.
> +
> +Booting your i.MX processor secure and implementing i.MX8 secure boot in barebox
> +--------------------------------------------------------------------------------
> +
> +Rouven Czerwinski, `Stratum 0 Talk 2019 <https://stratum0.org/wiki/Vortr%C3%A4ge/Vorbei#2019>`__
> +`[video] <https://www.youtube.com/watch?v=ZUGLEulZLWM>`__
> +
> +  A walkthrough of NXP i.MX8MQ high assurance boot with barebox.
> +
> +Porting Barebox to the Digi CC-MX6UL SBC Pro (German)
> +-----------------------------------------------------
> +
> +Rouven Czerwinski, `Stratum 0 Live-Hacking 2019 <https://stratum0.org/wiki/Vortr%C3%A4ge/Vorbei#2019>`__
> +`[video] <https://www.youtube.com/watch?v=FIwF6GfmsWM>`__
> +
> +  Live-coding a barebox port to a new i.MX6UL board while
> +  explaining the details (in German).
> +
> +Remote update adventures with RAUC, Yocto and Barebox
> +-----------------------------------------------------
> +
> +Patrick Boettcher, `Embedded Recipes 2019 <https://embedded-recipes.org/2019/remote-update-adventures-with-rauc-yocto-and-barebox/>`__
> +`[video] <https://www.youtube.com/watch?v=hS3Fjf7fuHM>`__
> +
> +  Remote update and redundant boot of Embedded Linux devices
> +  in the field with RAUC and barebox bootchooser.
> +
> +Verified Boot: From ROM to Userspace
> +------------------------------------
> +
> +Marc Kleine-Budde, Embedded Linux Conference - Europe 2016
> +`[slides] <https://elinux.org/images/f/f8/Verified_Boot.pdf>`__
> +`[video] <https://www.youtube.com/watch?v=lkFKtCh2SaU>`__
> +
> +  Using FOSS components, including barebox, for a cryptographically
> +  secured boot chain on NXP i.MX6 SoCs.
> +
> +Booting Linux Made Easy: A Barebox Update
> +-----------------------------------------
> +
> +Robert Schwebel, `FOSDEM 2014 <https://archive.fosdem.org/2014/schedule/event/_booting_linux_made_easy:_a_barebox_update/>`__
> +`[video] <https://www.youtube.com/watch?v=p-mHAQaJQcM>`__
> +
> +  An overview talk on barebox use in embedded Linux systems.
> +
> +Barebox and Bootloader Specification
> +------------------------------------
> +
> +Sascha Hauer, Embedded Linux Conference - Europe 2013
> +`[slides] <https://elinux.org/images/9/90/Barebox-elce2013-bootloaderspec.pdf>`__
> +`[video] <https://www.youtube.com/watch?v=Z8FcIGXox_Y>`__
> +
> +  The freedesktop.org bootloader specification and its support in barebox.
> +
> +Barebox Bootloader
> +------------------
> +
> +Sascha Hauer, Embedded Linux Conference - Europe 2012
> +`[slides] <https://elinux.org/images/6/6b/PRE-20121108-1-Barebox.pdf>`__
> +`[video] <https://www.youtube.com/watch?v=oY8BjCEt_p8>`__
> +
> +  An update on barebox development progress with a discussion of newly
> +  implemented features in the preceding three years.
> +
> +Barebox: Booting Linux Fast and Fancy
> +-------------------------------------
> +
> +Robert Schwebel & Sascha Hauer, Embedded Linux Conference - Europe 2010
> +`[slides] <https://elinux.org/images/8/89/ELCE-2010-Barebox-Booting-Linux-Fast-and-Fancy.pdf>`__
> +
> +  Boot time optimization while using barebox.
> +
> +U-Boot-v2
> +---------
> +
> +Sascha Hauer & Marc Kleine-Budde, Embedded Linux Conference 2009
> +`[slides] <https://elinux.org/images/9/90/Hauer-U_BootV2.pdf>`__
> +
> +  Early barebox (still named U-Boot v2 back then) presentation on
> +  the motivation for the fork and the niceties made possible by it.
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Tue Jan 25 00:24:35 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 25 Jan 2022 09:24:35 +0100
Subject: [PATCH] ARM: rockchip-v8-defconfig: Enable USB
Message-ID: <20220125082435.1812912-1-s.hauer@pengutronix.de>

The USB controllers on the rk3568 are supported, so enable them in the
defconfig file.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/configs/rockchip_v8_defconfig | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/arm/configs/rockchip_v8_defconfig b/arch/arm/configs/rockchip_v8_defconfig
index 4ceb036db6..973d666afa 100644
--- a/arch/arm/configs/rockchip_v8_defconfig
+++ b/arch/arm/configs/rockchip_v8_defconfig
@@ -8,7 +8,6 @@ CONFIG_MMU=y
 CONFIG_MALLOC_SIZE=0x0
 CONFIG_MALLOC_TLSF=y
 CONFIG_KALLSYMS=y
-CONFIG_RELOCATABLE=y
 CONFIG_PROMPT="barebox> "
 CONFIG_BAUDRATE=1500000
 CONFIG_HUSH_FANCY_PROMPT=y
@@ -21,7 +20,6 @@ CONFIG_BOOTM_OFTREE=y
 CONFIG_BOOTM_OFTREE_UIMAGE=y
 CONFIG_BOOTM_AIMAGE=y
 CONFIG_BLSPEC=y
-CONFIG_SYSTEM_PARTITIONS=y
 CONFIG_CONSOLE_ACTIVATE_NONE=y
 CONFIG_CONSOLE_ALLOW_COLOR=y
 CONFIG_PBL_CONSOLE=y
@@ -37,6 +35,7 @@ CONFIG_LONGHELP=y
 CONFIG_CMD_IOMEM=y
 CONFIG_CMD_IMD=y
 CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_GO=y
 CONFIG_CMD_RESET=y
 CONFIG_CMD_UIMAGE=y
@@ -90,8 +89,22 @@ CONFIG_DRIVER_SERIAL_NS16550=y
 CONFIG_DRIVER_NET_DESIGNWARE_EQOS=y
 CONFIG_DRIVER_NET_DESIGNWARE_ROCKCHIP=y
 CONFIG_SMSC_PHY=y
+CONFIG_NET_USB=y
+CONFIG_NET_USB_ASIX=y
+CONFIG_USB_NET_AX88179_178A=y
+CONFIG_NET_USB_SMSC95XX=y
+CONFIG_NET_USB_RTL8152=y
 CONFIG_I2C=y
 CONFIG_I2C_GPIO=y
+CONFIG_USB_HOST=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_DUAL_ROLE=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_SERIAL=y
+CONFIG_USB_GADGET_FASTBOOT=y
+CONFIG_USB_GADGET_MASS_STORAGE=y
 CONFIG_MCI=y
 CONFIG_MCI_STARTUP=y
 CONFIG_MCI_MMC_BOOT_PARTITIONS=y
@@ -106,7 +119,12 @@ CONFIG_LED_GPIO_OF=y
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_POLLER=y
 CONFIG_WATCHDOG_DW=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED=y
 CONFIG_GENERIC_PHY=y
+CONFIG_USB_NOP_XCEIV=y
+CONFIG_PHY_ROCKCHIP_INNO_USB2=y
+CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY=y
 # CONFIG_VIRTIO_MENU is not set
 CONFIG_FS_CRAMFS=y
 CONFIG_FS_EXT4=y
-- 
2.30.2



From s.hauer at pengutronix.de  Tue Jan 25 02:41:40 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 25 Jan 2022 11:41:40 +0100
Subject: [PATCH] dos-partitions: Fix extended partitions
Message-ID: <20220125104140.3056337-1-s.hauer@pengutronix.de>

extended partitions are currently registered with their full size which
means they overlap with the logical partitions therein. Since 7f9f45b9bf
("devfs: Do not create overlapping partitions") we no longer register
overlapping partitions, so the logical partitions are no longer
accessible. Fix this by reducing the size of the extended partition to
two blocks (1kiB) which is the same as Linux does.

Fixes: 7f9f45b9bf ("devfs: Do not create overlapping partitions")
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Reported-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/partitions/dos.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/common/partitions/dos.c b/common/partitions/dos.c
index 6c76aac371..597d7bf9bc 100644
--- a/common/partitions/dos.c
+++ b/common/partitions/dos.c
@@ -200,6 +200,8 @@ static void dos_partition(void *buf, struct block_device *blk,
 			pd->used_entries++;
 
 			if (is_extended_partition(&pentry)) {
+				pd->parts[n].size = 2;
+
 				if (!extended_partition)
 					extended_partition = &pd->parts[n];
 				else
-- 
2.30.2



From sha at pengutronix.de  Tue Jan 25 06:16:22 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Tue, 25 Jan 2022 15:16:22 +0100
Subject: use string as variable name
In-Reply-To: <trinity-82a62e55-a3b0-43a3-8656-8a983119c309-1642931916783@3c-app-gmx-bs30>
References: <trinity-82a62e55-a3b0-43a3-8656-8a983119c309-1642931916783@3c-app-gmx-bs30>
Message-ID: <20220125141622.GC23490@pengutronix.de>

Hi Frank,

On Sun, Jan 23, 2022 at 10:58:36AM +0100, Frank Wunderlich wrote:
> Hi,
> 
> is it possible to use a string as variable-name?
> 
> example:
> 
> i=1
> img_$i=foo
> 
> now i have defined $img_1, but how to display it using $i again?
> 
> echo ${img_$i}
> echo ${img_${i}}
> 
> alternative may be a variable-array, but it seems not possible
> 
> img[$i]=bar
> img[1]=bar: No such file or directory
> 
> i just want to create a dynamic list and access the items of this list by index
> 
> another way may be appending new string with separator to existing string and split afterwards,
> but then i have the index-problem again.
> 
> i know barebox shell is limited (but much more mighty than expected for just a bootloader),
> but maybe it is possible :)

Nah, you're kidding, the barebox shell is not limited ;)

#!/bin/sh

list="foo bar baz"

index=$1

i=0
for elem in $list; do
        let i=$i+1
        if [ "$i" = "$index" ]; then
                result="$elem"
        fi
done

echo result: $result

Regards,
  Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From antonynpavlov at gmail.com  Tue Jan 25 22:32:33 2022
From: antonynpavlov at gmail.com (Antony Pavlov)
Date: Wed, 26 Jan 2022 09:32:33 +0300
Subject: [PATCH 06/12] mci: sdhci: Use Linux defines for
 SDHCI_HOST_CONTROL register
In-Reply-To: <20210607104411.23071-7-s.hauer@pengutronix.de>
References: <20210607104411.23071-1-s.hauer@pengutronix.de>
 <20210607104411.23071-7-s.hauer@pengutronix.de>
Message-ID: <20220126093233.026701eddc2a1a7dceb76849@gmail.com>

On Mon,  7 Jun 2021 12:44:05 +0200
Sascha Hauer <s.hauer at pengutronix.de> wrote:

Hi Sascha!

> To ease porting and comparing of Linux code.
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
>  drivers/mci/arasan-sdhci.c       | 12 ++++++------
>  drivers/mci/atmel-sdhci-common.c | 14 +++++++-------
>  drivers/mci/dove-sdhci.c         | 10 +++++-----
>  drivers/mci/sdhci.h              | 17 ++++++++++++-----
>  4 files changed, 30 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
> index e22db4cfa3..e02f222345 100644
> --- a/drivers/mci/arasan-sdhci.c
> +++ b/drivers/mci/arasan-sdhci.c

...

> @@ -200,21 +200,21 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
>  	}
>  
>  	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
> -			~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
> +			~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
>  
>  	switch (ios->bus_width) {
>  	case MMC_BUS_WIDTH_8:
> -		val |= SDHCI_DATA_WIDTH_8BIT;
> +		val |= SDHCI_CTRL_8BITBUS;
>  		break;
>  	case MMC_BUS_WIDTH_4:
                     ^^^^^^^^
> -		val |= SDHCI_DATA_WIDTH_4BIT;
                                  ^^^^^^^^^^^
> +		val |= SDHCI_CTRL_8BITBUS;
                                  ^^^^^^^
Is this correct?

>  		break;
>  	}
>  
>  	if (ios->clock > 26000000)
> -		val |= SDHCI_HIGHSPEED_EN;
> +		val |= SDHCI_CTRL_HISPD;
>  	else
> -		val &= ~SDHCI_HIGHSPEED_EN;
> +		val &= ~SDHCI_CTRL_HISPD;
>  
>  	sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
>  }
> diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
> index b391775b00..d2b777a93c 100644
> --- a/drivers/mci/atmel-sdhci-common.c
> +++ b/drivers/mci/atmel-sdhci-common.c

...

> @@ -297,15 +297,15 @@ static int at91_sdhci_set_bus_width(struct at91_sdhci *host, unsigned bus_width)
>  
>  	switch(bus_width) {
>  	case MMC_BUS_WIDTH_8:
> -		reg |= SDHCI_DATA_WIDTH_8BIT;
> +		reg |= SDHCI_CTRL_8BITBUS;
>  		break;
>  	case MMC_BUS_WIDTH_4:
                     ^^^^^^^

> -		reg &= ~SDHCI_DATA_WIDTH_8BIT;
> -		reg |= SDHCI_DATA_WIDTH_4BIT;
                                  ^^^^^^^^^^^
> +		reg &= ~SDHCI_CTRL_8BITBUS;
> +		reg |= SDHCI_CTRL_8BITBUS;
                                  ^^^^^^^^

just the same question here

>  		break;
>  	default:
> -		reg &= ~SDHCI_DATA_WIDTH_8BIT;
> -		reg &= ~SDHCI_DATA_WIDTH_4BIT;
> +		reg &= ~SDHCI_CTRL_8BITBUS;
> +		reg &= ~SDHCI_CTRL_8BITBUS;

and here

>  	}
>  
>  	sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
> diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
> index 9c10e67eb8..cafc9dc579 100644
> --- a/drivers/mci/dove-sdhci.c
> +++ b/drivers/mci/dove-sdhci.c
> @@ -224,20 +224,20 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
>  
>  	/* set bus width */
>  	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
> -		~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
> +		~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
>  	switch (ios->bus_width) {
>  	case MMC_BUS_WIDTH_8:
> -		val |= SDHCI_DATA_WIDTH_8BIT;
> +		val |= SDHCI_CTRL_8BITBUS;
>  		break;
>  	case MMC_BUS_WIDTH_4:
> -		val |= SDHCI_DATA_WIDTH_4BIT;
> +		val |= SDHCI_CTRL_8BITBUS;

and here

>  		break;
>  	}
>  
>  	if (ios->clock > 26000000)
> -		val |= SDHCI_HIGHSPEED_EN;
> +		val |= SDHCI_CTRL_HISPD;
>  	else
> -		val &= ~SDHCI_HIGHSPEED_EN;
> +		val &= ~SDHCI_CTRL_HISPD;
>  
>  	sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
>  

-- 
Best regards,
? Antony Pavlov


From sha at pengutronix.de  Tue Jan 25 23:57:27 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 26 Jan 2022 08:57:27 +0100
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <20220124100458.2924679-4-m.olbrich@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
Message-ID: <20220126075727.GD23490@pengutronix.de>

On Mon, Jan 24, 2022 at 11:04:58AM +0100, Michael Olbrich wrote:
> On some platforms (e.g. EFI on x86_64) the state backend can only be
> selected by a partiton UUID. On existing devices with a DOS partition
> table, there may be no spare partition available for state.
> 
> This makes it possible to select the disk via UUID. The exact position is
> defined by an explicitly specified offset.
> 
> Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
> ---
> 
> I wasn't sure where to add the helper function. Is include/fs.h ok or
> should I put it somewhere else?
> 
> I'll implement the same helper for dt-utils, so we can avoid additional
> #ifdef here.
> 
>  common/state/state.c | 55 +++++++++++++++++++++++++++++---------------
>  include/fs.h         | 12 ++++++++++
>  2 files changed, 49 insertions(+), 18 deletions(-)
> 
> diff --git a/common/state/state.c b/common/state/state.c
> index 8c34ae83e52b..2a8b12d20c5a 100644
> --- a/common/state/state.c
> +++ b/common/state/state.c
> @@ -592,6 +592,7 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
>  	const char *backend_type;
>  	const char *storage_type = NULL;
>  	const char *alias;
> +	const char *diskuuid;
>  	uint32_t stridesize;
>  	struct device_node *partition_node;
>  	off_t offset = 0;
> @@ -607,30 +608,48 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
>  	if (IS_ERR(state))
>  		return state;
>  
> -	partition_node = of_parse_phandle(node, "backend", 0);
> -	if (!partition_node) {
> -		dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n");
> -		ret = -EINVAL;
> -		goto out_release_state;
> -	}
> +	ret = of_property_read_string(node, "backend-diskuuid", &diskuuid);

This needs some documentation in
Documentation/devicetree/bindings/barebox/barebox,state.rst.

> +	if (ret == 0) {
> +		u64 off;
> +
> +		ret = devpath_from_diskuuid(diskuuid, &state->backend_path);
> +		if (ret) {
> +			dev_err(&state->dev, "state failed find backend device for diskuuid='%s'\n",
> +				diskuuid);
> +			goto out_release_state;
> +		}
> +		ret = of_property_read_u64(node, "backend-offset", &off);

I stumbled upon this because you have to use a 64bit type here instead
of using 'offset' directly. I think 'offset' should be 64bit instead so
that larger offsets can be used.

> +		if (ret) {
> +			dev_err(&state->dev, "'backend-offset' property undefined\n");
> +			goto out_release_state;
> +		}
> +		offset = off;

What about the size of the state partition? This is not set anywhere in
this case so it's still zero. It should be specified the in device tree
as well. At the same time I'm a bit nervous that it apparently still
works with size zero.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Wed Jan 26 01:02:30 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 26 Jan 2022 10:02:30 +0100
Subject: [PATCH 2/6] Documentation: add chapter on Talks about barebox
In-Reply-To: <c7a12071-176b-a5c0-be94-a7f670c2a430@pengutronix.de>
References: <20220124151827.3313412-1-a.fatoum@pengutronix.de>
 <20220124151827.3313412-2-a.fatoum@pengutronix.de>
 <c7a12071-176b-a5c0-be94-a7f670c2a430@pengutronix.de>
Message-ID: <20220126090230.GF23490@pengutronix.de>

On Mon, Jan 24, 2022 at 04:21:00PM +0100, Ahmad Fatoum wrote:
> On 24.01.22 16:18, Ahmad Fatoum wrote:
> 
> Argh, botched authorship on rebase. @Sascha, could you fix up
> Johannes as git author on apply if there's no v2? Thanks.

Did that while applying, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Jan 26 01:20:07 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 26 Jan 2022 10:20:07 +0100
Subject: [PATCH] mmc: sdhci: Fix setting wrong buswidth
Message-ID: <20220126092007.4010252-1-s.hauer@pengutronix.de>

a0e22fc7bc accidently replaced SDHCI_DATA_WIDTH_4BIT with SDHCI_CTRL_8BITBUS.
Replace with SDHCI_CTRL_4BITBUS.

Reported-by: Antony Pavlov <antonynpavlov at gmail.com>
Fixes: a0e22fc7bc ("mci: sdhci: Use Linux defines for SDHCI_HOST_CONTROL register")
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/mci/atmel-sdhci-common.c | 4 ++--
 drivers/mci/dove-sdhci.c         | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index eff2a993db..129480aa55 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -302,11 +302,11 @@ static int at91_sdhci_set_bus_width(struct at91_sdhci *host, unsigned bus_width)
 		break;
 	case MMC_BUS_WIDTH_4:
 		reg &= ~SDHCI_CTRL_8BITBUS;
-		reg |= SDHCI_CTRL_8BITBUS;
+		reg |= SDHCI_CTRL_4BITBUS;
 		break;
 	default:
 		reg &= ~SDHCI_CTRL_8BITBUS;
-		reg &= ~SDHCI_CTRL_8BITBUS;
+		reg &= ~SDHCI_CTRL_4BITBUS;
 	}
 
 	sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index e6ac769bde..7581511285 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -181,13 +181,13 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 
 	/* set bus width */
 	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
-		~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
+		~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS);
 	switch (ios->bus_width) {
 	case MMC_BUS_WIDTH_8:
 		val |= SDHCI_CTRL_8BITBUS;
 		break;
 	case MMC_BUS_WIDTH_4:
-		val |= SDHCI_CTRL_8BITBUS;
+		val |= SDHCI_CTRL_4BITBUS;
 		break;
 	}
 
-- 
2.30.2



From s.hauer at pengutronix.de  Wed Jan 26 01:23:17 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 26 Jan 2022 10:23:17 +0100
Subject: [PATCH 06/12] mci: sdhci: Use Linux defines for
 SDHCI_HOST_CONTROL register
In-Reply-To: <20220126093233.026701eddc2a1a7dceb76849@gmail.com>
References: <20210607104411.23071-1-s.hauer@pengutronix.de>
 <20210607104411.23071-7-s.hauer@pengutronix.de>
 <20220126093233.026701eddc2a1a7dceb76849@gmail.com>
Message-ID: <20220126092317.GG23490@pengutronix.de>

On Wed, Jan 26, 2022 at 09:32:33AM +0300, Antony Pavlov wrote:
> On Mon,  7 Jun 2021 12:44:05 +0200
> Sascha Hauer <s.hauer at pengutronix.de> wrote:
> 
> Hi Sascha!
> 
> > To ease porting and comparing of Linux code.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> > ---
> >  drivers/mci/arasan-sdhci.c       | 12 ++++++------
> >  drivers/mci/atmel-sdhci-common.c | 14 +++++++-------
> >  drivers/mci/dove-sdhci.c         | 10 +++++-----
> >  drivers/mci/sdhci.h              | 17 ++++++++++++-----
> >  4 files changed, 30 insertions(+), 23 deletions(-)
> > 
> > diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
> > index e22db4cfa3..e02f222345 100644
> > --- a/drivers/mci/arasan-sdhci.c
> > +++ b/drivers/mci/arasan-sdhci.c
> 
> ...
> 
> > @@ -200,21 +200,21 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
> >  	}
> >  
> >  	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
> > -			~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
> > +			~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
> >  
> >  	switch (ios->bus_width) {
> >  	case MMC_BUS_WIDTH_8:
> > -		val |= SDHCI_DATA_WIDTH_8BIT;
> > +		val |= SDHCI_CTRL_8BITBUS;
> >  		break;
> >  	case MMC_BUS_WIDTH_4:
>                      ^^^^^^^^
> > -		val |= SDHCI_DATA_WIDTH_4BIT;
>                                   ^^^^^^^^^^^
> > +		val |= SDHCI_CTRL_8BITBUS;
>                                   ^^^^^^^
> Is this correct?

Nope, indeed not. Fortunately it's fixed in the same series in "[PATCH
08/12] mci: sdhci: arasan: Use sdhci_set_bus_width()". The other places
need fixing though, patch is out.

Thanks for noting

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From m.olbrich at pengutronix.de  Wed Jan 26 01:35:13 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Wed, 26 Jan 2022 10:35:13 +0100
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <20220126075727.GD23490@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
 <20220126075727.GD23490@pengutronix.de>
Message-ID: <20220126093513.GI11273@pengutronix.de>

On Wed, Jan 26, 2022 at 08:57:27AM +0100, Sascha Hauer wrote:
> On Mon, Jan 24, 2022 at 11:04:58AM +0100, Michael Olbrich wrote:
> > On some platforms (e.g. EFI on x86_64) the state backend can only be
> > selected by a partiton UUID. On existing devices with a DOS partition
> > table, there may be no spare partition available for state.
> > 
> > This makes it possible to select the disk via UUID. The exact position is
> > defined by an explicitly specified offset.
> > 
> > Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
> > ---
> > 
> > I wasn't sure where to add the helper function. Is include/fs.h ok or
> > should I put it somewhere else?
> > 
> > I'll implement the same helper for dt-utils, so we can avoid additional
> > #ifdef here.
> > 
> >  common/state/state.c | 55 +++++++++++++++++++++++++++++---------------
> >  include/fs.h         | 12 ++++++++++
> >  2 files changed, 49 insertions(+), 18 deletions(-)
> > 
> > diff --git a/common/state/state.c b/common/state/state.c
> > index 8c34ae83e52b..2a8b12d20c5a 100644
> > --- a/common/state/state.c
> > +++ b/common/state/state.c
> > @@ -592,6 +592,7 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> >  	const char *backend_type;
> >  	const char *storage_type = NULL;
> >  	const char *alias;
> > +	const char *diskuuid;
> >  	uint32_t stridesize;
> >  	struct device_node *partition_node;
> >  	off_t offset = 0;
> > @@ -607,30 +608,48 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> >  	if (IS_ERR(state))
> >  		return state;
> >  
> > -	partition_node = of_parse_phandle(node, "backend", 0);
> > -	if (!partition_node) {
> > -		dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n");
> > -		ret = -EINVAL;
> > -		goto out_release_state;
> > -	}
> > +	ret = of_property_read_string(node, "backend-diskuuid", &diskuuid);
> 
> This needs some documentation in
> Documentation/devicetree/bindings/barebox/barebox,state.rst.

I can do that.

> > +	if (ret == 0) {
> > +		u64 off;
> > +
> > +		ret = devpath_from_diskuuid(diskuuid, &state->backend_path);
> > +		if (ret) {
> > +			dev_err(&state->dev, "state failed find backend device for diskuuid='%s'\n",
> > +				diskuuid);
> > +			goto out_release_state;
> > +		}
> > +		ret = of_property_read_u64(node, "backend-offset", &off);
> 
> I stumbled upon this because you have to use a 64bit type here instead
> of using 'offset' directly. I think 'offset' should be 64bit instead so
> that larger offsets can be used.

It's not that simple. 'offset' used as a 'off_t' and 'ssize_t' all over the
place in the state framework. On 32bit architecture both are defined as
'long' or 'int'. Both are 32 bit types so changing 'offset' to a 64bit type
here doesn't really help.
On 64bit architectures 'off_t' and 'ssize_t' are both 'long' which is a
64bit type. We still need to cast from unsigned to signed, but I don't
think that's really a problem here.

So it works for large offsets on 64bit architectures as it is, and it can
be extended to work in 32bit architectures without changing the binding.
But doing that requires larger code changes. And I have no way to test
those.

> > +		if (ret) {
> > +			dev_err(&state->dev, "'backend-offset' property undefined\n");
> > +			goto out_release_state;
> > +		}
> > +		offset = off;
> 
> What about the size of the state partition? This is not set anywhere in
> this case so it's still zero. It should be specified the in device tree
> as well. At the same time I'm a bit nervous that it apparently still
> works with size zero.

The code explicitly checks if the size is specified and skips any range
checks if it's not. From what I can tell, it has been like that from the
beginning.

If that's not ok, then I could add a 'backend-size' property, or do you
have something else in mind?

Regards,
Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From antonynpavlov at gmail.com  Wed Jan 26 02:13:21 2022
From: antonynpavlov at gmail.com (Antony Pavlov)
Date: Wed, 26 Jan 2022 13:13:21 +0300
Subject: [PATCH 06/12] mci: sdhci: Use Linux defines for
 SDHCI_HOST_CONTROL register
In-Reply-To: <20220126092317.GG23490@pengutronix.de>
References: <20210607104411.23071-1-s.hauer@pengutronix.de>
 <20210607104411.23071-7-s.hauer@pengutronix.de>
 <20220126093233.026701eddc2a1a7dceb76849@gmail.com>
 <20220126092317.GG23490@pengutronix.de>
Message-ID: <20220126131321.f2e0e289b79bc83da781a382@gmail.com>

On Wed, 26 Jan 2022 10:23:17 +0100
Sascha Hauer <s.hauer at pengutronix.de> wrote:

> On Wed, Jan 26, 2022 at 09:32:33AM +0300, Antony Pavlov wrote:
> > On Mon,  7 Jun 2021 12:44:05 +0200
> > Sascha Hauer <s.hauer at pengutronix.de> wrote:
> > 
> > Hi Sascha!
> > 
> > > To ease porting and comparing of Linux code.
> > > 
> > > Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> > > ---
> > >  drivers/mci/arasan-sdhci.c       | 12 ++++++------
> > >  drivers/mci/atmel-sdhci-common.c | 14 +++++++-------
> > >  drivers/mci/dove-sdhci.c         | 10 +++++-----
> > >  drivers/mci/sdhci.h              | 17 ++++++++++++-----
> > >  4 files changed, 30 insertions(+), 23 deletions(-)
> > > 
> > > diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
> > > index e22db4cfa3..e02f222345 100644
> > > --- a/drivers/mci/arasan-sdhci.c
> > > +++ b/drivers/mci/arasan-sdhci.c
> > 
> > ...
> > 
> > > @@ -200,21 +200,21 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
> > >  	}
> > >  
> > >  	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
> > > -			~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
> > > +			~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
> > >  
> > >  	switch (ios->bus_width) {
> > >  	case MMC_BUS_WIDTH_8:
> > > -		val |= SDHCI_DATA_WIDTH_8BIT;
> > > +		val |= SDHCI_CTRL_8BITBUS;
> > >  		break;
> > >  	case MMC_BUS_WIDTH_4:
> >                      ^^^^^^^^
> > > -		val |= SDHCI_DATA_WIDTH_4BIT;
> >                                   ^^^^^^^^^^^
> > > +		val |= SDHCI_CTRL_8BITBUS;
> >                                   ^^^^^^^
> > Is this correct?
> 
> Nope, indeed not. Fortunately it's fixed in the same series in "[PATCH
> 08/12] mci: sdhci: arasan: Use sdhci_set_bus_width()". The other places
> need fixing though, patch is out.
> 
> Thanks for noting
> 

It looks like that there is one more line to fix. Please see

> diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
> index 9c10e67eb8..cafc9dc579 100644
> --- a/drivers/mci/dove-sdhci.c
> +++ b/drivers/mci/dove-sdhci.c
> @@ -224,20 +224,20 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
>  
>  	/* set bus width */
>  	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
> -		~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
> +		~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);

"SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS" instead of "SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS",
I suppose.


-- 
Best regards,
? Antony Pavlov


From sha at pengutronix.de  Wed Jan 26 02:15:24 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Wed, 26 Jan 2022 11:15:24 +0100
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <20220126093513.GI11273@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
 <20220126075727.GD23490@pengutronix.de>
 <20220126093513.GI11273@pengutronix.de>
Message-ID: <20220126101524.GH23490@pengutronix.de>

On Wed, Jan 26, 2022 at 10:35:13AM +0100, Michael Olbrich wrote:
> On Wed, Jan 26, 2022 at 08:57:27AM +0100, Sascha Hauer wrote:
> > On Mon, Jan 24, 2022 at 11:04:58AM +0100, Michael Olbrich wrote:
> > > On some platforms (e.g. EFI on x86_64) the state backend can only be
> > > selected by a partiton UUID. On existing devices with a DOS partition
> > > table, there may be no spare partition available for state.
> > > 
> > > This makes it possible to select the disk via UUID. The exact position is
> > > defined by an explicitly specified offset.
> > > 
> > > Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
> > > ---
> > > 
> > > I wasn't sure where to add the helper function. Is include/fs.h ok or
> > > should I put it somewhere else?
> > > 
> > > I'll implement the same helper for dt-utils, so we can avoid additional
> > > #ifdef here.
> > > 
> > >  common/state/state.c | 55 +++++++++++++++++++++++++++++---------------
> > >  include/fs.h         | 12 ++++++++++
> > >  2 files changed, 49 insertions(+), 18 deletions(-)
> > > 
> > > diff --git a/common/state/state.c b/common/state/state.c
> > > index 8c34ae83e52b..2a8b12d20c5a 100644
> > > --- a/common/state/state.c
> > > +++ b/common/state/state.c
> > > @@ -592,6 +592,7 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> > >  	const char *backend_type;
> > >  	const char *storage_type = NULL;
> > >  	const char *alias;
> > > +	const char *diskuuid;
> > >  	uint32_t stridesize;
> > >  	struct device_node *partition_node;
> > >  	off_t offset = 0;
> > > @@ -607,30 +608,48 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> > >  	if (IS_ERR(state))
> > >  		return state;
> > >  
> > > -	partition_node = of_parse_phandle(node, "backend", 0);
> > > -	if (!partition_node) {
> > > -		dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n");
> > > -		ret = -EINVAL;
> > > -		goto out_release_state;
> > > -	}
> > > +	ret = of_property_read_string(node, "backend-diskuuid", &diskuuid);
> > 
> > This needs some documentation in
> > Documentation/devicetree/bindings/barebox/barebox,state.rst.
> 
> I can do that.
> 
> > > +	if (ret == 0) {
> > > +		u64 off;
> > > +
> > > +		ret = devpath_from_diskuuid(diskuuid, &state->backend_path);
> > > +		if (ret) {
> > > +			dev_err(&state->dev, "state failed find backend device for diskuuid='%s'\n",
> > > +				diskuuid);
> > > +			goto out_release_state;
> > > +		}
> > > +		ret = of_property_read_u64(node, "backend-offset", &off);
> > 
> > I stumbled upon this because you have to use a 64bit type here instead
> > of using 'offset' directly. I think 'offset' should be 64bit instead so
> > that larger offsets can be used.
> 
> It's not that simple. 'offset' used as a 'off_t' and 'ssize_t' all over the
> place in the state framework. On 32bit architecture both are defined as
> 'long' or 'int'. Both are 32 bit types so changing 'offset' to a 64bit type
> here doesn't really help.

Of course not, we would have to replace all variables which are used as
offset into a device to 64bit types. That's a separate topic which
doesn't have to be solved as part of this series.

> > > +		}
> > > +		offset = off;
> > 
> > What about the size of the state partition? This is not set anywhere in
> > this case so it's still zero. It should be specified the in device tree
> > as well. At the same time I'm a bit nervous that it apparently still
> > works with size zero.
> 
> The code explicitly checks if the size is specified and skips any range
> checks if it's not. From what I can tell, it has been like that from the
> beginning.

That's likely ok for real partitions. When reading/writing them past the end
we'll get an error from the lower layers which can be handled, but not
so in this case where size is potentially the rest of the whole disk.

> 
> If that's not ok, then I could add a 'backend-size' property, or do you
> have something else in mind?

Yes, that's what I had in mind. And I think it should be mandatory.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From m.olbrich at pengutronix.de  Wed Jan 26 03:16:09 2022
From: m.olbrich at pengutronix.de (Michael Olbrich)
Date: Wed, 26 Jan 2022 12:16:09 +0100
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <20220126101524.GH23490@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
 <20220126075727.GD23490@pengutronix.de>
 <20220126093513.GI11273@pengutronix.de>
 <20220126101524.GH23490@pengutronix.de>
Message-ID: <20220126111609.GK11273@pengutronix.de>

On Wed, Jan 26, 2022 at 11:15:24AM +0100, Sascha Hauer wrote:
> On Wed, Jan 26, 2022 at 10:35:13AM +0100, Michael Olbrich wrote:
> > On Wed, Jan 26, 2022 at 08:57:27AM +0100, Sascha Hauer wrote:
> > > On Mon, Jan 24, 2022 at 11:04:58AM +0100, Michael Olbrich wrote:
> > > > On some platforms (e.g. EFI on x86_64) the state backend can only be
> > > > selected by a partiton UUID. On existing devices with a DOS partition
> > > > table, there may be no spare partition available for state.
> > > > 
> > > > This makes it possible to select the disk via UUID. The exact position is
> > > > defined by an explicitly specified offset.
> > > > 
> > > > Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
> > > > ---
> > > > 
> > > > I wasn't sure where to add the helper function. Is include/fs.h ok or
> > > > should I put it somewhere else?
> > > > 
> > > > I'll implement the same helper for dt-utils, so we can avoid additional
> > > > #ifdef here.
> > > > 
> > > >  common/state/state.c | 55 +++++++++++++++++++++++++++++---------------
> > > >  include/fs.h         | 12 ++++++++++
> > > >  2 files changed, 49 insertions(+), 18 deletions(-)
> > > > 
> > > > diff --git a/common/state/state.c b/common/state/state.c
> > > > index 8c34ae83e52b..2a8b12d20c5a 100644
> > > > --- a/common/state/state.c
> > > > +++ b/common/state/state.c
> > > > @@ -592,6 +592,7 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> > > >  	const char *backend_type;
> > > >  	const char *storage_type = NULL;
> > > >  	const char *alias;
> > > > +	const char *diskuuid;
> > > >  	uint32_t stridesize;
> > > >  	struct device_node *partition_node;
> > > >  	off_t offset = 0;
> > > > @@ -607,30 +608,48 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> > > >  	if (IS_ERR(state))
> > > >  		return state;
> > > >  
> > > > -	partition_node = of_parse_phandle(node, "backend", 0);
> > > > -	if (!partition_node) {
> > > > -		dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n");
> > > > -		ret = -EINVAL;
> > > > -		goto out_release_state;
> > > > -	}
> > > > +	ret = of_property_read_string(node, "backend-diskuuid", &diskuuid);
> > > 
> > > This needs some documentation in
> > > Documentation/devicetree/bindings/barebox/barebox,state.rst.
> > 
> > I can do that.
> > 
> > > > +	if (ret == 0) {
> > > > +		u64 off;
> > > > +
> > > > +		ret = devpath_from_diskuuid(diskuuid, &state->backend_path);
> > > > +		if (ret) {
> > > > +			dev_err(&state->dev, "state failed find backend device for diskuuid='%s'\n",
> > > > +				diskuuid);
> > > > +			goto out_release_state;
> > > > +		}
> > > > +		ret = of_property_read_u64(node, "backend-offset", &off);
> > > 
> > > I stumbled upon this because you have to use a 64bit type here instead
> > > of using 'offset' directly. I think 'offset' should be 64bit instead so
> > > that larger offsets can be used.
> > 
> > It's not that simple. 'offset' used as a 'off_t' and 'ssize_t' all over the
> > place in the state framework. On 32bit architecture both are defined as
> > 'long' or 'int'. Both are 32 bit types so changing 'offset' to a 64bit type
> > here doesn't really help.
> 
> Of course not, we would have to replace all variables which are used as
> offset into a device to 64bit types. That's a separate topic which
> doesn't have to be solved as part of this series.

So what should I do here?
- use 'u64' for 'offset' and remove the separate variable
- use 'loff_t' for 'offset'
- keep it as it is
- something else?

> > > > +		}
> > > > +		offset = off;
> > > 
> > > What about the size of the state partition? This is not set anywhere in
> > > this case so it's still zero. It should be specified the in device tree
> > > as well. At the same time I'm a bit nervous that it apparently still
> > > works with size zero.
> > 
> > The code explicitly checks if the size is specified and skips any range
> > checks if it's not. From what I can tell, it has been like that from the
> > beginning.
> 
> That's likely ok for real partitions. When reading/writing them past the end
> we'll get an error from the lower layers which can be handled, but not
> so in this case where size is potentially the rest of the whole disk.
> 
> > 
> > If that's not ok, then I could add a 'backend-size' property, or do you
> > have something else in mind?
> 
> Yes, that's what I had in mind. And I think it should be mandatory.

So, if we add a size, then it should also be validated in some way, right?
Maybe ensure that it does not overlap with existing partitions?

Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From antonynpavlov at gmail.com  Wed Jan 26 04:29:45 2022
From: antonynpavlov at gmail.com (Antony Pavlov)
Date: Wed, 26 Jan 2022 15:29:45 +0300
Subject: [PATCH v2 1/1] kbuild: dtc: Allow adding device tree fragments
 via config
In-Reply-To: <20210922181336.1350460-1-trent.piepho@igorinstitute.com>
References: <20210922181336.1350460-1-trent.piepho@igorinstitute.com>
Message-ID: <20220126152945.bb1104efad47e5a22be66fb9@gmail.com>

On Wed, 22 Sep 2021 11:13:36 -0700
Trent Piepho <trent.piepho at igorinstitute.com> wrote:

Hi!

This patch was applied to barebox source tree as 
  
  2ae7ac7ab2 kbuild: dtc: Allow adding device tree fragments via config

With this patch I see build error if device tree file name starts with digit (0-9),
e.g.:

  barebox$ git checkout v2022.01.0

  barebox$ make mrproper

  barebox$ export ARCH=arm
  barebox$ export CROSS_COMPILE=arm-none-eabi-
  barebox$ sed -i "s/virt2real.dtb/2virt2real.dtb/" arch/arm/dts/Makefile
  barebox$ mv arch/arm/dts/virt2real.dts arch/arm/dts/2virt2real.dts

  barebox$ make virt2real_defconfig
  ...
  barebox$ make -s
  <stdin>:1:9: error: macro names must be identifiers                                              make[1]:  [scripts/Makefile.lib:352: arch/arm/dts/2virt2real.dtb] Error 1
  make:  [Makefile:952: arch/arm/dts] Error 2




> This introduces a config variable that allows adding additional fragments
> to the Barebox device tree(s).
> 
> Example uses are adjusting the flash partition layout, adding barebox
> state variables, or adding an I2C device.  These can be now be done with
> build configuration only, without needing to patch the existing dts
> files in the Barebox source.
> 
> The advantage is greater when an external build system, such as Yocto or
> Buildroot, is being used to build Barebox.  The build system can drop in
> a dts fragment to partition flash and build from unaltered Barebox
> source.  This avoids the need for cumbersome maintenance of patch files
> to modify Barebox's source for each flash partition layout.
> 
> Preprocessing the dts file gains another layer, where a generated dts
> source consisting of an include directive for the original dts source is
> followed by more includes for each fragment.  This is piped to the
> existing preprocessor call on stdin to avoid another temporary file.
> cpp/dtc will correctly identify errors in the source files they occur
> in.  The -MT option is used so the cpp auto-dependencies reference the
> original dts source and not the generated code passed on stdin.
> 
> A preprocessor macro named after the base dts file, e.g. foo-bar.dts
> will define foo_bar_dts, will be defined so that the fragments can
> possibly operate differently based on which image's dts is being built.
> 
> Signed-off-by: Trent Piepho <trent.piepho at igorinstitute.com>
> ---
> Changes from v1:
>   - Remove 2nd config variable for in-tree fragments.
>   - Add macro to preproccessed dts
> 
>  common/Kconfig       | 18 ++++++++++++++++++
>  scripts/Makefile.lib |  8 +++++++-
>  2 files changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/common/Kconfig b/common/Kconfig
> index a9feae2ae..6fdc14148 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -1091,6 +1091,24 @@ config SYSTEMD_OF_WATCHDOG
>  	  in the kernel device tree. If the kernel is booted without a device
>  	  tree or with one that lacks aliases, nothing is added.
>  
> +config EXTERNAL_DTS_FRAGMENTS
> +	string "external dts file fragments"
> +	depends on OFTREE
> +	help
> +	  List of dts fragment files that will be appended to Barebox's device
> +	  tree(s) source when building the dtb file(s).  If multiple files are
> +	  listed, they will be appended in order.  Relative filenames will use
> +	  the dtc include search path.
> +
> +	  A preprocessor macro based on the name of the main dts will be
> +	  defined, which allows the dts fragments to based on which image of a
> +	  multi image build they are being used in.
> +
> +	  It not intended that this be put into into Barebox defconfig files.
> +	  Instead, it's an external build system, like Yocto or buildroot, to
> +	  add dts fragments from outside the Barebox source tree into the
> +	  Barebox build.
> +
>  menu "OP-TEE loading"
>  
>  config OPTEE_SIZE
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 80d76b177..4496f1a70 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -201,6 +201,7 @@ cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(__cpp_flags)
>  ld_flags       = $(KBUILD_LDFLAGS) $(ldflags-y)
>  
>  dtc_cpp_flags  = -Wp,-MD,$(depfile).pre -nostdinc                        \
> +		 -Wp,-MT,$(basename $(notdir $@)).o                      \
>  		 -I$(srctree)/arch/$(SRCARCH)/dts/include		 \
>  		 -I$(srctree)/dts/include                                \
>  		 -I$(srctree)/include                                    \
> @@ -335,8 +336,13 @@ cmd_dt_S_dtb = $(srctree)/scripts/gen-dtb-s $(subst -,_,$(*F)) $< $(CONFIG_IMD)
>  $(obj)/%.dtb.S: $(obj)/%.dtb $(srctree)/scripts/gen-dtb-s FORCE
>  	$(call if_changed,dt_S_dtb)
>  
> +dts-frags = $(subst $(quote),,$(CONFIG_EXTERNAL_DTS_FRAGMENTS))
>  quiet_cmd_dtc = DTC     $@
> -cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
> +# For compatibility between make 4.2 and 4.3
> +H := \#
> +cmd_dtc = /bin/echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"\n') | \
> +	$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \
>  	$(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \
>  		-i $(srctree)/arch/$(SRCARCH)/dts $(DTC_FLAGS) \
>  		-i $(srctree)/dts/src/$(SRCARCH) \
> -- 
> 2.31.1
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox


-- 
Best regards,
? Antony Pavlov


From trent.piepho at igorinstitute.com  Wed Jan 26 14:10:10 2022
From: trent.piepho at igorinstitute.com (Trent Piepho)
Date: Wed, 26 Jan 2022 14:10:10 -0800
Subject: [PATCH v2 1/1] kbuild: dtc: Allow adding device tree fragments
 via config
In-Reply-To: <20220126152945.bb1104efad47e5a22be66fb9@gmail.com>
References: <20210922181336.1350460-1-trent.piepho@igorinstitute.com>
 <20220126152945.bb1104efad47e5a22be66fb9@gmail.com>
Message-ID: <CAMHeXxOV7bunucQWHCaZBVm8GD-+qpqp9JfShuP-aE6fqz=PFA@mail.gmail.com>

There are no defconfigs that begin with a digit, but I guess there are
dts names that do.

Should probably just change the macro name from FOO_BOARD_DTS to DTS_FOO_BOARD.


On Wed, Jan 26, 2022 at 4:29 AM Antony Pavlov <antonynpavlov at gmail.com> wrote:
>
> On Wed, 22 Sep 2021 11:13:36 -0700
> Trent Piepho <trent.piepho at igorinstitute.com> wrote:
>
> Hi!
>
> This patch was applied to barebox source tree as
>
>   2ae7ac7ab2 kbuild: dtc: Allow adding device tree fragments via config
>
> With this patch I see build error if device tree file name starts with digit (0-9),
> e.g.:
>
>   barebox$ git checkout v2022.01.0
>
>   barebox$ make mrproper
>
>   barebox$ export ARCH=arm
>   barebox$ export CROSS_COMPILE=arm-none-eabi-
>   barebox$ sed -i "s/virt2real.dtb/2virt2real.dtb/" arch/arm/dts/Makefile
>   barebox$ mv arch/arm/dts/virt2real.dts arch/arm/dts/2virt2real.dts
>
>   barebox$ make virt2real_defconfig
>   ...
>   barebox$ make -s
>   <stdin>:1:9: error: macro names must be identifiers                                              make[1]:  [scripts/Makefile.lib:352: arch/arm/dts/2virt2real.dtb] Error 1
>   make:  [Makefile:952: arch/arm/dts] Error 2
>
>
>
>
> > This introduces a config variable that allows adding additional fragments
> > to the Barebox device tree(s).
> >
> > Example uses are adjusting the flash partition layout, adding barebox
> > state variables, or adding an I2C device.  These can be now be done with
> > build configuration only, without needing to patch the existing dts
> > files in the Barebox source.
> >
> > The advantage is greater when an external build system, such as Yocto or
> > Buildroot, is being used to build Barebox.  The build system can drop in
> > a dts fragment to partition flash and build from unaltered Barebox
> > source.  This avoids the need for cumbersome maintenance of patch files
> > to modify Barebox's source for each flash partition layout.
> >
> > Preprocessing the dts file gains another layer, where a generated dts
> > source consisting of an include directive for the original dts source is
> > followed by more includes for each fragment.  This is piped to the
> > existing preprocessor call on stdin to avoid another temporary file.
> > cpp/dtc will correctly identify errors in the source files they occur
> > in.  The -MT option is used so the cpp auto-dependencies reference the
> > original dts source and not the generated code passed on stdin.
> >
> > A preprocessor macro named after the base dts file, e.g. foo-bar.dts
> > will define foo_bar_dts, will be defined so that the fragments can
> > possibly operate differently based on which image's dts is being built.
> >
> > Signed-off-by: Trent Piepho <trent.piepho at igorinstitute.com>
> > ---
> > Changes from v1:
> >   - Remove 2nd config variable for in-tree fragments.
> >   - Add macro to preproccessed dts
> >
> >  common/Kconfig       | 18 ++++++++++++++++++
> >  scripts/Makefile.lib |  8 +++++++-
> >  2 files changed, 25 insertions(+), 1 deletion(-)
> >
> > diff --git a/common/Kconfig b/common/Kconfig
> > index a9feae2ae..6fdc14148 100644
> > --- a/common/Kconfig
> > +++ b/common/Kconfig
> > @@ -1091,6 +1091,24 @@ config SYSTEMD_OF_WATCHDOG
> >         in the kernel device tree. If the kernel is booted without a device
> >         tree or with one that lacks aliases, nothing is added.
> >
> > +config EXTERNAL_DTS_FRAGMENTS
> > +     string "external dts file fragments"
> > +     depends on OFTREE
> > +     help
> > +       List of dts fragment files that will be appended to Barebox's device
> > +       tree(s) source when building the dtb file(s).  If multiple files are
> > +       listed, they will be appended in order.  Relative filenames will use
> > +       the dtc include search path.
> > +
> > +       A preprocessor macro based on the name of the main dts will be
> > +       defined, which allows the dts fragments to based on which image of a
> > +       multi image build they are being used in.
> > +
> > +       It not intended that this be put into into Barebox defconfig files.
> > +       Instead, it's an external build system, like Yocto or buildroot, to
> > +       add dts fragments from outside the Barebox source tree into the
> > +       Barebox build.
> > +
> >  menu "OP-TEE loading"
> >
> >  config OPTEE_SIZE
> > diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> > index 80d76b177..4496f1a70 100644
> > --- a/scripts/Makefile.lib
> > +++ b/scripts/Makefile.lib
> > @@ -201,6 +201,7 @@ cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(__cpp_flags)
> >  ld_flags       = $(KBUILD_LDFLAGS) $(ldflags-y)
> >
> >  dtc_cpp_flags  = -Wp,-MD,$(depfile).pre -nostdinc                        \
> > +              -Wp,-MT,$(basename $(notdir $@)).o                      \
> >                -I$(srctree)/arch/$(SRCARCH)/dts/include                \
> >                -I$(srctree)/dts/include                                \
> >                -I$(srctree)/include                                    \
> > @@ -335,8 +336,13 @@ cmd_dt_S_dtb = $(srctree)/scripts/gen-dtb-s $(subst -,_,$(*F)) $< $(CONFIG_IMD)
> >  $(obj)/%.dtb.S: $(obj)/%.dtb $(srctree)/scripts/gen-dtb-s FORCE
> >       $(call if_changed,dt_S_dtb)
> >
> > +dts-frags = $(subst $(quote),,$(CONFIG_EXTERNAL_DTS_FRAGMENTS))
> >  quiet_cmd_dtc = DTC     $@
> > -cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
> > +# For compatibility between make 4.2 and 4.3
> > +H := \#
> > +cmd_dtc = /bin/echo -e '$(H)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(H)include "$(f)"\n') | \
> > +     $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \
> >       $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \
> >               -i $(srctree)/arch/$(SRCARCH)/dts $(DTC_FLAGS) \
> >               -i $(srctree)/dts/src/$(SRCARCH) \
> > --
> > 2.31.1
> >
> >
> > _______________________________________________
> > barebox mailing list
> > barebox at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/barebox
>
>
> --
> Best regards,
>   Antony Pavlov


From trent.piepho at igorinstitute.com  Wed Jan 26 16:18:51 2022
From: trent.piepho at igorinstitute.com (Trent Piepho)
Date: Wed, 26 Jan 2022 16:18:51 -0800
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <20220126111609.GK11273@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
 <20220126075727.GD23490@pengutronix.de>
 <20220126093513.GI11273@pengutronix.de>
 <20220126101524.GH23490@pengutronix.de>
 <20220126111609.GK11273@pengutronix.de>
Message-ID: <CAMHeXxPJJuC=MrtXp2iiQUnozs+2p1a8nC40LZd0Wf43t_g0Og@mail.gmail.com>

DTS ranges are usually specified as <offset> <length> in one property.
The sizes of offset and length fields are done with the #address-cells
and #size-cells of the bus the node is on.  I.e., barebox state
shouldn't be defining if offsets or lengths are 32 or 64 bits, it
should/is done by the device the offset or length refers to.

Like the normal 'reg' property in most nodes for register banks, or
the various "ranges" properties map an address space in the current
node to one in another node.

This backend-diskuuid, backend-offset, and backend-length seems like a
custom alternative version of a range that is specific to barebox
state.  Also, if the backend is a partition defined in the dts, then
the node of the partition specifies its size.  But if the partition is
found by uuid, then the barebox state device specifies the size of the
partition.  Seems inconsistent.

It seems like there should be a better and more consistent way to do this.

Here's an idea.  Identify the device by uuid and use existing
fixed-partitions.  Example:

{
    compatible = "storage-by-uuid";
    uuid = "abcd-1234";
    // Everything below here already exists and is unchanged
    partitions {
        compatible = "fixed-partitions";
        barebox_state: state at 1000 {
            label = "barebox-state";
            reg = <0x1000 0x200>;
        };
        barebox_env: env at 1200 {
            label = "barebox-env";
            reg = <0x1200 0x1000>;
        };
    };
};

When the top level node here is found, the matching device is located
by uuid and contents of the node are added to that device.  Adding
fixed partitions is done the same way it's already done.  The
difference is we can specify the device by uuid instead of needing to
locate the path of the exact hardware device.


On Wed, Jan 26, 2022 at 3:23 AM Michael Olbrich
<m.olbrich at pengutronix.de> wrote:
>
> On Wed, Jan 26, 2022 at 11:15:24AM +0100, Sascha Hauer wrote:
> > On Wed, Jan 26, 2022 at 10:35:13AM +0100, Michael Olbrich wrote:
> > > On Wed, Jan 26, 2022 at 08:57:27AM +0100, Sascha Hauer wrote:
> > > > On Mon, Jan 24, 2022 at 11:04:58AM +0100, Michael Olbrich wrote:
> > > > > On some platforms (e.g. EFI on x86_64) the state backend can only be
> > > > > selected by a partiton UUID. On existing devices with a DOS partition
> > > > > table, there may be no spare partition available for state.
> > > > >
> > > > > This makes it possible to select the disk via UUID. The exact position is
> > > > > defined by an explicitly specified offset.
> > > > >
> > > > > Signed-off-by: Michael Olbrich <m.olbrich at pengutronix.de>
> > > > > ---
> > > > >
> > > > > I wasn't sure where to add the helper function. Is include/fs.h ok or
> > > > > should I put it somewhere else?
> > > > >
> > > > > I'll implement the same helper for dt-utils, so we can avoid additional
> > > > > #ifdef here.
> > > > >
> > > > >  common/state/state.c | 55 +++++++++++++++++++++++++++++---------------
> > > > >  include/fs.h         | 12 ++++++++++
> > > > >  2 files changed, 49 insertions(+), 18 deletions(-)
> > > > >
> > > > > diff --git a/common/state/state.c b/common/state/state.c
> > > > > index 8c34ae83e52b..2a8b12d20c5a 100644
> > > > > --- a/common/state/state.c
> > > > > +++ b/common/state/state.c
> > > > > @@ -592,6 +592,7 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> > > > >         const char *backend_type;
> > > > >         const char *storage_type = NULL;
> > > > >         const char *alias;
> > > > > +       const char *diskuuid;
> > > > >         uint32_t stridesize;
> > > > >         struct device_node *partition_node;
> > > > >         off_t offset = 0;
> > > > > @@ -607,30 +608,48 @@ struct state *state_new_from_node(struct device_node *node, bool readonly)
> > > > >         if (IS_ERR(state))
> > > > >                 return state;
> > > > >
> > > > > -       partition_node = of_parse_phandle(node, "backend", 0);
> > > > > -       if (!partition_node) {
> > > > > -               dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n");
> > > > > -               ret = -EINVAL;
> > > > > -               goto out_release_state;
> > > > > -       }
> > > > > +       ret = of_property_read_string(node, "backend-diskuuid", &diskuuid);
> > > >
> > > > This needs some documentation in
> > > > Documentation/devicetree/bindings/barebox/barebox,state.rst.
> > >
> > > I can do that.
> > >
> > > > > +       if (ret == 0) {
> > > > > +               u64 off;
> > > > > +
> > > > > +               ret = devpath_from_diskuuid(diskuuid, &state->backend_path);
> > > > > +               if (ret) {
> > > > > +                       dev_err(&state->dev, "state failed find backend device for diskuuid='%s'\n",
> > > > > +                               diskuuid);
> > > > > +                       goto out_release_state;
> > > > > +               }
> > > > > +               ret = of_property_read_u64(node, "backend-offset", &off);
> > > >
> > > > I stumbled upon this because you have to use a 64bit type here instead
> > > > of using 'offset' directly. I think 'offset' should be 64bit instead so
> > > > that larger offsets can be used.
> > >
> > > It's not that simple. 'offset' used as a 'off_t' and 'ssize_t' all over the
> > > place in the state framework. On 32bit architecture both are defined as
> > > 'long' or 'int'. Both are 32 bit types so changing 'offset' to a 64bit type
> > > here doesn't really help.
> >
> > Of course not, we would have to replace all variables which are used as
> > offset into a device to 64bit types. That's a separate topic which
> > doesn't have to be solved as part of this series.
>
> So what should I do here?
> - use 'u64' for 'offset' and remove the separate variable
> - use 'loff_t' for 'offset'
> - keep it as it is
> - something else?
>
> > > > > +               }
> > > > > +               offset = off;
> > > >
> > > > What about the size of the state partition? This is not set anywhere in
> > > > this case so it's still zero. It should be specified the in device tree
> > > > as well. At the same time I'm a bit nervous that it apparently still
> > > > works with size zero.
> > >
> > > The code explicitly checks if the size is specified and skips any range
> > > checks if it's not. From what I can tell, it has been like that from the
> > > beginning.
> >
> > That's likely ok for real partitions. When reading/writing them past the end
> > we'll get an error from the lower layers which can be handled, but not
> > so in this case where size is potentially the rest of the whole disk.
> >
> > >
> > > If that's not ok, then I could add a 'backend-size' property, or do you
> > > have something else in mind?
> >
> > Yes, that's what I had in mind. And I think it should be mandatory.
>
> So, if we add a size, then it should also be validated in some way, right?
> Maybe ensure that it does not overlap with existing partitions?
>
> Michael
>
> --
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox


From sha at pengutronix.de  Thu Jan 27 04:39:24 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Thu, 27 Jan 2022 13:39:24 +0100
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <CAMHeXxPJJuC=MrtXp2iiQUnozs+2p1a8nC40LZd0Wf43t_g0Og@mail.gmail.com>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
 <20220126075727.GD23490@pengutronix.de>
 <20220126093513.GI11273@pengutronix.de>
 <20220126101524.GH23490@pengutronix.de>
 <20220126111609.GK11273@pengutronix.de>
 <CAMHeXxPJJuC=MrtXp2iiQUnozs+2p1a8nC40LZd0Wf43t_g0Og@mail.gmail.com>
Message-ID: <20220127123924.GQ23490@pengutronix.de>

On Wed, Jan 26, 2022 at 04:18:51PM -0800, Trent Piepho wrote:
> DTS ranges are usually specified as <offset> <length> in one property.
> The sizes of offset and length fields are done with the #address-cells
> and #size-cells of the bus the node is on.  I.e., barebox state
> shouldn't be defining if offsets or lengths are 32 or 64 bits, it
> should/is done by the device the offset or length refers to.
> 
> Like the normal 'reg' property in most nodes for register banks, or
> the various "ranges" properties map an address space in the current
> node to one in another node.
> 
> This backend-diskuuid, backend-offset, and backend-length seems like a
> custom alternative version of a range that is specific to barebox
> state.  Also, if the backend is a partition defined in the dts, then
> the node of the partition specifies its size.  But if the partition is
> found by uuid, then the barebox state device specifies the size of the
> partition.  Seems inconsistent.
> 
> It seems like there should be a better and more consistent way to do this.
> 
> Here's an idea.  Identify the device by uuid and use existing
> fixed-partitions.  Example:
> 
> {
>     compatible = "storage-by-uuid";
>     uuid = "abcd-1234";
>     // Everything below here already exists and is unchanged
>     partitions {
>         compatible = "fixed-partitions";
>         barebox_state: state at 1000 {
>             label = "barebox-state";
>             reg = <0x1000 0x200>;
>         };
>         barebox_env: env at 1200 {
>             label = "barebox-env";
>             reg = <0x1200 0x1000>;
>         };
>     };
> };
> 
> When the top level node here is found, the matching device is located
> by uuid and contents of the node are added to that device.  Adding
> fixed partitions is done the same way it's already done.  The
> difference is we can specify the device by uuid instead of needing to
> locate the path of the exact hardware device.

We discussed this approach internally as well and decided for the way
Michael has implemented it for two reasons. First it is easier to
implement, if not in barebox, but in Linux userspace where we need to
parse that binding as well. Second we don't need another barebox custom
binding when we extend the existing custom binding.

The fact that with the current approach we have to know that an
arbitrary property contains a 64bit value rather than the default 32bit
made me think if the approach of having a compatible =
"storage-by-uuid" driver is really the better one. I know that Ahmad
agrees here as well :)

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From trent.piepho at igorinstitute.com  Thu Jan 27 10:53:33 2022
From: trent.piepho at igorinstitute.com (Trent Piepho)
Date: Thu, 27 Jan 2022 10:53:33 -0800
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <20220127123924.GQ23490@pengutronix.de>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
 <20220126075727.GD23490@pengutronix.de>
 <20220126093513.GI11273@pengutronix.de>
 <20220126101524.GH23490@pengutronix.de>
 <20220126111609.GK11273@pengutronix.de>
 <CAMHeXxPJJuC=MrtXp2iiQUnozs+2p1a8nC40LZd0Wf43t_g0Og@mail.gmail.com>
 <20220127123924.GQ23490@pengutronix.de>
Message-ID: <CAMHeXxMCGpq4+jkhU0hOHy6x6sn9a2=gUW_rfhfF9UtSZZNpDQ@mail.gmail.com>

Could a linux dtb fixup be done in barebox?  This way userspace will
only have existing properties: storage devices with partitions
node(s), and barebox-state backend that points to a partition.  In
this case, the partition node was added by Barebox.

In fact, Barebox already does partition fixups exactly like this.  So
I think this would probably already happen.  It won't work if Linux
dtb does not have the storage device at all, as the partition fixup
considers that an error.  But maybe the Linux dtb will have the
storage device node?  Or if it doesn't have it because the storage is
"too dynamic" to put into the dts, then another fixup can make the
node.

On Thu, Jan 27, 2022 at 4:39 AM Sascha Hauer <sha at pengutronix.de> wrote:
>
> On Wed, Jan 26, 2022 at 04:18:51PM -0800, Trent Piepho wrote:
> > DTS ranges are usually specified as <offset> <length> in one property.
> > The sizes of offset and length fields are done with the #address-cells
> > and #size-cells of the bus the node is on.  I.e., barebox state
> > shouldn't be defining if offsets or lengths are 32 or 64 bits, it
> > should/is done by the device the offset or length refers to.
> >
> > Like the normal 'reg' property in most nodes for register banks, or
> > the various "ranges" properties map an address space in the current
> > node to one in another node.
> >
> > This backend-diskuuid, backend-offset, and backend-length seems like a
> > custom alternative version of a range that is specific to barebox
> > state.  Also, if the backend is a partition defined in the dts, then
> > the node of the partition specifies its size.  But if the partition is
> > found by uuid, then the barebox state device specifies the size of the
> > partition.  Seems inconsistent.
> >
> > It seems like there should be a better and more consistent way to do this.
> >
> > Here's an idea.  Identify the device by uuid and use existing
> > fixed-partitions.  Example:
> >
> > {
> >     compatible = "storage-by-uuid";
> >     uuid = "abcd-1234";
> >     // Everything below here already exists and is unchanged
> >     partitions {
> >         compatible = "fixed-partitions";
> >         barebox_state: state at 1000 {
> >             label = "barebox-state";
> >             reg = <0x1000 0x200>;
> >         };
> >         barebox_env: env at 1200 {
> >             label = "barebox-env";
> >             reg = <0x1200 0x1000>;
> >         };
> >     };
> > };
> >
> > When the top level node here is found, the matching device is located
> > by uuid and contents of the node are added to that device.  Adding
> > fixed partitions is done the same way it's already done.  The
> > difference is we can specify the device by uuid instead of needing to
> > locate the path of the exact hardware device.
>
> We discussed this approach internally as well and decided for the way
> Michael has implemented it for two reasons. First it is easier to
> implement, if not in barebox, but in Linux userspace where we need to
> parse that binding as well. Second we don't need another barebox custom
> binding when we extend the existing custom binding.
>
> The fact that with the current approach we have to know that an
> arbitrary property contains a 64bit value rather than the default 32bit
> made me think if the approach of having a compatible =
> "storage-by-uuid" driver is really the better one. I know that Ahmad
> agrees here as well :)
>
> Sascha
>
> --
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Thu Jan 27 23:48:12 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Jan 2022 08:48:12 +0100
Subject: [PATCH 3/3] state: support backend-diskuuid / backend-offset
In-Reply-To: <CAMHeXxMCGpq4+jkhU0hOHy6x6sn9a2=gUW_rfhfF9UtSZZNpDQ@mail.gmail.com>
References: <20220124100458.2924679-1-m.olbrich@pengutronix.de>
 <20220124100458.2924679-4-m.olbrich@pengutronix.de>
 <20220126075727.GD23490@pengutronix.de>
 <20220126093513.GI11273@pengutronix.de>
 <20220126101524.GH23490@pengutronix.de>
 <20220126111609.GK11273@pengutronix.de>
 <CAMHeXxPJJuC=MrtXp2iiQUnozs+2p1a8nC40LZd0Wf43t_g0Og@mail.gmail.com>
 <20220127123924.GQ23490@pengutronix.de>
 <CAMHeXxMCGpq4+jkhU0hOHy6x6sn9a2=gUW_rfhfF9UtSZZNpDQ@mail.gmail.com>
Message-ID: <20220128074812.GS23490@pengutronix.de>

On Thu, Jan 27, 2022 at 10:53:33AM -0800, Trent Piepho wrote:
> Could a linux dtb fixup be done in barebox?  This way userspace will
> only have existing properties: storage devices with partitions
> node(s), and barebox-state backend that points to a partition.  In
> this case, the partition node was added by Barebox.
> 
> In fact, Barebox already does partition fixups exactly like this.  So
> I think this would probably already happen.  It won't work if Linux
> dtb does not have the storage device at all, as the partition fixup
> considers that an error.  But maybe the Linux dtb will have the
> storage device node?  Or if it doesn't have it because the storage is
> "too dynamic" to put into the dts, then another fixup can make the
> node.

Michael wants to use this for EFI, so there is no full device tree under
Linux, there will only be the device tree snippet containing the state
node and now some dummy device describing the disk UUID.
While it sounds like an interesting idea it won't help us here.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From andrej.picej at norik.com  Fri Jan 28 00:00:33 2022
From: andrej.picej at norik.com (Andrej Picej)
Date: Fri, 28 Jan 2022 09:00:33 +0100
Subject: [PATCH] scripts/common: fix write_file when opened with mmap
Message-ID: <20220128080033.167251-1-andrej.picej@norik.com>

Usage of bareboximd with -c option (Create checksum for FILE and write
it to the crc32 tag) was broken. Possibly by applying 2154de1cf36c
(bareboximd: Use mmap when possibly). The script fails with:

    $ ./scripts/bareboximd -c images/<barebox-image.img>
    Cannot write to images/<barebox-mage.img>: Bad address
    CRC: write crc token to images/<barebox-image.img> failed: -14
    Bad address

This has to do with the usage of "mmap" and "open" with O_TRUNC flag
which truncates the file length to 0. Writing to files fails with:
EFAULT (14) buf is outside your accessible address space.
Remove the truncate flag and truncate manually after writing the data.

This fixes the bareboximd script, which is now again usable with -c
option.

Signed-off-by: Anze Lesnik <anze.lesnik at norik.com>
Signed-off-by: Andrej Picej <andrej.picej at norik.com>
---
 scripts/common.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/scripts/common.c b/scripts/common.c
index 3f8dcd2d38..331988d593 100644
--- a/scripts/common.c
+++ b/scripts/common.c
@@ -107,7 +107,7 @@ int write_file(const char *filename, const void *buf, size_t size)
 	int fd, ret = 0;
 	int now;
 
-	fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT,
+	fd = open(filename, O_WRONLY | O_CREAT,
 		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 	if (fd < 0) {
 		fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
@@ -126,6 +126,11 @@ int write_file(const char *filename, const void *buf, size_t size)
 		buf += now;
 	}
 
+	if (ftruncate(fd, now) < 0) {
+		fprintf(stderr, "Cannot truncate file: %s", strerror(errno));
+		ret = -errno;
+	}
+
 out:
 	close(fd);
 
-- 
2.25.1



From o.rempel at pengutronix.de  Fri Jan 28 00:23:13 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 28 Jan 2022 09:23:13 +0100
Subject: [PATCH v2 0/4] refactore rpi board code
Message-ID: <20220128082317.2410427-1-o.rempel@pengutronix.de>

changes v2:
- rework clk driver to properly support deep-probe
- remove currently not supported compatibles from board code
- reduce struct size
- rework rpi_get_dcfg to return *dcfg directly

Oleksij Rempel (4):
  ARM: rpi: convert board code to a driver
  ARM: rpi: move clk support to a separate driver and enable deep-probe
  ARM: rpi: validate devicetree compatible instead of changing model
    name
  ARM: rpi: set host name based on DT compatible

 arch/arm/boards/raspberry-pi/rpi-common.c | 486 +++++++++++++---------
 drivers/clk/Makefile                      |   1 +
 drivers/clk/clk-rpi.c                     | 109 +++++
 3 files changed, 396 insertions(+), 200 deletions(-)
 create mode 100644 drivers/clk/clk-rpi.c

-- 
2.30.2



From o.rempel at pengutronix.de  Fri Jan 28 00:23:14 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 28 Jan 2022 09:23:14 +0100
Subject: [PATCH v2 1/4] ARM: rpi: convert board code to a driver
In-Reply-To: <20220128082317.2410427-1-o.rempel@pengutronix.de>
References: <20220128082317.2410427-1-o.rempel@pengutronix.de>
Message-ID: <20220128082317.2410427-2-o.rempel@pengutronix.de>

Convert board code to a driver model. This will prevent executing this
part of code on any other BCM2xxx based boards.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 33 +++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 2684bd5ed7..247d12467a 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -511,7 +511,7 @@ static void rpi_vc_fdt(void)
 	}
 }
 
-static int rpi_devices_init(void)
+static int rpi_devices_probe(struct device_d *dev)
 {
 	struct regulator *reg;
 
@@ -529,4 +529,33 @@ static int rpi_devices_init(void)
 
 	return 0;
 }
-late_initcall(rpi_devices_init);
+
+static const struct of_device_id rpi_of_match[] = {
+	/* BCM2835 based Boards */
+	{ .compatible = "raspberrypi,model-a" },
+	{ .compatible = "raspberrypi,model-a-plus" },
+	{ .compatible = "raspberrypi,model-b" },
+	/* Raspberry Pi Model B (no P5) */
+	{ .compatible = "raspberrypi,model-b-i2c0" },
+	{ .compatible = "raspberrypi,model-b-rev2" },
+	{ .compatible = "raspberrypi,model-b-plus" },
+	{ .compatible = "raspberrypi,compute-module" },
+	{ .compatible = "raspberrypi,model-zero" },
+	{ .compatible = "raspberrypi,model-zero-w" },
+
+	/* BCM2836 based Boards */
+	{ .compatible = "raspberrypi,2-model-b" },
+
+	/* BCM2837 based Boards */
+	{ .compatible = "raspberrypi,3-model-a-plus" },
+	{ .compatible = "raspberrypi,3-model-b" },
+	{ .compatible = "raspberrypi,3-model-b-plus" },
+	{ /* sentinel */ },
+};
+
+static struct driver_d rpi_board_driver = {
+	.name = "board-rpi",
+	.probe = rpi_devices_probe,
+	.of_compatible = DRV_OF_COMPAT(rpi_of_match),
+};
+late_platform_driver(rpi_board_driver);
-- 
2.30.2



From o.rempel at pengutronix.de  Fri Jan 28 00:23:17 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 28 Jan 2022 09:23:17 +0100
Subject: [PATCH v2 4/4] ARM: rpi: set host name based on DT compatible
In-Reply-To: <20220128082317.2410427-1-o.rempel@pengutronix.de>
References: <20220128082317.2410427-1-o.rempel@pengutronix.de>
Message-ID: <20220128082317.2410427-5-o.rempel@pengutronix.de>

The "rpi" host name is not practical if you need to work with different
variants of RPi at same time. Usually, removing barebox_set_hostname()
would let barebox generate it automatically. But in this case, the name
would look less informative. For example "2-model-b".

So, make board code generate something usable, for example
"rpi-2-model-b"

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 8c5f442843..9aa150de56 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -379,6 +379,8 @@ static int rpi_devices_probe(struct device_d *dev)
 	const struct rpi_machine_data *dcfg;
 	struct regulator *reg;
 	struct rpi_priv *priv;
+	const char *name, *ptr;
+	char *hostname;
 	int ret;
 
 	priv = xzalloc(sizeof(*priv));
@@ -392,7 +394,12 @@ static int rpi_devices_probe(struct device_d *dev)
 	if (IS_ERR(dcfg))
 		goto free_priv;
 
-	barebox_set_hostname("rpi");
+	/* construct short recognizable host name */
+	name = of_device_get_match_compatible(priv->dev);
+	ptr = strchr(name, ',');
+	hostname = basprintf("rpi-%s", ptr ? ptr + 1 : name);
+	barebox_set_hostname(hostname);
+	free(hostname);
 
 	rpi_add_led();
 	bcm2835_register_fb();
-- 
2.30.2



From o.rempel at pengutronix.de  Fri Jan 28 00:23:15 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 28 Jan 2022 09:23:15 +0100
Subject: [PATCH v2 2/4] ARM: rpi: move clk support to a separate driver and
 enable deep-probe
In-Reply-To: <20220128082317.2410427-1-o.rempel@pengutronix.de>
References: <20220128082317.2410427-1-o.rempel@pengutronix.de>
Message-ID: <20220128082317.2410427-3-o.rempel@pengutronix.de>

To make deep-probe work properly, we need clock support be registered as
driver to related device.

To avoid regression, deep-probe is enabled in the same patch.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c |  75 +--------------
 drivers/clk/Makefile                      |   1 +
 drivers/clk/clk-rpi.c                     | 109 ++++++++++++++++++++++
 3 files changed, 112 insertions(+), 73 deletions(-)
 create mode 100644 drivers/clk/clk-rpi.c

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index 247d12467a..ab40dba50f 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -2,6 +2,7 @@
 // SPDX-FileCopyrightText: 2009 Carlo Caione <carlo at carlocaione.org>
 
 #include <common.h>
+#include <deep-probe.h>
 #include <init.h>
 #include <fs.h>
 #include <of.h>
@@ -45,12 +46,6 @@ struct msg_get_arm_mem {
 	u32 end_tag;
 };
 
-struct msg_get_clock_rate {
-	struct bcm2835_mbox_hdr hdr;
-	struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
-	u32 end_tag;
-};
-
 struct msg_get_board_rev {
 	struct bcm2835_mbox_hdr hdr;
 	struct bcm2835_mbox_tag_get_board_rev get_board_rev;
@@ -80,22 +75,6 @@ static int rpi_get_arm_mem(u32 *size)
 	return 0;
 }
 
-static struct clk *rpi_register_firmware_clock(u32 clock_id, const char *name)
-{
-	BCM2835_MBOX_STACK_ALIGN(struct msg_get_clock_rate, msg);
-	int ret;
-
-	BCM2835_MBOX_INIT_HDR(msg);
-	BCM2835_MBOX_INIT_TAG(&msg->get_clock_rate, GET_CLOCK_RATE);
-	msg->get_clock_rate.body.req.clock_id = clock_id;
-
-	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
-	if (ret)
-		return ERR_PTR(ret);
-
-	return clk_fixed(name, msg->get_clock_rate.body.resp.rate_hz);
-}
-
 static void rpi_set_usbethaddr(void)
 {
 	BCM2835_MBOX_STACK_ALIGN(struct msg_get_mac_address, msg);
@@ -343,57 +322,6 @@ static int rpi_postcore_init(void)
 }
 postcore_initcall(rpi_postcore_init);
 
-static int rpi_clock_init(void)
-{
-	struct clk *clk;
-
-	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_EMMC,
-					 "bcm2835_mci0");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	clkdev_add_physbase(clk, 0x20300000, NULL);
-	clkdev_add_physbase(clk, 0x3f300000, NULL);
-
-	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
-					  "bcm2835_sdhost");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	clkdev_add_physbase(clk, 0x20202000, NULL);
-	clkdev_add_physbase(clk, 0x3f202000, NULL);
-
-	return 0;
-}
-postconsole_initcall(rpi_clock_init);
-
-static int rpi_console_clock_init(void)
-{
-	struct clk *clk;
-
-	clk = clk_fixed("apb_pclk", 0);
-	clk_register_clkdev(clk, "apb_pclk", NULL);
-
-	clk = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
-	clk_register_clkdev(clk, NULL, "uart0-pl0110");
-	clkdev_add_physbase(clk, BCM2835_PL011_BASE, NULL);
-	clkdev_add_physbase(clk, BCM2836_PL011_BASE, NULL);
-
-	clk = rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
-					  "uart1-8250");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	clkdev_add_physbase(clk, BCM2835_MINIUART_BASE, NULL);
-	clkdev_add_physbase(clk, BCM2836_MINIUART_BASE, NULL);
-
-	clk = clk_fixed("bcm2835-cs", 1 * 1000 * 1000);
-	clk_register_clkdev(clk, NULL, "bcm2835-cs");
-
-	return 0;
-}
-postcore_initcall(rpi_console_clock_init);
-
 static int rpi_env_init(void)
 {
 	struct stat s;
@@ -552,6 +480,7 @@ static const struct of_device_id rpi_of_match[] = {
 	{ .compatible = "raspberrypi,3-model-b-plus" },
 	{ /* sentinel */ },
 };
+BAREBOX_DEEP_PROBE_ENABLE(rpi_of_match);
 
 static struct driver_d rpi_board_driver = {
 	.name = "board-rpi",
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 499df2fe39..9675d45dc9 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_ARCH_LAYERSCAPE)	+= clk-qoric.o
 obj-y				+= analogbits/
 obj-$(CONFIG_CLK_SIFIVE)	+= sifive/
 obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
+obj-$(CONFIG_MACH_RPI_COMMON)	+= clk-rpi.o
diff --git a/drivers/clk/clk-rpi.c b/drivers/clk/clk-rpi.c
new file mode 100644
index 0000000000..5afaa6e8bb
--- /dev/null
+++ b/drivers/clk/clk-rpi.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+
+#include <mach/core.h>
+#include <mach/mbox.h>
+#include <mach/platform.h>
+#include <dt-bindings/clock/bcm2835.h>
+
+#define BCM2711_CLOCK_END			(BCM2711_CLOCK_EMMC2 + 1)
+
+static struct clk *clks[BCM2711_CLOCK_END];
+static struct clk_onecell_data clk_data;
+
+struct msg_get_clock_rate {
+	struct bcm2835_mbox_hdr hdr;
+	struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
+	u32 end_tag;
+};
+
+static struct clk *rpi_register_firmware_clock(u32 clock_id, const char *name)
+{
+	BCM2835_MBOX_STACK_ALIGN(struct msg_get_clock_rate, msg);
+	int ret;
+
+	BCM2835_MBOX_INIT_HDR(msg);
+	BCM2835_MBOX_INIT_TAG(&msg->get_clock_rate, GET_CLOCK_RATE);
+	msg->get_clock_rate.body.req.clock_id = clock_id;
+
+	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return clk_fixed(name, msg->get_clock_rate.body.resp.rate_hz);
+}
+
+static int bcm2835_cprman_probe(struct device_d *dev)
+{
+	struct device_node *mbox_node;
+	struct clk *clk_cs;
+	int ret;
+
+	mbox_node = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-mbox");
+	if (!mbox_node) {
+		pr_err("Missing mbox node\n");
+		return -ENOENT;
+	}
+
+	ret = of_device_ensure_probed(mbox_node);
+	if (ret) {
+		pr_err("Can't probe mbox node. %i\n", ret);
+		return ret;
+	}
+
+	clks[BCM2835_CLOCK_EMMC] =
+		rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_EMMC,
+					 "bcm2835_mci0");
+	if (IS_ERR(clks[BCM2835_CLOCK_EMMC]))
+		return PTR_ERR(clks[BCM2835_CLOCK_EMMC]);
+
+	clkdev_add_physbase(clks[BCM2835_CLOCK_EMMC], 0x20300000, NULL);
+	clkdev_add_physbase(clks[BCM2835_CLOCK_EMMC], 0x3f300000, NULL);
+
+	clks[BCM2835_CLOCK_VPU] =
+		rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_CORE,
+					    "vpu");
+	if (IS_ERR(clks[BCM2835_CLOCK_VPU]))
+		return PTR_ERR(clks[BCM2835_CLOCK_VPU]);
+
+	clkdev_add_physbase(clks[BCM2835_CLOCK_VPU], 0x20202000, NULL);
+	clkdev_add_physbase(clks[BCM2835_CLOCK_VPU], 0x3f202000, NULL);
+	clkdev_add_physbase(clks[BCM2835_CLOCK_VPU], BCM2835_MINIUART_BASE, NULL);
+	clkdev_add_physbase(clks[BCM2835_CLOCK_VPU], BCM2836_MINIUART_BASE, NULL);
+
+	clks[BCM2835_CLOCK_UART] = clk_fixed("uart0-pl0110", 48 * 1000 * 1000);
+	clk_register_clkdev(clks[BCM2835_CLOCK_UART], NULL, "uart0-pl0110");
+	clkdev_add_physbase(clks[BCM2835_CLOCK_UART], BCM2835_PL011_BASE, NULL);
+	clkdev_add_physbase(clks[BCM2835_CLOCK_UART], BCM2836_PL011_BASE, NULL);
+
+	clk_cs = clk_fixed("bcm2835-cs", 1 * 1000 * 1000);
+	clk_register_clkdev(clk_cs, NULL, "bcm2835-cs");
+
+	clk_data.clks = clks;
+	clk_data.clk_num = BCM2711_CLOCK_END;
+	of_clk_add_provider(dev->device_node, of_clk_src_onecell_get, &clk_data);
+
+	return 0;
+}
+
+static __maybe_unused struct of_device_id bcm2835_cprman_dt_ids[] = {
+	{
+		.compatible = "brcm,bcm2835-cprman",
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver_d bcm2835_cprman_driver = {
+	.probe	= bcm2835_cprman_probe,
+	.name	= "bcm2835-cprman",
+	.of_compatible = DRV_OF_COMPAT(bcm2835_cprman_dt_ids),
+};
+core_platform_driver(bcm2835_cprman_driver);
-- 
2.30.2



From o.rempel at pengutronix.de  Fri Jan 28 00:23:16 2022
From: o.rempel at pengutronix.de (Oleksij Rempel)
Date: Fri, 28 Jan 2022 09:23:16 +0100
Subject: [PATCH v2 3/4] ARM: rpi: validate devicetree compatible instead of
 changing model name
In-Reply-To: <20220128082317.2410427-1-o.rempel@pengutronix.de>
References: <20220128082317.2410427-1-o.rempel@pengutronix.de>
Message-ID: <20220128082317.2410427-4-o.rempel@pengutronix.de>

To cover all possible RPi variants we need to be able to work with DTs
provided by the 1. stage loader. If we get wrong DT for the barebox,
we will take wrong DT for kernel as well.

Since current device list was used only to update model name without
updating devicetree compatible, this patch will turn it around by using
device list to validate if we use right DT/compatible on the right HW.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 397 ++++++++++++++--------
 1 file changed, 259 insertions(+), 138 deletions(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index ab40dba50f..8c5f442843 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -6,6 +6,7 @@
 #include <init.h>
 #include <fs.h>
 #include <of.h>
+#include <of_device.h>
 #include <linux/stat.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
@@ -29,16 +30,20 @@
 
 #include "lowlevel.h"
 
-struct rpi_model {
-	const char *name;
-	void (*init)(void);
+struct rpi_priv;
+struct rpi_machine_data {
+	int (*init)(struct rpi_priv *priv);
+	u8 hw_id;
+#define RPI_OLD_SCHEMA			BIT(0)
+	u8 flags;
 };
 
-#define RPI_MODEL(_id, _name, _init)	\
-	[_id] = {				\
-		.name			= _name,\
-		.init			= _init,\
-	}
+struct rpi_priv {
+	struct device_d *dev;
+	const struct rpi_machine_data *dcfg;
+	unsigned int hw_id;
+	const char *name;
+};
 
 struct msg_get_arm_mem {
 	struct bcm2835_mbox_hdr hdr;
@@ -133,98 +138,56 @@ static void rpi_add_led(void)
 		led_set_trigger(LED_TRIGGER_HEARTBEAT, &l->led);
 }
 
-static void rpi_b_init(void)
+static int rpi_b_init(struct rpi_priv *priv)
 {
 	rpi_leds[0].gpio = 16;
 	rpi_leds[0].active_low = 1;
 	rpi_set_usbethaddr();
+
+	return 0;
 }
 
-static void rpi_b_plus_init(void)
+static int rpi_b_plus_init(struct rpi_priv *priv)
 {
 	rpi_leds[0].gpio = 47;
 	rpi_leds[1].gpio = 35;
 	rpi_set_usbethaddr();
+
+	return 0;
 }
 
-static void rpi_0_init(void)
+static int rpi_0_init(struct rpi_priv *priv)
 {
 	rpi_leds[0].gpio = 47;
 	rpi_set_usbotg("usb0");
+
+	return 0;
 }
 
-static void rpi_0_w_init(void)
+static int rpi_0_w_init(struct rpi_priv *priv)
 {
 	struct device_node *np;
 	int ret;
 
-	rpi_0_init();
+	rpi_0_init(priv);
 
 	np = of_find_node_by_path("/chosen");
 	if (!np)
-		return;
+		return -ENODEV;
 
 	if (!of_device_enable_and_register_by_alias("serial1"))
-		return;
+		return -ENODEV;
 
 	ret = of_property_write_string(np, "stdout-path", "serial1:115200n8");
 	if (ret)
-		return;
+		return ret;
 
-	of_device_disable_by_alias("serial0");
+	return of_device_disable_by_alias("serial0");
 }
 
-/* See comments in mbox.h for data source */
-static const struct rpi_model rpi_models_old_scheme[] = {
-	RPI_MODEL(0, "Unknown model", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_2, "Model B (no P5)", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_3, "Model B (no P5)", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_4, "Model B", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_5, "Model B", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_6, "Model B", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_A_7, "Model A", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_8, "Model A", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_9, "Model A", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_B_REV2_d, "Model B rev2", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_REV2_e, "Model B rev2", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_REV2_f, "Model B rev2", rpi_b_init),
-	RPI_MODEL(BCM2835_BOARD_REV_B_PLUS_10, "Model B+", rpi_b_plus_init),
-	RPI_MODEL(BCM2835_BOARD_REV_CM_11, "Compute Module", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_PLUS_12, "Model A+", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_B_PLUS_13, "Model B+", rpi_b_plus_init),
-	RPI_MODEL(BCM2835_BOARD_REV_CM_14, "Compute Module", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_A_PLUS_15, "Model A+", NULL),
-};
-
-static const struct rpi_model rpi_models_new_scheme[] = {
-	RPI_MODEL(BCM2835_BOARD_REV_A, 		"Model A",	NULL ),
-	RPI_MODEL(BCM2835_BOARD_REV_B, 		"Model B", 	rpi_b_init ),
-	RPI_MODEL(BCM2835_BOARD_REV_A_PLUS, 	"Model A+", 	NULL ),
-	RPI_MODEL(BCM2835_BOARD_REV_B_PLUS, 	"Model B+", 	rpi_b_plus_init ),
-	RPI_MODEL(BCM2836_BOARD_REV_2_B, 	"Model 2B", 	rpi_b_plus_init),
-	RPI_MODEL(BCM283x_BOARD_REV_Alpha, 	"Alpha", 	NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_CM1, 	"Compute Module", NULL ),
-	RPI_MODEL(0x7, "Unknown model", NULL),
-	RPI_MODEL(BCM2837_BOARD_REV_3_B, 	"Model 3B", 	rpi_b_init ),
-	RPI_MODEL(BCM2835_BOARD_REV_ZERO, 	"Zero", 	rpi_0_init),
-	RPI_MODEL(BCM2837_BOARD_REV_CM3, 	"Compute Module 3", NULL ),
-	RPI_MODEL(0xb, "Unknown model", NULL),
-	RPI_MODEL(BCM2835_BOARD_REV_ZERO_W, 	"Zero W", 	rpi_0_w_init),
-	RPI_MODEL(BCM2837B0_BOARD_REV_3B_PLUS, 	"Model 3B+", 	rpi_b_plus_init ),
-	RPI_MODEL(BCM2837B0_BOARD_REV_3A_PLUS, 	"Model 3A+", 	rpi_b_plus_init),
-	RPI_MODEL(0xf, "Unknown model", NULL),
-	RPI_MODEL(BCM2837B0_BOARD_REV_CM3_PLUS, "Compute Module 3+", NULL),
-};
-
-static int rpi_board_rev = 0;
-static const struct rpi_model *model = NULL;
-
-static void rpi_get_board_rev(void)
+static int rpi_get_board_rev(struct rpi_priv *priv)
 {
 	int ret;
-	char *name;
-	const struct rpi_model *rpi_models;
-	size_t rpi_models_size;
 
 	BCM2835_MBOX_STACK_ALIGN(struct msg_get_board_rev, msg);
 	BCM2835_MBOX_INIT_HDR(msg);
@@ -232,9 +195,8 @@ static void rpi_get_board_rev(void)
 
 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
 	if (ret) {
-		printf("bcm2835: Could not query board revision\n");
-		/* Ignore error; not critical */
-		return;
+		dev_err(priv->dev, "Could not query board revision\n");
+		return ret;
 	}
 
 	/* Comments from u-boot:
@@ -248,53 +210,9 @@ static void rpi_get_board_rev(void)
 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250
 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594
 	 */
-	rpi_board_rev = msg->get_board_rev.body.resp.rev;
-	if (rpi_board_rev & 0x800000) {
-		rpi_board_rev = (rpi_board_rev >> 4) & 0xff;
-		rpi_models = rpi_models_new_scheme;
-		rpi_models_size = ARRAY_SIZE(rpi_models_new_scheme);
-
-	} else {
-		rpi_board_rev &= 0xff;
-		rpi_models = rpi_models_old_scheme;
-		rpi_models_size = ARRAY_SIZE(rpi_models_old_scheme);
-	}
-
-	if (rpi_board_rev >= rpi_models_size) {
-		printf("RPI: Board rev %u outside known range\n",
-		       rpi_board_rev);
-		goto unknown_rev;
-	}
-
-	if (!rpi_models[rpi_board_rev].name) {
-		printf("RPI: Board rev %u unknown\n", rpi_board_rev);
-		goto unknown_rev;
-	}
-
-	if (!rpi_board_rev)
-		goto unknown_rev;
-
-	model = &rpi_models[rpi_board_rev];
-	name = basprintf("RaspberryPi %s", model->name);
-	barebox_set_model(name);
-	free(name);
-
-	return;
-
-unknown_rev:
-	rpi_board_rev = 0;
-	barebox_set_model("RaspberryPi (unknown rev)");
-}
-
-static void rpi_model_init(void)
-{
-	if (!model)
-		return;
+	priv->hw_id = msg->get_board_rev.body.resp.rev;
 
-	if (!model->init)
-		return;
-
-	model->init();
+	return 0;
 }
 
 static int rpi_mem_init(void)
@@ -312,16 +230,6 @@ static int rpi_mem_init(void)
 }
 mem_initcall(rpi_mem_init);
 
-static int rpi_postcore_init(void)
-{
-	rpi_get_board_rev();
-	barebox_set_hostname("rpi");
-	rpi_model_init();
-
-	return 0;
-}
-postcore_initcall(rpi_postcore_init);
-
 static int rpi_env_init(void)
 {
 	struct stat s;
@@ -439,9 +347,52 @@ static void rpi_vc_fdt(void)
 	}
 }
 
+static const struct rpi_machine_data *rpi_get_dcfg(struct rpi_priv *priv)
+{
+	const struct rpi_machine_data *dcfg;
+
+	dcfg = of_device_get_match_data(priv->dev);
+	if (!dcfg)
+		return ERR_PTR(-EINVAL);
+
+	for (; dcfg->hw_id != U8_MAX; dcfg++) {
+		if (priv->hw_id & 0x800000) {
+			if (dcfg->hw_id != ((priv->hw_id >> 4) & 0xff))
+				continue;
+		} else {
+			if (!(dcfg->flags & RPI_OLD_SCHEMA))
+				continue;
+			if (dcfg->hw_id != (priv->hw_id & 0xff))
+				continue;
+		}
+
+		return dcfg;
+	}
+
+	dev_err(priv->dev, "Failed to get dcfg for board_id: 0x%x.\n",
+		priv->hw_id);
+	return ERR_PTR(-ENODEV);
+}
+
 static int rpi_devices_probe(struct device_d *dev)
 {
+	const struct rpi_machine_data *dcfg;
 	struct regulator *reg;
+	struct rpi_priv *priv;
+	int ret;
+
+	priv = xzalloc(sizeof(*priv));
+	priv->dev = dev;
+
+	ret = rpi_get_board_rev(priv);
+	if (ret)
+		goto free_priv;
+
+	dcfg = rpi_get_dcfg(priv);
+	if (IS_ERR(dcfg))
+		goto free_priv;
+
+	barebox_set_hostname("rpi");
 
 	rpi_add_led();
 	bcm2835_register_fb();
@@ -449,6 +400,9 @@ static int rpi_devices_probe(struct device_d *dev)
 	rpi_env_init();
 	rpi_vc_fdt();
 
+	if (dcfg->init)
+		dcfg->init(priv);
+
 	reg = regulator_get_name("bcm2835_usb");
 	if (IS_ERR(reg))
 		return PTR_ERR(reg);
@@ -456,28 +410,195 @@ static int rpi_devices_probe(struct device_d *dev)
 	regulator_enable(reg);
 
 	return 0;
+
+free_priv:
+	kfree(priv);
+	return ret;
 }
 
+static const struct rpi_machine_data rpi_model_a[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_A_7,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_8,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_9,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_a_plus[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_A_PLUS_12,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_PLUS_15,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_A_PLUS,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_I2C1_4,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_I2C1_5,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_I2C1_6,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b_i2c0[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_I2C0_2,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_I2C0_3,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b_rev2[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_REV2_d,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_REV2_e,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_REV2_f,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_b_plus[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_B_PLUS_10,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_PLUS_13,
+		.flags = RPI_OLD_SCHEMA,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_B_PLUS,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_compute_module[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_CM_11,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_CM_14,
+		.flags = RPI_OLD_SCHEMA,
+	}, {
+		.hw_id = BCM2835_BOARD_REV_CM1,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_zero[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_ZERO,
+		.init = rpi_0_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_model_zero_w[] = {
+	{
+		.hw_id = BCM2835_BOARD_REV_ZERO_W,
+		.init = rpi_0_w_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_2_model_b[] = {
+	{
+		.hw_id = BCM2836_BOARD_REV_2_B,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_3_model_a_plus[] = {
+	{
+		.hw_id = BCM2837B0_BOARD_REV_3A_PLUS,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_3_model_b[] = {
+	{
+		.hw_id = BCM2837_BOARD_REV_3_B,
+		.init = rpi_b_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
+static const struct rpi_machine_data rpi_3_model_b_plus[] = {
+	{
+		.hw_id = BCM2837B0_BOARD_REV_3B_PLUS,
+		.init = rpi_b_plus_init,
+	}, {
+		.hw_id = U8_MAX
+	},
+};
+
 static const struct of_device_id rpi_of_match[] = {
 	/* BCM2835 based Boards */
-	{ .compatible = "raspberrypi,model-a" },
-	{ .compatible = "raspberrypi,model-a-plus" },
-	{ .compatible = "raspberrypi,model-b" },
+	{ .compatible = "raspberrypi,model-a", .data = rpi_model_a },
+	{ .compatible = "raspberrypi,model-a-plus", .data = rpi_model_a_plus },
+	{ .compatible = "raspberrypi,model-b", .data = rpi_model_b },
 	/* Raspberry Pi Model B (no P5) */
-	{ .compatible = "raspberrypi,model-b-i2c0" },
-	{ .compatible = "raspberrypi,model-b-rev2" },
-	{ .compatible = "raspberrypi,model-b-plus" },
-	{ .compatible = "raspberrypi,compute-module" },
-	{ .compatible = "raspberrypi,model-zero" },
-	{ .compatible = "raspberrypi,model-zero-w" },
+	{ .compatible = "raspberrypi,model-b-i2c0", .data = rpi_model_b_i2c0 },
+	{ .compatible = "raspberrypi,model-b-rev2", .data = rpi_model_b_rev2 },
+	{ .compatible = "raspberrypi,model-b-plus", .data = rpi_model_b_plus },
+	{ .compatible = "raspberrypi,compute-module", .data = rpi_compute_module },
+	{ .compatible = "raspberrypi,model-zero", .data = rpi_model_zero },
+	{ .compatible = "raspberrypi,model-zero-w", .data = rpi_model_zero_w },
 
 	/* BCM2836 based Boards */
-	{ .compatible = "raspberrypi,2-model-b" },
+	{ .compatible = "raspberrypi,2-model-b", .data = rpi_2_model_b },
 
 	/* BCM2837 based Boards */
-	{ .compatible = "raspberrypi,3-model-a-plus" },
-	{ .compatible = "raspberrypi,3-model-b" },
-	{ .compatible = "raspberrypi,3-model-b-plus" },
+	{ .compatible = "raspberrypi,3-model-a-plus", .data = rpi_3_model_a_plus },
+	{ .compatible = "raspberrypi,3-model-b", .data = rpi_3_model_b },
+	{ .compatible = "raspberrypi,3-model-b-plus", .data = rpi_3_model_b_plus },
 	{ /* sentinel */ },
 };
 BAREBOX_DEEP_PROBE_ENABLE(rpi_of_match);
-- 
2.30.2



From s.hauer at pengutronix.de  Fri Jan 28 06:32:12 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Jan 2022 15:32:12 +0100
Subject: [PATCH] build: Include dts/include/ after include/
Message-ID: <20220128143212.3950286-1-s.hauer@pengutronix.de>

dts/include/ contains Kernel upstream dt-binding include files. includes
are searched for in this directory before our own include directories
are used. This becomes a problem when we have files existing in the
barebox include directory which then appear in dts/include/ due to a dts
update. Make sure that we still use the barebox files in this case so
that we can later drop the barebox custom file explicitly along with the
fixes that might be needed to use the upstream file.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 Makefile             | 3 ++-
 scripts/Makefile.lib | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 3125d62811..a79773513b 100644
--- a/Makefile
+++ b/Makefile
@@ -431,8 +431,9 @@ USERINCLUDE    := \
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
-LINUXINCLUDE    := -Iinclude -I$(srctree)/dts/include \
+LINUXINCLUDE    := -Iinclude \
                    $(if $(building_out_of_srctree), -I$(srctree)/include) \
+                   -I$(srctree)/dts/include \
 		   -I$(srctree)/arch/$(SRCARCH)/include \
 		   -I$(objtree)/arch/$(SRCARCH)/include \
 		   $(USERINCLUDE)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 13b1789c01..b5ff621b07 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -203,8 +203,8 @@ ld_flags       = $(KBUILD_LDFLAGS) $(ldflags-y)
 dtc_cpp_flags  = -Wp,-MD,$(depfile).pre -nostdinc                        \
 		 -Wp,-MT,$(basename $(notdir $@)).o                      \
 		 -I$(srctree)/arch/$(SRCARCH)/dts/include		 \
-		 -I$(srctree)/dts/include                                \
 		 -I$(srctree)/include                                    \
+		 -I$(srctree)/dts/include                                \
 		 -I$(srctree)/dts/src/                                   \
 		 $(DTC_CPP_FLAGS_$(basetarget).dtb)                      \
 		 -undef -D__DTS__
-- 
2.30.2



From frank-w at public-files.de  Sat Jan 29 02:40:08 2022
From: frank-w at public-files.de (Frank Wunderlich)
Date: Sat, 29 Jan 2022 11:40:08 +0100
Subject: Aw: Re: Re: barebox extending boot-scripts
In-Reply-To: <20220106080838.GV6003@pengutronix.de>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
Message-ID: <trinity-eba130ad-1bd5-46a1-95bd-4a2ee29c1f96-1643452807981@3c-app-gmx-bs07>

Hi,
> Gesendet: Donnerstag, 06. Januar 2022 um 09:08 Uhr
> Von: "Sascha Hauer" <sha at pengutronix.de>

> It works for example with:
>
> for i in /mnt/sd.1/extlinux/Image*; do basename $i b; echo $b; done

this works with full path, but not if using a var for dir var

barebox at BPI R2PRO:/ i=0;for f in /mnt/sd.1/extlinux/Image*; do basename $f b; echo "$i:$b";let i++; done
0:Image_5.16
1:Image_5.16-next.gz
2:Image_5.16.gz
3:Image_5.16.gz.bak
4:Image_5.16_q64
5:Image_bpi
barebox at BPI R2PRO:/ imgdir=/mnt/sd.1/extlinux/
barebox at BPI R2PRO:/ i=0;for f in $imgdir/Image*; do basename $f b; echo "$i:$b";let i++; done

basename - strip directory and suffix from filenames

Usage: basename PATH VAR

Remove directory part from the PATH and store result into variable VAR.

0:Image_bpi
barebox at BPI R2PRO:/

any idea how to get it working with variable path?

i can do a cd before and drop the basename

cd $imgdir
for f in Image*; do echo $f;done
Image_5.16
Image_5.16-next.gz
Image_5.16.gz
Image_5.16.gz.bak
Image_5.16_q64
Image_bpi


but then i need to restore the path again (something like prevdir=$(pwd);cd $prevdir) if script fails

regards Frank


From antonynpavlov at gmail.com  Sun Jan 30 01:49:56 2022
From: antonynpavlov at gmail.com (Antony Pavlov)
Date: Sun, 30 Jan 2022 12:49:56 +0300
Subject: [PATCH] pinctrl: rockchip: drop unused variable 'name'
Message-ID: <20220130094956.73266-1-antonynpavlov@gmail.com>

Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 869cce1982..c99074407f 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -877,7 +877,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
 	struct device_node *np;
 	struct rockchip_pin_ctrl *ctrl;
 	struct rockchip_pin_bank *bank;
-	char *name;
 	int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
 	int gpio = 0;
 
-- 
2.33.0



From antonynpavlov at gmail.com  Sun Jan 30 04:00:11 2022
From: antonynpavlov at gmail.com (Antony Pavlov)
Date: Sun, 30 Jan 2022 15:00:11 +0300
Subject: RFC: Gitlab CI for barebox
Message-ID: <20220130150011.e8b22a088b654f6a0b0f96de@gmail.com>

Hi!

I have made simple Gitlab CI for barebox.

Gitlab CI runner setup instruction and
the source for Debian 11 docker image can be found at:

  https://gitlab.com/frantony/barebox-gitlab-ci-runner

Sample gitlab-ci.yaml config file:

  https://gitlab.com/frantony/barebox/-/commit/b1ed597d8e67c8f76f4f98cd1c6605b936cf2471

Corresponding gitlab pipeline results:

  https://gitlab.com/frantony/barebox/-/pipelines/459422690


Some notes:

  * there are several "images size > maximum size" errors during 'build ARM'
  * fake firmware blobs for ARM are used
  * 'build doc' produces sphinx generated html docs archive artifact
  * 'build ARM/MIPS/RISC-V/X86/sandbox' produce log/ directory archive artifacts
  * no support for kvx, openrisc and powerpc

@Ahmad

I suppose we can add your qemu barebox/test/emulate.pl tests into CI.

-- 
Best regards,
? Antony Pavlov


From a.fatoum at pengutronix.de  Sun Jan 30 23:53:38 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:53:38 +0100
Subject: [PATCH 2/2] reset: stm32: drop STM32 MCU support in favor of simple
 reset driver
In-Reply-To: <20220131075338.1869305-1-a.fatoum@pengutronix.de>
References: <20220131075338.1869305-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075338.1869305-2-a.fatoum@pengutronix.de>

RCC reset will eventually get more involved when we add SCMI support.
Linux already has reset and clock control in the same driver.

As we now have a simple driver that can toggle resets on the STM32 MCUs
as well, we can drop the now duplicate support from the dedicated
STM32 reset driver.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/reset/Kconfig       |  2 +-
 drivers/reset/reset-stm32.c | 15 +--------------
 2 files changed, 2 insertions(+), 15 deletions(-)

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 82c85162533d..b12159094d88 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -43,7 +43,7 @@ config RESET_STM32
 	bool "STM32 Reset Driver"
 	depends on ARCH_STM32MP || COMPILE_TEST
 	help
-	  This enables the reset controller driver for STM32MP and STM32 MCUs.
+	  This enables the reset controller driver for STM32MP1.
 
 config RESET_STARFIVE
 	bool "StarFive Controller Driver" if COMPILE_TEST
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
index 703ba1f072c5..186b2a8bc654 100644
--- a/drivers/reset/reset-stm32.c
+++ b/drivers/reset/reset-stm32.c
@@ -66,14 +66,6 @@ static void stm32mp_reset(void __iomem *reg, unsigned offset, bool assert)
 	writel(BIT(offset), reg);
 }
 
-static void stm32mcu_reset(void __iomem *reg, unsigned offset, bool assert)
-{
-	if (assert)
-		setbits_le32(reg, BIT(offset));
-	else
-		clrbits_le32(reg, BIT(offset));
-}
-
 static u32 stm32_reset_status(struct stm32_reset *priv, unsigned long bank)
 {
 	return readl(priv->base + bank);
@@ -195,18 +187,13 @@ static const struct stm32_reset_ops stm32mp1_reset_ops = {
 	.reset_reasons = stm32mp_reset_reasons,
 };
 
-static const struct stm32_reset_ops stm32mcu_reset_ops = {
-	.reset = stm32mcu_reset,
-};
-
 static const struct of_device_id stm32_rcc_reset_dt_ids[] = {
 	{ .compatible = "st,stm32mp1-rcc", .data = &stm32mp1_reset_ops },
-	{ .compatible = "st,stm32-rcc", .data = &stm32mcu_reset_ops },
 	{ /* sentinel */ },
 };
 
 static struct driver_d stm32_rcc_reset_driver = {
-	.name = "stm32_rcc_reset",
+	.name = "stm32mp_rcc_reset",
 	.probe = stm32_reset_probe,
 	.of_compatible = DRV_OF_COMPAT(stm32_rcc_reset_dt_ids),
 };
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:53:37 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:53:37 +0100
Subject: [PATCH 1/2] reset: add simple reset controller support
Message-ID: <20220131075338.1869305-1-a.fatoum@pengutronix.de>

Incoming STM32 MCU support will leverage this driver, so port it over
from Linux v5.16.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/reset/Kconfig              |  17 +++
 drivers/reset/Makefile             |   1 +
 drivers/reset/reset-simple.c       | 189 +++++++++++++++++++++++++++++
 include/linux/reset/reset-simple.h |  45 +++++++
 4 files changed, 252 insertions(+)
 create mode 100644 drivers/reset/reset-simple.c
 create mode 100644 include/linux/reset/reset-simple.h

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 6c70c1026998..82c85162533d 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -15,6 +15,23 @@ menuconfig RESET_CONTROLLER
 
 if RESET_CONTROLLER
 
+config RESET_SIMPLE
+	bool "Simple Reset Controller Driver" if COMPILE_TEST
+	help
+	  This enables a simple reset controller driver for reset lines that
+	  that can be asserted and deasserted by toggling bits in a contiguous,
+	  exclusive register space.
+
+	  Currently this driver supports:
+	   - Altera 64-Bit SoCFPGAs
+	   - ASPEED BMC SoCs
+	   - Bitmain BM1880 SoC
+	   - Realtek SoCs
+	   - RCC reset controller in STM32 MCUs
+	   - Allwinner SoCs
+	   - SiFive FU740 SoCs
+
+
 config RESET_IMX7
 	bool "i.MX7 Reset Driver"
 	default ARCH_IMX7
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index d884a83aa3f7..b4270411fdaf 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
+obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
 obj-$(CONFIG_RESET_STM32) += reset-stm32.o
diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c
new file mode 100644
index 000000000000..082956d94dae
--- /dev/null
+++ b/drivers/reset/reset-simple.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Simple Reset Controller Driver
+ *
+ * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel at pengutronix.de>
+ *
+ * Based on Allwinner SoCs Reset Controller driver
+ *
+ * Copyright 2013 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard at free-electrons.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/err.h>
+#include <linux/reset-controller.h>
+#include <linux/reset/reset-simple.h>
+#include <restart.h>
+#include <reset_source.h>
+#include <asm/io.h>
+
+static inline struct reset_simple_data *
+to_reset_simple_data(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct reset_simple_data, rcdev);
+}
+
+static int reset_simple_update(struct reset_controller_dev *rcdev,
+			       unsigned long id, bool assert)
+{
+	struct reset_simple_data *data = to_reset_simple_data(rcdev);
+	int reg_width = sizeof(u32);
+	int bank = id / (reg_width * BITS_PER_BYTE);
+	int offset = id % (reg_width * BITS_PER_BYTE);
+	u32 reg;
+
+	reg = readl(data->membase + (bank * reg_width));
+	if (assert ^ data->active_low)
+		reg |= BIT(offset);
+	else
+		reg &= ~BIT(offset);
+	writel(reg, data->membase + (bank * reg_width));
+
+	return 0;
+}
+
+static int reset_simple_assert(struct reset_controller_dev *rcdev,
+			       unsigned long id)
+{
+	return reset_simple_update(rcdev, id, true);
+}
+
+static int reset_simple_deassert(struct reset_controller_dev *rcdev,
+				 unsigned long id)
+{
+	return reset_simple_update(rcdev, id, false);
+}
+
+static int reset_simple_reset(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct reset_simple_data *data = to_reset_simple_data(rcdev);
+	int ret;
+
+	if (!data->reset_us)
+		return -ENOTSUPP;
+
+	ret = reset_simple_assert(rcdev, id);
+	if (ret)
+		return ret;
+
+	udelay(data->reset_us);
+
+	return reset_simple_deassert(rcdev, id);
+}
+
+static int __maybe_unused reset_simple_status(struct reset_controller_dev *rcdev,
+					      unsigned long id)
+{
+	struct reset_simple_data *data = to_reset_simple_data(rcdev);
+	int reg_width = sizeof(u32);
+	int bank = id / (reg_width * BITS_PER_BYTE);
+	int offset = id % (reg_width * BITS_PER_BYTE);
+	u32 reg;
+
+	reg = readl(data->membase + (bank * reg_width));
+
+	return !(reg & BIT(offset)) ^ !data->status_active_low;
+}
+
+const struct reset_control_ops reset_simple_ops = {
+	.assert		= reset_simple_assert,
+	.deassert	= reset_simple_deassert,
+	.reset		= reset_simple_reset,
+};
+EXPORT_SYMBOL_GPL(reset_simple_ops);
+
+/**
+ * struct reset_simple_devdata - simple reset controller properties
+ * @reg_offset: offset between base address and first reset register.
+ * @nr_resets: number of resets. If not set, default to resource size in bits.
+ * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits
+ *              are set to assert the reset.
+ * @status_active_low: if true, bits read back as cleared while the reset is
+ *                     asserted. Otherwise, bits read back as set while the
+ *                     reset is asserted.
+ */
+struct reset_simple_devdata {
+	u32 reg_offset;
+	u32 nr_resets;
+	bool active_low;
+	bool status_active_low;
+};
+
+#define SOCFPGA_NR_BANKS	8
+
+static const struct reset_simple_devdata reset_simple_socfpga = {
+	.reg_offset = 0x20,
+	.nr_resets = SOCFPGA_NR_BANKS * 32,
+	.status_active_low = true,
+};
+
+static const struct reset_simple_devdata reset_simple_active_low = {
+	.active_low = true,
+	.status_active_low = true,
+};
+
+static const struct of_device_id reset_simple_dt_ids[] = {
+	{ .compatible = "altr,stratix10-rst-mgr",
+		.data = &reset_simple_socfpga },
+	{ .compatible = "st,stm32-rcc", },
+	{ .compatible = "allwinner,sun6i-a31-clock-reset",
+		.data = &reset_simple_active_low },
+	{ .compatible = "zte,zx296718-reset",
+		.data = &reset_simple_active_low },
+	{ .compatible = "aspeed,ast2400-lpc-reset" },
+	{ .compatible = "aspeed,ast2500-lpc-reset" },
+	{ .compatible = "bitmain,bm1880-reset",
+		.data = &reset_simple_active_low },
+	{ .compatible = "brcm,bcm4908-misc-pcie-reset",
+		.data = &reset_simple_active_low },
+	{ .compatible = "snps,dw-high-reset" },
+	{ .compatible = "snps,dw-low-reset",
+		.data = &reset_simple_active_low },
+	{ /* sentinel */ },
+};
+
+static int reset_simple_probe(struct device_d *dev)
+{
+	const struct reset_simple_devdata *devdata;
+	struct reset_simple_data *data;
+	struct resource *res;
+	u32 reg_offset = 0;
+
+	devdata = device_get_match_data(dev);
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	data->membase = IOMEM(res->start);
+	data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE;
+	data->rcdev.ops = &reset_simple_ops;
+	data->rcdev.of_node = dev->device_node;
+
+	if (devdata) {
+		reg_offset = devdata->reg_offset;
+		if (devdata->nr_resets)
+			data->rcdev.nr_resets = devdata->nr_resets;
+		data->active_low = devdata->active_low;
+		data->status_active_low = devdata->status_active_low;
+	}
+
+	data->membase += reg_offset;
+
+	return reset_controller_register(&data->rcdev);
+}
+
+static struct driver_d reset_simple_driver = {
+	.probe	= reset_simple_probe,
+	.name		= "simple-reset",
+	.of_compatible	= reset_simple_dt_ids,
+};
+postcore_platform_driver(reset_simple_driver);
diff --git a/include/linux/reset/reset-simple.h b/include/linux/reset/reset-simple.h
new file mode 100644
index 000000000000..cb38a4b59765
--- /dev/null
+++ b/include/linux/reset/reset-simple.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Simple Reset Controller ops
+ *
+ * Based on Allwinner SoCs Reset Controller driver
+ *
+ * Copyright 2013 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard at free-electrons.com>
+ */
+
+#ifndef __RESET_SIMPLE_H__
+#define __RESET_SIMPLE_H__
+
+#include <io.h>
+#include <linux/reset-controller.h>
+
+/**
+ * struct reset_simple_data - driver data for simple reset controllers
+ * @membase: memory mapped I/O register range
+ * @rcdev: reset controller device base structure
+ * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits
+ *              are set to assert the reset. Note that this says nothing about
+ *              the voltage level of the actual reset line.
+ * @status_active_low: if true, bits read back as cleared while the reset is
+ *                     asserted. Otherwise, bits read back as set while the
+ *                     reset is asserted.
+ * @reset_us: Minimum delay in microseconds needed that needs to be
+ *            waited for between an assert and a deassert to reset the
+ *            device. If multiple consumers with different delay
+ *            requirements are connected to this controller, it must
+ *            be the largest minimum delay. 0 means that such a delay is
+ *            unknown and the reset operation is unsupported.
+ */
+struct reset_simple_data {
+	void __iomem			*membase;
+	struct reset_controller_dev	rcdev;
+	bool				active_low;
+	bool				status_active_low;
+	unsigned int			reset_us;
+};
+
+extern const struct reset_control_ops reset_simple_ops;
+
+#endif /* __RESET_SIMPLE_H__ */
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:53:50 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:53:50 +0100
Subject: [PATCH] include: <asm-generic/bug.h>: implement WARN_ON_ONCE
Message-ID: <20220131075350.1869535-1-a.fatoum@pengutronix.de>

We have WARN_ON and WARN_ONCE. Add WARN_ON_ONCE as well to accommodate
Linux driver code using it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/asm-generic/bug.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index f20e1b4d65ac..5d0a458eae74 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -50,4 +50,16 @@
 	}					\
 	unlikely(__ret_warn_once);		\
 })
+
+#define WARN_ON_ONCE(condition) ({			\
+	static int __warned;				\
+	int __ret_warn_once = !!(condition);		\
+							\
+	if (unlikely(__ret_warn_once && !__warned)) {	\
+		__warned = 1;				\
+		__WARN();				\
+	}						\
+	unlikely(__ret_warn_once);			\
+})
+
 #endif
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:13 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:13 +0100
Subject: [PATCH 00/12] clk: add STM32F429 clock driver support
Message-ID: <20220131075725.1873026-1-a.fatoum@pengutronix.de>

and use the occasion to provide a whole bunch of clk_hw helpers to
make future clock driver ports easier.

Ahmad Fatoum (12):
  string: define new memdup_array
  clk: composite: add clk_hw registration functions
  clk: divider: add clk_hw registration functions
  clk: fixed-factor: add clk_hw registration functions
  clk: clk-fixed: add clk_hw registration functions
  clk: define clk_hw_register
  clk: mux: add clk_hw registration functions
  clk: mux: export clk_mux_round_rate
  clk: implement of_clk_add_hw_provider
  clk: gate: add clk_hw registration functions
  ARM: stm32mp: allow driver reuse for STM32 MCUs
  clk: add clock driver for stm32f4 and stm32f7

 arch/arm/Kconfig                  |    7 +
 drivers/aiodev/Kconfig            |    2 +-
 drivers/clk/Kconfig               |    6 +
 drivers/clk/Makefile              |    1 +
 drivers/clk/clk-composite.c       |   25 +
 drivers/clk/clk-divider.c         |   21 +
 drivers/clk/clk-fixed-factor.c    |    9 +
 drivers/clk/clk-fixed.c           |    8 +
 drivers/clk/clk-mux.c             |   87 +-
 drivers/clk/clk-stm32f4.c         | 1901 +++++++++++++++++++++++++++++
 drivers/clk/clk.c                 |   43 +-
 drivers/hw_random/Kconfig         |    2 +-
 drivers/i2c/busses/Kconfig        |    2 +-
 drivers/mci/Kconfig               |    2 +-
 drivers/mfd/Kconfig               |    2 +-
 drivers/pinctrl/Kconfig           |    2 +-
 drivers/pwm/Kconfig               |    2 +-
 drivers/regulator/Kconfig         |    2 +-
 drivers/serial/Kconfig            |    4 +-
 drivers/watchdog/Kconfig          |    2 +-
 include/asm-generic/bitsperlong.h |    4 +
 include/linux/clk.h               |   91 ++
 include/linux/string.h            |    3 +
 23 files changed, 2205 insertions(+), 23 deletions(-)
 create mode 100644 drivers/clk/clk-stm32f4.c

-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:14 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:14 +0100
Subject: [PATCH 01/12] string: define new memdup_array
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-2-a.fatoum@pengutronix.de>

This will come in handy later for duplicating parent arrays when doing
clock registration.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/linux/string.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index 3da174116a92..ae5e5bca8d24 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -5,6 +5,7 @@
 
 #include <linux/types.h>	/* for size_t */
 #include <linux/stddef.h>	/* for NULL */
+#include <linux/overflow.h>	/* for array_size */
 
 #ifdef __cplusplus
 extern "C" {
@@ -133,6 +134,8 @@ static inline const char *kbasename(const char *path)
 
 void *memdup(const void *, size_t);
 
+#define memdup_array(arr, count) memdup(arr, array_size(count, sizeof(*arr)));
+
 static inline void *kmemdup(const void *src, size_t len, gfp_t gfp)
 {
 	return memdup(src, len);
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:15 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:15 +0100
Subject: [PATCH 02/12] clk: composite: add clk_hw registration functions
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-3-a.fatoum@pengutronix.de>

Save users the hassle of opencoding by providing wrappers with the same
Linux semantics: names are duplicated, same arguments and struct clk_hw
is returned.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk-composite.c | 25 +++++++++++++++++++++++++
 include/linux/clk.h         |  8 ++++++++
 2 files changed, 33 insertions(+)

diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 479ac5e8ef53..63056b769647 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -171,3 +171,28 @@ err:
 	kfree(composite);
 	return 0;
 }
+
+struct clk_hw *clk_hw_register_composite(struct device_d *dev,
+		const char *name, const char * const *parent_names,
+		int num_parents,
+		struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+		struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+		struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+		unsigned long flags)
+{
+	struct clk *clk;
+	mux_hw->clk.ops = mux_ops;
+	rate_hw->clk.ops = rate_ops;
+	gate_hw->clk.ops = gate_ops;
+
+	parent_names = memdup_array(parent_names, num_parents);
+	if (!parent_names)
+		return ERR_PTR(-ENOMEM);
+
+	clk = clk_register_composite(xstrdup(name), parent_names, num_parents,
+				      mux_hw ? &mux_hw->clk : NULL,
+				      rate_hw ? &rate_hw->clk : NULL,
+				      gate_hw ? &gate_hw->clk : NULL,
+				      flags);
+	return clk_to_clk_hw(clk);
+}
diff --git a/include/linux/clk.h b/include/linux/clk.h
index ffc1ac8489b0..f4aa5c7c57f0 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -676,6 +676,14 @@ struct clk *clk_register_composite(const char *name,
 			struct clk *gate_clk,
 			unsigned long flags);
 
+struct clk_hw *clk_hw_register_composite(struct device_d *dev,
+		const char *name, const char * const *parent_names,
+		int num_parents,
+		struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+		struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+		struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+		unsigned long flags);
+
 static inline const char *clk_hw_get_name(struct clk_hw *hw)
 {
 	return hw->clk.name;
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:17 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:17 +0100
Subject: [PATCH 04/12] clk: fixed-factor: add clk_hw registration functions
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-5-a.fatoum@pengutronix.de>

Save users the hassle of opencoding by providing wrappers with the same
Linux semantics: names are duplicated, same arguments and struct clk_hw
is returned.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk-fixed-factor.c | 9 +++++++++
 include/linux/clk.h            | 4 ++++
 2 files changed, 13 insertions(+)

diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index fd4a3805f192..a6d3fdc6a14c 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -84,6 +84,15 @@ struct clk *clk_register_fixed_factor(struct device_d *dev, const char *name,
 	return clk_fixed_factor(name, parent_name, mult, div, flags);
 }
 
+struct clk_hw *clk_hw_register_fixed_factor(struct device_d *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		unsigned int mult, unsigned int div)
+{
+	return clk_to_clk_hw(clk_register_fixed_factor(dev, xstrdup(name),
+						       xstrdup(parent_name),
+						       flags, mult, div));
+}
+
 /**
  * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
  */
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 6a041440e399..52aeeba878e0 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -551,6 +551,10 @@ struct clk *clk_register_fixed_factor(struct device_d *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		unsigned int mult, unsigned int div);
 
+struct clk_hw *clk_hw_register_fixed_factor(struct device_d *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		unsigned int mult, unsigned int div);
+
 /**
  * struct clk_fractional_divider - adjustable fractional divider clock
  *
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:16 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:16 +0100
Subject: [PATCH 03/12] clk: divider: add clk_hw registration functions
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-4-a.fatoum@pengutronix.de>

Save users the hassle of opencoding by providing wrappers with the same
Linux semantics: names are duplicated, same arguments and struct clk_hw
is returned.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk-divider.c | 21 +++++++++++++++++++++
 include/linux/clk.h       | 11 +++++++++++
 2 files changed, 32 insertions(+)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 856b8a064866..fed9ad9d24b1 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -428,3 +428,24 @@ struct clk *clk_register_divider(struct device_d *dev, const char *name,
 	return clk_divider(name, parent_name, flags, reg, shift, width,
 			   clk_divider_flags);
 }
+
+struct clk_hw *clk_hw_register_divider_table(struct device_d *dev,
+	        const char *name, const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		spinlock_t *lock)
+{
+	return clk_to_clk_hw(clk_register_divider_table(dev, xstrdup(name),
+		xstrdup(parent_name), flags, reg, shift, width,
+		clk_divider_flags, table, lock));
+}
+
+struct clk_hw *clk_hw_register_divider(struct device_d *dev,
+	        const char *name, const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock)
+{
+	return clk_to_clk_hw(clk_register_divider(dev, xstrdup(name),
+		xstrdup(parent_name), flags, reg, shift, width,
+		clk_divider_flags, lock));
+}
diff --git a/include/linux/clk.h b/include/linux/clk.h
index f4aa5c7c57f0..6a041440e399 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -519,6 +519,17 @@ struct clk *clk_register_divider_table(struct device_d *dev, const char *name,
 		u8 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock);
 
+struct clk_hw *clk_hw_register_divider_table(struct device_d *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		spinlock_t *lock);
+
+struct clk_hw *clk_hw_register_divider(struct device_d *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock);
+
 struct clk_fixed_factor {
 	struct clk_hw hw;
 	int mult;
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:18 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:18 +0100
Subject: [PATCH 05/12] clk: clk-fixed: add clk_hw registration functions
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-6-a.fatoum@pengutronix.de>

Save users the hassle of opencoding by providing wrappers with the same
Linux semantics: names are duplicated, same arguments and struct clk_hw
is returned.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk-fixed.c | 8 ++++++++
 include/linux/clk.h     | 4 ++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/clk/clk-fixed.c b/drivers/clk/clk-fixed.c
index e813f31d76d9..9e5a07817bc0 100644
--- a/drivers/clk/clk-fixed.c
+++ b/drivers/clk/clk-fixed.c
@@ -63,6 +63,14 @@ struct clk *clk_register_fixed_rate(const char *name,
 	return &fix->hw.clk;
 }
 
+struct clk_hw *clk_hw_register_fixed_rate(struct device_d *dev,
+					  const char *name, const char *parent_name,
+					  unsigned long flags, unsigned long rate)
+{
+	return clk_to_clk_hw(clk_register_fixed_rate(xstrdup(name), parent_name,
+						     flags, rate));
+}
+
 /**
  * of_fixed_clk_setup() - Setup function for simple fixed rate clock
  */
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 52aeeba878e0..03d46de25ac6 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -449,6 +449,10 @@ struct clk *clk_register_fixed_rate(const char *name,
 				    const char *parent_name, unsigned long flags,
 				    unsigned long fixed_rate);
 
+struct clk_hw *clk_hw_register_fixed_rate(struct device_d *dev, const char *name,
+				    const char *parent_name, unsigned long flags,
+				    unsigned long rate);
+
 static inline struct clk *clk_fixed(const char *name, int rate)
 {
 	return clk_register_fixed_rate(name, NULL, 0, rate);
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:19 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:19 +0100
Subject: [PATCH 06/12] clk: define clk_hw_register
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-7-a.fatoum@pengutronix.de>

Save users the hassle of opencoding by providing a wrapper with the same
Linux semantics: same arguments and return type.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/linux/clk.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/clk.h b/include/linux/clk.h
index 03d46de25ac6..6e59418aba3c 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -683,6 +683,11 @@ int clk_parent_set_rate(struct clk_hw *hw, unsigned long rate,
 int bclk_register(struct clk *clk);
 struct clk *clk_register(struct device_d *dev, struct clk_hw *hw);
 
+static inline int clk_hw_register(struct device_d *dev, struct clk_hw *hw)
+{
+	return PTR_ERR_OR_ZERO(clk_register(dev, hw));
+}
+
 struct clk *clk_lookup(const char *name);
 
 void clk_dump(int verbose);
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:20 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:20 +0100
Subject: [PATCH 07/12] clk: mux: add clk_hw registration functions
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-8-a.fatoum@pengutronix.de>

Save users the hassle of opencoding by providing wrappers with the same
Linux semantics: names are duplicated, same arguments and struct clk_hw
is returned.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk-mux.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/clk.h   | 27 ++++++++++++++
 2 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index d8c09e4a7519..d608e0e2c565 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -10,12 +10,36 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 
+int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
+			 unsigned int val)
+{
+	int num_parents = clk_hw_get_num_parents(hw);
+
+	if (table) {
+		int i;
+
+		for (i = 0; i < num_parents; i++)
+			if (table[i] == val)
+				return i;
+		return -EINVAL;
+	}
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(clk_mux_val_to_index);
+
+unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index)
+{
+	return table ? table[index] : index;
+}
+EXPORT_SYMBOL_GPL(clk_mux_index_to_val);
+
 static int clk_mux_get_parent(struct clk_hw *hw)
 {
 	struct clk_mux *m = to_clk_mux(hw);
 	int idx = readl(m->reg) >> m->shift & ((1 << m->width) - 1);
 
-	return idx;
+	return clk_mux_val_to_index(hw, m->table, m->flags, idx);
 }
 
 static int clk_mux_set_parent(struct clk_hw *hw, u8 idx)
@@ -30,6 +54,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 idx)
 			return 0;
 	}
 
+	idx = clk_mux_index_to_val(m->table, m->flags, idx);
+
 	val = readl(m->reg);
 	val &= ~(((1 << m->width) - 1) << m->shift);
 	val |= idx << m->shift;
@@ -186,3 +212,57 @@ struct clk *clk_register_mux(struct device_d *dev, const char *name,
 	return clk_mux(name, flags, reg, shift, width, parent_names,
 		       num_parents, clk_mux_flags);
 }
+
+struct clk_hw *__clk_hw_register_mux(struct device_d *dev,
+		const char *name, u8 num_parents,
+		const char * const *parent_names,
+		unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+{
+	struct clk_mux *mux;
+	struct clk_hw *hw;
+	struct clk_init_data init = {};
+	u8 width = 0;
+	int ret = -EINVAL;
+
+	width = fls(mask) - ffs(mask) + 1;
+
+	if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
+		if (width + shift > 16) {
+			pr_err("mux value exceeds LOWORD field\n");
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	/* allocate the mux */
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	if (clk_mux_flags & CLK_MUX_READ_ONLY)
+		init.ops = &clk_mux_ro_ops;
+	else
+		init.ops = &clk_mux_ops;
+	init.flags = flags;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+
+	/* struct clk_mux assignments */
+	mux->reg = reg;
+	mux->shift = shift;
+	mux->width = width;
+	mux->flags = clk_mux_flags;
+	mux->lock = lock;
+	mux->table = table;
+	mux->hw.init = &init;
+
+	hw = &mux->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(mux);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 6e59418aba3c..81bd1ec2dad9 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -619,6 +619,7 @@ struct clk_mux {
 	int shift;
 	int width;
 	unsigned flags;
+	u32 *table;
 	spinlock_t *lock;
 };
 
@@ -641,6 +642,32 @@ struct clk *clk_register_mux(struct device_d *dev, const char *name,
 		void __iomem *reg, u8 shift, u8 width,
 		u8 clk_mux_flags, spinlock_t *lock);
 
+struct clk_hw *__clk_hw_register_mux(struct device_d *dev,
+		const char *name, u8 num_parents,
+		const char * const *parent_names,
+		unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+
+#define clk_hw_register_mux(dev, name, parent_names,                  \
+		num_parents, flags, reg, shift, mask,                 \
+		clk_mux_flags, lock)                                  \
+	__clk_hw_register_mux((dev), (name), (num_parents),           \
+				     (parent_names),                  \
+				     (flags), (reg), (shift), (mask), \
+				     (clk_mux_flags), NULL, (lock))
+
+#define clk_hw_register_mux_table(dev, name, parent_names, num_parents,	  \
+				  flags, reg, shift, mask, clk_mux_flags, \
+				  table, lock)				  \
+	__clk_hw_register_mux((dev), (name), (num_parents),	          \
+			      (parent_names), (flags), (reg),             \
+			      (shift), (mask), (clk_mux_flags), (table),  \
+			      (lock))
+
+int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
+			 unsigned int val);
+unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index);
+
 struct clk_gate {
 	struct clk_hw hw;
 	void __iomem *reg;
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:23 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:23 +0100
Subject: [PATCH 10/12] clk: gate: add clk_hw registration functions
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-11-a.fatoum@pengutronix.de>

Save users the hassle of opencoding by providing wrappers with the same
Linux semantics: names are duplicated, same arguments and struct clk_hw
is returned.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/linux/clk.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/include/linux/clk.h b/include/linux/clk.h
index 94ac7f288ad7..397520a4815c 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/spinlock.h>
 #include <linux/stringify.h>
+#include <xfuncs.h>
 
 struct device_d;
 
@@ -701,6 +702,16 @@ struct clk *clk_register_gate(struct device_d *dev, const char *name,
 		void __iomem *reg, u8 bit_idx,
 		u8 clk_gate_flags, spinlock_t *lock);
 
+static inline struct clk_hw *clk_hw_register_gate(struct device_d *dev,
+		const char *name, const char *parent_name,
+		unsigned long flags, void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	return clk_to_clk_hw(clk_register_gate(dev, xstrdup(name), xstrdup(parent_name),
+					       flags, reg, bit_idx,
+					       clk_gate_flags, lock));
+}
+
 int clk_is_enabled(struct clk *clk);
 int clk_hw_is_enabled(struct clk_hw *hw);
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:24 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:24 +0100
Subject: [PATCH 11/12] ARM: stm32mp: allow driver reuse for STM32 MCUs
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-12-a.fatoum@pengutronix.de>

Most peripheral driver are usable for both STM32 MPUs and MCUs, but so
far we they were only used for STM32MP1. In preparation for adding
MCU support, introduce a new ARCH_STM32 selected by ARCH_STM32MP and
migrate common drivers to it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/Kconfig           | 7 +++++++
 drivers/aiodev/Kconfig     | 2 +-
 drivers/hw_random/Kconfig  | 2 +-
 drivers/i2c/busses/Kconfig | 2 +-
 drivers/mci/Kconfig        | 2 +-
 drivers/mfd/Kconfig        | 2 +-
 drivers/pinctrl/Kconfig    | 2 +-
 drivers/pwm/Kconfig        | 2 +-
 drivers/regulator/Kconfig  | 2 +-
 drivers/serial/Kconfig     | 4 ++--
 drivers/watchdog/Kconfig   | 2 +-
 11 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fecbe392333b..299e0ab08049 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -29,6 +29,12 @@ config TEXT_BASE
 
 menu "System Type"
 
+config ARCH_STM32
+	bool
+	help
+	  Selected by both STM32 MCUs and MPUs to restrict driver
+	  visibility.
+
 choice
 	prompt "ARM system type"
 
@@ -185,6 +191,7 @@ config ARCH_S3C64xx
 
 config ARCH_STM32MP
 	bool "STMicroelectronics STM32MP"
+	select ARCH_STM32
 	select CPU_V7
 	select HAVE_PBL_MULTI_IMAGES
 	select CLKDEV_LOOKUP
diff --git a/drivers/aiodev/Kconfig b/drivers/aiodev/Kconfig
index b0af2ebfd382..88a3b9a3431c 100644
--- a/drivers/aiodev/Kconfig
+++ b/drivers/aiodev/Kconfig
@@ -46,7 +46,7 @@ config AM335X_ADC
 
 config STM32_ADC
 	tristate "STM32 ADC driver"
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 	help
 	  Support for ADC on STM32.  Supports simple one-shot readings
 	  rather than continuous sampling with DMA, etc.  ADC channels should be
diff --git a/drivers/hw_random/Kconfig b/drivers/hw_random/Kconfig
index 4b4200b5db5c..32b84b028b0e 100644
--- a/drivers/hw_random/Kconfig
+++ b/drivers/hw_random/Kconfig
@@ -17,7 +17,7 @@ config HWRNG_MXC_RNGC
 
 config HWRNG_STM32
 	tristate "STM32 Random Number Generator"
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 	help
 	  This driver provides barebox support for the Random Number
 	  Generator hardware found on the STM32 family of MPUs and MCUs.
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index a551df537a69..d4e74552b7ad 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -60,7 +60,7 @@ config I2C_STM32
 	bool "STM32 I2C master driver"
 	select RESET_CONTROLLER
 	depends on HAVE_CLK
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 
 config I2C_RK3X
 	tristate "Rockchip RK3xxx I2C adapter"
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 95a73a761ca1..21d53c0c3f0b 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -206,7 +206,7 @@ config MCI_STM32_SDMMC2
 	bool "STMicroelectronics STM32H7 SD/MMC Host Controller support"
 	depends on ARM_AMBA
 	depends on RESET_CONTROLLER
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 	help
 	  This selects support for the SD/MMC controller on STM32H7 SoCs.
 	  If you have a board based on such a SoC and with a SD/MMC slot,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 160248072ab1..9d4a82a9bbb4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -93,7 +93,7 @@ config SMSC_SUPERIO
 
 config MFD_STM32_TIMERS
 	bool "STM32 Timers"
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 	help
 	  Select this to get regmap support for the timer blocks on STM32
 	  MCUs and MPUs.
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d3d5c7be23cd..2ff99a39c877 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -102,7 +102,7 @@ config PINCTRL_VF610
 
 config PINCTRL_STM32
 	bool "STM32 pinctrl support" if  COMPILE_TEST
-	default y if ARCH_STM32MP
+	default y if ARCH_STM32
 	help
 	  Pinmux and GPIO controller found on STM32 family
 endif
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 8219c1eaff7d..0b12278e80e7 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -38,7 +38,7 @@ config PWM_MXS
 
 config PWM_STM32
 	bool "STM32 PWM Support"
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 	help
 	  This enables PWM support for STM32 MCUs and MPUs.
 
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 02cea362eb5d..c468e459153b 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -31,7 +31,7 @@ config REGULATOR_STM32_PWR
 
 config REGULATOR_STM32_VREFBUF
 	tristate "STMicroelectronics STM32 VREFBUF"
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 	help
 	  This driver supports STMicroelectronics STM32 VREFBUF (voltage
 	  reference buffer) which can be used as voltage reference for
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 8bf9fcd07e1b..9d4a534580ef 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -39,8 +39,8 @@ config DRIVER_SERIAL_IMX
 	bool "i.MX serial driver"
 
 config DRIVER_SERIAL_STM32
-	depends on ARCH_STM32MP
-	bool "stm32mp serial driver"
+	depends on ARCH_STM32
+	bool "stm32 serial driver"
 
 config DRIVER_SERIAL_STM378X
 	depends on ARCH_MXS
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b8772e016fe0..6f209e096ebe 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -97,7 +97,7 @@ config RAVE_SP_WATCHDOG
 
 config STM32_IWDG_WATCHDOG
 	bool "STM32 IWDG"
-	depends on ARCH_STM32MP || COMPILE_TEST
+	depends on ARCH_STM32 || COMPILE_TEST
 	select MFD_SYSCON
 	help
 	  Enable to support configuration of the STM32's on-SoC IWDG watchdog.
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:21 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:21 +0100
Subject: [PATCH 08/12] clk: mux: export clk_mux_round_rate
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-9-a.fatoum@pengutronix.de>

Clock drivers may want to implement round rate for their custom clocks
in term of clk_mux_round_rate. Export the function to facilitate this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk-mux.c | 5 +++--
 include/linux/clk.h   | 3 +++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index d608e0e2c565..8463f1ee82c5 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -110,8 +110,8 @@ static struct clk *clk_mux_best_parent(struct clk *mux, unsigned long rate,
 	return bestparent;
 }
 
-static long clk_mux_round_rate(struct clk_hw *hw, unsigned long rate,
-			       unsigned long *prate)
+long clk_mux_round_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long *prate)
 {
 	struct clk *clk = clk_hw_to_clk(hw);
 	unsigned long rrate;
@@ -124,6 +124,7 @@ static long clk_mux_round_rate(struct clk_hw *hw, unsigned long rate,
 
 	return rrate;
 }
+EXPORT_SYMBOL_GPL(clk_mux_round_rate);
 
 static int clk_mux_set_rate(struct clk_hw *hw, unsigned long rate,
 			unsigned long parent_rate)
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 81bd1ec2dad9..0aa29c4720fe 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -668,6 +668,9 @@ int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
 			 unsigned int val);
 unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index);
 
+long clk_mux_round_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long *prate);
+
 struct clk_gate {
 	struct clk_hw hw;
 	void __iomem *reg;
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:22 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:22 +0100
Subject: [PATCH 09/12] clk: implement of_clk_add_hw_provider
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-10-a.fatoum@pengutronix.de>

New Linux drivers rather use of_clk_add_hw_provider, so port it over.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/clk.c   | 43 ++++++++++++++++++++++++++++++++++---------
 include/linux/clk.h | 13 +++++++++++++
 2 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 18373edbe40d..227ab75ed65d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -561,6 +561,7 @@ struct of_clk_provider {
 
 	struct device_node *node;
 	struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
+	struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data);
 	void *data;
 };
 
@@ -591,15 +592,11 @@ struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
 }
 EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
 
-/**
- * of_clk_add_provider() - Register a clock provider for a node
- * @np: Device node pointer associated with clock provider
- * @clk_src_get: callback for decoding clock
- * @data: context pointer for @clk_src_get callback.
- */
-int of_clk_add_provider(struct device_node *np,
+static int __of_clk_add_provider(struct device_node *np,
 			struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,
 						   void *data),
+			struct clk_hw *(*clk_hw_src_get)(struct of_phandle_args *clkspec,
+						   void *data),
 			void *data)
 {
 	struct of_clk_provider *cp;
@@ -611,6 +608,7 @@ int of_clk_add_provider(struct device_node *np,
 	cp->node = np;
 	cp->data = data;
 	cp->get = clk_src_get;
+	cp->get_hw = clk_hw_src_get;
 
 	list_add(&cp->link, &of_clk_providers);
 	pr_debug("Added clock from %s\n", np ? np->full_name : "<none>");
@@ -619,8 +617,31 @@ int of_clk_add_provider(struct device_node *np,
 
 	return 0;
 }
+
+/**
+ * of_clk_add_provider() - Register a clock provider for a node
+ * @np: Device node pointer associated with clock provider
+ * @clk_src_get: callback for decoding clock
+ * @data: context pointer for @clk_src_get callback.
+ */
+int of_clk_add_provider(struct device_node *np,
+			struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,
+						   void *data),
+			void *data)
+{
+	return __of_clk_add_provider(np, clk_src_get, NULL, data);
+}
 EXPORT_SYMBOL_GPL(of_clk_add_provider);
 
+int of_clk_add_hw_provider(struct device_node *np,
+			struct clk_hw *(*clk_hw_src_get)(struct of_phandle_args *clkspec,
+							 void *data),
+			void *data)
+{
+	return __of_clk_add_provider(np, NULL, clk_hw_src_get, data);
+}
+EXPORT_SYMBOL_GPL(of_clk_add_hw_provider);
+
 /**
  * of_clk_del_provider() - Remove a previously registered clock provider
  * @np: Device node pointer associated with clock provider
@@ -649,8 +670,12 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
 
 	/* Check if we have such a provider in our array */
 	list_for_each_entry(provider, &of_clk_providers, link) {
-		if (provider->node == clkspec->np)
-			clk = provider->get(clkspec, provider->data);
+		if (provider->node == clkspec->np) {
+			if (provider->get)
+				clk = provider->get(clkspec, provider->data);
+			else
+				clk = clk_hw_to_clk(provider->get_hw(clkspec, provider->data));
+		}
 		if (!IS_ERR(clk))
 			break;
 	}
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 0aa29c4720fe..94ac7f288ad7 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -783,6 +783,11 @@ int of_clk_add_provider(struct device_node *np,
 						   void *data),
 			void *data);
 
+int of_clk_add_hw_provider(struct device_node *np,
+			struct clk_hw *(*clk_hw_src_get)(struct of_phandle_args *clkspec,
+							 void *data),
+			void *data);
+
 static inline unsigned int clk_hw_get_num_parents(const struct clk_hw *hw)
 {
 	return hw->clk.num_parents;
@@ -835,6 +840,14 @@ static inline int of_clk_add_provider(struct device_node *np,
 {
 	return 0;
 }
+
+static inline int of_clk_add_hw_provider(struct device_node *np,
+			struct clk_hw *(*clk_hw_src_get)(struct of_phandle_args *clkspec,
+							 void *data),
+			void *data)
+{
+	return 0;
+}
 #endif
 
 #define CLK_OF_DECLARE_DRIVER(name, compat, fn) CLK_OF_DECLARE(name, compat, fn)
-- 
2.30.2



From a.fatoum at pengutronix.de  Sun Jan 30 23:57:25 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 08:57:25 +0100
Subject: [PATCH 12/12] clk: add clock driver for stm32f4 and stm32f7
In-Reply-To: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
References: <20220131075725.1873026-1-a.fatoum@pengutronix.de>
Message-ID: <20220131075725.1873026-13-a.fatoum@pengutronix.de>

Port over the Linux v5.16 state of the clock driver.
Tested on a STM32F429.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clk/Kconfig               |    6 +
 drivers/clk/Makefile              |    1 +
 drivers/clk/clk-stm32f4.c         | 1901 +++++++++++++++++++++++++++++
 include/asm-generic/bitsperlong.h |    4 +
 include/linux/clk.h               |    5 +
 5 files changed, 1917 insertions(+)
 create mode 100644 drivers/clk/clk-stm32f4.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d8649c3f9bf0..e01ffe10f249 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -20,4 +20,10 @@ config CLK_SOCFPGA
 	select COMMON_CLK_OF_PROVIDER
 	default y if ARCH_SOCFPGA && OFDEVICE
 
+config COMMON_CLK_STM32F
+	bool "STM32F4 and STM32F7 clock driver" if COMPILE_TEST
+	depends on COMMON_CLK && ARCH_STM32
+	help
+	  Support for stm32f4 and stm32f7 SoC families clocks
+
 source "drivers/clk/sifive/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 499df2fe392b..bab0498d7c07 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_ARCH_LAYERSCAPE)	+= clk-qoric.o
 obj-y				+= analogbits/
 obj-$(CONFIG_CLK_SIFIVE)	+= sifive/
 obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
+obj-$(CONFIG_COMMON_CLK_STM32F)		+= clk-stm32f4.o
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
new file mode 100644
index 000000000000..4611038f4b45
--- /dev/null
+++ b/drivers/clk/clk-stm32f4.c
@@ -0,0 +1,1901 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Author: Daniel Thompson <daniel.thompson at linaro.org>
+ *
+ * Inspired by clk-asm9260.c .
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <io.h>
+#include <of.h>
+#include <of_address.h>
+#include <linux/math64.h>
+#include <linux/iopoll.h>
+#include <regmap.h>
+#include <mfd/syscon.h>
+
+/*
+ * Include list of clocks wich are not derived from system clock (SYSCLOCK)
+ * The index of these clocks is the secondary index of DT bindings
+ *
+ */
+#include <dt-bindings/clock/stm32fx-clock.h>
+
+#define STM32F4_RCC_CR			0x00
+#define STM32F4_RCC_PLLCFGR		0x04
+#define STM32F4_RCC_CFGR		0x08
+#define STM32F4_RCC_AHB1ENR		0x30
+#define STM32F4_RCC_AHB2ENR		0x34
+#define STM32F4_RCC_AHB3ENR		0x38
+#define STM32F4_RCC_APB1ENR		0x40
+#define STM32F4_RCC_APB2ENR		0x44
+#define STM32F4_RCC_BDCR		0x70
+#define STM32F4_RCC_CSR			0x74
+#define STM32F4_RCC_PLLI2SCFGR		0x84
+#define STM32F4_RCC_PLLSAICFGR		0x88
+#define STM32F4_RCC_DCKCFGR		0x8c
+#define STM32F7_RCC_DCKCFGR2		0x90
+
+#define NONE -1
+#define NO_IDX  NONE
+#define NO_MUX  NONE
+#define NO_GATE NONE
+
+struct stm32f4_gate_data {
+	u8	offset;
+	u8	bit_idx;
+	const char *name;
+	const char *parent_name;
+	unsigned long flags;
+};
+
+static const struct stm32f4_gate_data stm32f429_gates[] __initconst = {
+	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 20,	"ccmdatam",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
+
+	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48" },
+	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48" },
+
+	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
+		CLK_IGNORE_UNUSED },
+
+	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 17,	"uart2",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 18,	"uart3",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 19,	"uart4",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 20,	"uart5",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 21,	"i2c1",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 22,	"i2c2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 23,	"i2c3",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 30,	"uart7",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 31,	"uart8",	"apb1_div" },
+
+	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  4,	"usart1",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  5,	"usart6",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 11,	"sdio",		"pll48" },
+	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
+};
+
+static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
+	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 20,	"ccmdatam",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
+
+	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48" },
+	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48" },
+
+	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
+		CLK_IGNORE_UNUSED },
+	{ STM32F4_RCC_AHB3ENR,  1,	"qspi",		"ahb_div",
+		CLK_IGNORE_UNUSED },
+
+	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 17,	"uart2",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 18,	"uart3",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 19,	"uart4",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 20,	"uart5",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 21,	"i2c1",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 22,	"i2c2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 23,	"i2c3",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 30,	"uart7",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 31,	"uart8",	"apb1_div" },
+
+	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  4,	"usart1",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  5,	"usart6",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 11,	"sdio",		"sdmux" },
+	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
+};
+
+static const struct stm32f4_gate_data stm32f746_gates[] __initconst = {
+	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 20,	"dtcmram",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
+
+	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48"   },
+	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48"   },
+
+	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
+		CLK_IGNORE_UNUSED },
+	{ STM32F4_RCC_AHB3ENR,  1,	"qspi",		"ahb_div",
+		CLK_IGNORE_UNUSED },
+
+	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 16,	"spdifrx",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 27,	"cec",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
+
+	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  7,	"sdmmc2",	"sdmux"    },
+	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 11,	"sdmmc",	"sdmux"    },
+	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 23,	"sai2",		"apb2_div" },
+};
+
+static const struct stm32f4_gate_data stm32f769_gates[] __initconst = {
+	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 20,	"dtcmram",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
+	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
+
+	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  1,	"jpeg",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
+	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48"   },
+	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48"   },
+
+	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
+		CLK_IGNORE_UNUSED },
+	{ STM32F4_RCC_AHB3ENR,  1,	"qspi",		"ahb_div",
+		CLK_IGNORE_UNUSED },
+
+	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR, 10,	"rtcapb",	"apb1_mul" },
+	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 13,	"can3",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 16,	"spdifrx",	"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 27,	"cec",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
+	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
+
+	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR,  7,	"sdmmc2",	"sdmux2" },
+	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 11,	"sdmmc1",	"sdmux1" },
+	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
+	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 23,	"sai2",		"apb2_div" },
+	{ STM32F4_RCC_APB2ENR, 30,	"mdio",		"apb2_div" },
+};
+
+/*
+ * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
+ * have gate bits associated with them. Its combined hweight is 71.
+ */
+#define MAX_GATE_MAP 3
+
+static const u64 stm32f42xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull,
+						       0x0000000000000001ull,
+						       0x04777f33f6fec9ffull };
+
+static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull,
+						       0x0000000000000003ull,
+						       0x0c777f33f6fec9ffull };
+
+static const u64 stm32f746_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull,
+						      0x0000000000000003ull,
+						      0x04f77f833e01c9ffull };
+
+static const u64 stm32f769_gate_map[MAX_GATE_MAP] = { 0x000000f37ef417ffull,
+						      0x0000000000000003ull,
+						      0x44F77F833E01EDFFull };
+
+static const u64 *stm32f4_gate_map;
+
+static struct clk_hw **clks;
+
+static DEFINE_SPINLOCK(stm32f4_clk_lock);
+static void __iomem *base;
+
+static struct regmap *pdrm;
+
+static int stm32fx_end_primary_clk;
+
+/*
+ * "Multiplier" device for APBx clocks.
+ *
+ * The APBx dividers are power-of-two dividers and, if *not* running in 1:1
+ * mode, they also tap out the one of the low order state bits to run the
+ * timers. ST datasheets represent this feature as a (conditional) clock
+ * multiplier.
+ */
+struct clk_apb_mul {
+	struct clk_hw hw;
+	u8 bit_idx;
+};
+
+#define to_clk_apb_mul(_hw) container_of(_hw, struct clk_apb_mul, hw)
+
+static unsigned long clk_apb_mul_recalc_rate(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct clk_apb_mul *am = to_clk_apb_mul(hw);
+
+	if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
+		return parent_rate * 2;
+
+	return parent_rate;
+}
+
+static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long *prate)
+{
+	struct clk_apb_mul *am = to_clk_apb_mul(hw);
+	unsigned long mult = 1;
+
+	if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
+		mult = 2;
+
+	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+		unsigned long best_parent = rate / mult;
+
+		*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
+	}
+
+	return *prate * mult;
+}
+
+static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	/*
+	 * We must report success but we can do so unconditionally because
+	 * clk_apb_mul_round_rate returns values that ensure this call is a
+	 * nop.
+	 */
+
+	return 0;
+}
+
+static const struct clk_ops clk_apb_mul_factor_ops = {
+	.round_rate = clk_apb_mul_round_rate,
+	.set_rate = clk_apb_mul_set_rate,
+	.recalc_rate = clk_apb_mul_recalc_rate,
+};
+
+static struct clk *clk_register_apb_mul(struct device_d *dev, const char *name,
+					const char *parent_name,
+					unsigned long flags, u8 bit_idx)
+{
+	struct clk_apb_mul *am;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	am = kzalloc(sizeof(*am), GFP_KERNEL);
+	if (!am)
+		return ERR_PTR(-ENOMEM);
+
+	am->bit_idx = bit_idx;
+	am->hw.init = &init;
+
+	init.name = name;
+	init.ops = &clk_apb_mul_factor_ops;
+	init.flags = flags;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	clk = clk_register(dev, &am->hw);
+
+	if (IS_ERR(clk))
+		kfree(am);
+
+	return clk;
+}
+
+enum {
+	PLL,
+	PLL_I2S,
+	PLL_SAI,
+};
+
+static const struct clk_div_table pll_divp_table[] = {
+	{ 0, 2 }, { 1, 4 }, { 2, 6 }, { 3, 8 }, { 0 }
+};
+
+static const struct clk_div_table pll_divq_table[] = {
+	{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 },
+	{ 8, 8 }, { 9, 9 }, { 10, 10 }, { 11, 11 }, { 12, 12 }, { 13, 13 },
+	{ 14, 14 }, { 15, 15 },
+	{ 0 }
+};
+
+static const struct clk_div_table pll_divr_table[] = {
+	{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 }
+};
+
+struct stm32f4_pll {
+	spinlock_t *lock;
+	struct	clk_gate gate;
+	u8 offset;
+	u8 bit_rdy_idx;
+	u8 status;
+	u8 n_start;
+};
+
+#define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
+
+struct stm32f4_pll_post_div_data {
+	int idx;
+	int pll_idx;
+	const char *name;
+	const char *parent;
+	u8 flag;
+	u8 offset;
+	u8 shift;
+	u8 width;
+	u8 flag_div;
+	const struct clk_div_table *div_table;
+};
+
+struct stm32f4_vco_data {
+	const char *vco_name;
+	u8 offset;
+	u8 bit_idx;
+	u8 bit_rdy_idx;
+};
+
+static const struct stm32f4_vco_data  vco_data[] = {
+	{ "vco",     STM32F4_RCC_PLLCFGR,    24, 25 },
+	{ "vco-i2s", STM32F4_RCC_PLLI2SCFGR, 26, 27 },
+	{ "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 },
+};
+
+
+static const struct clk_div_table post_divr_table[] = {
+	{ 0, 2 }, { 1, 4 }, { 2, 8 }, { 3, 16 }, { 0 }
+};
+
+#define MAX_POST_DIV 3
+static const struct stm32f4_pll_post_div_data  post_div_data[MAX_POST_DIV] = {
+	{ CLK_I2SQ_PDIV, PLL_VCO_I2S, "plli2s-q-div", "plli2s-q",
+		CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL},
+
+	{ CLK_SAIQ_PDIV, PLL_VCO_SAI, "pllsai-q-div", "pllsai-q",
+		CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL },
+
+	{ NO_IDX, PLL_VCO_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
+		STM32F4_RCC_DCKCFGR, 16, 2, 0, post_divr_table },
+};
+
+struct stm32f4_div_data {
+	u8 shift;
+	u8 width;
+	u8 flag_div;
+	const struct clk_div_table *div_table;
+};
+
+#define MAX_PLL_DIV 3
+static const struct stm32f4_div_data  div_data[MAX_PLL_DIV] = {
+	{ 16, 2, 0, pll_divp_table },
+	{ 24, 4, 0, pll_divq_table },
+	{ 28, 3, 0, pll_divr_table },
+};
+
+struct stm32f4_pll_data {
+	u8 pll_num;
+	u8 n_start;
+	const char *div_name[MAX_PLL_DIV];
+};
+
+static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = {
+	{ PLL,	   192, { "pll", "pll48",    NULL	} },
+	{ PLL_I2S, 192, { NULL,  "plli2s-q", "plli2s-r" } },
+	{ PLL_SAI,  49, { NULL,  "pllsai-q", "pllsai-r" } },
+};
+
+static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = {
+	{ PLL,	   50, { "pll",	     "pll-q",    "pll-r"    } },
+	{ PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } },
+	{ PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } },
+};
+
+static int stm32f4_pll_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+#define PLL_TIMEOUT 10000
+
+static int stm32f4_pll_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+	int bit_status;
+	unsigned int timeout = PLL_TIMEOUT;
+
+	if (clk_gate_ops.is_enabled(hw))
+		return 0;
+
+	clk_gate_ops.enable(hw);
+
+	do {
+		bit_status = !(readl(gate->reg) & BIT(pll->bit_rdy_idx));
+
+	} while (bit_status && --timeout);
+
+	return bit_status;
+}
+
+static void stm32f4_pll_disable(struct clk_hw *hw)
+{
+	clk_gate_ops.disable(hw);
+}
+
+static unsigned long stm32f4_pll_recalc(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+	unsigned long n;
+
+	n = (readl(base + pll->offset) >> 6) & 0x1ff;
+
+	return parent_rate * n;
+}
+
+static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *prate)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+	unsigned long n;
+
+	n = rate / *prate;
+
+	if (n < pll->n_start)
+		n = pll->n_start;
+	else if (n > 432)
+		n = 432;
+
+	return *prate * n;
+}
+
+static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
+
+	unsigned long n;
+	unsigned long val;
+	int pll_state;
+
+	pll_state = stm32f4_pll_is_enabled(hw);
+
+	if (pll_state)
+		stm32f4_pll_disable(hw);
+
+	n = rate  / parent_rate;
+
+	val = readl(base + pll->offset) & ~(0x1ff << 6);
+
+	writel(val | ((n & 0x1ff) <<  6), base + pll->offset);
+
+	if (pll_state)
+		stm32f4_pll_enable(hw);
+
+	return 0;
+}
+
+static const struct clk_ops stm32f4_pll_gate_ops = {
+	.enable		= stm32f4_pll_enable,
+	.disable	= stm32f4_pll_disable,
+	.is_enabled	= stm32f4_pll_is_enabled,
+	.recalc_rate	= stm32f4_pll_recalc,
+	.round_rate	= stm32f4_pll_round_rate,
+	.set_rate	= stm32f4_pll_set_rate,
+};
+
+struct stm32f4_pll_div {
+	struct clk_divider div;
+	struct clk_hw *hw_pll;
+};
+
+#define to_pll_div_clk(_div) container_of(_div, struct stm32f4_pll_div, div)
+
+static unsigned long stm32f4_pll_div_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long stm32f4_pll_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long *prate)
+{
+	return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int stm32f4_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	int pll_state, ret;
+
+	struct clk_divider *div = to_clk_divider(hw);
+	struct stm32f4_pll_div *pll_div = to_pll_div_clk(div);
+
+	pll_state = stm32f4_pll_is_enabled(pll_div->hw_pll);
+
+	if (pll_state)
+		stm32f4_pll_disable(pll_div->hw_pll);
+
+	ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+	if (pll_state)
+		stm32f4_pll_enable(pll_div->hw_pll);
+
+	return ret;
+}
+
+static const struct clk_ops stm32f4_pll_div_ops = {
+	.recalc_rate = stm32f4_pll_div_recalc_rate,
+	.round_rate = stm32f4_pll_div_round_rate,
+	.set_rate = stm32f4_pll_div_set_rate,
+};
+
+static struct clk_hw *clk_register_pll_div(const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		struct clk_hw *pll_hw, spinlock_t *lock)
+{
+	struct stm32f4_pll_div *pll_div;
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	/* allocate the divider */
+	pll_div = kzalloc(sizeof(*pll_div), GFP_KERNEL);
+	if (!pll_div)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &stm32f4_pll_div_ops;
+	init.flags = flags;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	/* struct clk_divider assignments */
+	pll_div->div.reg = reg;
+	pll_div->div.shift = shift;
+	pll_div->div.width = width;
+	pll_div->div.flags = clk_divider_flags;
+	pll_div->div.lock = lock;
+	pll_div->div.table = table;
+	pll_div->div.hw.init = &init;
+
+	pll_div->hw_pll = pll_hw;
+
+	/* register the clock */
+	hw = &pll_div->div.hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(pll_div);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+static struct clk_hw *stm32f4_rcc_register_pll(const char *pllsrc,
+		const struct stm32f4_pll_data *data,  spinlock_t *lock)
+{
+	struct stm32f4_pll *pll;
+	struct clk_init_data init = { NULL };
+	void __iomem *reg;
+	struct clk_hw *pll_hw;
+	int ret;
+	int i;
+	const struct stm32f4_vco_data *vco;
+
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	vco = &vco_data[data->pll_num];
+
+	init.name = vco->vco_name;
+	init.ops = &stm32f4_pll_gate_ops;
+	/* init.flags = CLK_SET_RATE_GATE; */
+	init.parent_names = &pllsrc;
+	init.num_parents = 1;
+
+	pll->gate.lock = lock;
+	pll->gate.reg = base + STM32F4_RCC_CR;
+	pll->gate.shift = vco->bit_idx;
+	pll->gate.hw.init = &init;
+
+	pll->offset = vco->offset;
+	pll->n_start = data->n_start;
+	pll->bit_rdy_idx = vco->bit_rdy_idx;
+	pll->status = (readl(base + STM32F4_RCC_CR) >> vco->bit_idx) & 0x1;
+
+	reg = base + pll->offset;
+
+	pll_hw = &pll->gate.hw;
+	ret = clk_hw_register(NULL, pll_hw);
+	if (ret) {
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+
+	for (i = 0; i < MAX_PLL_DIV; i++)
+		if (data->div_name[i])
+			clk_register_pll_div(data->div_name[i],
+					vco->vco_name,
+					0,
+					reg,
+					div_data[i].shift,
+					div_data[i].width,
+					div_data[i].flag_div,
+					div_data[i].div_table,
+					pll_hw,
+					lock);
+	return pll_hw;
+}
+
+/*
+ * Converts the primary and secondary indices (as they appear in DT) to an
+ * offset into our struct clock array.
+ */
+static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary)
+{
+	u64 table[MAX_GATE_MAP];
+
+	if (primary == 1) {
+		if (WARN_ON(secondary >= stm32fx_end_primary_clk))
+			return -EINVAL;
+		return secondary;
+	}
+
+	memcpy(table, stm32f4_gate_map, sizeof(table));
+
+	/* only bits set in table can be used as indices */
+	if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) ||
+		    0 == (table[BIT_ULL_WORD(secondary)] &
+			  BIT_ULL_MASK(secondary))))
+		return -EINVAL;
+
+	/* mask out bits above our current index */
+	table[BIT_ULL_WORD(secondary)] &=
+	    GENMASK_ULL(secondary % BITS_PER_LONG_LONG, 0);
+
+	return stm32fx_end_primary_clk - 1 + hweight64(table[0]) +
+	       (BIT_ULL_WORD(secondary) >= 1 ? hweight64(table[1]) : 0) +
+	       (BIT_ULL_WORD(secondary) >= 2 ? hweight64(table[2]) : 0);
+}
+
+static struct clk_hw *
+stm32f4_rcc_lookup_clk(struct of_phandle_args *clkspec, void *data)
+{
+	int i = stm32f4_rcc_lookup_clk_idx(clkspec->args[0], clkspec->args[1]);
+
+	if (i < 0)
+		return ERR_PTR(-EINVAL);
+
+	return clks[i];
+}
+
+#define to_rgclk(_rgate) container_of(_rgate, struct stm32_rgate, gate)
+
+static inline void disable_power_domain_write_protection(void)
+{
+	if (pdrm)
+		regmap_update_bits(pdrm, 0x00, (1 << 8), (1 << 8));
+}
+
+static inline void enable_power_domain_write_protection(void)
+{
+	if (pdrm)
+		regmap_update_bits(pdrm, 0x00, (1 << 8), (0 << 8));
+}
+
+static inline void sofware_reset_backup_domain(void)
+{
+	unsigned long val;
+
+	val = readl(base + STM32F4_RCC_BDCR);
+	writel(val | BIT(16), base + STM32F4_RCC_BDCR);
+	writel(val & ~BIT(16), base + STM32F4_RCC_BDCR);
+}
+
+struct stm32_rgate {
+	struct	clk_gate gate;
+	u8	bit_rdy_idx;
+};
+
+#define RGATE_TIMEOUT 50000
+
+static int rgclk_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32_rgate *rgate = to_rgclk(gate);
+	int bit_status;
+	unsigned int timeout = RGATE_TIMEOUT;
+
+	if (clk_gate_ops.is_enabled(hw))
+		return 0;
+
+	disable_power_domain_write_protection();
+
+	clk_gate_ops.enable(hw);
+
+	do {
+		bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy_idx));
+		if (bit_status)
+			udelay(100);
+
+	} while (bit_status && --timeout);
+
+	enable_power_domain_write_protection();
+
+	return bit_status;
+}
+
+static void rgclk_disable(struct clk_hw *hw)
+{
+	clk_gate_ops.disable(hw);
+}
+
+static int rgclk_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+static const struct clk_ops rgclk_ops = {
+	.enable = rgclk_enable,
+	.disable = rgclk_disable,
+	.is_enabled = rgclk_is_enabled,
+};
+
+static struct clk_hw *clk_register_rgate(struct device_d *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx, u8 bit_rdy_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	struct stm32_rgate *rgate;
+	struct clk_init_data init = { NULL };
+	struct clk_hw *hw;
+	int ret;
+
+	rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
+	if (!rgate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &rgclk_ops;
+	init.flags = flags;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	rgate->bit_rdy_idx = bit_rdy_idx;
+
+	rgate->gate.lock = lock;
+	rgate->gate.reg = reg;
+	rgate->gate.shift = bit_idx;
+	rgate->gate.hw.init = &init;
+
+	hw = &rgate->gate.hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(rgate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+static int cclk_gate_enable(struct clk_hw *hw)
+{
+	int ret;
+
+	disable_power_domain_write_protection();
+
+	ret = clk_gate_ops.enable(hw);
+
+	enable_power_domain_write_protection();
+
+	return ret;
+}
+
+static void cclk_gate_disable(struct clk_hw *hw)
+{
+	disable_power_domain_write_protection();
+
+	clk_gate_ops.disable(hw);
+
+	enable_power_domain_write_protection();
+}
+
+static int cclk_gate_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+static const struct clk_ops cclk_gate_ops = {
+	.enable		= cclk_gate_enable,
+	.disable	= cclk_gate_disable,
+	.is_enabled	= cclk_gate_is_enabled,
+};
+
+static int cclk_mux_get_parent(struct clk_hw *hw)
+{
+	return clk_mux_ops.get_parent(hw);
+}
+
+static int cclk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	int ret;
+
+	disable_power_domain_write_protection();
+
+	sofware_reset_backup_domain();
+
+	ret = clk_mux_ops.set_parent(hw, index);
+
+	enable_power_domain_write_protection();
+
+	return ret;
+}
+
+static const struct clk_ops cclk_mux_ops = {
+	.get_parent = cclk_mux_get_parent,
+	.set_parent = cclk_mux_set_parent,
+};
+
+static struct clk_hw *stm32_register_cclk(struct device_d *dev, const char *name,
+		const char * const *parent_names, int num_parents,
+		void __iomem *reg, u8 bit_idx, u8 shift, unsigned long flags,
+		spinlock_t *lock)
+{
+	struct clk_hw *hw;
+	struct clk_gate *gate;
+	struct clk_mux *mux;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate) {
+		hw = ERR_PTR(-EINVAL);
+		goto fail;
+	}
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux) {
+		kfree(gate);
+		hw = ERR_PTR(-EINVAL);
+		goto fail;
+	}
+
+	gate->reg = reg;
+	gate->shift = bit_idx;
+	gate->flags = 0;
+	gate->lock = lock;
+
+	mux->reg = reg;
+	mux->shift = shift;
+	mux->width = 2;
+	mux->flags = 0;
+
+	hw = clk_hw_register_composite(dev, name, parent_names, num_parents,
+			&mux->hw, &cclk_mux_ops,
+			NULL, NULL,
+			&gate->hw, &cclk_gate_ops,
+			flags);
+
+	if (IS_ERR(hw)) {
+		kfree(gate);
+		kfree(mux);
+	}
+
+fail:
+	return hw;
+}
+
+static const char *sys_parents[] __initdata =   { "hsi", NULL, "pll" };
+
+static const struct clk_div_table ahb_div_table[] = {
+	{ 0x0,   1 }, { 0x1,   1 }, { 0x2,   1 }, { 0x3,   1 },
+	{ 0x4,   1 }, { 0x5,   1 }, { 0x6,   1 }, { 0x7,   1 },
+	{ 0x8,   2 }, { 0x9,   4 }, { 0xa,   8 }, { 0xb,  16 },
+	{ 0xc,  64 }, { 0xd, 128 }, { 0xe, 256 }, { 0xf, 512 },
+	{ 0 },
+};
+
+static const struct clk_div_table apb_div_table[] = {
+	{ 0,  1 }, { 0,  1 }, { 0,  1 }, { 0,  1 },
+	{ 4,  2 }, { 5,  4 }, { 6,  8 }, { 7, 16 },
+	{ 0 },
+};
+
+static const char *rtc_parents[4] = {
+	"no-clock", "lse", "lsi", "hse-rtc"
+};
+
+static const char *pll_src = "pll-src";
+
+static const char *pllsrc_parent[2] = { "hsi", NULL };
+
+static const char *dsi_parent[2] = { NULL, "pll-r" };
+
+static const char *lcd_parent[1] = { "pllsai-r-div" };
+
+static const char *i2s_parents[2] = { "plli2s-r", NULL };
+
+static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL,
+	"no-clock" };
+
+static const char *pll48_parents[2] = { "pll-q", "pllsai-p" };
+
+static const char *sdmux_parents[2] = { "pll48", "sys" };
+
+static const char *hdmi_parents[2] = { "lse", "hsi_div488" };
+
+static const char *spdif_parent[1] = { "plli2s-p" };
+
+static const char *lptim_parent[4] = { "apb1_mul", "lsi", "hsi", "lse" };
+
+static const char *uart_parents1[4] = { "apb2_div", "sys", "hsi", "lse" };
+static const char *uart_parents2[4] = { "apb1_div", "sys", "hsi", "lse" };
+
+static const char *i2c_parents[4] = { "apb1_div", "sys", "hsi", "no-clock" };
+
+static const char * const dfsdm1_src[] = { "apb2_div", "sys" };
+static const char * const adsfdm1_parent[] = { "sai1_clk", "sai2_clk" };
+
+struct stm32_aux_clk {
+	int idx;
+	const char *name;
+	const char * const *parent_names;
+	int num_parents;
+	int offset_mux;
+	u8 shift;
+	u8 mask;
+	int offset_gate;
+	u8 bit_idx;
+	unsigned long flags;
+};
+
+struct stm32f4_clk_data {
+	const struct stm32f4_gate_data *gates_data;
+	const u64 *gates_map;
+	int gates_num;
+	const struct stm32f4_pll_data *pll_data;
+	const struct stm32_aux_clk *aux_clk;
+	int aux_clk_num;
+	int end_primary;
+};
+
+static const struct stm32_aux_clk stm32f429_aux_clk[] = {
+	{
+		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+		NO_MUX, 0, 0,
+		STM32F4_RCC_APB2ENR, 26,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+		STM32F4_RCC_CFGR, 23, 1,
+		NO_GATE, 0,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 20, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 22, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+};
+
+static const struct stm32_aux_clk stm32f469_aux_clk[] = {
+	{
+		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+		NO_MUX, 0, 0,
+		STM32F4_RCC_APB2ENR, 26,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+		STM32F4_RCC_CFGR, 23, 1,
+		NO_GATE, 0,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 20, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 22, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
+		STM32F4_RCC_DCKCFGR, 27, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents),
+		STM32F4_RCC_DCKCFGR, 28, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		CLK_F469_DSI, "dsi", dsi_parent, ARRAY_SIZE(dsi_parent),
+		STM32F4_RCC_DCKCFGR, 29, 1,
+		STM32F4_RCC_APB2ENR, 27,
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
+	},
+};
+
+static const struct stm32_aux_clk stm32f746_aux_clk[] = {
+	{
+		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+		NO_MUX, 0, 0,
+		STM32F4_RCC_APB2ENR, 26,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+		STM32F4_RCC_CFGR, 23, 1,
+		NO_GATE, 0,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI1, "sai1_clk", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 20, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI2, "sai2_clk", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 22, 3,
+		STM32F4_RCC_APB2ENR, 23,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
+		STM32F7_RCC_DCKCFGR2, 27, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents),
+		STM32F7_RCC_DCKCFGR2, 28, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		CLK_HDMI_CEC, "hdmi-cec",
+		hdmi_parents, ARRAY_SIZE(hdmi_parents),
+		STM32F7_RCC_DCKCFGR2, 26, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		CLK_SPDIF, "spdif-rx",
+		spdif_parent, ARRAY_SIZE(spdif_parent),
+		STM32F7_RCC_DCKCFGR2, 22, 3,
+		STM32F4_RCC_APB2ENR, 23,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_USART1, "usart1",
+		uart_parents1, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 0, 3,
+		STM32F4_RCC_APB2ENR, 4,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_USART2, "usart2",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 2, 3,
+		STM32F4_RCC_APB1ENR, 17,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_USART3, "usart3",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 4, 3,
+		STM32F4_RCC_APB1ENR, 18,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_UART4, "uart4",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 6, 3,
+		STM32F4_RCC_APB1ENR, 19,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_UART5, "uart5",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 8, 3,
+		STM32F4_RCC_APB1ENR, 20,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_USART6, "usart6",
+		uart_parents1, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 10, 3,
+		STM32F4_RCC_APB2ENR, 5,
+		CLK_SET_RATE_PARENT,
+	},
+
+	{
+		CLK_UART7, "uart7",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 12, 3,
+		STM32F4_RCC_APB1ENR, 30,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_UART8, "uart8",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 14, 3,
+		STM32F4_RCC_APB1ENR, 31,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C1, "i2c1",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 16, 3,
+		STM32F4_RCC_APB1ENR, 21,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C2, "i2c2",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 18, 3,
+		STM32F4_RCC_APB1ENR, 22,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C3, "i2c3",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 20, 3,
+		STM32F4_RCC_APB1ENR, 23,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C4, "i2c4",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 22, 3,
+		STM32F4_RCC_APB1ENR, 24,
+		CLK_SET_RATE_PARENT,
+	},
+
+	{
+		CLK_LPTIMER, "lptim1",
+		lptim_parent, ARRAY_SIZE(lptim_parent),
+		STM32F7_RCC_DCKCFGR2, 24, 3,
+		STM32F4_RCC_APB1ENR, 9,
+		CLK_SET_RATE_PARENT
+	},
+};
+
+static const struct stm32_aux_clk stm32f769_aux_clk[] = {
+	{
+		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
+		NO_MUX, 0, 0,
+		STM32F4_RCC_APB2ENR, 26,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
+		STM32F4_RCC_CFGR, 23, 1,
+		NO_GATE, 0,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI1, "sai1_clk", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 20, 3,
+		STM32F4_RCC_APB2ENR, 22,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_SAI2, "sai2_clk", sai_parents, ARRAY_SIZE(sai_parents),
+		STM32F4_RCC_DCKCFGR, 22, 3,
+		STM32F4_RCC_APB2ENR, 23,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
+		STM32F7_RCC_DCKCFGR2, 27, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		NO_IDX, "sdmux1", sdmux_parents, ARRAY_SIZE(sdmux_parents),
+		STM32F7_RCC_DCKCFGR2, 28, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		NO_IDX, "sdmux2", sdmux_parents, ARRAY_SIZE(sdmux_parents),
+		STM32F7_RCC_DCKCFGR2, 29, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		CLK_HDMI_CEC, "hdmi-cec",
+		hdmi_parents, ARRAY_SIZE(hdmi_parents),
+		STM32F7_RCC_DCKCFGR2, 26, 1,
+		NO_GATE, 0,
+		0
+	},
+	{
+		CLK_SPDIF, "spdif-rx",
+		spdif_parent, ARRAY_SIZE(spdif_parent),
+		STM32F7_RCC_DCKCFGR2, 22, 3,
+		STM32F4_RCC_APB2ENR, 23,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_USART1, "usart1",
+		uart_parents1, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 0, 3,
+		STM32F4_RCC_APB2ENR, 4,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_USART2, "usart2",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 2, 3,
+		STM32F4_RCC_APB1ENR, 17,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_USART3, "usart3",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 4, 3,
+		STM32F4_RCC_APB1ENR, 18,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_UART4, "uart4",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 6, 3,
+		STM32F4_RCC_APB1ENR, 19,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_UART5, "uart5",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 8, 3,
+		STM32F4_RCC_APB1ENR, 20,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_USART6, "usart6",
+		uart_parents1, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 10, 3,
+		STM32F4_RCC_APB2ENR, 5,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_UART7, "uart7",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 12, 3,
+		STM32F4_RCC_APB1ENR, 30,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_UART8, "uart8",
+		uart_parents2, ARRAY_SIZE(uart_parents1),
+		STM32F7_RCC_DCKCFGR2, 14, 3,
+		STM32F4_RCC_APB1ENR, 31,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C1, "i2c1",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 16, 3,
+		STM32F4_RCC_APB1ENR, 21,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C2, "i2c2",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 18, 3,
+		STM32F4_RCC_APB1ENR, 22,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C3, "i2c3",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 20, 3,
+		STM32F4_RCC_APB1ENR, 23,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_I2C4, "i2c4",
+		i2c_parents, ARRAY_SIZE(i2c_parents),
+		STM32F7_RCC_DCKCFGR2, 22, 3,
+		STM32F4_RCC_APB1ENR, 24,
+		CLK_SET_RATE_PARENT,
+	},
+	{
+		CLK_LPTIMER, "lptim1",
+		lptim_parent, ARRAY_SIZE(lptim_parent),
+		STM32F7_RCC_DCKCFGR2, 24, 3,
+		STM32F4_RCC_APB1ENR, 9,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_F769_DSI, "dsi",
+		dsi_parent, ARRAY_SIZE(dsi_parent),
+		STM32F7_RCC_DCKCFGR2, 0, 1,
+		STM32F4_RCC_APB2ENR, 27,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_DFSDM1, "dfsdm1",
+		dfsdm1_src, ARRAY_SIZE(dfsdm1_src),
+		STM32F4_RCC_DCKCFGR, 25, 1,
+		STM32F4_RCC_APB2ENR, 29,
+		CLK_SET_RATE_PARENT
+	},
+	{
+		CLK_ADFSDM1, "adfsdm1",
+		adsfdm1_parent, ARRAY_SIZE(adsfdm1_parent),
+		STM32F4_RCC_DCKCFGR, 26, 1,
+		STM32F4_RCC_APB2ENR, 29,
+		CLK_SET_RATE_PARENT
+	},
+};
+
+static const struct stm32f4_clk_data stm32f429_clk_data = {
+	.end_primary	= END_PRIMARY_CLK,
+	.gates_data	= stm32f429_gates,
+	.gates_map	= stm32f42xx_gate_map,
+	.gates_num	= ARRAY_SIZE(stm32f429_gates),
+	.pll_data	= stm32f429_pll,
+	.aux_clk	= stm32f429_aux_clk,
+	.aux_clk_num	= ARRAY_SIZE(stm32f429_aux_clk),
+};
+
+static const struct stm32f4_clk_data stm32f469_clk_data = {
+	.end_primary	= END_PRIMARY_CLK,
+	.gates_data	= stm32f469_gates,
+	.gates_map	= stm32f46xx_gate_map,
+	.gates_num	= ARRAY_SIZE(stm32f469_gates),
+	.pll_data	= stm32f469_pll,
+	.aux_clk	= stm32f469_aux_clk,
+	.aux_clk_num	= ARRAY_SIZE(stm32f469_aux_clk),
+};
+
+static const struct stm32f4_clk_data stm32f746_clk_data = {
+	.end_primary	= END_PRIMARY_CLK_F7,
+	.gates_data	= stm32f746_gates,
+	.gates_map	= stm32f746_gate_map,
+	.gates_num	= ARRAY_SIZE(stm32f746_gates),
+	.pll_data	= stm32f469_pll,
+	.aux_clk	= stm32f746_aux_clk,
+	.aux_clk_num	= ARRAY_SIZE(stm32f746_aux_clk),
+};
+
+static const struct stm32f4_clk_data stm32f769_clk_data = {
+	.end_primary	= END_PRIMARY_CLK_F7,
+	.gates_data	= stm32f769_gates,
+	.gates_map	= stm32f769_gate_map,
+	.gates_num	= ARRAY_SIZE(stm32f769_gates),
+	.pll_data	= stm32f469_pll,
+	.aux_clk	= stm32f769_aux_clk,
+	.aux_clk_num	= ARRAY_SIZE(stm32f769_aux_clk),
+};
+
+static const struct of_device_id stm32f4_of_match[] = {
+	{
+		.compatible = "st,stm32f42xx-rcc",
+		.data = &stm32f429_clk_data
+	},
+	{
+		.compatible = "st,stm32f469-rcc",
+		.data = &stm32f469_clk_data
+	},
+	{
+		.compatible = "st,stm32f746-rcc",
+		.data = &stm32f746_clk_data
+	},
+	{
+		.compatible = "st,stm32f769-rcc",
+		.data = &stm32f769_clk_data
+	},
+	{}
+};
+
+static struct clk_hw *stm32_register_aux_clk(const char *name,
+		const char * const *parent_names, int num_parents,
+		int offset_mux, u8 shift, u8 mask,
+		int offset_gate, u8 bit_idx,
+		unsigned long flags, spinlock_t *lock)
+{
+	struct clk_hw *hw;
+	struct clk_gate *gate = NULL;
+	struct clk_mux *mux = NULL;
+	struct clk_hw *mux_hw = NULL, *gate_hw = NULL;
+	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL;
+
+	if (offset_gate != NO_GATE) {
+		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+		if (!gate) {
+			hw = ERR_PTR(-EINVAL);
+			goto fail;
+		}
+
+		gate->reg = base + offset_gate;
+		gate->shift = bit_idx;
+		gate->flags = 0;
+		gate->lock = lock;
+		gate_hw = &gate->hw;
+		gate_ops = &clk_gate_ops;
+	}
+
+	if (offset_mux != NO_MUX) {
+		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+		if (!mux) {
+			hw = ERR_PTR(-EINVAL);
+			goto fail;
+		}
+
+		mux->reg = base + offset_mux;
+		mux->shift = shift;
+		mux->width = hweight8(mask);
+		mux->flags = 0;
+		mux_hw = &mux->hw;
+		mux_ops = &clk_mux_ops;
+	}
+
+	if (mux_hw == NULL && gate_hw == NULL) {
+		hw = ERR_PTR(-EINVAL);
+		goto fail;
+	}
+
+	hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+			mux_hw, mux_ops,
+			NULL, NULL,
+			gate_hw, gate_ops,
+			flags);
+
+fail:
+	if (IS_ERR(hw)) {
+		kfree(gate);
+		kfree(mux);
+	}
+
+	return hw;
+}
+
+static void __init stm32f4_rcc_init(struct device_node *np)
+{
+	const char *hse_clk, *i2s_in_clk;
+	int n;
+	const struct of_device_id *match;
+	const struct stm32f4_clk_data *data;
+	unsigned long pllm;
+	struct clk_hw *pll_src_hw;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%pOFn: unable to map resource\n", np);
+		return;
+	}
+
+	pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+	if (IS_ERR(pdrm)) {
+		pdrm = NULL;
+		pr_warn("%s: Unable to get syscfg\n", __func__);
+	}
+
+	match = of_match_node(stm32f4_of_match, np);
+	if (WARN_ON(!match))
+		return;
+
+	data = match->data;
+
+	stm32fx_end_primary_clk = data->end_primary;
+
+	clks = kmalloc_array(data->gates_num + stm32fx_end_primary_clk,
+			sizeof(*clks), GFP_KERNEL);
+	if (!clks)
+		goto fail;
+
+	stm32f4_gate_map = data->gates_map;
+
+	hse_clk = of_clk_get_parent_name(np, 0);
+	dsi_parent[0] = hse_clk;
+	pllsrc_parent[1] = hse_clk;
+
+	i2s_in_clk = of_clk_get_parent_name(np, 1);
+
+	i2s_parents[1] = i2s_in_clk;
+	sai_parents[2] = i2s_in_clk;
+
+	if (of_device_is_compatible(np, "st,stm32f769-rcc")) {
+		clk_hw_register_gate(NULL, "dfsdm1_apb", "apb2_div", 0,
+				     base + STM32F4_RCC_APB2ENR, 29,
+				     CLK_IGNORE_UNUSED, &stm32f4_clk_lock);
+		dsi_parent[0] = pll_src;
+		sai_parents[3] = pll_src;
+	}
+
+	clks[CLK_HSI] = clk_hw_register_fixed_rate(NULL, "hsi",
+			NULL, 0, 16000000);
+
+	pll_src_hw = clk_hw_register_mux(NULL, pll_src, pllsrc_parent,
+					 ARRAY_SIZE(pllsrc_parent), 0,
+					 base + STM32F4_RCC_PLLCFGR, 22, 1, 0,
+					 &stm32f4_clk_lock);
+
+	pllm = readl(base + STM32F4_RCC_PLLCFGR) & 0x3f;
+
+	clk_hw_register_fixed_factor(NULL, "vco_in", pll_src,
+				     0, 1, pllm);
+
+	stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
+			&stm32f4_clk_lock);
+
+	clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in",
+			&data->pll_data[1], &stm32f4_clk_lock);
+
+	clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
+			&data->pll_data[2], &stm32f4_clk_lock);
+
+	for (n = 0; n < MAX_POST_DIV; n++) {
+		const struct stm32f4_pll_post_div_data *post_div;
+		struct clk_hw *hw;
+
+		post_div = &post_div_data[n];
+
+		hw = clk_register_pll_div(post_div->name,
+				post_div->parent,
+				post_div->flag,
+				base + post_div->offset,
+				post_div->shift,
+				post_div->width,
+				post_div->flag_div,
+				post_div->div_table,
+				clks[post_div->pll_idx],
+				&stm32f4_clk_lock);
+
+		if (post_div->idx != NO_IDX)
+			clks[post_div->idx] = hw;
+	}
+
+	sys_parents[1] = hse_clk;
+
+	clks[CLK_SYSCLK] = clk_hw_register_mux_table(
+	    NULL, "sys", sys_parents, ARRAY_SIZE(sys_parents), 0,
+	    base + STM32F4_RCC_CFGR, 0, 3, 0, NULL, &stm32f4_clk_lock);
+
+	clk_register_divider_table(NULL, "ahb_div", "sys",
+				   CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
+				   4, 4, 0, ahb_div_table, &stm32f4_clk_lock);
+
+	clk_register_divider_table(NULL, "apb1_div", "ahb_div",
+				   CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
+				   10, 3, 0, apb_div_table, &stm32f4_clk_lock);
+	clk_register_apb_mul(NULL, "apb1_mul", "apb1_div",
+			     CLK_SET_RATE_PARENT, 12);
+
+	clk_register_divider_table(NULL, "apb2_div", "ahb_div",
+				   CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
+				   13, 3, 0, apb_div_table, &stm32f4_clk_lock);
+	clk_register_apb_mul(NULL, "apb2_mul", "apb2_div",
+			     CLK_SET_RATE_PARENT, 15);
+
+	clks[SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick", "ahb_div",
+						  0, 1, 8);
+	clks[FCLK] = clk_hw_register_fixed_factor(NULL, "fclk", "ahb_div",
+					       0, 1, 1);
+
+	for (n = 0; n < data->gates_num; n++) {
+		const struct stm32f4_gate_data *gd;
+		unsigned int secondary;
+		int idx;
+
+		gd = &data->gates_data[n];
+		secondary = 8 * (gd->offset - STM32F4_RCC_AHB1ENR) +
+			gd->bit_idx;
+		idx = stm32f4_rcc_lookup_clk_idx(0, secondary);
+
+		if (idx < 0)
+			goto fail;
+
+		clks[idx] = clk_hw_register_gate(
+		    NULL, gd->name, gd->parent_name, gd->flags,
+		    base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
+
+		if (IS_ERR(clks[idx])) {
+			pr_err("%pOF: Unable to register leaf clock %s\n",
+			       np, gd->name);
+			goto fail;
+		}
+	}
+
+	clks[CLK_LSI] = clk_register_rgate(NULL, "lsi", "clk-lsi", 0,
+			base + STM32F4_RCC_CSR, 0, 1, 0, &stm32f4_clk_lock);
+
+	if (IS_ERR(clks[CLK_LSI])) {
+		pr_err("Unable to register lsi clock\n");
+		goto fail;
+	}
+
+	clks[CLK_LSE] = clk_register_rgate(NULL, "lse", "clk-lse", 0,
+			base + STM32F4_RCC_BDCR, 0, 1, 0, &stm32f4_clk_lock);
+
+	if (IS_ERR(clks[CLK_LSE])) {
+		pr_err("Unable to register lse clock\n");
+		goto fail;
+	}
+
+	clks[CLK_HSE_RTC] = clk_hw_register_divider(NULL, "hse-rtc", "clk-hse",
+			0, base + STM32F4_RCC_CFGR, 16, 5, 0,
+			&stm32f4_clk_lock);
+
+	if (IS_ERR(clks[CLK_HSE_RTC])) {
+		pr_err("Unable to register hse-rtc clock\n");
+		goto fail;
+	}
+
+	clks[CLK_RTC] = stm32_register_cclk(NULL, "rtc", rtc_parents, 4,
+			base + STM32F4_RCC_BDCR, 15, 8, 0, &stm32f4_clk_lock);
+
+	if (IS_ERR(clks[CLK_RTC])) {
+		pr_err("Unable to register rtc clock\n");
+		goto fail;
+	}
+
+	for (n = 0; n < data->aux_clk_num; n++) {
+		const struct stm32_aux_clk *aux_clk;
+		struct clk_hw *hw;
+
+		aux_clk = &data->aux_clk[n];
+
+		hw = stm32_register_aux_clk(aux_clk->name,
+				aux_clk->parent_names, aux_clk->num_parents,
+				aux_clk->offset_mux, aux_clk->shift,
+				aux_clk->mask, aux_clk->offset_gate,
+				aux_clk->bit_idx, aux_clk->flags,
+				&stm32f4_clk_lock);
+
+		if (IS_ERR(hw)) {
+			pr_warn("Unable to register %s clk\n", aux_clk->name);
+			continue;
+		}
+
+		if (aux_clk->idx != NO_IDX)
+			clks[aux_clk->idx] = hw;
+	}
+
+	if (of_device_is_compatible(np, "st,stm32f746-rcc")) {
+
+		clk_hw_register_fixed_factor(NULL, "hsi_div488", "hsi", 0,
+				1, 488);
+
+		clks[CLK_PLL_SRC] = pll_src_hw;
+	}
+
+	of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
+
+	return;
+fail:
+	kfree(clks);
+}
+CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init);
+CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init);
+CLK_OF_DECLARE_DRIVER(stm32f746_rcc, "st,stm32f746-rcc", stm32f4_rcc_init);
+CLK_OF_DECLARE_DRIVER(stm32f769_rcc, "st,stm32f769-rcc", stm32f4_rcc_init);
diff --git a/include/asm-generic/bitsperlong.h b/include/asm-generic/bitsperlong.h
index 836a1d4c83dd..20c055c6bd59 100644
--- a/include/asm-generic/bitsperlong.h
+++ b/include/asm-generic/bitsperlong.h
@@ -9,4 +9,8 @@
 #define BITS_PER_LONG 32
 #endif /* CONFIG_64BIT */
 
+#ifndef BITS_PER_LONG_LONG
+#define BITS_PER_LONG_LONG 64
+#endif
+
 #endif /* __ASM_GENERIC_BITS_PER_LONG */
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 397520a4815c..a90a5400d56f 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -754,6 +754,11 @@ static inline const char *clk_hw_get_name(struct clk_hw *hw)
 	return hw->clk.name;
 }
 
+static inline unsigned long clk_hw_get_flags(const struct clk_hw *hw)
+{
+	return hw->clk.flags;
+}
+
 int clk_name_set_parent(const char *clkname, const char *clkparentname);
 int clk_name_set_rate(const char *clkname, unsigned long rate);
 
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 31 00:02:58 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 09:02:58 +0100
Subject: [PATCH 0/4] video: add STM32F429-DISCO video pipeline support
Message-ID: <20220131080302.1873443-1-a.fatoum@pengutronix.de>

The STM32F429-DISCO has the LCD-TFT display controller connected to a
parallel panel with MIPI-DBI over SPI for panel control.

The LTDC driver was originally written for the STM32MP1, but had some
issues last time I tested it a few years ago. I debugged it into
submission on the STM32F429 now though, so it might just work on the MP1
as well.

Ahmad Fatoum (4):
  gpiolib: implement gpiod_set_value
  video: add driver for STM32 LCD-TFT Display Controller
  video: add MIPI DBI Type C Option 3 support
  video: add Ilitek ILI9341 panel support

 commands/Kconfig                     |  19 +
 commands/Makefile                    |   1 +
 commands/mipi_dbi.c                  | 104 +++++
 drivers/video/Kconfig                |  22 ++
 drivers/video/Makefile               |   3 +
 drivers/video/mipi_dbi.c             | 467 +++++++++++++++++++++++
 drivers/video/panel-ilitek-ili9341.c | 541 +++++++++++++++++++++++++++
 drivers/video/stm32_ltdc.c           | 336 +++++++++++++++++
 drivers/video/stm32_ltdc.h           | 130 +++++++
 include/gpiod.h                      |   8 +-
 include/spi/spi.h                    |  20 +
 include/video/mipi_dbi.h             | 105 ++++++
 include/video/mipi_display.h         | 150 ++++++++
 13 files changed, 1905 insertions(+), 1 deletion(-)
 create mode 100644 commands/mipi_dbi.c
 create mode 100644 drivers/video/mipi_dbi.c
 create mode 100644 drivers/video/panel-ilitek-ili9341.c
 create mode 100644 drivers/video/stm32_ltdc.c
 create mode 100644 drivers/video/stm32_ltdc.h
 create mode 100644 include/video/mipi_dbi.h
 create mode 100644 include/video/mipi_display.h

-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 31 00:02:59 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 09:02:59 +0100
Subject: [PATCH 1/4] gpiolib: implement gpiod_set_value
In-Reply-To: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
References: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
Message-ID: <20220131080302.1873443-2-a.fatoum@pengutronix.de>

Linux gpiod_set_value is silent if the GPIO descriptor is NULL, but
barebox warns about it. Also having gpio_set_value not respect active
low/high, while Linux gpiod_set_value respects it is error-prone.

Add a new gpiod_set_value function that covers this. gpio == -ENOENT is
taken as the dummy value for optional GPIOs.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/gpiod.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/include/gpiod.h b/include/gpiod.h
index c8b2cd47a3cb..adac50b4c36d 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -14,7 +14,7 @@ enum gpiod_flags {
 	GPIOD_IN	= GPIOF_IN,
 	/*
 	 * To change this later to a different logic level (i.e. taking
-	 * active low into account), use gpio_direction_active()
+	 * active low into account), use gpiod_set_value()
 	 */
 	GPIOD_OUT_LOW	= GPIOF_OUT_INIT_INACTIVE,
 	GPIOD_OUT_HIGH	= GPIOF_OUT_INIT_ACTIVE,
@@ -23,4 +23,10 @@ enum gpiod_flags {
 /* returned gpio descriptor can be passed to any normal gpio_* function */
 int gpiod_get(struct device_d *dev, const char *_con_id, enum gpiod_flags flags);
 
+static inline void gpiod_set_value(unsigned gpio, bool value)
+{
+	if (gpio != -ENOENT)
+		gpio_direction_active(gpio, value);
+}
+
 #endif
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 31 00:03:00 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 09:03:00 +0100
Subject: [PATCH 2/4] video: add driver for STM32 LCD-TFT Display Controller
In-Reply-To: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
References: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
Message-ID: <20220131080302.1873443-3-a.fatoum@pengutronix.de>

This driver has been tested on a STM32F429 connected to an Ilitek 9341
Display for which support is added in a follow-up commit. The same
driver can be used (but wasn't tested in its current form) for the
STM32MP1 as well. The official ST evaluation kits all use MIPI-DSI
for which we still lack support. The LXA MC-1 has a parallel display
connected to the LTDC, but I didn't have one readily available to test.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/video/Kconfig      |   8 +
 drivers/video/Makefile     |   1 +
 drivers/video/stm32_ltdc.c | 336 +++++++++++++++++++++++++++++++++++++
 drivers/video/stm32_ltdc.h | 130 ++++++++++++++
 4 files changed, 475 insertions(+)
 create mode 100644 drivers/video/stm32_ltdc.c
 create mode 100644 drivers/video/stm32_ltdc.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index cfbd541a956e..1b8672fdea82 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -59,6 +59,14 @@ config DRIVER_VIDEO_STM
 	  Say 'Y' here to enable framebuffer and splash screen support for
 	  i.MX23 and i.MX28 based systems.
 
+config DRIVER_VIDEO_STM32_LTDC
+	bool "STM32 LTDC framebuffer driver"
+	select VIDEO_VPL
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	  Say 'Y' here to enable framebuffer and splash screen support for
+	  STM32 and STM32MP1.
+
 config DRIVER_VIDEO_S3C24XX
 	bool "S3C244x framebuffer driver"
 	depends on ARCH_S3C24xx
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8344bdd2af2a..7f4429278987 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_DRIVER_VIDEO_SIMPLE_PANEL) += simple-panel.o
 obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
 obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
 obj-$(CONFIG_DRIVER_VIDEO_STM) += stm.o
+obj-$(CONFIG_DRIVER_VIDEO_STM32_LTDC) += stm32_ltdc.o
 obj-$(CONFIG_DRIVER_VIDEO_IMX) += imx.o
 obj-$(CONFIG_DRIVER_VIDEO_IMX_IPU) += imx-ipu-fb.o
 obj-$(CONFIG_DRIVER_VIDEO_S3C24XX) += s3c24xx.o
diff --git a/drivers/video/stm32_ltdc.c b/drivers/video/stm32_ltdc.c
new file mode 100644
index 000000000000..645c20b5545f
--- /dev/null
+++ b/drivers/video/stm32_ltdc.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017-2018 STMicroelectronics - All Rights Reserved
+ * Author(s): Philippe Cornu <philippe.cornu at st.com> for STMicroelectronics.
+ *	      Yannick Fertre <yannick.fertre at st.com> for STMicroelectronics.
+ *	      Ahmad Fatoum <a.fatoum at pengutronix.de>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <io.h>
+#include <fb.h>
+#include <dma.h>
+#include <video/media-bus-format.h>
+#include <video/vpl.h>
+#include <of_graph.h>
+
+#include "stm32_ltdc.h"
+
+struct ltdc_hw {
+	void __iomem *regs;
+	struct device_d *dev;
+	struct clk *pclk;
+	bool claimed;
+};
+
+struct ltdc_fb {
+	int id;
+	struct fb_info info;
+	u32 bg_col_argb;
+	u32 alpha;
+	u32 bus_format;
+	enum stm32_ltdc_pixfmt pixfmt;
+	struct vpl vpl;
+	struct ltdc_hw *hw;
+};
+
+static bool has_alpha(enum stm32_ltdc_pixfmt pixfmt)
+{
+	switch (pixfmt) {
+	case PF_ARGB8888:
+	case PF_ARGB1555:
+	case PF_ARGB4444:
+	case PF_AL44:
+	case PF_AL88:
+		return true;
+	case PF_RGB888:
+	case PF_RGB565:
+	case PF_L8:
+	default:
+		return false;
+	}
+}
+
+static void ltdc_set_mode(struct ltdc_fb *priv,
+			  struct fb_videomode *mode)
+{
+	void __iomem *regs = priv->hw->regs;
+	u32 hsync, vsync, acc_hbp, acc_vbp, acc_act_w, acc_act_h;
+	u32 total_w, total_h;
+	u32 val;
+
+	/* Convert video timings to ltdc timings */
+	hsync = mode->hsync_len - 1;
+	vsync = mode->vsync_len - 1;
+	acc_hbp = hsync + mode->left_margin;
+	acc_vbp = vsync + mode->upper_margin;
+	acc_act_w = acc_hbp + mode->xres;
+	acc_act_h = acc_vbp + mode->yres;
+	total_w = acc_act_w + mode->right_margin;
+	total_h = acc_act_h + mode->lower_margin;
+
+	/* Synchronization sizes */
+	val = (hsync << 16) | vsync;
+	clrsetbits_le32(regs + LTDC_SSCR, SSCR_VSH | SSCR_HSW, val);
+
+	/* Accumulated back porch */
+	val = (acc_hbp << 16) | acc_vbp;
+	clrsetbits_le32(regs + LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val);
+
+	/* Accumulated active width */
+	val = (acc_act_w << 16) | acc_act_h;
+	clrsetbits_le32(regs + LTDC_AWCR, AWCR_AAW | AWCR_AAH, val);
+
+	/* Total width & height */
+	val = (total_w << 16) | total_h;
+	clrsetbits_le32(regs + LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val);
+
+	setbits_le32(regs + LTDC_LIPCR, acc_act_h + 1);
+
+	/* Signal polarities */
+	val = 0;
+	dev_dbg(priv->hw->dev, "mode->display_flags 0x%x mode->sync 0x%x\n",
+		mode->display_flags, mode->sync);
+	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+		val |= GCR_HSPOL;
+	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+		val |= GCR_VSPOL;
+	if (mode->display_flags & DISPLAY_FLAGS_DE_HIGH)
+		val |= GCR_DEPOL;
+	if (mode->display_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+		val |= GCR_PCPOL;
+
+	clrsetbits_le32(regs + LTDC_GCR,
+			GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val);
+
+	/* Overall background color */
+	writel(priv->bg_col_argb, regs + LTDC_BCCR);
+}
+
+static void ltdc_set_layer1(struct ltdc_fb *priv)
+{
+	void __iomem *regs = priv->hw->regs;
+	u32 x0, x1, y0, y1;
+	u32 pitch_in_bytes;
+	u32 line_length;
+	u32 bus_width;
+	u32 val, tmp, bpp;
+	struct fb_videomode *mode = priv->info.mode;
+
+	x0 = y0 = 0;
+	x1 = mode->xres - 1;
+	y1 = mode->yres - 1;
+
+	/* Horizontal start and stop position */
+	tmp = (readl(regs + LTDC_BPCR) & BPCR_AHBP) >> 16;
+	val = ((x1 + 1 + tmp) << 16) + (x0 + 1 + tmp);
+	clrsetbits_le32(regs + LTDC_L1WHPCR, LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS,
+			val);
+
+	/* Vertical start & stop position */
+	tmp = readl(regs + LTDC_BPCR) & BPCR_AVBP;
+	val = ((y1 + 1 + tmp) << 16) + (y0 + 1 + tmp);
+	clrsetbits_le32(regs + LTDC_L1WVPCR, LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS,
+			val);
+
+	/* Layer background color */
+	writel(priv->bg_col_argb, regs + LTDC_L1DCCR);
+
+	/* Color frame buffer pitch in bytes & line length */
+	bpp = priv->info.bits_per_pixel;
+	pitch_in_bytes = mode->xres * (bpp >> 3);
+	bus_width = 8 << ((readl(regs + LTDC_GC2R) & GC2R_BW) >> 4);
+	line_length = ((bpp >> 3) * mode->xres) + (bus_width >> 3) - 1;
+	val = (pitch_in_bytes << 16) | line_length;
+	clrsetbits_le32(regs + LTDC_L1CFBLR, LXCFBLR_CFBLL | LXCFBLR_CFBP, val);
+
+	/* Pixel format */
+	clrsetbits_le32(regs + LTDC_L1PFCR, LXPFCR_PF, priv->pixfmt);
+
+	/* Constant alpha value */
+	clrsetbits_le32(regs + LTDC_L1CACR, LXCACR_CONSTA, priv->alpha);
+
+	/* Specifies the blending factors : with or without pixel alpha */
+	/* Manage hw-specific capabilities */
+	val = has_alpha(priv->pixfmt) ? BF1_PAXCA | BF2_1PAXCA : BF1_CA | BF2_1CA;
+
+	/* Blending factors */
+	clrsetbits_le32(regs + LTDC_L1BFCR, LXBFCR_BF2 | LXBFCR_BF1, val);
+
+	/* Frame buffer line number */
+	clrsetbits_le32(regs + LTDC_L1CFBLNR, LXCFBLNR_CFBLN, mode->yres);
+
+	/* Frame buffer address */
+	writel((unsigned long)priv->info.screen_base, regs + LTDC_L1CFBAR);
+
+	/* Enable layer 1 */
+	setbits_le32(regs + LTDC_L1CR, LXCR_LEN);
+}
+
+static int ltdc_activate_var(struct fb_info *info)
+{
+	info->line_length = info->xres * (info->bits_per_pixel >> 3);
+
+	info->screen_base = dma_alloc_writecombine(info->line_length * info->yres,
+						   DMA_ADDRESS_BROKEN);
+	if (!info->screen_base)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void ltdc_enable(struct fb_info *info)
+{
+	struct fb_videomode *mode = info->mode;
+	struct ltdc_fb *priv = info->priv;
+	struct ltdc_hw *hw = priv->hw;
+	u32 pixclock;
+	int ret;
+
+	if (hw->claimed) {
+		dev_warn(hw->dev, "CRTC currently claimed by other frame buffer!\n");
+		return;
+	}
+
+	vpl_ioctl_prepare(&priv->vpl, priv->id, mode);
+
+	pixclock = PICOS2KHZ(mode->pixclock) * 1000;
+
+	ret = clk_enable(hw->pclk);
+	if (ret) {
+		dev_err(hw->dev, "peripheral clock enable error %d\n", ret);
+		return;
+	}
+
+	clk_set_rate(clk_get_parent(hw->pclk), pixclock);
+	if (!ret)
+		ret = clk_set_rate(hw->pclk, pixclock);
+	if (ret < 0) {
+		dev_err(hw->dev, "fail to set pixel clock %d hz: %d\n",
+			pixclock, ret);
+		return;
+	}
+
+	ret = device_reset_us(hw->dev, 100000);
+	if (ret) {
+		dev_err(hw->dev, "error resetting controller %d\n", ret);
+		return;
+	}
+
+	/* Configure & start LTDC */
+	ltdc_set_mode(priv, mode);
+	ltdc_set_layer1(priv);
+
+	/* Reload configuration immediately & enable LTDC */
+	setbits_le32(hw->regs + LTDC_SRCR, SRCR_IMR);
+	setbits_le32(hw->regs + LTDC_GCR, GCR_LTDCEN);
+
+	vpl_ioctl_enable(&priv->vpl, priv->id);
+
+	hw->claimed = true;
+}
+
+static void ltdc_disable(struct fb_info *info)
+{
+	struct ltdc_fb *priv = info->priv;
+
+	vpl_ioctl_disable(&priv->vpl, priv->id);
+
+	clrbits_le32(priv->hw->regs + LTDC_GCR, GCR_LTDCEN);
+	clk_disable(priv->hw->pclk);
+	priv->hw->claimed = false;
+
+	vpl_ioctl_unprepare(&priv->vpl, priv->id);
+}
+
+static struct fb_ops ltdc_ops = {
+	.fb_activate_var	= ltdc_activate_var,
+	.fb_enable		= ltdc_enable,
+	.fb_disable		= ltdc_disable,
+};
+
+static int ltdc_probe(struct device_d *dev)
+{
+	struct device_node *np;
+	struct resource *iores;
+	struct ltdc_hw *hw;
+	int ret;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	hw = xzalloc(sizeof *hw);
+	hw->dev = dev;
+	hw->regs = IOMEM(iores->start);
+
+	hw->pclk = clk_get(dev, NULL);
+	if (IS_ERR(hw->pclk)) {
+		dev_err(dev, "peripheral clock get error %d\n", ret);
+		return PTR_ERR(hw->pclk);
+	}
+
+	for_each_available_child_of_node(dev->device_node, np) {
+		struct ltdc_fb *priv;
+		struct of_endpoint ep;
+		struct fb_info *info;
+
+		if (!of_graph_port_is_available(np))
+			continue;
+
+		ret = of_graph_parse_endpoint(np, &ep);
+		if (ret)
+			return ret;
+
+		dev_dbg(hw->dev, "register vpl for %s\n", np->full_name);
+
+		priv = xzalloc(sizeof(*priv));
+		priv->hw = hw;
+		priv->id = ep.id;
+		priv->vpl.node = dev->device_node;
+
+		ret = vpl_register(&priv->vpl);
+		if (ret)
+			return ret;
+
+		info = &priv->info;
+		info->priv = priv;
+		info->fbops = &ltdc_ops;
+
+		info->red	= (struct fb_bitfield){ .offset = 11, .length = 5, };
+		info->green	= (struct fb_bitfield){ .offset =  5, .length = 6, };
+		info->blue	= (struct fb_bitfield){ .offset =  0, .length = 5, };
+		info->bits_per_pixel = 16,
+		priv->pixfmt = PF_RGB565;
+		/* TODO Below parameters are hard-coded for the moment... */
+		priv->bg_col_argb = 0xFFFFFFFF; /* white no transparency */
+		priv->alpha = 0xFF;
+
+		ret = vpl_ioctl(&priv->vpl, priv->id, VPL_GET_VIDEOMODES, &info->modes);
+		if (ret)
+			dev_dbg(dev, "failed to get modes: %s\n", strerror(-ret));
+
+		ret = register_framebuffer(info);
+		if (ret < 0) {
+			dev_err(dev, "failed to register framebuffer\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static __maybe_unused struct of_device_id ltdc_ids[] = {
+	{ .compatible = "st,stm32-ltdc" },
+	{ /* sentinel */ }
+};
+
+static struct driver_d ltdc_driver = {
+	.name = "stm32-ltdc",
+	.probe = ltdc_probe,
+	.of_compatible = DRV_OF_COMPAT(ltdc_ids),
+};
+device_platform_driver(ltdc_driver);
diff --git a/drivers/video/stm32_ltdc.h b/drivers/video/stm32_ltdc.h
new file mode 100644
index 000000000000..6481f2613b95
--- /dev/null
+++ b/drivers/video/stm32_ltdc.h
@@ -0,0 +1,130 @@
+#ifndef STM32_LTDC_H__
+#define STM32_LTDC_H__
+
+/* LTDC main registers */
+#define LTDC_IDR	0x00	/* IDentification */
+#define LTDC_LCR	0x04	/* Layer Count */
+#define LTDC_SSCR	0x08	/* Synchronization Size Configuration */
+#define LTDC_BPCR	0x0C	/* Back Porch Configuration */
+#define LTDC_AWCR	0x10	/* Active Width Configuration */
+#define LTDC_TWCR	0x14	/* Total Width Configuration */
+#define LTDC_GCR	0x18	/* Global Control */
+#define LTDC_GC1R	0x1C	/* Global Configuration 1 */
+#define LTDC_GC2R	0x20	/* Global Configuration 2 */
+#define LTDC_SRCR	0x24	/* Shadow Reload Configuration */
+#define LTDC_GACR	0x28	/* GAmma Correction */
+#define LTDC_BCCR	0x2C	/* Background Color Configuration */
+#define LTDC_IER	0x34	/* Interrupt Enable */
+#define LTDC_ISR	0x38	/* Interrupt Status */
+#define LTDC_ICR	0x3C	/* Interrupt Clear */
+#define LTDC_LIPCR	0x40	/* Line Interrupt Position Conf. */
+#define LTDC_CPSR	0x44	/* Current Position Status */
+#define LTDC_CDSR	0x48	/* Current Display Status */
+
+/* LTDC layer 1 registers */
+#define LTDC_L1LC1R	0x80	/* L1 Layer Configuration 1 */
+#define LTDC_L1LC2R	0x84	/* L1 Layer Configuration 2 */
+#define LTDC_L1CR	0x84	/* L1 Control */
+#define LTDC_L1WHPCR	0x88	/* L1 Window Hor Position Config */
+#define LTDC_L1WVPCR	0x8C	/* L1 Window Vert Position Config */
+#define LTDC_L1CKCR	0x90	/* L1 Color Keying Configuration */
+#define LTDC_L1PFCR	0x94	/* L1 Pixel Format Configuration */
+#define LTDC_L1CACR	0x98	/* L1 Constant Alpha Config */
+#define LTDC_L1DCCR	0x9C	/* L1 Default Color Configuration */
+#define LTDC_L1BFCR	0xA0	/* L1 Blend Factors Configuration */
+#define LTDC_L1FBBCR	0xA4	/* L1 FrameBuffer Bus Control */
+#define LTDC_L1AFBCR	0xA8	/* L1 AuxFB Control */
+#define LTDC_L1CFBAR	0xAC	/* L1 Color FrameBuffer Address */
+#define LTDC_L1CFBLR	0xB0	/* L1 Color FrameBuffer Length */
+#define LTDC_L1CFBLNR	0xB4	/* L1 Color FrameBuffer Line Nb */
+#define LTDC_L1AFBAR	0xB8	/* L1 AuxFB Address */
+#define LTDC_L1AFBLR	0xBC	/* L1 AuxFB Length */
+#define LTDC_L1AFBLNR	0xC0	/* L1 AuxFB Line Number */
+#define LTDC_L1CLUTWR	0xC4	/* L1 CLUT Write */
+
+/* Bit definitions */
+#define SSCR_VSH	GENMASK(10, 0)	/* Vertical Synchronization Height */
+#define SSCR_HSW	GENMASK(27, 16)	/* Horizontal Synchronization Width */
+
+#define BPCR_AVBP	GENMASK(10, 0)	/* Accumulated Vertical Back Porch */
+#define BPCR_AHBP	GENMASK(27, 16)	/* Accumulated Horizontal Back Porch */
+
+#define AWCR_AAH	GENMASK(10, 0)	/* Accumulated Active Height */
+#define AWCR_AAW	GENMASK(27, 16)	/* Accumulated Active Width */
+
+#define TWCR_TOTALH	GENMASK(10, 0)	/* TOTAL Height */
+#define TWCR_TOTALW	GENMASK(27, 16)	/* TOTAL Width */
+
+#define GCR_LTDCEN	BIT(0)		/* LTDC ENable */
+#define GCR_DEN		BIT(16)		/* Dither ENable */
+#define GCR_PCPOL	BIT(28)		/* Pixel Clock POLarity-Inverted */
+#define GCR_DEPOL	BIT(29)		/* Data Enable POLarity-High */
+#define GCR_VSPOL	BIT(30)		/* Vertical Synchro POLarity-High */
+#define GCR_HSPOL	BIT(31)		/* Horizontal Synchro POLarity-High */
+
+#define GC1R_WBCH	GENMASK(3, 0)	/* Width of Blue CHannel output */
+#define GC1R_WGCH	GENMASK(7, 4)	/* Width of Green Channel output */
+#define GC1R_WRCH	GENMASK(11, 8)	/* Width of Red Channel output */
+#define GC1R_PBEN	BIT(12)		/* Precise Blending ENable */
+#define GC1R_DT		GENMASK(15, 14)	/* Dithering Technique */
+#define GC1R_GCT	GENMASK(19, 17)	/* Gamma Correction Technique */
+#define GC1R_SHREN	BIT(21)		/* SHadow Registers ENabled */
+#define GC1R_BCP	BIT(22)		/* Background Colour Programmable */
+#define GC1R_BBEN	BIT(23)		/* Background Blending ENabled */
+#define GC1R_LNIP	BIT(24)		/* Line Number IRQ Position */
+#define GC1R_TP		BIT(25)		/* Timing Programmable */
+#define GC1R_IPP	BIT(26)		/* IRQ Polarity Programmable */
+#define GC1R_SPP	BIT(27)		/* Sync Polarity Programmable */
+#define GC1R_DWP	BIT(28)		/* Dither Width Programmable */
+#define GC1R_STREN	BIT(29)		/* STatus Registers ENabled */
+#define GC1R_BMEN	BIT(31)		/* Blind Mode ENabled */
+
+#define GC2R_EDCA	BIT(0)		/* External Display Control Ability  */
+#define GC2R_STSAEN	BIT(1)		/* Slave Timing Sync Ability ENabled */
+#define GC2R_DVAEN	BIT(2)		/* Dual-View Ability ENabled */
+#define GC2R_DPAEN	BIT(3)		/* Dual-Port Ability ENabled */
+#define GC2R_BW		GENMASK(6, 4)	/* Bus Width (log2 of nb of bytes) */
+#define GC2R_EDCEN	BIT(7)		/* External Display Control ENabled */
+
+#define SRCR_IMR	BIT(0)		/* IMmediate Reload */
+#define SRCR_VBR	BIT(1)		/* Vertical Blanking Reload */
+
+#define LXCR_LEN	BIT(0)		/* Layer ENable */
+#define LXCR_COLKEN	BIT(1)		/* Color Keying Enable */
+#define LXCR_CLUTEN	BIT(4)		/* Color Look-Up Table ENable */
+
+#define LXWHPCR_WHSTPOS	GENMASK(11, 0)	/* Window Horizontal StarT POSition */
+#define LXWHPCR_WHSPPOS	GENMASK(27, 16)	/* Window Horizontal StoP POSition */
+
+#define LXWVPCR_WVSTPOS	GENMASK(10, 0)	/* Window Vertical StarT POSition */
+#define LXWVPCR_WVSPPOS	GENMASK(26, 16)	/* Window Vertical StoP POSition */
+
+#define LXPFCR_PF	GENMASK(2, 0)	/* Pixel Format */
+
+#define LXCACR_CONSTA	GENMASK(7, 0)	/* CONSTant Alpha */
+
+#define LXBFCR_BF2	GENMASK(2, 0)	/* Blending Factor 2 */
+#define LXBFCR_BF1	GENMASK(10, 8)	/* Blending Factor 1 */
+
+#define LXCFBLR_CFBLL	GENMASK(12, 0)	/* Color Frame Buffer Line Length */
+#define LXCFBLR_CFBP	GENMASK(28, 16)	/* Color Frame Buffer Pitch in bytes */
+
+#define LXCFBLNR_CFBLN	GENMASK(10, 0)	/* Color Frame Buffer Line Number */
+
+#define BF1_PAXCA	0x600		/* Pixel Alpha x Constant Alpha */
+#define BF1_CA		0x400		/* Constant Alpha */
+#define BF2_1PAXCA	0x007		/* 1 - (Pixel Alpha x Constant Alpha) */
+#define BF2_1CA		0x005		/* 1 - Constant Alpha */
+
+enum stm32_ltdc_pixfmt {
+	PF_ARGB8888 = 0,
+	PF_RGB888,
+	PF_RGB565,
+	PF_ARGB1555,
+	PF_ARGB4444,
+	PF_L8,
+	PF_AL44,
+	PF_AL88
+};
+
+#endif
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 31 00:03:02 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 09:03:02 +0100
Subject: [PATCH 4/4] video: add Ilitek ILI9341 panel support
In-Reply-To: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
References: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
Message-ID: <20220131080302.1873443-5-a.fatoum@pengutronix.de>

Port the Linux v5.15 DRM panel driver to barebox. This has been tested
against a STM32F4 LTDC.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/video/Makefile               |   1 +
 drivers/video/panel-ilitek-ili9341.c | 541 +++++++++++++++++++++++++++
 2 files changed, 542 insertions(+)
 create mode 100644 drivers/video/panel-ilitek-ili9341.c

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a7b70d82072a..9ec0420ccad1 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DRIVER_VIDEO_MTL017) += mtl017.o
 obj-$(CONFIG_DRIVER_VIDEO_TC358767) += tc358767.o
 obj-$(CONFIG_DRIVER_VIDEO_SIMPLE_PANEL) += simple-panel.o
 obj-$(CONFIG_DRIVER_VIDEO_MIPI_DBI) += mipi_dbi.o
+obj-$(CONFIG_DRIVER_VIDEO_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
 
 obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
 obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
diff --git a/drivers/video/panel-ilitek-ili9341.c b/drivers/video/panel-ilitek-ili9341.c
new file mode 100644
index 000000000000..d8774420226d
--- /dev/null
+++ b/drivers/video/panel-ilitek-ili9341.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ilitek ILI9341 TFT LCD driver.
+ *
+ * This panel can be configured to support:
+ * - 16-bit parallel RGB interface
+ * - 18-bit parallel RGB interface
+ * - 4-line serial spi interface
+ *
+ * Copyright 2018 David Lechner <david at lechnology.com>
+ * Copyright (C) 2021 Dillon Min <dillon.minfei at gmail.com>
+ *
+ * Derived from Linux drivers/drm/gpu/panel/panel-ilitek-ili9341.c
+ */
+#define DEBUG 1
+#include <common.h>
+#include <linux/bitops.h>
+#include <gpiod.h>
+#include <of.h>
+#include <regulator.h>
+#include <spi/spi.h>
+#include <video/vpl.h>
+#include <video/mipi_dbi.h>
+
+#include <video/mipi_display.h>
+
+#define ILI9341_RGB_INTERFACE  0xb0   /* RGB Interface Signal Control */
+#define ILI9341_FRC            0xb1   /* Frame Rate Control register */
+#define ILI9341_DFC            0xb6   /* Display Function Control register */
+#define ILI9341_POWER1         0xc0   /* Power Control 1 register */
+#define ILI9341_POWER2         0xc1   /* Power Control 2 register */
+#define ILI9341_VCOM1          0xc5   /* VCOM Control 1 register */
+#define ILI9341_VCOM2          0xc7   /* VCOM Control 2 register */
+#define ILI9341_POWERA         0xcb   /* Power control A register */
+#define ILI9341_POWERB         0xcf   /* Power control B register */
+#define ILI9341_PGAMMA         0xe0   /* Positive Gamma Correction register */
+#define ILI9341_NGAMMA         0xe1   /* Negative Gamma Correction register */
+#define ILI9341_DTCA           0xe8   /* Driver timing control A */
+#define ILI9341_DTCB           0xea   /* Driver timing control B */
+#define ILI9341_POWER_SEQ      0xed   /* Power on sequence register */
+#define ILI9341_3GAMMA_EN      0xf2   /* 3 Gamma enable register */
+#define ILI9341_INTERFACE      0xf6   /* Interface control register */
+#define ILI9341_PRC            0xf7   /* Pump ratio control register */
+#define ILI9341_ETMOD	       0xb7   /* Entry mode set */
+
+#define ILI9341_MADCTL_BGR	BIT(3)
+#define ILI9341_MADCTL_MV	BIT(5)
+#define ILI9341_MADCTL_MX	BIT(6)
+#define ILI9341_MADCTL_MY	BIT(7)
+
+#define ILI9341_POWER_B_LEN	3
+#define ILI9341_POWER_SEQ_LEN	4
+#define ILI9341_DTCA_LEN	3
+#define ILI9341_DTCB_LEN	2
+#define ILI9341_POWER_A_LEN	5
+#define ILI9341_DFC_1_LEN	2
+#define ILI9341_FRC_LEN		2
+#define ILI9341_VCOM_1_LEN	2
+#define ILI9341_DFC_2_LEN	4
+#define ILI9341_COLUMN_ADDR_LEN	4
+#define ILI9341_PAGE_ADDR_LEN	4
+#define ILI9341_INTERFACE_LEN	3
+#define ILI9341_PGAMMA_LEN	15
+#define ILI9341_NGAMMA_LEN	15
+#define ILI9341_CA_LEN		3
+
+#define ILI9341_PIXEL_DPI_16_BITS	(BIT(6) | BIT(4))
+#define ILI9341_PIXEL_DPI_18_BITS	(BIT(6) | BIT(5))
+#define ILI9341_GAMMA_CURVE_1		BIT(0)
+#define ILI9341_IF_WE_MODE		BIT(0)
+#define ILI9341_IF_BIG_ENDIAN		0x00
+#define ILI9341_IF_DM_RGB		BIT(2)
+#define ILI9341_IF_DM_INTERNAL		0x00
+#define ILI9341_IF_DM_VSYNC		BIT(3)
+#define ILI9341_IF_RM_RGB		BIT(1)
+#define ILI9341_IF_RIM_RGB		0x00
+
+#define ILI9341_COLUMN_ADDR		0x00ef
+#define ILI9341_PAGE_ADDR		0x013f
+
+#define ILI9341_RGB_EPL			BIT(0)
+#define ILI9341_RGB_DPL			BIT(1)
+#define ILI9341_RGB_HSPL		BIT(2)
+#define ILI9341_RGB_VSPL		BIT(3)
+#define ILI9341_RGB_DE_MODE		BIT(6)
+#define ILI9341_RGB_DISP_PATH_MEM	BIT(7)
+
+#define ILI9341_DBI_VCOMH_4P6V		0x23
+#define ILI9341_DBI_PWR_2_DEFAULT	0x10
+#define ILI9341_DBI_PRC_NORMAL		0x20
+#define ILI9341_DBI_VCOM_1_VMH_4P25V	0x3e
+#define ILI9341_DBI_VCOM_1_VML_1P5V	0x28
+#define ILI9341_DBI_VCOM_2_DEC_58	0x86
+#define ILI9341_DBI_FRC_DIVA		0x00
+#define ILI9341_DBI_FRC_RTNA		0x1b
+#define ILI9341_DBI_EMS_GAS		BIT(0)
+#define ILI9341_DBI_EMS_DTS		BIT(1)
+#define ILI9341_DBI_EMS_GON		BIT(2)
+
+/* struct ili9341_config - the system specific ILI9341 configuration */
+struct ili9341_config {
+	u32 max_spi_speed;
+	/* mode: the display mode */
+	const struct fb_videomode mode;
+	/* ca: TODO: need comments for this register */
+	u8 ca[ILI9341_CA_LEN];
+	/* power_b: TODO: need comments for this register */
+	u8 power_b[ILI9341_POWER_B_LEN];
+	/* power_seq: TODO: need comments for this register */
+	u8 power_seq[ILI9341_POWER_SEQ_LEN];
+	/* dtca: TODO: need comments for this register */
+	u8 dtca[ILI9341_DTCA_LEN];
+	/* dtcb: TODO: need comments for this register */
+	u8 dtcb[ILI9341_DTCB_LEN];
+	/* power_a: TODO: need comments for this register */
+	u8 power_a[ILI9341_POWER_A_LEN];
+	/* frc: Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
+	u8 frc[ILI9341_FRC_LEN];
+	/* prc: TODO: need comments for this register */
+	u8 prc;
+	/* dfc_1: B6h DISCTRL (Display Function Control) */
+	u8 dfc_1[ILI9341_DFC_1_LEN];
+	/* power_1: Power Control 1 (C0h) */
+	u8 power_1;
+	/* power_2: Power Control 2 (C1h) */
+	u8 power_2;
+	/* vcom_1: VCOM Control 1(C5h) */
+	u8 vcom_1[ILI9341_VCOM_1_LEN];
+	/* vcom_2: VCOM Control 2(C7h) */
+	u8 vcom_2;
+	/* address_mode: Memory Access Control (36h) */
+	u8 address_mode;
+	/* g3amma_en: TODO: need comments for this register */
+	u8 g3amma_en;
+	/* rgb_interface: RGB Interface Signal Control (B0h) */
+	u8 rgb_interface;
+	/* dfc_2: refer to dfc_1 */
+	u8 dfc_2[ILI9341_DFC_2_LEN];
+	/* column_addr: Column Address Set (2Ah) */
+	u8 column_addr[ILI9341_COLUMN_ADDR_LEN];
+	/* page_addr: Page Address Set (2Bh) */
+	u8 page_addr[ILI9341_PAGE_ADDR_LEN];
+	/* interface: Interface Control (F6h) */
+	u8 interface[ILI9341_INTERFACE_LEN];
+	/*
+	 * pixel_format: This command sets the pixel format for the RGB
+	 * image data used by
+	 */
+	u8 pixel_format;
+	/*
+	 * gamma_curve: This command is used to select the desired Gamma
+	 * curve for the
+	 */
+	u8 gamma_curve;
+	/* pgamma: Positive Gamma Correction (E0h) */
+	u8 pgamma[ILI9341_PGAMMA_LEN];
+	/* ngamma: Negative Gamma Correction (E1h) */
+	u8 ngamma[ILI9341_NGAMMA_LEN];
+};
+
+struct ili9341 {
+	struct device_d *dev;
+	struct vpl vpl;
+	const struct ili9341_config *conf;
+	int reset_gpio;
+	int dc_gpio;
+	struct mipi_dbi *dbi;
+	u32 max_spi_speed;
+	struct regulator_bulk_data supplies[3];
+};
+
+/*
+ * The Stm32f429-disco board has a panel ili9341 connected to ltdc controller
+ */
+static const struct ili9341_config ili9341_stm32f429_disco_data = {
+	.max_spi_speed = 10000000,
+	.mode = {
+		.name = "240x320",
+		.xres = 240,
+		.yres = 320,
+		.pixclock = KHZ2PICOS(6100),
+		.left_margin = 10,
+		.hsync_len = 10,
+		.right_margin = 20,
+		.upper_margin = 4,
+		.lower_margin = 2,
+		.vsync_len = 2,
+	},
+	.ca = {0xc3, 0x08, 0x50},
+	.power_b = {0x00, 0xc1, 0x30},
+	.power_seq = {0x64, 0x03, 0x12, 0x81},
+	.dtca = {0x85, 0x00, 0x78},
+	.power_a = {0x39, 0x2c, 0x00, 0x34, 0x02},
+	.prc = 0x20,
+	.dtcb = {0x00, 0x00},
+	/* 0x00 fosc, 0x1b 70hz */
+	.frc = {0x00, 0x1b},
+	/*
+	 * 0x0a Interval scan, AGND AGND AGND AGND
+	 * 0xa2 Normally white, G1 -> G320, S720 -> S1,
+	 *	Scan Cycle 5 frames,85ms
+	 */
+	.dfc_1 = {0x0a, 0xa2},
+	/* 0x10 3.65v */
+	.power_1 = 0x10,
+	/* 0x10 AVDD=vci*2, VGH=vci*7, VGL=-vci*4 */
+	.power_2 = 0x10,
+	/* 0x45 VCOMH 4.425v, 0x15 VCOML -1.975*/
+	.vcom_1 = {0x45, 0x15},
+	/* 0x90 offset voltage, VMH-48, VML-48 */
+	.vcom_2 = 0x90,
+	/*
+	 * 0xc8 Row Address Order, Column Address Order
+	 * BGR 1
+	 */
+	.address_mode = 0xc8,
+	.g3amma_en = 0x00,
+	/*
+	 * 0xc2
+	 * Display Data Path: Memory
+	 * RGB: DE mode
+	 * DOTCLK polarity set (data fetched at the falling time)
+	 */
+	.rgb_interface = ILI9341_RGB_DISP_PATH_MEM |
+			ILI9341_RGB_DE_MODE |
+			ILI9341_RGB_DPL,
+	/*
+	 * 0x0a
+	 * Gate outputs in non-display area: Interval scan
+	 * Determine source/VCOM output in a non-display area in the partial
+	 * display mode: AGND AGND AGND AGND
+	 *
+	 * 0xa7
+	 * Scan Cycle: 15 frames
+	 * fFLM = 60Hz: 255ms
+	 * Liquid crystal type: Normally white
+	 * Gate Output Scan Direction: G1 -> G320
+	 * Source Output Scan Direction: S720 -> S1
+	 *
+	 * 0x27
+	 * LCD Driver Line: 320 lines
+	 *
+	 * 0x04
+	 * PCDIV: 4
+	 */
+	.dfc_2 = {0x0a, 0xa7, 0x27, 0x04},
+	/* column address: 240 */
+	.column_addr = {0x00, 0x00, (ILI9341_COLUMN_ADDR >> 4) & 0xff,
+				ILI9341_COLUMN_ADDR & 0xff},
+	/* page address: 320 */
+	.page_addr = {0x00, 0x00, (ILI9341_PAGE_ADDR >> 4) & 0xff,
+				ILI9341_PAGE_ADDR & 0xff},
+	/*
+	 * Memory write control: When the transfer number of data exceeds
+	 * (EC-SC+1)*(EP-SP+1), the column and page number will be
+	 * reset, and the exceeding data will be written into the following
+	 * column and page.
+	 * Display Operation Mode: RGB Interface Mode
+	 * Interface for RAM Access: RGB interface
+	 * 16- bit RGB interface (1 transfer/pixel)
+	 */
+	.interface = {ILI9341_IF_WE_MODE, 0x00,
+			ILI9341_IF_DM_RGB | ILI9341_IF_RM_RGB},
+	/* DPI: 16 bits / pixel */
+	.pixel_format = ILI9341_PIXEL_DPI_16_BITS,
+	/* Curve Selected: Gamma curve 1 (G2.2) */
+	.gamma_curve = ILI9341_GAMMA_CURVE_1,
+	.pgamma = {0x0f, 0x29, 0x24, 0x0c, 0x0e,
+			0x09, 0x4e, 0x78, 0x3c, 0x09,
+			0x13, 0x05, 0x17, 0x11, 0x00},
+	.ngamma = {0x00, 0x16, 0x1b, 0x04, 0x11,
+			0x07, 0x31, 0x33, 0x42, 0x05,
+			0x0c, 0x0a, 0x28, 0x2f, 0x0f},
+};
+
+static inline struct ili9341 *vpl_to_ili9341(struct vpl *vpl)
+{
+	return container_of(vpl, struct ili9341, vpl);
+}
+
+static void ili9341_dpi_init(struct ili9341 *ili)
+{
+	struct device_d *dev = ili->dev;
+	struct mipi_dbi *dbi = ili->dbi;
+	struct ili9341_config *cfg = (struct ili9341_config *)ili->conf;
+
+	/* Power Control */
+	mipi_dbi_command_stackbuf(dbi, 0xca, cfg->ca, ILI9341_CA_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_POWERB, cfg->power_b,
+				  ILI9341_POWER_B_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_POWER_SEQ, cfg->power_seq,
+				  ILI9341_POWER_SEQ_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_DTCA, cfg->dtca,
+				  ILI9341_DTCA_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_POWERA, cfg->power_a,
+				  ILI9341_POWER_A_LEN);
+	mipi_dbi_command(ili->dbi, ILI9341_PRC, cfg->prc);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_DTCB, cfg->dtcb,
+				  ILI9341_DTCB_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_FRC, cfg->frc, ILI9341_FRC_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_1,
+				  ILI9341_DFC_1_LEN);
+	mipi_dbi_command(dbi, ILI9341_POWER1, cfg->power_1);
+	mipi_dbi_command(dbi, ILI9341_POWER2, cfg->power_2);
+
+	/* VCOM */
+	mipi_dbi_command_stackbuf(dbi, ILI9341_VCOM1, cfg->vcom_1,
+				  ILI9341_VCOM_1_LEN);
+	mipi_dbi_command(dbi, ILI9341_VCOM2, cfg->vcom_2);
+	mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, cfg->address_mode);
+
+	/* Gamma */
+	mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, cfg->g3amma_en);
+	mipi_dbi_command(dbi, ILI9341_RGB_INTERFACE, cfg->rgb_interface);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_2,
+				  ILI9341_DFC_2_LEN);
+
+	/* Colomn address set */
+	mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_COLUMN_ADDRESS,
+				  cfg->column_addr, ILI9341_COLUMN_ADDR_LEN);
+
+	/* Page address set */
+	mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_PAGE_ADDRESS,
+				  cfg->page_addr, ILI9341_PAGE_ADDR_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_INTERFACE, cfg->interface,
+				  ILI9341_INTERFACE_LEN);
+
+	/* Format */
+	mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, cfg->pixel_format);
+	mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
+	mdelay(200);
+	mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, cfg->gamma_curve);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_PGAMMA, cfg->pgamma,
+				  ILI9341_PGAMMA_LEN);
+	mipi_dbi_command_stackbuf(dbi, ILI9341_NGAMMA, cfg->ngamma,
+				  ILI9341_NGAMMA_LEN);
+	mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
+	mdelay(200);
+	mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
+	mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
+
+	dev_info(dev, "Initialized display rgb interface\n");
+}
+
+static int ili9341_dpi_power_on(struct ili9341 *ili)
+{
+	struct device_d *dev = ili->dev;
+	int ret = 0;
+
+	/* Assert RESET */
+	gpiod_set_value(ili->reset_gpio, 1);
+
+	/* Enable power */
+	ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies),
+				    ili->supplies);
+	if (ret < 0) {
+		dev_err(dev, "unable to enable vcc\n");
+		return ret;
+	}
+	mdelay(20);
+
+	/* De-assert RESET */
+	gpiod_set_value(ili->reset_gpio, 0);
+	mdelay(20);
+
+	return 0;
+}
+
+static int ili9341_dpi_power_off(struct ili9341 *ili)
+{
+	/* Assert RESET */
+	gpiod_set_value(ili->reset_gpio, 1);
+
+	/* Disable power */
+	return regulator_bulk_disable(ARRAY_SIZE(ili->supplies),
+				      ili->supplies);
+}
+
+static void ili9341_dpi_disable(struct ili9341 *ili)
+{
+	mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_OFF);
+}
+
+static int ili9341_dpi_prepare(struct ili9341 *ili)
+{
+	int ret;
+
+	ret = ili9341_dpi_power_on(ili);
+	if (ret < 0)
+		return ret;
+
+	ili9341_dpi_init(ili);
+
+	return ret;
+}
+
+static void ili9341_dpi_enable(struct ili9341 *ili)
+{
+	mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_ON);
+}
+
+static int ili9341_dpi_get_modes(struct ili9341 *ili,
+				 struct display_timings *timings)
+{
+	struct fb_videomode *mode;
+
+	mode = memdup(&ili->conf->mode, sizeof(*mode));
+	if (!mode)
+		return -ENOMEM;
+
+	/*
+	 * These are from the PoV of the display controller, so
+	 * DPL=1 => display samples at positive edge
+	 *       => controller drives at negative edge
+	 */
+	if (ili->conf->rgb_interface & ILI9341_RGB_DPL)
+		mode->display_flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+	else
+		mode->display_flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+
+	if (ili->conf->rgb_interface & ILI9341_RGB_EPL)
+		mode->display_flags |= DISPLAY_FLAGS_DE_HIGH;
+	else
+		mode->display_flags |= DISPLAY_FLAGS_DE_LOW;
+
+	/* Set up the polarity */
+	if (ili->conf->rgb_interface & ILI9341_RGB_HSPL)
+		mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+	if (ili->conf->rgb_interface & ILI9341_RGB_VSPL)
+		mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	timings->modes = mode;
+	timings->num_modes = 1;
+	return 0;
+}
+
+static int ili9341_ioctl(struct vpl *vpl, unsigned int port,
+			unsigned int cmd, void *ptr)
+{
+	struct ili9341 *ili = vpl_to_ili9341(vpl);
+
+	switch (cmd) {
+	case VPL_PREPARE:
+		return ili9341_dpi_prepare(ili);
+	case VPL_ENABLE:
+		ili9341_dpi_enable(ili);
+		return 0;
+	case VPL_DISABLE:
+		ili9341_dpi_disable(ili);
+		return 0;
+	case VPL_UNPREPARE:
+		return ili9341_dpi_power_off(ili);
+	case VPL_GET_VIDEOMODES:
+		return ili9341_dpi_get_modes(ili, ptr);
+	default:
+		return 0;
+	}
+}
+
+static int ili9341_dpi_probe(struct spi_device *spi, int dc, int reset)
+{
+	struct device_d *dev = &spi->dev;
+	struct ili9341 *ili;
+	int ret;
+
+	ili = kzalloc(sizeof(struct ili9341), GFP_KERNEL);
+	if (!ili)
+		return -ENOMEM;
+
+	ili->dbi = kzalloc(sizeof(struct mipi_dbi), GFP_KERNEL);
+	if (!ili->dbi)
+		return -ENOMEM;
+
+	ili->supplies[0].supply = "vci";
+	ili->supplies[1].supply = "vddi";
+	ili->supplies[2].supply = "vddi-led";
+	ret = regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
+				 ili->supplies);
+	if (ret < 0) {
+		dev_err(dev, "failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
+	ret = mipi_dbi_spi_init(spi, ili->dbi, dc);
+	if (ret)
+		return ret;
+
+	ili->reset_gpio = reset;
+	/*
+	 * Every new incarnation of this display must have a unique
+	 * data entry for the system in this driver.
+	 */
+	ili->conf = device_get_match_data(dev);
+	if (!ili->conf) {
+		dev_err(dev, "missing device configuration\n");
+		return -ENODEV;
+	}
+
+	ili->dev = dev;
+	ili->max_spi_speed = ili->conf->max_spi_speed;
+	ili->vpl.node = dev->device_node;
+	ili->vpl.ioctl = ili9341_ioctl;
+
+	return vpl_register(&ili->vpl);
+}
+
+static int ili9341_probe(struct device_d *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	int dc, reset;
+
+	reset = gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+	if (!gpio_is_valid(reset) && reset != -ENOENT)
+		dev_err(dev, "Failed to get gpio 'reset'\n");
+
+	dc = gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+	if (!gpio_is_valid(dc) && dc != -ENOENT)
+		dev_err(dev, "Failed to get gpio 'dc'\n");
+
+	return ili9341_dpi_probe(spi, dc, reset);
+}
+
+static const struct of_device_id ili9341_of_match[] = {
+	{
+		.compatible = "st,sf-tc240t-9370-t",
+		.data = &ili9341_stm32f429_disco_data,
+	},
+	{ }
+};
+
+static struct driver_d ili9341_driver = {
+	.name = "panel-ilitek-ili9341",
+	.of_compatible = ili9341_of_match,
+	.probe = ili9341_probe,
+};
+device_spi_driver(ili9341_driver);
+
+MODULE_AUTHOR("Dillon Min <dillon.minfei at gmail.com>");
+MODULE_DESCRIPTION("ILI9341 LCD panel driver");
+MODULE_LICENSE("GPL v2");
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 31 00:03:01 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 09:03:01 +0100
Subject: [PATCH 3/4] video: add MIPI DBI Type C Option 3 support
In-Reply-To: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
References: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
Message-ID: <20220131080302.1873443-4-a.fatoum@pengutronix.de>

Import the Linux v5.15 state of the driver to allow easy porting of
MIPI-DBI displays like the Ilitek 9431 added in a follow-up commit.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/Kconfig             |  19 ++
 commands/Makefile            |   1 +
 commands/mipi_dbi.c          | 104 ++++++++
 drivers/video/Kconfig        |  14 ++
 drivers/video/Makefile       |   1 +
 drivers/video/mipi_dbi.c     | 467 +++++++++++++++++++++++++++++++++++
 include/spi/spi.h            |  20 ++
 include/video/mipi_dbi.h     | 105 ++++++++
 include/video/mipi_display.h | 150 +++++++++++
 9 files changed, 881 insertions(+)
 create mode 100644 commands/mipi_dbi.c
 create mode 100644 drivers/video/mipi_dbi.c
 create mode 100644 include/video/mipi_dbi.h
 create mode 100644 include/video/mipi_display.h

diff --git a/commands/Kconfig b/commands/Kconfig
index ba8ca5cdebce..2e13a4ed90bd 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1969,6 +1969,25 @@ config CMD_SPI
 		  -w BIT	bits per word (default 8)
 		  -v		verbose
 
+config CMD_MIPI_DBI
+	bool
+	depends on DRIVER_VIDEO_MIPI_DBI && SPI
+	select PRINTF_HEXSTR
+	prompt "mipi_dbi command"
+	help
+	  Write/read from MIPI DBI device on SPI bus
+
+	  Usage: mipi_dbi [-brcmfwv] DATA...
+
+	  Options:
+		  -b BUS	SPI bus number (default 0)
+		  -r COUNT	bytes to read
+		  -c		chip select (default 0)
+		  -m MODE	SPI mode (default 0)
+		  -f HZ		max speed frequency, in Hz (default 1 MHz)
+		  -w BIT	bits per word (default 8)
+		  -v		verbose
+
 config CMD_LED_TRIGGER
 	bool
 	depends on LED_TRIGGERS
diff --git a/commands/Makefile b/commands/Makefile
index db78d0b877f6..fffb6d979e82 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_CMD_GPIO)		+= gpio.o
 obj-$(CONFIG_CMD_UNCOMPRESS)	+= uncompress.o
 obj-$(CONFIG_CMD_I2C)		+= i2c.o
 obj-$(CONFIG_CMD_SPI)		+= spi.o
+obj-$(CONFIG_CMD_MIPI_DBI)	+= mipi_dbi.o
 obj-$(CONFIG_CMD_UBI)		+= ubi.o
 obj-$(CONFIG_CMD_UBIFORMAT)	+= ubiformat.o
 obj-$(CONFIG_CMD_MENU)		+= menu.o
diff --git a/commands/mipi_dbi.c b/commands/mipi_dbi.c
new file mode 100644
index 000000000000..b9b665b72151
--- /dev/null
+++ b/commands/mipi_dbi.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: ? 2022 Ahmad Fatoum
+
+#include <common.h>
+#include <command.h>
+#include <getopt.h>
+#include <video/mipi_dbi.h>
+#include <video/mipi_display.h>
+
+static int mipi_dbi_command_show(struct mipi_dbi *dbi, int cmd)
+{
+	u8 val[4];
+	int ret;
+	size_t len;
+
+	if (!mipi_dbi_command_is_read(dbi, cmd))
+		return -EACCES;
+
+	len = mipi_dbi_command_read_len(cmd);
+
+	printf("%02x: ", cmd);
+	ret = mipi_dbi_command_buf(dbi, cmd, val, len);
+	if (ret) {
+		printf("XX\n");
+		return ret;
+	}
+	printf("%*phN\n", (int)len, val);
+
+	return 0;
+}
+
+static int do_mipi_dbi(int argc, char *argv[])
+{
+	struct mipi_dbi *dbi;
+	int opt, ret, i;
+	bool write = false;
+	u8 cmd, val[4];
+
+	dbi = list_first_entry_or_null(&mipi_dbi_list, struct mipi_dbi, list);
+
+	while ((opt = getopt(argc, argv, "wld:")) > 0) {
+		struct mipi_dbi *tmp;
+
+		switch (opt) {
+		case 'w':
+			write = true;
+			break;
+		case 'l':
+			list_for_each_entry(tmp, &mipi_dbi_list, list)
+				printf("%s\n", mipi_dbi_name(tmp));
+			return 0;
+		case 'd':
+			dbi = NULL;
+			list_for_each_entry(tmp, &mipi_dbi_list, list) {
+				if (!strcmp(optarg, mipi_dbi_name(tmp))) {
+					dbi = tmp;
+					break;
+				}
+			}
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	if (!dbi)
+		return -ENODEV;
+
+	if (optind == argc) {
+		for (cmd = 0; cmd < 255; cmd++)
+			mipi_dbi_command_show(dbi, cmd);
+		return 0;
+	}
+
+	ret = kstrtou8(argv[optind++], 16, &cmd);
+	if (ret < 0)
+		return ret;
+
+	if (optind == argc && !write)
+		return mipi_dbi_command_show(dbi, cmd);
+
+	for (i = optind; i < argc; i++) {
+		ret = kstrtou8(argv[optind + i], 16, &val[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return mipi_dbi_command_buf(dbi, cmd, val, argc - optind);
+}
+
+BAREBOX_CMD_HELP_START(mipi_dbi)
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-l\t",  "list all MIPI DBI devices")
+BAREBOX_CMD_HELP_OPT ("-d DEVICE",  "select specific device (default is first registered)")
+BAREBOX_CMD_HELP_OPT ("-w",  "issue write command")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(mipi_dbi)
+	.cmd		= do_mipi_dbi,
+	BAREBOX_CMD_DESC("write/read from MIPI DBI SPI device")
+	BAREBOX_CMD_OPTS("[-wld] [REG] [DATA...]")
+	BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
+	BAREBOX_CMD_HELP(cmd_mipi_dbi_help)
+BAREBOX_CMD_END
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1b8672fdea82..dcdc6c213591 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -129,6 +129,9 @@ config DRIVER_VIDEO_EDID
 	  This enabled support for reading and parsing EDID data from an attached
 	  monitor.
 
+config DRIVER_VIDEO_MIPI_DBI
+	bool
+
 config DRIVER_VIDEO_BACKLIGHT
 	bool "Add backlight support"
 	help
@@ -178,4 +181,15 @@ config DRIVER_VIDEO_SIMPLE_PANEL
 	  Linux Kernel implementation this one is able to understand display-timings
 	  nodes so that it's not necessary to keep a list of all known displays
 	  with their corresponding timings in barebox.
+
+config DRIVER_VIDEO_PANEL_ILITEK_ILI9341
+	tristate "Ilitek ILI9341 240x320 QVGA panels"
+	depends on OFTREE && SPI
+	select DRIVER_VIDEO_MIPI_DBI
+	select VIDEO_VPL
+	help
+	  Say Y here if you want to enable support for Ilitek IL9341
+	  QVGA (240x320) RGB panels. support serial & parallel rgb
+	  interface.
+
 endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 7f4429278987..a7b70d82072a 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_VIDEO_VPL) += vpl.o
 obj-$(CONFIG_DRIVER_VIDEO_MTL017) += mtl017.o
 obj-$(CONFIG_DRIVER_VIDEO_TC358767) += tc358767.o
 obj-$(CONFIG_DRIVER_VIDEO_SIMPLE_PANEL) += simple-panel.o
+obj-$(CONFIG_DRIVER_VIDEO_MIPI_DBI) += mipi_dbi.o
 
 obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
 obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
diff --git a/drivers/video/mipi_dbi.c b/drivers/video/mipi_dbi.c
new file mode 100644
index 000000000000..48b1110f72ab
--- /dev/null
+++ b/drivers/video/mipi_dbi.c
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MIPI Display Bus Interface (DBI) LCD controller support
+ *
+ * Copyright 2016 Noralf Tr?nnes
+ */
+
+#define pr_fmt(fmt) "mipi-dbi: " fmt
+
+#include <common.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <gpiod.h>
+#include <regulator.h>
+#include <spi/spi.h>
+#include <video/mipi_dbi.h>
+
+#include <video/vpl.h>
+#include <video/mipi_display.h>
+#include <video/fourcc.h>
+
+#define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */
+
+#define DCS_POWER_MODE_DISPLAY			BIT(2)
+#define DCS_POWER_MODE_DISPLAY_NORMAL_MODE	BIT(3)
+#define DCS_POWER_MODE_SLEEP_MODE		BIT(4)
+#define DCS_POWER_MODE_PARTIAL_MODE		BIT(5)
+#define DCS_POWER_MODE_IDLE_MODE		BIT(6)
+#define DCS_POWER_MODE_RESERVED_MASK		(BIT(0) | BIT(1) | BIT(7))
+
+LIST_HEAD(mipi_dbi_list);
+EXPORT_SYMBOL(mipi_dbi_list);
+
+/**
+ * DOC: overview
+ *
+ * This library provides helpers for MIPI Display Bus Interface (DBI)
+ * compatible display controllers.
+ *
+ * Many controllers for tiny lcd displays are MIPI compliant and can use this
+ * library. If a controller uses registers 0x2A and 0x2B to set the area to
+ * update and uses register 0x2C to write to frame memory, it is most likely
+ * MIPI compliant.
+ *
+ * Only MIPI Type 1 displays are supported since a full frame memory is needed.
+ *
+ * There are 3 MIPI DBI implementation types:
+ *
+ * A. Motorola 6800 type parallel bus
+ *
+ * B. Intel 8080 type parallel bus
+ *
+ * C. SPI type with 3 options:
+ *
+ *    1. 9-bit with the Data/Command signal as the ninth bit
+ *    2. Same as above except it's sent as 16 bits
+ *    3. 8-bit with the Data/Command signal as a separate D/CX pin
+ *
+ * Currently barebox mipi_dbi only supports Type C option 3 with
+ * mipi_dbi_spi_init().
+ */
+
+#define MIPI_DBI_DEBUG_COMMAND(cmd, data, len) \
+({ \
+	if (!len) \
+		pr_debug("cmd=%02x\n", cmd); \
+	else if (len <= 32) \
+		pr_debug("cmd=%02x, par=%*ph\n", cmd, (int)len, data);\
+	else \
+		pr_debug("cmd=%02x, len=%zu\n", cmd, len); \
+})
+
+static const u8 mipi_dbi_dcs_read_commands[] = {
+	MIPI_DCS_GET_DISPLAY_ID,
+	MIPI_DCS_GET_RED_CHANNEL,
+	MIPI_DCS_GET_GREEN_CHANNEL,
+	MIPI_DCS_GET_BLUE_CHANNEL,
+	MIPI_DCS_GET_DISPLAY_STATUS,
+	MIPI_DCS_GET_POWER_MODE,
+	MIPI_DCS_GET_ADDRESS_MODE,
+	MIPI_DCS_GET_PIXEL_FORMAT,
+	MIPI_DCS_GET_DISPLAY_MODE,
+	MIPI_DCS_GET_SIGNAL_MODE,
+	MIPI_DCS_GET_DIAGNOSTIC_RESULT,
+	MIPI_DCS_READ_MEMORY_START,
+	MIPI_DCS_READ_MEMORY_CONTINUE,
+	MIPI_DCS_GET_SCANLINE,
+	MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
+	MIPI_DCS_GET_CONTROL_DISPLAY,
+	MIPI_DCS_GET_POWER_SAVE,
+	MIPI_DCS_GET_CABC_MIN_BRIGHTNESS,
+	MIPI_DCS_READ_DDB_START,
+	MIPI_DCS_READ_DDB_CONTINUE,
+	0, /* sentinel */
+};
+
+bool mipi_dbi_command_is_read(struct mipi_dbi *dbi, u8 cmd)
+{
+	unsigned int i;
+
+	if (!dbi->read_commands)
+		return false;
+
+	for (i = 0; i < 0xff; i++) {
+		if (!dbi->read_commands[i])
+			return false;
+		if (cmd == dbi->read_commands[i])
+			return true;
+	}
+
+	return false;
+}
+
+int mipi_dbi_command_read_len(int cmd)
+{
+	switch (cmd) {
+	case MIPI_DCS_READ_MEMORY_START:
+	case MIPI_DCS_READ_MEMORY_CONTINUE:
+		return 2;
+	case MIPI_DCS_GET_DISPLAY_ID:
+		return 3;
+	case MIPI_DCS_GET_DISPLAY_STATUS:
+		return 4;
+	default:
+		return 1;
+	}
+}
+
+/**
+ * mipi_dbi_command_read - MIPI DCS read command
+ * @dbi: MIPI DBI structure
+ * @cmd: Command
+ * @val: Value read
+ *
+ * Send MIPI DCS read command to the controller.
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_command_read(struct mipi_dbi *dbi, u8 cmd, u8 *val)
+{
+	if (!dbi->read_commands)
+		return -EACCES;
+
+	if (!mipi_dbi_command_is_read(dbi, cmd))
+		return -EINVAL;
+
+	return mipi_dbi_command_buf(dbi, cmd, val, 1);
+}
+EXPORT_SYMBOL(mipi_dbi_command_read);
+
+/**
+ * mipi_dbi_command_buf - MIPI DCS command with parameter(s) in an array
+ * @dbi: MIPI DBI structure
+ * @cmd: Command
+ * @data: Parameter buffer
+ * @len: Buffer length
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len)
+{
+	u8 *cmdbuf;
+	int ret;
+
+	/* SPI requires dma-safe buffers */
+	cmdbuf = kmemdup(&cmd, 1, GFP_KERNEL);
+	if (!cmdbuf)
+		return -ENOMEM;
+
+	ret = dbi->command(dbi, cmdbuf, data, len);
+
+	kfree(cmdbuf);
+
+	return ret;
+}
+EXPORT_SYMBOL(mipi_dbi_command_buf);
+
+/* This should only be used by mipi_dbi_command() */
+int mipi_dbi_command_stackbuf(struct mipi_dbi *dbi, u8 cmd, const u8 *data,
+			      size_t len)
+{
+	u8 *buf;
+	int ret;
+
+	buf = kmemdup(data, len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = mipi_dbi_command_buf(dbi, cmd, buf, len);
+
+	kfree(buf);
+
+	return ret;
+}
+EXPORT_SYMBOL(mipi_dbi_command_stackbuf);
+
+/**
+ * mipi_dbi_hw_reset - Hardware reset of controller
+ * @dbi: MIPI DBI structure
+ *
+ * Reset controller if the &mipi_dbi->reset gpio is set.
+ */
+void mipi_dbi_hw_reset(struct mipi_dbi *dbi)
+{
+	if (!gpio_is_valid(dbi->reset))
+		return;
+
+	gpiod_set_value(dbi->reset, 0);
+	udelay(20);
+	gpiod_set_value(dbi->reset, 1);
+	mdelay(120);
+}
+EXPORT_SYMBOL(mipi_dbi_hw_reset);
+
+/**
+ * mipi_dbi_display_is_on - Check if display is on
+ * @dbi: MIPI DBI structure
+ *
+ * This function checks the Power Mode register (if readable) to see if
+ * display output is turned on. This can be used to see if the bootloader
+ * has already turned on the display avoiding flicker when the pipeline is
+ * enabled.
+ *
+ * Returns:
+ * true if the display can be verified to be on, false otherwise.
+ */
+bool mipi_dbi_display_is_on(struct mipi_dbi *dbi)
+{
+	u8 val;
+
+	if (mipi_dbi_command_read(dbi, MIPI_DCS_GET_POWER_MODE, &val))
+		return false;
+
+	val &= ~DCS_POWER_MODE_RESERVED_MASK;
+
+	/* The poweron/reset value is 08h DCS_POWER_MODE_DISPLAY_NORMAL_MODE */
+	if (val != (DCS_POWER_MODE_DISPLAY |
+	    DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE))
+		return false;
+
+	pr_debug("Display is ON\n");
+
+	return true;
+}
+EXPORT_SYMBOL(mipi_dbi_display_is_on);
+
+#if IS_ENABLED(CONFIG_SPI)
+
+/**
+ * mipi_dbi_spi_cmd_max_speed - get the maximum SPI bus speed
+ * @spi: SPI device
+ * @len: The transfer buffer length.
+ *
+ * Many controllers have a max speed of 10MHz, but can be pushed way beyond
+ * that. Increase reliability by running pixel data at max speed and the rest
+ * at 10MHz, preventing transfer glitches from messing up the init settings.
+ */
+u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len)
+{
+	if (len > 64)
+		return 0; /* use default */
+
+	return min_t(u32, 10000000, spi->max_speed_hz);
+}
+EXPORT_SYMBOL(mipi_dbi_spi_cmd_max_speed);
+
+static bool mipi_dbi_machine_little_endian(void)
+{
+#if defined(__LITTLE_ENDIAN)
+	return true;
+#else
+	return false;
+#endif
+}
+
+/* MIPI DBI Type C Option 3 */
+
+static int mipi_dbi_typec3_command_read(struct mipi_dbi *dbi, u8 *cmd,
+					u8 *data, size_t len)
+{
+	struct spi_device *spi = dbi->spi;
+	u32 speed_hz = min_t(u32, MIPI_DBI_MAX_SPI_READ_SPEED,
+			     spi->max_speed_hz / 2);
+	struct spi_transfer tr[2] = {
+		{
+			.speed_hz = speed_hz,
+			.tx_buf = cmd,
+			.len = 1,
+		}, {
+			.speed_hz = speed_hz,
+			.len = len,
+		},
+	};
+	struct spi_message m;
+	u8 *buf;
+	int ret;
+
+	if (!len)
+		return -EINVAL;
+
+	/*
+	 * Support non-standard 24-bit and 32-bit Nokia read commands which
+	 * start with a dummy clock, so we need to read an extra byte.
+	 */
+	if (*cmd == MIPI_DCS_GET_DISPLAY_ID ||
+	    *cmd == MIPI_DCS_GET_DISPLAY_STATUS) {
+		if (!(len == 3 || len == 4))
+			return -EINVAL;
+
+		tr[1].len = len + 1;
+	}
+
+	buf = kmalloc(tr[1].len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	tr[1].rx_buf = buf;
+	gpiod_set_value(dbi->dc, 0);
+
+	spi_message_init_with_transfers(&m, tr, ARRAY_SIZE(tr));
+	ret = spi_sync(spi, &m);
+	if (ret)
+		goto err_free;
+
+	if (tr[1].len == len) {
+		memcpy(data, buf, len);
+	} else {
+		unsigned int i;
+
+		for (i = 0; i < len; i++)
+			data[i] = (buf[i] << 1) | (buf[i + 1] >> 7);
+	}
+
+	MIPI_DBI_DEBUG_COMMAND(*cmd, data, len);
+
+err_free:
+	kfree(buf);
+
+	return ret;
+}
+
+static int mipi_dbi_typec3_command(struct mipi_dbi *dbi, u8 *cmd,
+				   u8 *par, size_t num)
+{
+	struct spi_device *spi = dbi->spi;
+	unsigned int bpw = 8;
+	u32 speed_hz;
+	int ret;
+
+	if (mipi_dbi_command_is_read(dbi, *cmd))
+		return mipi_dbi_typec3_command_read(dbi, cmd, par, num);
+
+	MIPI_DBI_DEBUG_COMMAND(*cmd, par, num);
+
+	gpiod_set_value(dbi->dc, 0);
+	speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1);
+	ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, cmd, 1);
+	if (ret || !num)
+		return ret;
+
+	if (*cmd == MIPI_DCS_WRITE_MEMORY_START && !dbi->swap_bytes)
+		bpw = 16;
+
+	gpiod_set_value(dbi->dc, 1);
+	speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
+
+	return mipi_dbi_spi_transfer(spi, speed_hz, bpw, par, num);
+}
+
+/**
+ * mipi_dbi_spi_init - Initialize MIPI DBI SPI interface
+ * @spi: SPI device
+ * @dbi: MIPI DBI structure to initialize
+ * @dc: D/C gpio
+ *
+ * This function sets &mipi_dbi->command, enables &mipi_dbi->read_commands for the
+ * usual read commands. It should be followed by a call to mipi_dbi_dev_init() or
+ * a driver-specific init.
+ *
+ * Type C Option 3 interface is assumed, Type C Option 1 is not yet supported,
+ * because barebox has no generic way yet to require a 9-bit SPI transfer
+ *
+ * If the SPI master driver doesn't support the necessary bits per word,
+ * the following transformation is used:
+ *
+ * - 9-bit: reorder buffer as 9x 8-bit words, padded with no-op command.
+ * - 16-bit: if big endian send as 8-bit, if little endian swap bytes
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi,
+		      int dc)
+{
+	struct device_d *dev = &spi->dev;
+
+	dbi->spi = spi;
+	dbi->read_commands = mipi_dbi_dcs_read_commands;
+
+	if (!gpio_is_valid(dc)) {
+		dev_dbg(dev, "MIPI DBI Type-C 1 unsupported\n");
+		return -ENOSYS;
+	}
+
+	dbi->command = mipi_dbi_typec3_command;
+	dbi->dc = dc;
+	// TODO: can we just force 16 bit?
+	if (mipi_dbi_machine_little_endian() && spi->bits_per_word != 16)
+		dbi->swap_bytes = true;
+
+	dev_dbg(dev, "SPI speed: %uMHz\n", spi->max_speed_hz / 1000000);
+
+	list_add(&dbi->list, &mipi_dbi_list);
+	return 0;
+}
+EXPORT_SYMBOL(mipi_dbi_spi_init);
+
+/**
+ * mipi_dbi_spi_transfer - SPI transfer helper
+ * @spi: SPI device
+ * @speed_hz: Override speed (optional)
+ * @bpw: Bits per word
+ * @buf: Buffer to transfer
+ * @len: Buffer length
+ *
+ * This SPI transfer helper breaks up the transfer of @buf into chunks which
+ * the SPI controller driver can handle.
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_spi_transfer(struct spi_device *spi, u32 speed_hz,
+			  u8 bpw, const void *buf, size_t len)
+{
+	size_t max_chunk = spi_max_transfer_size(spi);
+	struct spi_transfer tr = {
+		.bits_per_word = bpw,
+		.speed_hz = speed_hz,
+	};
+	struct spi_message m;
+	size_t chunk;
+	int ret;
+
+	spi_message_init_with_transfers(&m, &tr, 1);
+
+	while (len) {
+		chunk = min(len, max_chunk);
+
+		tr.tx_buf = buf;
+		tr.len = chunk;
+		buf += chunk;
+		len -= chunk;
+
+		ret = spi_sync(spi, &m);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(mipi_dbi_spi_transfer);
+
+#endif /* CONFIG_SPI */
+
+MODULE_LICENSE("GPL");
diff --git a/include/spi/spi.h b/include/spi/spi.h
index c5ad6bd39ff9..d133e0e21265 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -409,6 +409,26 @@ spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
 	list_add_tail(&t->transfer_list, &m->transfers);
 }
 
+/**
+ * spi_message_init_with_transfers - Initialize spi_message and append transfers
+ * @m: spi_message to be initialized
+ * @xfers: An array of spi transfers
+ * @num_xfers: Number of items in the xfer array
+ *
+ * This function initializes the given spi_message and adds each spi_transfer in
+ * the given array to the message.
+ */
+static inline void
+spi_message_init_with_transfers(struct spi_message *m,
+struct spi_transfer *xfers, unsigned int num_xfers)
+{
+	unsigned int i;
+
+	spi_message_init(m);
+	for (i = 0; i < num_xfers; ++i)
+		spi_message_add_tail(&xfers[i], m);
+}
+
 static inline void
 spi_transfer_del(struct spi_transfer *t)
 {
diff --git a/include/video/mipi_dbi.h b/include/video/mipi_dbi.h
new file mode 100644
index 000000000000..92fdc500d1ba
--- /dev/null
+++ b/include/video/mipi_dbi.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * MIPI Display Bus Interface (DBI) LCD controller support
+ *
+ * Copyright 2016 Noralf Tr?nnes
+ */
+
+#ifndef __LINUX_MIPI_DBI_H
+#define __LINUX_MIPI_DBI_H
+
+#include <linux/types.h>
+#include <spi/spi.h>
+#include <driver.h>
+
+struct regulator;
+struct fb_videomode;
+
+/**
+ * struct mipi_dbi - MIPI DBI interface
+ */
+struct mipi_dbi {
+	/**
+	 * @command: Bus specific callback executing commands.
+	 */
+	int (*command)(struct mipi_dbi *dbi, u8 *cmd, u8 *param, size_t num);
+
+	/**
+	 * @read_commands: Array of read commands terminated by a zero entry.
+	 *                 Reading is disabled if this is NULL.
+	 */
+	const u8 *read_commands;
+
+	/**
+	 * @swap_bytes: Swap bytes in buffer before transfer
+	 */
+	bool swap_bytes;
+
+	/**
+	 * @reset: Optional reset gpio
+	 */
+	int reset;
+
+	/* Type C specific */
+
+	/**
+	 * @spi: SPI device
+	 */
+	struct spi_device *spi;
+
+	/**
+	 * @dc: Optional D/C gpio.
+	 */
+	int dc;
+
+	struct list_head list;
+};
+
+static inline const char *mipi_dbi_name(struct mipi_dbi *dbi)
+{
+	return dev_name(&dbi->spi->dev);
+}
+
+int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi,
+		      int dc);
+void mipi_dbi_hw_reset(struct mipi_dbi *dbi);
+bool mipi_dbi_display_is_on(struct mipi_dbi *dbi);
+
+u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len);
+int mipi_dbi_spi_transfer(struct spi_device *spi, u32 speed_hz,
+			  u8 bpw, const void *buf, size_t len);
+
+int mipi_dbi_command_read(struct mipi_dbi *dbi, u8 cmd, u8 *val);
+int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len);
+int mipi_dbi_command_stackbuf(struct mipi_dbi *dbi, u8 cmd, const u8 *data,
+			      size_t len);
+
+/**
+ * mipi_dbi_command - MIPI DCS command with optional parameter(s)
+ * @dbi: MIPI DBI structure
+ * @cmd: Command
+ * @seq: Optional parameter(s)
+ *
+ * Send MIPI DCS command to the controller. Use mipi_dbi_command_read() for
+ * get/read.
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+#define mipi_dbi_command(dbi, cmd, seq...) \
+({ \
+	const u8 d[] = { seq }; \
+	struct device_d *dev = &(dbi)->spi->dev;	\
+	int ret; \
+	ret = mipi_dbi_command_stackbuf(dbi, cmd, d, ARRAY_SIZE(d)); \
+	if (ret) \
+		dev_err(dev, "error %pe when sending command %#02x\n", ERR_PTR(ret), cmd); \
+	ret; \
+})
+
+bool mipi_dbi_command_is_read(struct mipi_dbi *dbi, u8 cmd);
+int mipi_dbi_command_read_len(int cmd);
+
+extern struct list_head mipi_dbi_list;
+
+#endif /* __LINUX_MIPI_DBI_H */
diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h
new file mode 100644
index 000000000000..b6d8b874233f
--- /dev/null
+++ b/include/video/mipi_display.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Defines for Mobile Industry Processor Interface (MIPI(R))
+ * Display Working Group standards: DSI, DCS, DBI, DPI
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski at gmx.de>
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak at nokia.com>
+ */
+#ifndef MIPI_DISPLAY_H
+#define MIPI_DISPLAY_H
+
+/* MIPI DSI Processor-to-Peripheral transaction types */
+enum {
+	MIPI_DSI_V_SYNC_START				= 0x01,
+	MIPI_DSI_V_SYNC_END				= 0x11,
+	MIPI_DSI_H_SYNC_START				= 0x21,
+	MIPI_DSI_H_SYNC_END				= 0x31,
+
+	MIPI_DSI_COMPRESSION_MODE			= 0x07,
+	MIPI_DSI_END_OF_TRANSMISSION			= 0x08,
+
+	MIPI_DSI_COLOR_MODE_OFF				= 0x02,
+	MIPI_DSI_COLOR_MODE_ON				= 0x12,
+	MIPI_DSI_SHUTDOWN_PERIPHERAL			= 0x22,
+	MIPI_DSI_TURN_ON_PERIPHERAL			= 0x32,
+
+	MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM		= 0x03,
+	MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM		= 0x13,
+	MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM		= 0x23,
+
+	MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM		= 0x04,
+	MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM		= 0x14,
+	MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM		= 0x24,
+
+	MIPI_DSI_DCS_SHORT_WRITE			= 0x05,
+	MIPI_DSI_DCS_SHORT_WRITE_PARAM			= 0x15,
+
+	MIPI_DSI_DCS_READ				= 0x06,
+	MIPI_DSI_EXECUTE_QUEUE				= 0x16,
+
+	MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE		= 0x37,
+
+	MIPI_DSI_NULL_PACKET				= 0x09,
+	MIPI_DSI_BLANKING_PACKET			= 0x19,
+	MIPI_DSI_GENERIC_LONG_WRITE			= 0x29,
+	MIPI_DSI_DCS_LONG_WRITE				= 0x39,
+
+	MIPI_DSI_PICTURE_PARAMETER_SET			= 0x0a,
+	MIPI_DSI_COMPRESSED_PIXEL_STREAM		= 0x0b,
+
+	MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20	= 0x0c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24		= 0x1c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16		= 0x2c,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_30			= 0x0d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_36			= 0x1d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12		= 0x3d,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_16			= 0x0e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_18			= 0x1e,
+	MIPI_DSI_PIXEL_STREAM_3BYTE_18			= 0x2e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_24			= 0x3e,
+};
+
+/* MIPI DSI Peripheral-to-Processor transaction types */
+enum {
+	MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT	= 0x02,
+	MIPI_DSI_RX_END_OF_TRANSMISSION			= 0x08,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE	= 0x11,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE	= 0x12,
+	MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE		= 0x1a,
+	MIPI_DSI_RX_DCS_LONG_READ_RESPONSE		= 0x1c,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE	= 0x21,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE	= 0x22,
+};
+
+/* MIPI DCS commands */
+enum {
+	MIPI_DCS_NOP			= 0x00,
+	MIPI_DCS_SOFT_RESET		= 0x01,
+	MIPI_DCS_GET_COMPRESSION_MODE	= 0x03,
+	MIPI_DCS_GET_DISPLAY_ID		= 0x04,
+	MIPI_DCS_GET_ERROR_COUNT_ON_DSI	= 0x05,
+	MIPI_DCS_GET_RED_CHANNEL	= 0x06,
+	MIPI_DCS_GET_GREEN_CHANNEL	= 0x07,
+	MIPI_DCS_GET_BLUE_CHANNEL	= 0x08,
+	MIPI_DCS_GET_DISPLAY_STATUS	= 0x09,
+	MIPI_DCS_GET_POWER_MODE		= 0x0A,
+	MIPI_DCS_GET_ADDRESS_MODE	= 0x0B,
+	MIPI_DCS_GET_PIXEL_FORMAT	= 0x0C,
+	MIPI_DCS_GET_DISPLAY_MODE	= 0x0D,
+	MIPI_DCS_GET_SIGNAL_MODE	= 0x0E,
+	MIPI_DCS_GET_DIAGNOSTIC_RESULT	= 0x0F,
+	MIPI_DCS_ENTER_SLEEP_MODE	= 0x10,
+	MIPI_DCS_EXIT_SLEEP_MODE	= 0x11,
+	MIPI_DCS_ENTER_PARTIAL_MODE	= 0x12,
+	MIPI_DCS_ENTER_NORMAL_MODE	= 0x13,
+	MIPI_DCS_GET_IMAGE_CHECKSUM_RGB	= 0x14,
+	MIPI_DCS_GET_IMAGE_CHECKSUM_CT	= 0x15,
+	MIPI_DCS_EXIT_INVERT_MODE	= 0x20,
+	MIPI_DCS_ENTER_INVERT_MODE	= 0x21,
+	MIPI_DCS_SET_GAMMA_CURVE	= 0x26,
+	MIPI_DCS_SET_DISPLAY_OFF	= 0x28,
+	MIPI_DCS_SET_DISPLAY_ON		= 0x29,
+	MIPI_DCS_SET_COLUMN_ADDRESS	= 0x2A,
+	MIPI_DCS_SET_PAGE_ADDRESS	= 0x2B,
+	MIPI_DCS_WRITE_MEMORY_START	= 0x2C,
+	MIPI_DCS_WRITE_LUT		= 0x2D,
+	MIPI_DCS_READ_MEMORY_START	= 0x2E,
+	MIPI_DCS_SET_PARTIAL_ROWS	= 0x30,		/* MIPI DCS 1.02 - MIPI_DCS_SET_PARTIAL_AREA before that */
+	MIPI_DCS_SET_PARTIAL_COLUMNS	= 0x31,
+	MIPI_DCS_SET_SCROLL_AREA	= 0x33,
+	MIPI_DCS_SET_TEAR_OFF		= 0x34,
+	MIPI_DCS_SET_TEAR_ON		= 0x35,
+	MIPI_DCS_SET_ADDRESS_MODE	= 0x36,
+	MIPI_DCS_SET_SCROLL_START	= 0x37,
+	MIPI_DCS_EXIT_IDLE_MODE		= 0x38,
+	MIPI_DCS_ENTER_IDLE_MODE	= 0x39,
+	MIPI_DCS_SET_PIXEL_FORMAT	= 0x3A,
+	MIPI_DCS_WRITE_MEMORY_CONTINUE	= 0x3C,
+	MIPI_DCS_SET_3D_CONTROL		= 0x3D,
+	MIPI_DCS_READ_MEMORY_CONTINUE	= 0x3E,
+	MIPI_DCS_GET_3D_CONTROL		= 0x3F,
+	MIPI_DCS_SET_VSYNC_TIMING	= 0x40,
+	MIPI_DCS_SET_TEAR_SCANLINE	= 0x44,
+	MIPI_DCS_GET_SCANLINE		= 0x45,
+	MIPI_DCS_SET_DISPLAY_BRIGHTNESS = 0x51,		/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_DISPLAY_BRIGHTNESS = 0x52,		/* MIPI DCS 1.3 */
+	MIPI_DCS_WRITE_CONTROL_DISPLAY  = 0x53,		/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_CONTROL_DISPLAY	= 0x54,		/* MIPI DCS 1.3 */
+	MIPI_DCS_WRITE_POWER_SAVE	= 0x55,		/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_POWER_SAVE		= 0x56,		/* MIPI DCS 1.3 */
+	MIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 0x5E,	/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 0x5F,	/* MIPI DCS 1.3 */
+	MIPI_DCS_READ_DDB_START		= 0xA1,
+	MIPI_DCS_READ_PPS_START		= 0xA2,
+	MIPI_DCS_READ_DDB_CONTINUE	= 0xA8,
+	MIPI_DCS_READ_PPS_CONTINUE	= 0xA9,
+};
+
+/* MIPI DCS pixel formats */
+#define MIPI_DCS_PIXEL_FMT_24BIT	7
+#define MIPI_DCS_PIXEL_FMT_18BIT	6
+#define MIPI_DCS_PIXEL_FMT_16BIT	5
+#define MIPI_DCS_PIXEL_FMT_12BIT	3
+#define MIPI_DCS_PIXEL_FMT_8BIT		2
+#define MIPI_DCS_PIXEL_FMT_3BIT		1
+
+#endif
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 31 00:11:45 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 09:11:45 +0100
Subject: [PATCH 1/2] clocksource: add ARMv7-M SysTick driver
Message-ID: <20220131081146.1883859-1-a.fatoum@pengutronix.de>

The SysTick is a simple 24-bit system timer that's required for ARMv7-M
implementations. Add a clocksource driver for it for Cortex-M system
support.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clocksource/Kconfig          |  5 ++
 drivers/clocksource/Makefile         |  1 +
 drivers/clocksource/armv7m_systick.c | 87 ++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
 create mode 100644 drivers/clocksource/armv7m_systick.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index c6ca72d4e927..9fae1f2d352e 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -115,4 +115,9 @@ config CLINT_TIMER
 	  This option enables the CLINT timer for RISC-V systems.  The CLINT
 	  driver is usually used for NoMMU RISC-V systems.
 
+config ARMV7M_SYSTICK
+	bool "Support for the ARMv7M system timer" if COMPILE_TEST
+	help
+	  This option enables support for the ARMv7M system timer unit.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 21fd83a0930b..a4a7b84fae0c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_CLOCKSOURCE_TI_DM) += timer-ti-dm.o
 obj-$(CONFIG_CLOCKSOURCE_TI_32K) += timer-ti-32k.o
 obj-$(CONFIG_CLINT_TIMER) += timer-clint.o
 obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
+obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
new file mode 100644
index 000000000000..5f9222c50b8a
--- /dev/null
+++ b/drivers/clocksource/armv7m_systick.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32 at gmail.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <clock.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#define SYST_CSR	0x00
+#define SYST_RVR	0x04
+#define SYST_CVR	0x08
+#define SYST_CALIB	0x0c
+
+#define SYSTICK_CTRL_EN		BIT(0)
+/* Clock source: 0 = Ref clock, 1 = CPU clock */
+#define SYSTICK_CTRL_CPU_CLK	BIT(2)
+#define SYSTICK_CAL_NOREF	BIT(31)
+
+#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
+
+static __iomem void *systick_base;
+
+static u64 armv7m_systick_clocksource_read(void)
+{
+        return SYSTICK_LOAD_RELOAD_MASK - readl(systick_base + SYST_CVR);
+}
+
+static struct clocksource cs = {
+	.read	= armv7m_systick_clocksource_read,
+	.mask	= CLOCKSOURCE_MASK(24),
+	.shift	= 0,
+};
+
+static int armv7m_systick_probe(struct device_d *dev)
+{
+	struct clk *clk = NULL;
+	u32 rate, cal;
+	int ret;
+
+	systick_base = dev_request_mem_region_err_null(dev, 0);
+	if (!systick_base)
+		return -ENOENT;
+
+	ret = of_property_read_u32(dev->device_node, "clock-frequency", &rate);
+	if (ret) {
+		clk = clk_get(dev, NULL);
+		if (IS_ERR(clk))
+			return PTR_ERR(clk);
+
+		ret = clk_enable(clk);
+		if (ret)
+			return ret;
+
+		rate = clk_get_rate(clk);
+		if (!rate)
+			return -EINVAL;
+	}
+
+	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, systick_base + SYST_RVR);
+
+	cal = readl(&systick_base + SYST_CALIB);
+	if (cal & SYSTICK_CAL_NOREF)
+		writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, systick_base + SYST_CSR);
+	else
+		writel(SYSTICK_CTRL_EN, systick_base + SYST_CSR);
+
+	cs.mult = clocksource_hz2mult(rate, cs.shift);
+
+	return init_clock(&cs);
+}
+
+static struct of_device_id armv7m_systick_dt_ids[] = {
+	{ .compatible = "arm,armv7m-systick", },
+	{ }
+};
+
+static struct driver_d armv7m_systick_driver = {
+	.name = "armv7m-systick-timer",
+	.probe = armv7m_systick_probe,
+	.of_compatible = DRV_OF_COMPAT(armv7m_systick_dt_ids),
+};
+postcore_platform_driver(armv7m_systick_driver);
-- 
2.30.2



From a.fatoum at pengutronix.de  Mon Jan 31 00:11:46 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 09:11:46 +0100
Subject: [PATCH 2/2] clocksource: add STM32 Timer driver
In-Reply-To: <20220131081146.1883859-1-a.fatoum@pengutronix.de>
References: <20220131081146.1883859-1-a.fatoum@pengutronix.de>
Message-ID: <20220131081146.1883859-2-a.fatoum@pengutronix.de>

The STM32 timer is 32-bit and thus takes longer to wrap around than the
24-bit SysTick timer. Add a driver for it at a higher priority.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/clocksource/Kconfig       |   4 +
 drivers/clocksource/Makefile      |   1 +
 drivers/clocksource/timer-stm32.c | 122 ++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 9fae1f2d352e..e1bff23320de 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -120,4 +120,8 @@ config ARMV7M_SYSTICK
 	help
 	  This option enables support for the ARMv7M system timer unit.
 
+config CLKSRC_STM32
+	bool "Clocksource for STM32 SoCs"
+	depends on OFDEVICE && (ARCH_STM32 || COMPILE_TEST)
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index a4a7b84fae0c..eceaa990d43d 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_CLOCKSOURCE_TI_32K) += timer-ti-32k.o
 obj-$(CONFIG_CLINT_TIMER) += timer-clint.o
 obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
 obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o
+obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
new file mode 100644
index 000000000000..dec48fccf5a2
--- /dev/null
+++ b/drivers/clocksource/timer-stm32.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Author(s): Patrice Chotard, <patrice.chotard at foss.st.com> for STMicroelectronics.
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <clock.h>
+#include <init.h>
+#include <io.h>
+
+/* Timer control1 register  */
+#define CR1_CEN			BIT(0)
+#define CR1_ARPE		BIT(7)
+
+/* Event Generation Register register  */
+#define EGR_UG			BIT(0)
+
+/* Auto reload register for free running config */
+#define GPT_FREE_RUNNING	0xFFFFFFFF
+
+#define MHZ_1			1000000
+
+struct stm32_timer_regs {
+	u32 cr1;
+	u32 cr2;
+	u32 smcr;
+	u32 dier;
+	u32 sr;
+	u32 egr;
+	u32 ccmr1;
+	u32 ccmr2;
+	u32 ccer;
+	u32 cnt;
+	u32 psc;
+	u32 arr;
+	u32 reserved;
+	u32 ccr1;
+	u32 ccr2;
+	u32 ccr3;
+	u32 ccr4;
+	u32 reserved1;
+	u32 dcr;
+	u32 dmar;
+	u32 tim2_5_or;
+};
+
+static struct stm32_timer_regs *timer_base;
+
+static u64 stm32_timer_read(void)
+{
+	return readl(&timer_base->cnt);
+}
+
+/* A bit obvious isn't it? */
+static struct clocksource cs = {
+	.read = stm32_timer_read,
+	.mask	= CLOCKSOURCE_MASK(32),
+	.shift = 0,
+	.priority = 100,
+};
+
+static int stm32_timer_probe(struct device_d *dev)
+{
+	struct resource *iores;
+	struct clk *clk;
+	u32 rate, psc;
+	int ret;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	timer_base = IOMEM(iores->start);
+
+	clk = clk_get(dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	ret = clk_enable(clk);
+	if (ret)
+		return ret;
+
+	/* Stop the timer */
+	clrbits_le32(&timer_base->cr1, CR1_CEN);
+
+	/* get timer clock */
+	rate = clk_get_rate(clk);
+
+	/* we set timer prescaler to obtain a 1MHz timer counter frequency */
+	psc = (rate / MHZ_1) - 1;
+	writel(psc, &timer_base->psc);
+
+	/* Configure timer for auto-reload */
+	setbits_le32(&timer_base->cr1, CR1_ARPE);
+
+	/* load value for auto reload */
+	writel(GPT_FREE_RUNNING, &timer_base->arr);
+
+	/* start timer */
+	setbits_le32(&timer_base->cr1, CR1_CEN);
+
+	/* Update generation */
+	setbits_le32(&timer_base->egr, EGR_UG);
+
+	cs.mult = clocksource_hz2mult(MHZ_1, cs.shift);
+
+	return init_clock(&cs);
+}
+
+static struct of_device_id stm32_timer_dt_ids[] = {
+	{ .compatible = "st,stm32-timer" },
+	{ /* sentinel */ }
+};
+
+static struct driver_d stm32_timer_driver = {
+	.name = "stm32-timer",
+	.probe = stm32_timer_probe,
+	.of_compatible = stm32_timer_dt_ids,
+};
+postcore_platform_driver(stm32_timer_driver);
-- 
2.30.2



From sha at pengutronix.de  Mon Jan 31 01:23:58 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 10:23:58 +0100
Subject: [PATCH] scripts/common: fix write_file when opened with mmap
In-Reply-To: <20220128080033.167251-1-andrej.picej@norik.com>
References: <20220128080033.167251-1-andrej.picej@norik.com>
Message-ID: <20220131092358.GX23490@pengutronix.de>

Hi Andrej,

On Fri, Jan 28, 2022 at 09:00:33AM +0100, Andrej Picej wrote:
> Usage of bareboximd with -c option (Create checksum for FILE and write
> it to the crc32 tag) was broken. Possibly by applying 2154de1cf36c
> (bareboximd: Use mmap when possibly). The script fails with:
> 
>     $ ./scripts/bareboximd -c images/<barebox-image.img>
>     Cannot write to images/<barebox-mage.img>: Bad address
>     CRC: write crc token to images/<barebox-image.img> failed: -14
>     Bad address
> 
> This has to do with the usage of "mmap" and "open" with O_TRUNC flag
> which truncates the file length to 0. Writing to files fails with:
> EFAULT (14) buf is outside your accessible address space.
> Remove the truncate flag and truncate manually after writing the data.
> 
> This fixes the bareboximd script, which is now again usable with -c
> option.

That's a very unfortunate bug :(

> 
> Signed-off-by: Anze Lesnik <anze.lesnik at norik.com>
> Signed-off-by: Andrej Picej <andrej.picej at norik.com>
> ---
>  scripts/common.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/scripts/common.c b/scripts/common.c
> index 3f8dcd2d38..331988d593 100644
> --- a/scripts/common.c
> +++ b/scripts/common.c
> @@ -107,7 +107,7 @@ int write_file(const char *filename, const void *buf, size_t size)
>  	int fd, ret = 0;
>  	int now;
>  
> -	fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT,

I added a comment above this while applying to prevent people from
"optimizing" this patch away.

> +	fd = open(filename, O_WRONLY | O_CREAT,
>  		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
>  	if (fd < 0) {
>  		fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
> @@ -126,6 +126,11 @@ int write_file(const char *filename, const void *buf, size_t size)
>  		buf += now;
>  	}
>  
> +	if (ftruncate(fd, now) < 0) {
> +		fprintf(stderr, "Cannot truncate file: %s", strerror(errno));
> +		ret = -errno;
> +	}

truncating to 'now' is only correct when we were able to write all bytes
at once. Otherwise we must truncate to the input size. I fixed this up
to the patch below.

Sascha

-----------------------------8<----------------------------

>From 738601e1258c55953284ee10801b26b9977918c2 Mon Sep 17 00:00:00 2001
From: Andrej Picej <andrej.picej at norik.com>
Date: Fri, 28 Jan 2022 09:00:33 +0100
Subject: [PATCH] scripts/common: fix write_file when opened with mmap

Usage of bareboximd with -c option (Create checksum for FILE and write
it to the crc32 tag) was broken. Possibly by applying 2154de1cf36c
(bareboximd: Use mmap when possibly). The script fails with:

    $ ./scripts/bareboximd -c images/<barebox-image.img>
    Cannot write to images/<barebox-mage.img>: Bad address
    CRC: write crc token to images/<barebox-image.img> failed: -14
    Bad address

This has to do with the usage of "mmap" and "open" with O_TRUNC flag
which truncates the file length to 0. Writing to files fails with:
EFAULT (14) buf is outside your accessible address space.
Remove the truncate flag and truncate manually after writing the data.

This fixes the bareboximd script, which is now again usable with -c
option.

Signed-off-by: Anze Lesnik <anze.lesnik at norik.com>
Signed-off-by: Andrej Picej <andrej.picej at norik.com>
Link: https://lore.barebox.org/20220128080033.167251-1-andrej.picej at norik.com
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 scripts/common.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/scripts/common.c b/scripts/common.c
index b780b09941..154d6dffcb 100644
--- a/scripts/common.c
+++ b/scripts/common.c
@@ -105,26 +105,33 @@ int write_file(const char *filename, const void *buf, size_t size)
 {
 	int fd, ret = 0;
 	int now;
+	size_t left = size;
 
-	fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT,
+	/* The same file may be mmapped currently, so can't use O_TRUNC here */
+	fd = open(filename, O_WRONLY | O_CREAT,
 		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 	if (fd < 0) {
 		fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
 		return -errno;
 	}
 
-	while (size) {
-		now = write(fd, buf, size);
+	while (left) {
+		now = write(fd, buf, left);
 		if (now < 0) {
 			fprintf(stderr, "Cannot write to %s: %s\n", filename,
 				strerror(errno));
 			ret = -errno;
 			goto out;
 		}
-		size -= now;
+		left -= now;
 		buf += now;
 	}
 
+	if (ftruncate(fd, size) < 0) {
+		fprintf(stderr, "Cannot truncate file: %s", strerror(errno));
+		ret = -errno;
+	}
+
 out:
 	close(fd);
 
-- 
2.30.2

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 31 01:35:10 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 10:35:10 +0100
Subject: [PATCH v2 2/4] ARM: rpi: move clk support to a separate driver
 and enable deep-probe
In-Reply-To: <20220128082317.2410427-3-o.rempel@pengutronix.de>
References: <20220128082317.2410427-1-o.rempel@pengutronix.de>
 <20220128082317.2410427-3-o.rempel@pengutronix.de>
Message-ID: <20220131093510.GY23490@pengutronix.de>

On Fri, Jan 28, 2022 at 09:23:15AM +0100, Oleksij Rempel wrote:
> To make deep-probe work properly, we need clock support be registered as
> driver to related device.
> 
> To avoid regression, deep-probe is enabled in the same patch.

Is this really needed?

> +static int bcm2835_cprman_probe(struct device_d *dev)
> +{
> +	struct device_node *mbox_node;
> +	struct clk *clk_cs;
> +	int ret;
> +
> +	mbox_node = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-mbox");
> +	if (!mbox_node) {
> +		pr_err("Missing mbox node\n");
> +		return -ENOENT;
> +	}
> +
> +	ret = of_device_ensure_probed(mbox_node);
> +	if (ret) {
> +		pr_err("Can't probe mbox node. %i\n", ret);
> +		return ret;
> +	}
> +
> +	clks[BCM2835_CLOCK_EMMC] =
> +		rpi_register_firmware_clock(BCM2835_MBOX_CLOCK_ID_EMMC,
> +					 "bcm2835_mci0");
> +	if (IS_ERR(clks[BCM2835_CLOCK_EMMC]))
> +		return PTR_ERR(clks[BCM2835_CLOCK_EMMC]);
> +
> +	clkdev_add_physbase(clks[BCM2835_CLOCK_EMMC], 0x20300000, NULL);
> +	clkdev_add_physbase(clks[BCM2835_CLOCK_EMMC], 0x3f300000, NULL);

You shouldn't need these calls anymore because the consumers are now
connected to the clock provider by the device tree binding.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Mon Jan 31 01:38:46 2022
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 10:38:46 +0100
Subject: [PATCH] pinctrl: rockchip: drop unused variable 'name'
In-Reply-To: <20220130094956.73266-1-antonynpavlov@gmail.com>
References: <20220130094956.73266-1-antonynpavlov@gmail.com>
Message-ID: <20220131093846.GZ23490@pengutronix.de>

On Sun, Jan 30, 2022 at 12:49:56PM +0300, Antony Pavlov wrote:
> Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
> ---
>  drivers/pinctrl/pinctrl-rockchip.c | 1 -
>  1 file changed, 1 deletion(-)

Applied, thanks

Sascha

> 
> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
> index 869cce1982..c99074407f 100644
> --- a/drivers/pinctrl/pinctrl-rockchip.c
> +++ b/drivers/pinctrl/pinctrl-rockchip.c
> @@ -877,7 +877,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
>  	struct device_node *np;
>  	struct rockchip_pin_ctrl *ctrl;
>  	struct rockchip_pin_bank *bank;
> -	char *name;
>  	int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
>  	int gpio = 0;
>  
> -- 
> 2.33.0
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 31 01:42:07 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 10:42:07 +0100
Subject: [PATCH 1/2] reset: add simple reset controller support
In-Reply-To: <20220131075338.1869305-1-a.fatoum@pengutronix.de>
References: <20220131075338.1869305-1-a.fatoum@pengutronix.de>
Message-ID: <20220131094207.GA23490@pengutronix.de>

On Mon, Jan 31, 2022 at 08:53:37AM +0100, Ahmad Fatoum wrote:
> Incoming STM32 MCU support will leverage this driver, so port it over
> from Linux v5.16.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/reset/Kconfig              |  17 +++
>  drivers/reset/Makefile             |   1 +
>  drivers/reset/reset-simple.c       | 189 +++++++++++++++++++++++++++++
>  include/linux/reset/reset-simple.h |  45 +++++++
>  4 files changed, 252 insertions(+)
>  create mode 100644 drivers/reset/reset-simple.c
>  create mode 100644 include/linux/reset/reset-simple.h

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 31 01:43:36 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 10:43:36 +0100
Subject: [PATCH] include: <asm-generic/bug.h>: implement WARN_ON_ONCE
In-Reply-To: <20220131075350.1869535-1-a.fatoum@pengutronix.de>
References: <20220131075350.1869535-1-a.fatoum@pengutronix.de>
Message-ID: <20220131094336.GB23490@pengutronix.de>

On Mon, Jan 31, 2022 at 08:53:50AM +0100, Ahmad Fatoum wrote:
> We have WARN_ON and WARN_ONCE. Add WARN_ON_ONCE as well to accommodate
> Linux driver code using it.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  include/asm-generic/bug.h | 12 ++++++++++++
>  1 file changed, 12 insertions(+)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 31 02:21:41 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 11:21:41 +0100
Subject: [PATCH 3/4] video: add MIPI DBI Type C Option 3 support
In-Reply-To: <20220131080302.1873443-4-a.fatoum@pengutronix.de>
References: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
 <20220131080302.1873443-4-a.fatoum@pengutronix.de>
Message-ID: <20220131102141.GC23490@pengutronix.de>

On Mon, Jan 31, 2022 at 09:03:01AM +0100, Ahmad Fatoum wrote:
> Import the Linux v5.15 state of the driver to allow easy porting of
> MIPI-DBI displays like the Ilitek 9431 added in a follow-up commit.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  commands/Kconfig             |  19 ++
>  commands/Makefile            |   1 +
>  commands/mipi_dbi.c          | 104 ++++++++
>  drivers/video/Kconfig        |  14 ++
>  drivers/video/Makefile       |   1 +
>  drivers/video/mipi_dbi.c     | 467 +++++++++++++++++++++++++++++++++++
>  include/spi/spi.h            |  20 ++
>  include/video/mipi_dbi.h     | 105 ++++++++
>  include/video/mipi_display.h | 150 +++++++++++
>  9 files changed, 881 insertions(+)
>  create mode 100644 commands/mipi_dbi.c
>  create mode 100644 drivers/video/mipi_dbi.c
>  create mode 100644 include/video/mipi_dbi.h
>  create mode 100644 include/video/mipi_display.h
> 
> diff --git a/commands/Kconfig b/commands/Kconfig
> index ba8ca5cdebce..2e13a4ed90bd 100644
> --- a/commands/Kconfig
> +++ b/commands/Kconfig
> @@ -1969,6 +1969,25 @@ config CMD_SPI
>  		  -w BIT	bits per word (default 8)
>  		  -v		verbose
>  
> +config CMD_MIPI_DBI
> +	bool
> +	depends on DRIVER_VIDEO_MIPI_DBI && SPI
> +	select PRINTF_HEXSTR
> +	prompt "mipi_dbi command"
> +	help
> +	  Write/read from MIPI DBI device on SPI bus
> +
> +	  Usage: mipi_dbi [-brcmfwv] DATA...
> +
> +	  Options:
> +		  -b BUS	SPI bus number (default 0)
> +		  -r COUNT	bytes to read
> +		  -c		chip select (default 0)
> +		  -m MODE	SPI mode (default 0)
> +		  -f HZ		max speed frequency, in Hz (default 1 MHz)
> +		  -w BIT	bits per word (default 8)
> +		  -v		verbose

This doesn't match the actual command. Copy-paste from CMD_SPI above?

> +BAREBOX_CMD_HELP_START(mipi_dbi)
> +BAREBOX_CMD_HELP_TEXT("Options:")
> +BAREBOX_CMD_HELP_OPT ("-l\t",  "list all MIPI DBI devices")
> +BAREBOX_CMD_HELP_OPT ("-d DEVICE",  "select specific device (default is first registered)")
> +BAREBOX_CMD_HELP_OPT ("-w",  "issue write command")
> +BAREBOX_CMD_HELP_END
> +
> +
>  config DRIVER_VIDEO_BACKLIGHT
>  	bool "Add backlight support"
>  	help
> @@ -178,4 +181,15 @@ config DRIVER_VIDEO_SIMPLE_PANEL
>  	  Linux Kernel implementation this one is able to understand display-timings
>  	  nodes so that it's not necessary to keep a list of all known displays
>  	  with their corresponding timings in barebox.
> +
> +config DRIVER_VIDEO_PANEL_ILITEK_ILI9341
> +	tristate "Ilitek ILI9341 240x320 QVGA panels"
> +	depends on OFTREE && SPI
> +	select DRIVER_VIDEO_MIPI_DBI
> +	select VIDEO_VPL
> +	help
> +	  Say Y here if you want to enable support for Ilitek IL9341
> +	  QVGA (240x320) RGB panels. support serial & parallel rgb
> +	  interface.

This hunk should be in 4/4.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 31 02:23:08 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 11:23:08 +0100
Subject: [PATCH 1/2] clocksource: add ARMv7-M SysTick driver
In-Reply-To: <20220131081146.1883859-1-a.fatoum@pengutronix.de>
References: <20220131081146.1883859-1-a.fatoum@pengutronix.de>
Message-ID: <20220131102308.GD23490@pengutronix.de>

On Mon, Jan 31, 2022 at 09:11:45AM +0100, Ahmad Fatoum wrote:
> The SysTick is a simple 24-bit system timer that's required for ARMv7-M
> implementations. Add a clocksource driver for it for Cortex-M system
> support.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/clocksource/Kconfig          |  5 ++
>  drivers/clocksource/Makefile         |  1 +
>  drivers/clocksource/armv7m_systick.c | 87 ++++++++++++++++++++++++++++
>  3 files changed, 93 insertions(+)
>  create mode 100644 drivers/clocksource/armv7m_systick.c

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From andrej.picej at norik.com  Mon Jan 31 02:23:39 2022
From: andrej.picej at norik.com (Andrej Picej)
Date: Mon, 31 Jan 2022 11:23:39 +0100
Subject: [PATCH] scripts/common: fix write_file when opened with mmap
In-Reply-To: <20220131092358.GX23490@pengutronix.de>
References: <20220128080033.167251-1-andrej.picej@norik.com>
 <20220131092358.GX23490@pengutronix.de>
Message-ID: <813ef0f4-d6d4-1ca4-0729-09db490b811e@norik.com>

Hi Sascha,

On 31. 01. 22 10:23, Sascha Hauer wrote:
> Hi Andrej,
> 
> On Fri, Jan 28, 2022 at 09:00:33AM +0100, Andrej Picej wrote:
>> Usage of bareboximd with -c option (Create checksum for FILE and write
>> it to the crc32 tag) was broken. Possibly by applying 2154de1cf36c
>> (bareboximd: Use mmap when possibly). The script fails with:
>>
>>      $ ./scripts/bareboximd -c images/<barebox-image.img>
>>      Cannot write to images/<barebox-mage.img>: Bad address
>>      CRC: write crc token to images/<barebox-image.img> failed: -14
>>      Bad address
>>
>> This has to do with the usage of "mmap" and "open" with O_TRUNC flag
>> which truncates the file length to 0. Writing to files fails with:
>> EFAULT (14) buf is outside your accessible address space.
>> Remove the truncate flag and truncate manually after writing the data.
>>
>> This fixes the bareboximd script, which is now again usable with -c
>> option.
> 
> That's a very unfortunate bug :(
> 
>>
>> Signed-off-by: Anze Lesnik <anze.lesnik at norik.com>
>> Signed-off-by: Andrej Picej <andrej.picej at norik.com>
>> ---
>>   scripts/common.c | 7 ++++++-
>>   1 file changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/scripts/common.c b/scripts/common.c
>> index 3f8dcd2d38..331988d593 100644
>> --- a/scripts/common.c
>> +++ b/scripts/common.c
>> @@ -107,7 +107,7 @@ int write_file(const char *filename, const void *buf, size_t size)
>>   	int fd, ret = 0;
>>   	int now;
>>   
>> -	fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT,
> 
> I added a comment above this while applying to prevent people from
> "optimizing" this patch away.
> 
>> +	fd = open(filename, O_WRONLY | O_CREAT,
>>   		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
>>   	if (fd < 0) {
>>   		fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
>> @@ -126,6 +126,11 @@ int write_file(const char *filename, const void *buf, size_t size)
>>   		buf += now;
>>   	}
>>   
>> +	if (ftruncate(fd, now) < 0) {
>> +		fprintf(stderr, "Cannot truncate file: %s", strerror(errno));
>> +		ret = -errno;
>> +	}
> 
> truncating to 'now' is only correct when we were able to write all bytes
> at once. Otherwise we must truncate to the input size. I fixed this up
> to the patch below.

That makes sense. Good thing you caught that.

Thanks.

> 
> Sascha
> 
> -----------------------------8<----------------------------
> 
>  From 738601e1258c55953284ee10801b26b9977918c2 Mon Sep 17 00:00:00 2001
> From: Andrej Picej <andrej.picej at norik.com>
> Date: Fri, 28 Jan 2022 09:00:33 +0100
> Subject: [PATCH] scripts/common: fix write_file when opened with mmap
> 
> Usage of bareboximd with -c option (Create checksum for FILE and write
> it to the crc32 tag) was broken. Possibly by applying 2154de1cf36c
> (bareboximd: Use mmap when possibly). The script fails with:
> 
>      $ ./scripts/bareboximd -c images/<barebox-image.img>
>      Cannot write to images/<barebox-mage.img>: Bad address
>      CRC: write crc token to images/<barebox-image.img> failed: -14
>      Bad address
> 
> This has to do with the usage of "mmap" and "open" with O_TRUNC flag
> which truncates the file length to 0. Writing to files fails with:
> EFAULT (14) buf is outside your accessible address space.
> Remove the truncate flag and truncate manually after writing the data.
> 
> This fixes the bareboximd script, which is now again usable with -c
> option.
> 
> Signed-off-by: Anze Lesnik <anze.lesnik at norik.com>
> Signed-off-by: Andrej Picej <andrej.picej at norik.com>
> Link: https://lore.barebox.org/20220128080033.167251-1-andrej.picej at norik.com
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
>   scripts/common.c | 15 +++++++++++----
>   1 file changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/scripts/common.c b/scripts/common.c
> index b780b09941..154d6dffcb 100644
> --- a/scripts/common.c
> +++ b/scripts/common.c
> @@ -105,26 +105,33 @@ int write_file(const char *filename, const void *buf, size_t size)
>   {
>   	int fd, ret = 0;
>   	int now;
> +	size_t left = size;
>   
> -	fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT,
> +	/* The same file may be mmapped currently, so can't use O_TRUNC here */
> +	fd = open(filename, O_WRONLY | O_CREAT,
>   		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
>   	if (fd < 0) {
>   		fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
>   		return -errno;
>   	}
>   
> -	while (size) {
> -		now = write(fd, buf, size);
> +	while (left) {
> +		now = write(fd, buf, left);
>   		if (now < 0) {
>   			fprintf(stderr, "Cannot write to %s: %s\n", filename,
>   				strerror(errno));
>   			ret = -errno;
>   			goto out;
>   		}
> -		size -= now;
> +		left -= now;
>   		buf += now;
>   	}
>   
> +	if (ftruncate(fd, size) < 0) {
> +		fprintf(stderr, "Cannot truncate file: %s", strerror(errno));
> +		ret = -errno;
> +	}
> +
>   out:
>   	close(fd);
>   
> 


From a.fatoum at pengutronix.de  Mon Jan 31 02:28:53 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 11:28:53 +0100
Subject: [PATCH 3/4] video: add MIPI DBI Type C Option 3 support
In-Reply-To: <20220131102141.GC23490@pengutronix.de>
References: <20220131080302.1873443-1-a.fatoum@pengutronix.de>
 <20220131080302.1873443-4-a.fatoum@pengutronix.de>
 <20220131102141.GC23490@pengutronix.de>
Message-ID: <bebf48ce-c243-3052-0abb-f58ef246fa82@pengutronix.de>

On 31.01.22 11:21, Sascha Hauer wrote:
> On Mon, Jan 31, 2022 at 09:03:01AM +0100, Ahmad Fatoum wrote:
>> Import the Linux v5.15 state of the driver to allow easy porting of
>> MIPI-DBI displays like the Ilitek 9431 added in a follow-up commit.
>>
>> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
>> ---
>>  commands/Kconfig             |  19 ++
>>  commands/Makefile            |   1 +
>>  commands/mipi_dbi.c          | 104 ++++++++
>>  drivers/video/Kconfig        |  14 ++
>>  drivers/video/Makefile       |   1 +
>>  drivers/video/mipi_dbi.c     | 467 +++++++++++++++++++++++++++++++++++
>>  include/spi/spi.h            |  20 ++
>>  include/video/mipi_dbi.h     | 105 ++++++++
>>  include/video/mipi_display.h | 150 +++++++++++
>>  9 files changed, 881 insertions(+)
>>  create mode 100644 commands/mipi_dbi.c
>>  create mode 100644 drivers/video/mipi_dbi.c
>>  create mode 100644 include/video/mipi_dbi.h
>>  create mode 100644 include/video/mipi_display.h
>>
>> diff --git a/commands/Kconfig b/commands/Kconfig
>> index ba8ca5cdebce..2e13a4ed90bd 100644
>> --- a/commands/Kconfig
>> +++ b/commands/Kconfig
>> @@ -1969,6 +1969,25 @@ config CMD_SPI
>>  		  -w BIT	bits per word (default 8)
>>  		  -v		verbose
>>  
>> +config CMD_MIPI_DBI
>> +	bool
>> +	depends on DRIVER_VIDEO_MIPI_DBI && SPI
>> +	select PRINTF_HEXSTR
>> +	prompt "mipi_dbi command"
>> +	help
>> +	  Write/read from MIPI DBI device on SPI bus
>> +
>> +	  Usage: mipi_dbi [-brcmfwv] DATA...
>> +
>> +	  Options:
>> +		  -b BUS	SPI bus number (default 0)
>> +		  -r COUNT	bytes to read
>> +		  -c		chip select (default 0)
>> +		  -m MODE	SPI mode (default 0)
>> +		  -f HZ		max speed frequency, in Hz (default 1 MHz)
>> +		  -w BIT	bits per word (default 8)
>> +		  -v		verbose
> 
> This doesn't match the actual command. Copy-paste from CMD_SPI above?
> 
>> +BAREBOX_CMD_HELP_START(mipi_dbi)
>> +BAREBOX_CMD_HELP_TEXT("Options:")
>> +BAREBOX_CMD_HELP_OPT ("-l\t",  "list all MIPI DBI devices")
>> +BAREBOX_CMD_HELP_OPT ("-d DEVICE",  "select specific device (default is first registered)")
>> +BAREBOX_CMD_HELP_OPT ("-w",  "issue write command")
>> +BAREBOX_CMD_HELP_END
>> +
>> +
>>  config DRIVER_VIDEO_BACKLIGHT
>>  	bool "Add backlight support"
>>  	help
>> @@ -178,4 +181,15 @@ config DRIVER_VIDEO_SIMPLE_PANEL
>>  	  Linux Kernel implementation this one is able to understand display-timings
>>  	  nodes so that it's not necessary to keep a list of all known displays
>>  	  with their corresponding timings in barebox.
>> +
>> +config DRIVER_VIDEO_PANEL_ILITEK_ILI9341
>> +	tristate "Ilitek ILI9341 240x320 QVGA panels"
>> +	depends on OFTREE && SPI
>> +	select DRIVER_VIDEO_MIPI_DBI
>> +	select VIDEO_VPL
>> +	help
>> +	  Say Y here if you want to enable support for Ilitek IL9341
>> +	  QVGA (240x320) RGB panels. support serial & parallel rgb
>> +	  interface.
> 
> This hunk should be in 4/4.

Ouch. Will fix both for v2.

Thanks,
Ahmad

> 
> Sascha
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Jan 31 02:39:45 2022
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 31 Jan 2022 11:39:45 +0100
Subject: RFC: Gitlab CI for barebox
In-Reply-To: <20220130150011.e8b22a088b654f6a0b0f96de@gmail.com>
References: <20220130150011.e8b22a088b654f6a0b0f96de@gmail.com>
Message-ID: <9b440929-d7e8-da69-a4b0-dcca1f5a5ce7@pengutronix.de>

Hello Antony,

On 30.01.22 13:00, Antony Pavlov wrote:
> Hi!
> 
> I have made simple Gitlab CI for barebox.

Nice.

> Gitlab CI runner setup instruction and
> the source for Debian 11 docker image can be found at:
> 
>   https://gitlab.com/frantony/barebox-gitlab-ci-runner

I had tried something similar, but with Github actions

https://github.com/a3f/barebox/actions/runs/740206381

I didn't have the time to pursue this further. I am fine
with Gitlab as well.

> 
> Sample gitlab-ci.yaml config file:
> 
>   https://gitlab.com/frantony/barebox/-/commit/b1ed597d8e67c8f76f4f98cd1c6605b936cf2471

Here's how it looks for Github actions with emulate.pl:

https://github.com/a3f/barebox/blob/emulate.pl/.github/workflows/build-configs.yaml


> Corresponding gitlab pipeline results:
> 
>   https://gitlab.com/frantony/barebox/-/pipelines/459422690
> 
> 
> Some notes:
> 
>   * there are several "images size > maximum size" errors during 'build ARM'

Ye. IIRC Sascha disables these for his build tests..? Would be nice to get
those resolved sometime.

>   * fake firmware blobs for ARM are used

Could we just fetch them from the correct location? That way we could
just provide the prebuilt binaries for download. But for a first step,
fakes are fine.

>   * 'build doc' produces sphinx generated html docs archive artifact
>   * 'build ARM/MIPS/RISC-V/X86/sandbox' produce log/ directory archive artifacts

Nice.

>   * no support for kvx, openrisc and powerpc

My GA script supports openrisc. Perhaps Jules is interested in getting
CI working for kvx as well once we have the infrastructure in place?

> 
> @Ahmad
> 
> I suppose we can add your qemu barebox/test/emulate.pl tests into CI.

Here is the Github action config for the tests:
https://github.com/a3f/barebox/blob/emulate.pl/.github/workflows/vm-tests.yaml

Any thoughts on how/if to integrate with the mailing list?

Cheers,
Ahmad

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 31 03:03:15 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 12:03:15 +0100
Subject: barebox extending boot-scripts
In-Reply-To: <trinity-eba130ad-1bd5-46a1-95bd-4a2ee29c1f96-1643452807981@3c-app-gmx-bs07>
References: <trinity-236a89db-cfb0-4d29-bf25-44dc71d5d143-1641396043420@3c-app-gmx-bs58>
 <65c439c2-d82a-5cc7-133b-aae7df21b610@pengutronix.de>
 <trinity-48d6bfb8-862a-4bdf-9146-e208983a61b5-1641406402672@3c-app-gmx-bs58>
 <20220106080838.GV6003@pengutronix.de>
 <trinity-eba130ad-1bd5-46a1-95bd-4a2ee29c1f96-1643452807981@3c-app-gmx-bs07>
Message-ID: <20220131110315.GE23490@pengutronix.de>

Hi Frank,

On Sat, Jan 29, 2022 at 11:40:08AM +0100, Frank Wunderlich wrote:
> Hi,
> > Gesendet: Donnerstag, 06. Januar 2022 um 09:08 Uhr
> > Von: "Sascha Hauer" <sha at pengutronix.de>
> 
> > It works for example with:
> >
> > for i in /mnt/sd.1/extlinux/Image*; do basename $i b; echo $b; done
> 
> this works with full path, but not if using a var for dir var
> 
> barebox at BPI R2PRO:/ i=0;for f in /mnt/sd.1/extlinux/Image*; do basename $f b; echo "$i:$b";let i++; done
> 0:Image_5.16
> 1:Image_5.16-next.gz
> 2:Image_5.16.gz
> 3:Image_5.16.gz.bak
> 4:Image_5.16_q64
> 5:Image_bpi
> barebox at BPI R2PRO:/ imgdir=/mnt/sd.1/extlinux/
> barebox at BPI R2PRO:/ i=0;for f in $imgdir/Image*; do basename $f b; echo "$i:$b";let i++; done

You've hit yet another hush bug. Normally when you do a

# foo="bar baz"
# for i in $foo; echo $i; done
bar
baz

$foo expands to two words. This works as expected.

This also works with:

# for i in *; do echo $i; done
dev
env
foo
mnt
tmp

Using a combination of glob pattern and variable however does not work:

# foo="*"
# for i in $foo; do echo $i; done
dev env foo mnt tmp

hush inserts the expanded glob pattern of "*" as a single word into the
parsing data, so i doesn't contain the separated words, but instead "dev
env foo mnt tmp" at once.

There are many bugs like this in hush and we've fixed several of them,
possibly inserting other bugs along the way. I've starred on the code
for a long time over the years and still don't fully understand it. When
changing things I'm often not sure about its implications. To put it
shortly: hush is broken beyond repair.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From sha at pengutronix.de  Mon Jan 31 03:12:03 2022
From: sha at pengutronix.de (Sascha Hauer)
Date: Mon, 31 Jan 2022 12:12:03 +0100
Subject: RFC: Gitlab CI for barebox
In-Reply-To: <9b440929-d7e8-da69-a4b0-dcca1f5a5ce7@pengutronix.de>
References: <20220130150011.e8b22a088b654f6a0b0f96de@gmail.com>
 <9b440929-d7e8-da69-a4b0-dcca1f5a5ce7@pengutronix.de>
Message-ID: <20220131111203.GF23490@pengutronix.de>

On Mon, Jan 31, 2022 at 11:39:45AM +0100, Ahmad Fatoum wrote:
> Hello Antony,
> 
> On 30.01.22 13:00, Antony Pavlov wrote:
> > Hi!
> > 
> > I have made simple Gitlab CI for barebox.
> 
> Nice.
> 
> > Gitlab CI runner setup instruction and
> > the source for Debian 11 docker image can be found at:
> > 
> >   https://gitlab.com/frantony/barebox-gitlab-ci-runner
> 
> I had tried something similar, but with Github actions
> 
> https://github.com/a3f/barebox/actions/runs/740206381
> 
> I didn't have the time to pursue this further. I am fine
> with Gitlab as well.
> 
> > 
> > Sample gitlab-ci.yaml config file:
> > 
> >   https://gitlab.com/frantony/barebox/-/commit/b1ed597d8e67c8f76f4f98cd1c6605b936cf2471
> 
> Here's how it looks for Github actions with emulate.pl:
> 
> https://github.com/a3f/barebox/blob/emulate.pl/.github/workflows/build-configs.yaml
> 
> 
> > Corresponding gitlab pipeline results:
> > 
> >   https://gitlab.com/frantony/barebox/-/pipelines/459422690
> > 
> > 
> > Some notes:
> > 
> >   * there are several "images size > maximum size" errors during 'build ARM'
> 
> Ye. IIRC Sascha disables these for his build tests..? Would be nice to get
> those resolved sometime.

Yes, I disable these checks for my build tests. Getting these issues
resolved only holds for a certain time. Overall bloat will break it
sooner or later anyway :(
It's fighting against windmills.

> 
> >   * fake firmware blobs for ARM are used
> 
> Could we just fetch them from the correct location? That way we could
> just provide the prebuilt binaries for download. But for a first step,
> fakes are fine.

I'm not sure we even have all binaries. I guess some of the mvebu
startup binaries would have to be extracted from the hardware and I
don't know if we are allowed to share them for download if we extracted
them.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


