Compare commits

...

37 Commits

Author SHA1 Message Date
Yilin Sun 85e7731ec8
arm: dts: tlt113i: name mmc based on device order.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-04-21 13:41:42 +08:00
Yilin Sun 373439ec6e
configs: TLT113: support booting from MMC2.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-04-21 13:41:10 +08:00
Yilin Sun 7983de7e9d
config: Tronlong TLT113: Add eMMC variant defconfig.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-04-21 10:35:58 +08:00
Yilin Sun f40e65a1fa
arch: arm: dts: enabled MMC 0/2 boot for TLT113 SoM.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-04-21 10:35:08 +08:00
Yilin Sun 36e82a0265
configs: tlt113i-minievm: Added env ubi partition.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 09:36:38 +08:00
Yilin Sun 738ce1e4fd
arm: dts: Add fixed partition for TLT113-i SPI NAND.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 09:34:49 +08:00
Yilin Sun 9aa63a2ab5
drivers: mtd: nand: Add FORESEE F35SQA001G/002G support.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 09:34:15 +08:00
Yilin Sun 4eb8e11576
configs: sun8i-t113i-tronlong-tlt113-minievm: Add UBI CMD.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 00:21:30 +08:00
Yilin Sun ffb7ad153e
configs: Add defconfig for Tronlong TLT113-MiniEVM.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 00:15:42 +08:00
Yilin Sun a5ec3a143d
arm: dts: sun8i-t113i-tronlong-tlt113-minevm: Initial support
This patch add support for Tronlong TLT113-MiniEVM board.

Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 00:14:37 +08:00
Yilin Sun 0afbe90ad2
arm: dts: sun8i-t113i: Add dts.
T113-i is an industrial-grade DRAM-less SoC which is pretty much
identical to T113-S3 or R528.

Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 00:12:37 +08:00
Yilin Sun aca390cb24
sunxi: Enable additional UART2 pinmux on PORTG.
This patch enables additional pinmux for UART2 on PORT G PG17/PG18. This
is available on certain sun8i devices, e.g. T113

Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-01-11 00:11:11 +08:00
Jookia 89e8047f7a arm: dts: sun8i-t113s-mangopi-mq-r-t113: Add USB nodes 2023-12-08 20:57:06 +11:00
Jookia e27886d3c4 musb-new: Fix compilation for device model 2023-12-08 20:57:06 +11:00
Jookia 0fe6f1a12f spi-sunxi: Don't set clock divider on D1
This sets the SPI clock to 24MHz which seems to work fine.
2023-12-08 20:57:05 +11:00
Jookia 25cc03547d configs: Enable MTD, SPINAND flash and UBI on Mango Pi MQ-R 2023-12-08 20:57:05 +11:00
Jookia 1cd3de2337 spi: Add support for sun50i-r329-spi controller 2023-12-08 20:57:05 +11:00
Jookia c9c4031f35 configs: Enable loading FIT images on Mango Pi MQ-R 2023-12-08 20:57:05 +11:00
Jookia a2b04d91d2 spl_ubi: Support loading FIT from volume in RAM 2023-12-08 20:57:05 +11:00
Jookia 701910350f configs: Enable UBI in Mango Pi MQ-R 2023-12-08 20:57:05 +11:00
Jookia 0d323b1397 spl_ubi: Support SPINAND boot 2023-12-08 20:57:05 +11:00
Jookia 50b08adeeb nand: Add spinand_ helper functions and use them in sunxi 2023-12-08 20:57:05 +11:00
Jookia c09732de8d sunxi: Add and use SPL_SPINAND configuration options 2023-12-08 20:57:05 +11:00
Jookia 6a39611c35 ubi: Depends on MTD 2023-12-08 20:57:05 +11:00
Jookia 9a65cadec8 configs: Enable SPI NAND booting on the Mango Pi MQ-R 2023-12-08 20:57:05 +11:00
Jookia c680e9576e sunxi: Support for SPI booting on the T113 2023-12-08 20:57:05 +11:00
Jookia 2c97cf9958 Add BOOT_DEVICE_SPINAND option and use it for sunxi 2023-12-08 20:57:05 +11:00
Jookia cd95fd413d mach-sunxi: Separate boot device and boot position
While MMC1 and MMC2 each currently have only one upper byte possibility,
SPI NAND has quite a few. To solve this, split up the byte handling across
two functions in preparation for SPI NAND support.

I have not tested this patch to validate that MMC SPL offsets are working.
It looks like it should work though.
2023-12-08 20:57:05 +11:00
Jookia bea38baf59 arm: dts: sun8i-t113s-mangopi-mq-r-t113: Add SPI NAND node
The Mango Pi MQ R has an unpopulated spot for a SPI NAND chip.
Add it to the device tree so I can use it.
2023-12-08 20:57:05 +11:00
Jookia dcac3831d4 configs: mangopi_mq_r_defconfig: Use UART2 2023-12-08 20:57:05 +11:00
Jookia 401df2d803 arm: dts: sunxi-d1s-t113-mangopi-mq-r.dtsi: Use UART2
UART3 needs to be soldered, so use UART2 (PE2 and PE3) instead.
I picked this just because the board I'm using is using UART1 for GPIO.
2023-12-08 20:57:05 +11:00
Jookia 3a3b1e3889 sunxi: Support UART 1 and 2 on the Mango Pi MQ-R
I haven't fully tested this patch, but it should work.
2023-12-08 20:57:05 +11:00
Icenowy Zheng cc0b1dc927 sunxi: enable support for SPI NAND booting on SUNIV
As we added support for SPI NAND to the existing SPL SPI codepath, route
the boot code to it when it detects the BROM loads SPL from SPI NAND, as
for SoCs with both SPI NAND and boot media indicator support, the boot
media indicator is the same for SPI NOR and NAND.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2023-12-08 20:57:05 +11:00
Icenowy Zheng 002d9e9a4c sunxi: SPL SPI: add initial support for booting from SPI NAND
This commit adds support for booting from SPI NAND to SPL SPI code by
mimicing the behavior of boot ROM (use fixed page size and sequentially
try SPI NOR and NAND).

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Tested-by: Samuel Holland <samuel@sholland.org> # Orange Pi Zero Plus
2023-12-08 20:57:05 +11:00
Icenowy Zheng 34f631f0dc sunxi: SPL SPI: allow multiple boot attempt
As we're going to add support for SPI NAND to this code, add code that
allows multiple boot attempts with different load offsets and functions.

To keep compatibility with loading raw binary on SPI NOR, a bool
parameter is used to allow booting without valid magic number when
booting with SPI NOR.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Samuel Holland <samuel@sholland.org>
Tested-by: Samuel Holland <samuel@sholland.org> # Orange Pi Zero Plus
2023-12-08 20:57:05 +11:00
Icenowy Zheng 453ff2fb10 sunxi: SPL SPI: add support for read command with 2 byte address
This kind of read command is utilized in SPI NANDs for reading data
inside a selected page, which is obviously smaller than how much 2
byte address can address. So 2 bytes are used for the address and one
dummy byte is needed after the real address. As the address is sent out
in bit endian, this makes it not compatible with usual 3 byte address.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Samuel Holland <samuel@sholland.org>
Tested-by: Samuel Holland <samuel@sholland.org> # Orange Pi Zero Plus
2023-12-08 20:57:05 +11:00
Icenowy Zheng 6ecb0cba2a sunxi: SPL SPI: extract code for doing SPI transfer
To support SPI NAND flashes, more commands than Read (03h) are needed.

Extract the code for doing SPI transfer from the reading code for code
reuse.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Samuel Holland <samuel@sholland.org>
Tested-by: Samuel Holland <samuel@sholland.org> # Orange Pi Zero Plus
2023-12-08 20:57:05 +11:00
30 changed files with 957 additions and 130 deletions

View File

@ -810,6 +810,7 @@ dtb-$(CONFIG_MACH_SUN8I_V3S) += \
sun8i-v3-sl631-imx179.dtb \
sun8i-v3s-licheepi-zero.dtb
dtb-$(CONFIG_MACH_SUN8I_R528) += \
sun8i-t113i-tronlong-tlt113-minievm.dtb \
sun8i-t113s-mangopi-mq-r-t113.dtb
dtb-$(CONFIG_MACH_SUN50I_H5) += \
sun50i-h5-bananapi-m2-plus.dtb \

View File

@ -0,0 +1,34 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
// Copyright (C) 2022 Arm Ltd.
#include <dt-bindings/interrupt-controller/irq.h>
/dts-v1/;
#include "sun8i-t113i.dtsi"
#include "sunxi-t113i-tronlong-tlt113.dtsi"
/ {
model = "Tronlong TLT113-MiniEVM";
compatible = "tronlong,tlt113-minievm", "allwinner,sun8i-t113i";
};
&cpu0 {
cpu-supply = <&reg_vcc_core>;
};
&cpu1 {
cpu-supply = <&reg_vcc_core>;
};
&mmc0 {
bootph-all;
pinctrl-0 = <&mmc0_pins>;
pinctrl-names = "default";
vmmc-supply = <&reg_3v3>;
cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
disable-wp;
bus-width = <4>;
status = "okay";
};

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
// Copyright (C) 2022 Arm Ltd.
#define SOC_PERIPHERAL_IRQ(nr) GIC_SPI nr
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <../../riscv/dts/sunxi-d1s-t113.dtsi>
#include <../../riscv/dts/sunxi-d1-t113.dtsi>
/ {
interrupt-parent = <&gic>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
clocks = <&ccu CLK_CPUX>;
clock-names = "cpu";
};
cpu1: cpu@1 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <1>;
clocks = <&ccu CLK_CPUX>;
clock-names = "cpu";
};
};
gic: interrupt-controller@1c81000 {
compatible = "arm,gic-400";
reg = <0x03021000 0x1000>,
<0x03022000 0x2000>,
<0x03024000 0x2000>,
<0x03026000 0x2000>;
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
interrupt-controller;
#interrupt-cells = <3>;
};
timer {
compatible = "arm,armv7-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
pmu {
compatible = "arm,cortex-a7-pmu";
interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
interrupt-affinity = <&cpu0>, <&cpu1>;
};
};

View File

@ -33,3 +33,56 @@
interrupt-names = "host-wake";
};
};
&spi0 {
pinctrl-0 = <&spi0_pins>;
pinctrl-names = "default";
status = "okay";
flash@0 {
compatible = "spi-nand";
reg = <0>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "uboot";
reg = <0x00000000 0x00080000>;
};
partition@80000 {
label = "ubi";
reg = <0x00080000 0x0fb00000>;
};
};
};
};
&usb_otg {
status = "okay";
dr_mode = "peripheral";
};
&usbphy {
usb1_vbus-supply = <&reg_vcc5v>;
status = "okay";
};
&ohci0 {
status = "okay";
};
&ohci1 {
status = "okay";
};
&ehci0 {
status = "okay";
};
&ehci1 {
status = "okay";
};

View File

@ -9,11 +9,13 @@
/ {
aliases {
serial1 = &uart1;
serial2 = &uart2;
serial3 = &uart3;
};
chosen {
stdout-path = "serial3:115200n8";
stdout-path = "serial1:115200n8";
};
leds {
@ -108,10 +110,22 @@
vcc-pg-supply = <&reg_3v3>;
};
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&uart1_pg6_pins>;
status = "okay";
};
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&uart2_pe_pins>;
status = "disabled";
};
&uart3 {
pinctrl-names = "default";
pinctrl-0 = <&uart3_pb_pins>;
status = "okay";
status = "disabled";
};
/* The USB-C socket has its CC pins pulled to GND, so is hardwired as a UFP. */

View File

@ -0,0 +1,152 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
// Copyright (C) 2022 Arm Ltd.
/*
* Common peripherals and configurations for MangoPi MQ-R boards.
*/
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
/ {
aliases {
serial2 = &uart2;
mmc0 = &mmc0;
mmc2 = &mmc2;
};
chosen {
stdout-path = "serial2:115200n8";
};
leds {
compatible = "gpio-leds";
led-0 {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_STATUS;
gpios = <&pio 2 0 GPIO_ACTIVE_HIGH>; /* PC0 */
};
led-1 {
color = <LED_COLOR_ID_RED>;
function = LED_FUNCTION_STATUS;
gpios = <&pio 2 1 GPIO_ACTIVE_HIGH>; /* PC1 */
};
};
/* EC2232E DC/DC regulator on SoM */
reg_vcc5v: regulator-5v {
compatible = "regulator-fixed";
regulator-name = "vcc-5v";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
/* EC2232E DC/DC regulator on SoM */
reg_3v3: regulator-3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
vin-supply = <&reg_vcc5v>;
};
/* EC2232E DC/DC regulator on SoM, also supplying VDD-SYS */
reg_vcc_core: regulator-core {
compatible = "regulator-fixed";
regulator-name = "vcc-core";
regulator-min-microvolt = <880000>;
regulator-max-microvolt = <880000>;
vin-supply = <&reg_vcc5v>;
};
};
&dcxo {
clock-frequency = <24000000>;
};
&ehci1 {
status = "okay";
};
&ohci1 {
status = "okay";
};
&pio {
vcc-pb-supply = <&reg_3v3>;
vcc-pd-supply = <&reg_3v3>;
vcc-pe-supply = <&reg_3v3>;
vcc-pf-supply = <&reg_3v3>;
vcc-pg-supply = <&reg_3v3>;
uart2_pg_pins: uart2_pg_pins {
pins = "PG17", "PG18";
function = "uart2";
};
};
&uart2 {
bootph-all;
pinctrl-names = "default";
pinctrl-0 = <&uart2_pg_pins>;
status = "okay";
};
&mmc2 {
bootph-all;
pinctrl-0 = <&mmc2_pins>;
pinctrl-names = "default";
vmmc-supply = <&reg_3v3>;
non-removable;
disable-wp;
bus-width = <4>;
status = "okay";
};
&spi0 {
bootph-all;
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins>;
status = "okay";
spi_nand@0 {
bootph-all;
compatible = "spi-nand";
reg = <0>;
spi-max-frequency = <50000000>;
partitions {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fixed-partitions";
partition@0 {
label = "u-boot";
reg = <0x0 0x100000>; /* 1MB */
};
partition@100000 {
label = "env";
reg = <0x100000 0x400000>; /* 4MB */
};
partition@500000 {
label = "rootfs";
reg = <0x500000 0xfb00000>; /* 251MB */
};
};
};
};
/* The USB-C socket has its CC pins pulled to GND, so is hardwired as a UFP. */
&usb_otg {
dr_mode = "peripheral";
status = "okay";
};
&usbphy {
usb1_vbus-supply = <&reg_vcc5v>;
status = "okay";
};

View File

@ -16,8 +16,7 @@
#define SUNXI_BOOTED_FROM_NAND 1
#define SUNXI_BOOTED_FROM_MMC2 2
#define SUNXI_BOOTED_FROM_SPI 3
#define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10
#define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12
#define SUNXI_BOOTED_FROM_SPINAND 4
/*
* Values taken from the F1C200s BootROM stack

View File

@ -22,6 +22,7 @@ enum {
BOOT_DEVICE_NOR,
BOOT_DEVICE_UART,
BOOT_DEVICE_SPI,
BOOT_DEVICE_SPINAND,
BOOT_DEVICE_USB,
BOOT_DEVICE_SATA,
BOOT_DEVICE_I2C,

View File

@ -729,6 +729,17 @@ config UART0_PORT_F
at the same time, the system can be only booted in the FEL mode.
Only enable this if you really know what you are doing.
config UART2_PORT_G
bool "UART2 on Port G"
---help---
Select this option for boards where UART2 uses the Port G pinmux.
config UART2_PORT_E
bool "UART2 on PE2 and PE3 pins"
---help---
UART2 may used pins PE2 and PE3 on the Allwinner T113 board.
Enable this if you are using these pins for UART2.
config OLD_SUNXI_KERNEL_COMPAT
bool "Enable workarounds for booting old kernels"
---help---
@ -1061,7 +1072,7 @@ config SPL_STACK_R_ADDR
config SPL_SPI_SUNXI
bool "Support for SPI Flash on Allwinner SoCs in SPL"
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || SUN50I_GEN_H6 || MACH_SUNIV
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || SUN50I_GEN_H6 || MACH_SUN8I_R528 || MACH_SUNIV
help
Enable support for SPI Flash. This option allows SPL to read from
sunxi SPI Flash. It uses the same method as the boot ROM, so does

View File

@ -167,6 +167,20 @@ static int gpio_init(void)
sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN8I_GPB_UART2);
sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_GPB_UART2);
sunxi_gpio_set_pull(SUNXI_GPB(1), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I_R528)
#if IS_ENABLED(CONFIG_UART2_PORT_E)
sunxi_gpio_set_cfgpin(SUNXI_GPE(2), 3);
sunxi_gpio_set_cfgpin(SUNXI_GPE(3), 3);
sunxi_gpio_set_pull(SUNXI_GPE(2), SUNXI_GPIO_PULL_UP);
#elif IS_ENABLED(CONFIG_UART2_PORT_G)
sunxi_gpio_set_cfgpin(SUNXI_GPG(17), SUN8I_R528_GPG_UART2);
sunxi_gpio_set_cfgpin(SUNXI_GPG(18), SUN8I_R528_GPG_UART2);
sunxi_gpio_set_pull(SUNXI_GPG(18), SUNXI_GPIO_PULL_UP);
#else
sunxi_gpio_set_cfgpin(SUNXI_GPB(0), 7);
sunxi_gpio_set_cfgpin(SUNXI_GPB(1), 7);
sunxi_gpio_set_pull(SUNXI_GPB(1), SUNXI_GPIO_PULL_UP);
#endif
#elif CONFIG_CONS_INDEX == 4 && defined(CONFIG_MACH_SUN8I_R528)
sunxi_gpio_set_cfgpin(SUNXI_GPB(6), 7);
sunxi_gpio_set_cfgpin(SUNXI_GPB(7), 7);
@ -175,8 +189,9 @@ static int gpio_init(void)
sunxi_gpio_set_cfgpin(SUNXI_GPL(2), SUN8I_GPL_R_UART);
sunxi_gpio_set_cfgpin(SUNXI_GPL(3), SUN8I_GPL_R_UART);
sunxi_gpio_set_pull(SUNXI_GPL(3), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN8I) && \
!defined(CONFIG_MACH_SUN8I_R40)
#elif CONFIG_CONS_INDEX == 2 && (defined(CONFIG_MACH_SUN8I) && \
!defined(CONFIG_MACH_SUN8I_R40)) \
|| defined(CONFIG_MACH_SUN8I_R528)
sunxi_gpio_set_cfgpin(SUNXI_GPG(6), SUN8I_GPG_UART1);
sunxi_gpio_set_cfgpin(SUNXI_GPG(7), SUN8I_GPG_UART1);
sunxi_gpio_set_pull(SUNXI_GPG(7), SUNXI_GPIO_PULL_UP);
@ -223,13 +238,12 @@ static int suniv_get_boot_source(void)
switch (brom_call) {
case SUNIV_BOOTED_FROM_MMC0:
return SUNXI_BOOTED_FROM_MMC0;
case SUNIV_BOOTED_FROM_SPI:
case SUNIV_BOOTED_FROM_NAND:
return SUNXI_BOOTED_FROM_SPI;
case SUNIV_BOOTED_FROM_MMC1:
return SUNXI_BOOTED_FROM_MMC2;
/* SPI NAND is not supported yet. */
case SUNIV_BOOTED_FROM_NAND:
return SUNXI_INVALID_BOOT_SOURCE;
case SUNIV_BOOTED_FROM_SPI:
return SUNXI_BOOTED_FROM_SPINAND;
}
/* If we get here something went wrong try to boot from FEL.*/
printf("Unknown boot source from BROM: 0x%x\n", brom_call);
@ -279,6 +293,7 @@ static int sunxi_get_boot_source(void)
uint32_t sunxi_get_boot_device(void)
{
int boot_source = sunxi_get_boot_source();
int boot_dev = (boot_source & 0xF); /* Low nibble is device */
/*
* When booting from the SD card or NAND memory, the "eGON.BT0"
@ -296,25 +311,34 @@ uint32_t sunxi_get_boot_device(void)
* binary over USB. If it is found, it determines where SPL was
* read from.
*/
switch (boot_source) {
case SUNXI_INVALID_BOOT_SOURCE:
if (boot_source == SUNXI_INVALID_BOOT_SOURCE)
return BOOT_DEVICE_BOARD;
switch (boot_dev) {
case SUNXI_BOOTED_FROM_MMC0:
case SUNXI_BOOTED_FROM_MMC0_HIGH:
return BOOT_DEVICE_MMC1;
case SUNXI_BOOTED_FROM_NAND:
return BOOT_DEVICE_NAND;
case SUNXI_BOOTED_FROM_MMC2:
case SUNXI_BOOTED_FROM_MMC2_HIGH:
return BOOT_DEVICE_MMC2;
case SUNXI_BOOTED_FROM_SPI:
return BOOT_DEVICE_SPI;
case SUNXI_BOOTED_FROM_SPINAND:
return BOOT_DEVICE_SPINAND;
}
panic("Unknown boot source %d\n", boot_source);
return -1; /* Never reached */
}
uint32_t sunxi_get_boot_position(void)
{
int boot_source = sunxi_get_boot_source();
int boot_pos = ((boot_source >> 8) & 0xF); /* High nibble is position */
return boot_pos;
}
#ifdef CONFIG_SPL_BUILD
uint32_t sunxi_get_spl_size(void)
{
@ -346,11 +370,8 @@ unsigned long board_spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
sector = max(raw_sect, spl_size / 512);
switch (sunxi_get_boot_source()) {
case SUNXI_BOOTED_FROM_MMC0_HIGH:
case SUNXI_BOOTED_FROM_MMC2_HIGH:
if (sunxi_get_boot_position() == 1) {
sector += (128 - 8) * 2;
break;
}
return sector;
@ -459,6 +480,8 @@ void board_init_f(ulong dummy)
{
sunxi_sram_init();
spl_early_init();
#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I_H3
/* Enable non-secure access to some peripherals */
tzpc_init();

View File

@ -78,13 +78,17 @@
/*****************************************************************************/
#define CCM_AHB_GATING0 (0x01C20000 + 0x60)
#define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0)
#if defined(CONFIG_MACH_SUN8I_R528)
#define CCM_H6_SPI_BGR_REG (0x02001000 + 0x96c)
#define CCM_SPI0_CLK (0x02001000 + 0x940)
#elif defined(CONFIG_SUN50I_GEN_H6)
#define CCM_H6_SPI_BGR_REG (0x03001000 + 0x96c)
#ifdef CONFIG_SUN50I_GEN_H6
#define CCM_SPI0_CLK (0x03001000 + 0x940)
#else
#define CCM_SPI0_CLK (0x01C20000 + 0xA0)
#endif
#define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0)
#define AHB_RESET_SPI0_SHIFT 20
#define AHB_GATE_OFFSET_SPI0 20
@ -99,20 +103,24 @@
* Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting
* from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3.
* The H6 uses PC0, PC2, PC3, PC5, the H616 PC0, PC2, PC3, PC4.
* The R528 uses PC2, PC3, PC4, PC5, PC6, PC7.
*/
static void spi0_pinmux_setup(unsigned int pin_function)
{
/* All chips use PC0 and PC2. */
sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
/* All chips use PC2. */
sunxi_gpio_set_cfgpin(SUNXI_GPC(2), pin_function);
/* All chips except R528 use PC0. */
if (!IS_ENABLED(CONFIG_MACH_SUN8I_R528))
sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
/* All chips except H6 and H616 use PC1. */
if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6))
sunxi_gpio_set_cfgpin(SUNXI_GPC(1), pin_function);
if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
if (IS_ENABLED(CONFIG_MACH_SUN50I_H6) || IS_ENABLED(CONFIG_MACH_SUN8I_R528))
sunxi_gpio_set_cfgpin(SUNXI_GPC(5), pin_function);
if (IS_ENABLED(CONFIG_MACH_SUN50I_H616))
if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) || IS_ENABLED(CONFIG_MACH_SUN8I_R528))
sunxi_gpio_set_cfgpin(SUNXI_GPC(4), pin_function);
/* Older generations use PC23 for CS, newer ones use PC3. */
@ -121,12 +129,19 @@ static void spi0_pinmux_setup(unsigned int pin_function)
sunxi_gpio_set_cfgpin(SUNXI_GPC(23), pin_function);
else
sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
if (IS_ENABLED(CONFIG_MACH_SUN8I_R528))
sunxi_gpio_set_cfgpin(SUNXI_GPC(6), pin_function);
if (IS_ENABLED(CONFIG_MACH_SUN8I_R528))
sunxi_gpio_set_cfgpin(SUNXI_GPC(7), pin_function);
}
static bool is_sun6i_gen_spi(void)
{
return IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ||
IS_ENABLED(CONFIG_SUN50I_GEN_H6);
IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
IS_ENABLED(CONFIG_MACH_SUN8I_R528)
;
}
static uintptr_t spi0_base_address(void)
@ -137,6 +152,9 @@ static uintptr_t spi0_base_address(void)
if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
return 0x05010000;
if (IS_ENABLED(CONFIG_MACH_SUN8I_R528))
return 0x04025000;
if (!is_sun6i_gen_spi() ||
IS_ENABLED(CONFIG_MACH_SUNIV))
return 0x01C05000;
@ -152,19 +170,22 @@ static void spi0_enable_clock(void)
uintptr_t base = spi0_base_address();
/* Deassert SPI0 reset on SUN6I */
if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_MACH_SUN8I_R528))
setbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
else if (is_sun6i_gen_spi())
setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
(1 << AHB_RESET_SPI0_SHIFT));
/* Open the SPI0 gate */
if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6))
if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) && !IS_ENABLED(CONFIG_MACH_SUN8I_R528))
setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
if (IS_ENABLED(CONFIG_MACH_SUNIV)) {
/* Divide by 32, clock source is AHB clock 200MHz */
writel(SPI0_CLK_DIV_BY_32, base + SUN6I_SPI0_CCTL);
} else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
/* 24MHz from OSC24M */
writel((1 << 31), CCM_SPI0_CLK);
} else {
/* Divide by 4 */
writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
@ -206,11 +227,11 @@ static void spi0_disable_clock(void)
writel(0, CCM_SPI0_CLK);
/* Close the SPI0 gate */
if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6))
if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) && !IS_ENABLED(CONFIG_MACH_SUN8I_R528))
clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
/* Assert SPI0 reset on SUN6I */
if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_MACH_SUN8I_R528))
clrbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
else if (is_sun6i_gen_spi())
clrbits_le32(SUN6I_BUS_SOFT_RST_REG0,
@ -221,7 +242,9 @@ static void spi0_init(void)
{
unsigned int pin_function = SUNXI_GPC_SPI0;
if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
if (IS_ENABLED(CONFIG_MACH_SUN8I_R528))
pin_function = SUNIV_GPC_SPI0;
else if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
IS_ENABLED(CONFIG_SUN50I_GEN_H6))
pin_function = SUN50I_GPC_SPI0;
else if (IS_ENABLED(CONFIG_MACH_SUNIV))
@ -247,77 +270,139 @@ static void spi0_deinit(void)
#define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */
static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize,
ulong spi_ctl_reg,
ulong spi_ctl_xch_bitmask,
ulong spi_fifo_reg,
ulong spi_tx_reg,
ulong spi_rx_reg,
ulong spi_bc_reg,
ulong spi_tc_reg,
ulong spi_bcc_reg)
static void sunxi_spi0_xfer(const u8 *txbuf, u32 txlen,
u8 *rxbuf, u32 rxlen,
ulong spi_ctl_reg,
ulong spi_ctl_xch_bitmask,
ulong spi_fifo_reg,
ulong spi_tx_reg,
ulong spi_rx_reg,
ulong spi_bc_reg,
ulong spi_tc_reg,
ulong spi_bcc_reg)
{
writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
writel(4, spi_tc_reg); /* Transfer counter (bytes to send) */
writel(txlen + rxlen, spi_bc_reg); /* Burst counter (total bytes) */
writel(txlen, spi_tc_reg); /* Transfer counter (bytes to send) */
if (spi_bcc_reg)
writel(4, spi_bcc_reg); /* SUN6I also needs this */
writel(txlen, spi_bcc_reg); /* SUN6I also needs this */
/* Send the Read Data Bytes (03h) command header */
writeb(0x03, spi_tx_reg);
writeb((u8)(addr >> 16), spi_tx_reg);
writeb((u8)(addr >> 8), spi_tx_reg);
writeb((u8)(addr), spi_tx_reg);
for (u32 i = 0; i < txlen; i++)
writeb(*(txbuf++), spi_tx_reg);
/* Start the data transfer */
setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
/* Wait until everything is received in the RX FIFO */
while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize)
while ((readl(spi_fifo_reg) & 0x7F) < txlen + rxlen)
;
/* Skip 4 bytes */
readl(spi_rx_reg);
/* Skip txlen bytes */
for (u32 i = 0; i < txlen; i++)
readb(spi_rx_reg);
/* Read the data */
while (bufsize-- > 0)
*buf++ = readb(spi_rx_reg);
/* tSHSL time is up to 100 ns in various SPI flash datasheets */
udelay(1);
while (rxlen-- > 0)
*rxbuf++ = readb(spi_rx_reg);
}
static void spi0_read_data(void *buf, u32 addr, u32 len)
static void spi0_xfer(const u8 *txbuf, u32 txlen, u8 *rxbuf, u32 rxlen)
{
uintptr_t base = spi0_base_address();
if (is_sun6i_gen_spi()) {
sunxi_spi0_xfer(txbuf, txlen, rxbuf, rxlen,
base + SUN6I_SPI0_TCR,
SUN6I_TCR_XCH,
base + SUN6I_SPI0_FIFO_STA,
base + SUN6I_SPI0_TXD,
base + SUN6I_SPI0_RXD,
base + SUN6I_SPI0_MBC,
base + SUN6I_SPI0_MTC,
base + SUN6I_SPI0_BCC);
} else {
sunxi_spi0_xfer(txbuf, txlen, rxbuf, rxlen,
base + SUN4I_SPI0_CTL,
SUN4I_CTL_XCH,
base + SUN4I_SPI0_FIFO_STA,
base + SUN4I_SPI0_TX,
base + SUN4I_SPI0_RX,
base + SUN4I_SPI0_BC,
base + SUN4I_SPI0_TC,
0);
}
}
#if defined(CONFIG_SPL_SPINAND_SUPPORT)
static int spi0_nand_switch_page(u32 page)
{
unsigned count;
u8 buf[4];
/* Configure the Page Data Read (13h) command header */
buf[0] = 0x13;
buf[1] = (u8)(page >> 16);
buf[2] = (u8)(page >> 8);
buf[3] = (u8)(page);
spi0_xfer(buf, 4, NULL, 0);
/* Wait for NAND chip to exit busy state */
buf[0] = 0x0f;
buf[1] = 0xc0;
/* Load a NAND page can take up to 2-decimal-digit microseconds */
for (count = 0; count < 100; count ++) {
udelay(1);
spi0_xfer(buf, 2, buf+2, 1);
if (!(buf[2] & 0x1))
return 0;
}
return -ETIMEDOUT;
}
static void spi0_nand_reset(void)
{
u8 buf[1];
/* Configure the Device RESET (ffh) command */
buf[0] = 0xff;
spi0_xfer(buf, 1, NULL, 0);
/* Wait for the NAND to finish resetting */
udelay(10);
}
#endif
static void spi0_read_data(void *buf, u32 addr, u32 len, u32 addr_len)
{
u8 *buf8 = buf;
u32 chunk_len;
uintptr_t base = spi0_base_address();
u8 txbuf[4];
while (len > 0) {
chunk_len = len;
/* Configure the Read Data Bytes (03h) command header */
txbuf[0] = 0x03;
if (addr_len == 3) {
txbuf[1] = (u8)(addr >> 16);
txbuf[2] = (u8)(addr >> 8);
txbuf[3] = (u8)(addr);
} else if (addr_len == 2) {
txbuf[1] = (u8)(addr >> 8);
txbuf[2] = (u8)(addr);
txbuf[3] = 0; /* dummy */
}
if (chunk_len > SPI_READ_MAX_SIZE)
chunk_len = SPI_READ_MAX_SIZE;
if (is_sun6i_gen_spi()) {
sunxi_spi0_read_data(buf8, addr, chunk_len,
base + SUN6I_SPI0_TCR,
SUN6I_TCR_XCH,
base + SUN6I_SPI0_FIFO_STA,
base + SUN6I_SPI0_TXD,
base + SUN6I_SPI0_RXD,
base + SUN6I_SPI0_MBC,
base + SUN6I_SPI0_MTC,
base + SUN6I_SPI0_BCC);
} else {
sunxi_spi0_read_data(buf8, addr, chunk_len,
base + SUN4I_SPI0_CTL,
SUN4I_CTL_XCH,
base + SUN4I_SPI0_FIFO_STA,
base + SUN4I_SPI0_TX,
base + SUN4I_SPI0_RX,
base + SUN4I_SPI0_BC,
base + SUN4I_SPI0_TC,
0);
}
spi0_xfer(txbuf, 4, buf8, chunk_len);
/* tSHSL time is up to 100 ns in various SPI flash datasheets */
udelay(1);
len -= chunk_len;
buf8 += chunk_len;
@ -325,54 +410,130 @@ static void spi0_read_data(void *buf, u32 addr, u32 len)
}
}
static ulong spi_load_read(struct spl_load_info *load, ulong sector,
ulong count, void *buf)
static ulong spi_load_read_nor(struct spl_load_info *load, ulong sector,
ulong count, void *buf)
{
spi0_read_data(buf, sector, count);
spi0_read_data(buf, sector, count, 3);
return count;
}
#if defined(CONFIG_SPL_SPINAND_SUPPORT)
static ulong spi_load_read_nand(struct spl_load_info *load, ulong sector,
ulong count, void *buf)
{
const ulong pagesize = CONFIG_SPL_SPINAND_PAGE_SIZE;
ulong remain = count;
while (remain) {
ulong count_in_page = min(remain, pagesize - (sector % pagesize));
ulong current_page = sector / pagesize;
if (spi0_nand_switch_page(current_page) != 0)
return 0;
spi0_read_data(buf, sector % pagesize, count_in_page, 2);
remain -= count_in_page;
sector += count_in_page;
buf += count_in_page;
}
return count;
}
void spinand_init(void)
{
spi0_init();
spi0_nand_reset();
}
void spinand_deinit(void)
{
spi0_deinit();
}
int spinand_spl_read_block(int block, int offset, int len, void *dst)
{
ulong byte_offset = (block * CONFIG_SPL_SPINAND_BLOCK_SIZE) + offset;
spi_load_read_nand(NULL, byte_offset, len, dst);
return 0;
}
#endif
/*****************************************************************************/
static int spl_spi_try_load(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev,
struct spl_load_info *load, u32 offset,
bool allow_raw)
{
int ret = 0;
struct legacy_img_hdr *header;
header = (struct legacy_img_hdr *)CONFIG_TEXT_BASE;
if (load->read(load, offset, 0x40, (void *)header) == 0)
return -EINVAL;
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
image_get_magic(header) == FDT_MAGIC) {
debug("Found FIT image\n");
ret = spl_load_simple_fit(spl_image, load,
offset, header);
} else {
if (!allow_raw && image_get_magic(header) != IH_MAGIC)
return -EINVAL;
ret = spl_parse_image_header(spl_image, bootdev, header);
if (ret)
return ret;
if (load->read(load, offset, spl_image->size,
(void *)spl_image->load_addr) == 0)
ret = -EINVAL;
}
return ret;
}
static int spl_spi_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
int ret = 0;
struct legacy_img_hdr *header;
uint32_t load_offset = sunxi_get_spl_size();
struct spl_load_info load;
bool allow_raw = false;
header = (struct legacy_img_hdr *)CONFIG_TEXT_BASE;
load_offset = max_t(uint32_t, load_offset, CONFIG_SYS_SPI_U_BOOT_OFFS);
load.dev = NULL;
load.priv = NULL;
load.filename = NULL;
load.bl_len = 1;
spi0_init();
spi0_read_data((void *)header, load_offset, 0x40);
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
image_get_magic(header) == FDT_MAGIC) {
struct spl_load_info load;
debug("Found FIT image\n");
load.dev = NULL;
load.priv = NULL;
load.filename = NULL;
load.bl_len = 1;
load.read = spi_load_read;
ret = spl_load_simple_fit(spl_image, &load,
load_offset, header);
} else {
ret = spl_parse_image_header(spl_image, bootdev, header);
if (ret)
return ret;
spi0_read_data((void *)spl_image->load_addr,
load_offset, spl_image->size);
switch (bootdev->boot_device) {
#if defined(CONFIG_SPL_SPINAND_SUPPORT)
case BOOT_DEVICE_SPINAND:
spi0_nand_reset();
load.read = spi_load_read_nand;
break;
#endif
case BOOT_DEVICE_SPI:
load.read = spi_load_read_nor;
allow_raw = true;
break;
}
ret = spl_spi_try_load(spl_image, bootdev, &load, load_offset, allow_raw);
spi0_deinit();
return ret;
}
/* Use priorty 0 to override the default if it happens to be linked in */
SPL_LOAD_IMAGE_METHOD("sunxi SPI", 0, BOOT_DEVICE_SPI, spl_spi_load_image);
#if defined(CONFIG_SPL_SPINAND_SUPPORT)
SPL_LOAD_IMAGE_METHOD("sunxi SPI NAND", 0, BOOT_DEVICE_SPINAND, spl_spi_load_image);
#endif

View File

@ -16,6 +16,7 @@ enum {
BOOT_DEVICE_NOR,
BOOT_DEVICE_UART,
BOOT_DEVICE_SPI,
BOOT_DEVICE_SPINAND,
BOOT_DEVICE_USB,
BOOT_DEVICE_SATA,
BOOT_DEVICE_I2C,

View File

@ -138,6 +138,12 @@
function = "uart1";
};
/omit-if-no-ref/
uart2_pe_pins: uart2-pe-pins {
pins = "PE2", "PE3";
function = "uart2";
};
/omit-if-no-ref/
uart3_pb_pins: uart3-pb-pins {
pins = "PB6", "PB7";

View File

@ -18,6 +18,7 @@ enum {
BOOT_DEVICE_NOR,
BOOT_DEVICE_UART,
BOOT_DEVICE_SPI,
BOOT_DEVICE_SPINAND,
BOOT_DEVICE_USB,
BOOT_DEVICE_SATA,
BOOT_DEVICE_NVME,

View File

@ -15,6 +15,7 @@ enum {
BOOT_DEVICE_CPGMAC,
BOOT_DEVICE_NOR,
BOOT_DEVICE_SPI,
BOOT_DEVICE_SPINAND,
};
/**

View File

@ -874,6 +874,27 @@ config SPL_MUSB_NEW
the drivers in drivers/usb/musb-new as part of an SPL build. The
old drivers are in drivers/usb/musb.
config SPL_SPINAND_SUPPORT
bool "Support SPINAND flash"
help
Enable support for SPINAND (Negative AND) flash in SPL. SPINAND flash
can be used to allow SPL to load U-Boot from supported devices.
config SPL_SPINAND_PAGE_SIZE
hex "SPINAND chip page size"
depends on SPL_SPINAND_SUPPORT
help
Number of data bytes in one page for the SPINAND chip on the
board, not including the OOB area.
config SPL_SPINAND_BLOCK_SIZE
hex "SPINAND chip eraseblock size"
depends on SPL_SPINAND_SUPPORT
help
Number of data bytes in one eraseblock for the SPINAND chip on the
board. This is the multiple of SPINAND_PAGE_SIZE and the number of
pages.
config SPL_NAND_SUPPORT
bool "Support NAND flash"
help

View File

@ -12,6 +12,14 @@
#include <ubispl.h>
#include <spl.h>
static ulong ram_spl_load_read(struct spl_load_info *load, ulong sector,
ulong count, void *buf)
{
char* ubi_contents = load->priv;
memcpy(buf, ubi_contents + sector, count);
return count;
}
int spl_ubi_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
@ -21,6 +29,13 @@ int spl_ubi_load_image(struct spl_image_info *spl_image,
int ret = 1;
switch (bootdev->boot_device) {
#ifdef CONFIG_SPL_SPINAND_SUPPORT
case BOOT_DEVICE_SPINAND:
spinand_init();
info.read = spinand_spl_read_block;
info.peb_size = CONFIG_SPL_SPINAND_BLOCK_SIZE;
break;
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
case BOOT_DEVICE_NAND:
nand_init();
@ -62,7 +77,8 @@ int spl_ubi_load_image(struct spl_image_info *spl_image,
puts("Loading Linux failed, falling back to U-Boot.\n");
}
#endif
header = spl_get_load_buffer(-sizeof(*header), sizeof(header));
/* Ensure there's enough room for the full UBI volume! */
header = (void*)CONFIG_SYS_LOAD_ADDR;
#ifdef CONFIG_SPL_UBI_LOAD_BY_VOLNAME
volumes[0].vol_id = -1;
strncpy(volumes[0].name,
@ -74,15 +90,35 @@ int spl_ubi_load_image(struct spl_image_info *spl_image,
volumes[0].load_addr = (void *)header;
ret = ubispl_load_volumes(&info, volumes, 1);
if (!ret)
spl_parse_image_header(spl_image, bootdev, header);
if (ret)
goto out;
spl_parse_image_header(spl_image, bootdev, header);
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
image_get_magic(header) == FDT_MAGIC) {
struct spl_load_info load;
printf("Found FIT\n");
load.dev = NULL;
load.priv = (char*)header;
load.filename = NULL;
load.bl_len = 1;
load.read = ram_spl_load_read;
ret = spl_load_simple_fit(spl_image, &load, 0, header);
}
out:
#ifdef CONFIG_SPL_SPI_NAND_SUPPORT
if (bootdev->boot_device == BOOT_DEVICE_SPINAND)
spinand_deselect();
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
if (bootdev->boot_device == BOOT_DEVICE_NAND)
nand_deselect();
#endif
return ret;
}
/* Use priorty 0 so that Ubi will override NAND and ONENAND methods */
/* Use priority 0 so that UBI will override all NAND methods */
SPL_LOAD_IMAGE_METHOD("NAND", 0, BOOT_DEVICE_NAND, spl_ubi_load_image);
SPL_LOAD_IMAGE_METHOD("OneNAND", 0, BOOT_DEVICE_ONENAND, spl_ubi_load_image);
SPL_LOAD_IMAGE_METHOD("SPINAND", 0, BOOT_DEVICE_SPINAND, spl_ubi_load_image);

View File

@ -6,10 +6,38 @@ CONFIG_MACH_SUN8I_R528=y
CONFIG_DRAM_CLK=792
CONFIG_DRAM_ZQ=8092667
CONFIG_SUNXI_MINIMUM_DRAM_MB=128
CONFIG_UART2_PORT_E=y
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_LEGACY_IMAGE_FORMAT=y
CONFIG_SPL_FIT_IMAGE_TINY=y
CONFIG_SPL_SPINAND_SUPPORT=y
CONFIG_SPL_SPINAND_PAGE_SIZE=0x800
CONFIG_SPL_SPINAND_BLOCK_SIZE=0x20000
CONFIG_SPL_UBI=y
CONFIG_SPL_UBI_MAX_VOL_LEBS=2048
CONFIG_SPL_UBI_MAX_PEB_SIZE=131072
CONFIG_SPL_UBI_MAX_PEBS=2048
CONFIG_SPL_UBI_PEB_OFFSET=4
CONFIG_SPL_UBI_VID_OFFSET=2048
CONFIG_SPL_UBI_LEB_START=4096
CONFIG_SPL_UBI_INFO_ADDR=0x41000000
CONFIG_SPL_UBI_VOL_IDS=256
CONFIG_SPL_UBI_LOAD_MONITOR_ID=0
CONFIG_CMD_MTD=y
CONFIG_CMD_UBI=y
CONFIG_MTD=y
CONFIG_DM_MTD=y
CONFIG_MTD_SPI_NAND=y
# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
CONFIG_SPI_FLASH_MTD=y
CONFIG_MTD_UBI_FASTMAP=y
CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT=1
CONFIG_DRAM_SUNXI_ODT_EN=0
CONFIG_DRAM_SUNXI_TPR0=0x004a2195
CONFIG_DRAM_SUNXI_TPR11=0x340000
CONFIG_DRAM_SUNXI_TPR12=0x46
CONFIG_DRAM_SUNXI_TPR13=0x34000100
CONFIG_CONS_INDEX=4
CONFIG_CONS_INDEX=2
CONFIG_SPI=y

View File

@ -0,0 +1,36 @@
CONFIG_ARM=y
CONFIG_ARCH_SUNXI=y
CONFIG_ENV_SIZE=0x20000
CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113i-tronlong-tlt113-minievm"
CONFIG_SPL=y
CONFIG_MACH_SUN8I_R528=y
CONFIG_DRAM_CLK=792
CONFIG_DRAM_ZQ=8092667
CONFIG_UART2_PORT_G=y
CONFIG_MMC_SUNXI_SLOT_EXTRA=2
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL_SPINAND_SUPPORT=y
CONFIG_SPL_SPINAND_PAGE_SIZE=0x800
CONFIG_SPL_SPINAND_BLOCK_SIZE=0x20000
CONFIG_CMD_MTD=y
CONFIG_CMD_UBI=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_OF_LIVE=y
# CONFIG_ENV_IS_IN_SPI_FLASH is not set
CONFIG_ENV_FAT_DEVICE_AND_PART="0:auto"
CONFIG_SPL_DM=y
# CONFIG_SPL_BLK is not set
# CONFIG_SPL_DM_MMC is not set
CONFIG_MTD=y
CONFIG_DM_MTD=y
CONFIG_MTD_SPI_NAND=y
CONFIG_UBI_SILENCE_MSG=y
CONFIG_DRAM_SUNXI_ODT_EN=1
CONFIG_DRAM_SUNXI_TPR0=0x004a2195
CONFIG_DRAM_SUNXI_TPR11=0x770000
CONFIG_DRAM_SUNXI_TPR12=0x2
CONFIG_DRAM_SUNXI_TPR13=0x34050100
CONFIG_CONS_INDEX=3
CONFIG_SPI=y
CONFIG_UBIFS_SILENCE_MSG=y

View File

@ -0,0 +1,37 @@
CONFIG_ARM=y
CONFIG_ARCH_SUNXI=y
CONFIG_SYS_BOARD="tlt113-minievm"
CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113i-tronlong-tlt113-minievm"
CONFIG_MACH_SUN8I_R528=y
CONFIG_OF_LIVE=y
# CONFIG_ENV_IS_IN_FAT is not set
# CONFIG_ENV_IS_IN_SPI_FLASH is not set
CONFIG_ENV_IS_IN_UBI=y
CONFIG_ENV_UBI_PART="env"
CONFIG_ENV_UBI_VOLUME="env"
CONFIG_ENV_UBI_VID_OFFSET=2048
CONFIG_SPL=y
CONFIG_SPL_DM=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_SPL_SPINAND_SUPPORT=y
CONFIG_SPL_SPINAND_PAGE_SIZE=0x800
CONFIG_SPL_SPINAND_BLOCK_SIZE=0x20000
CONFIG_SPL_SPI_SUNXI=y
CONFIG_SUNXI_MINIMUM_DRAM_MB=256
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_DRAM_CLK=792
CONFIG_DRAM_ZQ=8092667
CONFIG_DRAM_SUNXI_ODT_EN=1
CONFIG_DRAM_SUNXI_TPR0=0x004a2195
CONFIG_DRAM_SUNXI_TPR11=0x770000
CONFIG_DRAM_SUNXI_TPR12=0x2
CONFIG_DRAM_SUNXI_TPR13=0x34050100
CONFIG_CONS_INDEX=3
CONFIG_UART2_PORT_G=y
CONFIG_MTD=y
CONFIG_DM_MTD=y
CONFIG_MTD_SPI_NAND=y
CONFIG_SPI=y
CONFIG_CMD_MTD=y
CONFIG_CMD_UBI=y

View File

@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
spinand-objs := core.o foresee.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o

View File

@ -822,6 +822,7 @@ static const struct nand_ops spinand_ops = {
};
static const struct spinand_manufacturer *spinand_manufacturers[] = {
&foresee_spinand_manufacturer,
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,

View File

@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 exceet electronics GmbH
* Copyright (c) 2024 Yilin Sun
*
* Authors:
* Frieder Schrempf <frieder.schrempf@exceet.de>
* Boris Brezillon <boris.brezillon@bootlin.com>
* Yilin Sun <imi415@imi.moe>
*/
#ifndef __UBOOT__
#include <linux/device.h>
#include <linux/kernel.h>
#endif
#include <linux/bug.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_FORESEE 0xCD
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int f35sqa001g_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 3)
return -ERANGE;
region->offset = (16 * section) + 8;
region->length = 8;
return 0;
}
static int f35sqa001g_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 3)
return -ERANGE;
region->offset = (16 * section) + 2;
region->length = 6;
return 0;
}
static const struct mtd_ooblayout_ops f35sqa001g_ooblayout = {
.ecc = f35sqa001g_ooblayout_ecc,
.rfree = f35sqa001g_ooblayout_free,
};
static const struct spinand_info foresee_spinand_table[] = {
SPINAND_INFO("F35SQA001G",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&f35sqa001g_ooblayout, NULL)),
SPINAND_INFO("F35SQA002G",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72, 0x72),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&f35sqa001g_ooblayout, NULL)),
};
static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
};
const struct spinand_manufacturer foresee_spinand_manufacturer = {
.id = SPINAND_MFR_FORESEE,
.name = "FORESEE",
.chips = foresee_spinand_table,
.nchips = ARRAY_SIZE(foresee_spinand_table),
.ops = &foresee_spinand_manuf_ops,
};

View File

@ -9,6 +9,7 @@ config UBI_SILENCE_MSG
config MTD_UBI
bool "Enable UBI - Unsorted block images"
depends on MTD
select RBTREE
select MTD_PARTITIONS
help

View File

@ -613,7 +613,13 @@ static const struct sunxi_pinctrl_function sun20i_d1_pinctrl_functions[] = {
{ "uart0", 6 }, /* PB0-PB1, PB8-PB9, PE2-PE3 */
#endif
{ "uart1", 2 }, /* PG6-PG7 */
#if IS_ENABLED(CONFIG_UART2_PORT_E)
{ "uart2", 3 }, /* PE2-PE3 */
#elif IS_ENABLED(CONFIG_UART2_PORT_G)
{ "uart2", 2 }, /* PG17-PG18 */
#else
{ "uart2", 7 }, /* PB0-PB1 */
#endif
{ "uart3", 7 }, /* PB6-PB7 */
};

View File

@ -128,6 +128,7 @@ struct sun4i_spi_variant {
u32 fifo_depth;
bool has_soft_reset;
bool has_burst_ctl;
bool clock_d1;
};
struct sun4i_spi_plat {
@ -229,7 +230,7 @@ err_ahb:
return ret;
}
static void sun4i_spi_set_speed_mode(struct udevice *dev)
static void sun4i_spi_adjust_clock(struct udevice *dev)
{
struct sun4i_spi_priv *priv = dev_get_priv(dev);
unsigned int div;
@ -270,6 +271,22 @@ static void sun4i_spi_set_speed_mode(struct udevice *dev)
}
writel(reg, SPI_REG(priv, SPI_CCR));
}
static void sun4i_spi_adjust_clock_d1(struct udevice *dev)
{
/* Do nothing for now: We run at HOSC 24MHz by default */
}
static void sun4i_spi_set_speed_mode(struct udevice *dev)
{
struct sun4i_spi_priv *priv = dev_get_priv(dev);
u32 reg;
if (priv->variant->clock_d1)
sun4i_spi_adjust_clock_d1(dev->parent);
else
sun4i_spi_adjust_clock(dev->parent);
reg = readl(SPI_REG(priv, SPI_TCR));
reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
@ -544,6 +561,15 @@ static const struct sun4i_spi_variant sun8i_h3_spi_variant = {
.has_burst_ctl = true,
};
static const struct sun4i_spi_variant sun50i_r329_spi_variant = {
.regs = sun6i_spi_regs,
.bits = sun6i_spi_bits,
.fifo_depth = 64,
.has_soft_reset = true,
.has_burst_ctl = true,
.clock_d1 = true,
};
static const struct udevice_id sun4i_spi_ids[] = {
{
.compatible = "allwinner,sun4i-a10-spi",
@ -557,6 +583,10 @@ static const struct udevice_id sun4i_spi_ids[] = {
.compatible = "allwinner,sun8i-h3-spi",
.data = (ulong)&sun8i_h3_spi_variant,
},
{
.compatible = "allwinner,sun50i-r329-spi",
.data = (ulong)&sun50i_r329_spi_variant,
},
{ /* sentinel */ }
};

View File

@ -283,6 +283,17 @@ static void sunxi_musb_disable(struct musb *musb)
enabled = false;
}
#ifdef CONFIG_DM_USB_GADGET
int dm_usb_gadget_handle_interrupts(struct udevice *dev)
{
struct sunxi_glue *glue = dev_get_priv(dev);
struct musb_host_data *host = &glue->mdata;
host->host->isr(0, host->host);
return 0;
}
#endif
static int sunxi_musb_init(struct musb *musb)
{
struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
@ -431,16 +442,13 @@ static struct musb_hdrc_config musb_config_h3 = {
static int musb_usb_probe(struct udevice *dev)
{
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
struct sunxi_glue *glue = dev_get_priv(dev);
struct musb_host_data *host = &glue->mdata;
struct musb_hdrc_platform_data pdata;
void *base = dev_read_addr_ptr(dev);
int ret;
#ifdef CONFIG_USB_MUSB_HOST
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
#endif
if (!base)
return -EINVAL;
@ -471,26 +479,30 @@ static int musb_usb_probe(struct udevice *dev)
pdata.platform_ops = &sunxi_musb_ops;
pdata.config = glue->cfg->config;
#ifdef CONFIG_USB_MUSB_HOST
priv->desc_before_addr = true;
if (IS_ENABLED(CONFIG_USB_MUSB_HOST)) {
priv->desc_before_addr = true;
pdata.mode = MUSB_HOST;
host->host = musb_init_controller(&pdata, &glue->dev, base);
if (!host->host)
return -EIO;
pdata.mode = MUSB_HOST;
host->host = musb_init_controller(&pdata, &glue->dev, base);
if (!host->host)
return -EIO;
return musb_lowlevel_init(host);
} else if (CONFIG_IS_ENABLED(DM_USB_GADGET)) {
pdata.mode = MUSB_PERIPHERAL;
host->host = musb_init_controller(&pdata, &glue->dev, base);
if (!host->host)
return -EIO;
printf("Allwinner mUSB OTG (Peripheral)\n");
musb_gadget_setup(host->host);
return usb_add_gadget_udc(&glue->dev, &host->host->g);
}
ret = musb_lowlevel_init(host);
if (!ret)
printf("Allwinner mUSB OTG (Host)\n");
#else
pdata.mode = MUSB_PERIPHERAL;
host->host = musb_register(&pdata, &glue->dev, base);
if (IS_ERR_OR_NULL(host->host))
return -EIO;
printf("Allwinner mUSB OTG (Peripheral)\n");
#endif
return ret;
}

View File

@ -245,6 +245,7 @@ struct spinand_manufacturer {
};
/* SPI NAND manufacturers */
extern const struct spinand_manufacturer foresee_spinand_manufacturer;
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
extern const struct spinand_manufacturer micron_spinand_manufacturer;

View File

@ -10,6 +10,7 @@
#include <config.h>
extern void spinand_init(void);
extern void nand_init(void);
unsigned long nand_size(void);
@ -107,7 +108,9 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset);
u32 nand_spl_adjust_offset(u32 sector, u32 offs);
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst);
int nand_spl_read_block(int block, int offset, int len, void *dst);
int spinand_spl_read_block(int block, int offset, int len, void *dst);
void nand_deselect(void);
void spinand_deselect(void);
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
void board_nand_select_device(struct nand_chip *nand, int chip);

View File

@ -142,6 +142,7 @@ enum sunxi_gpio_number {
#define SUN6I_GPG_SDC1 2
#define SUN8I_GPG_SDC1 2
#define SUN8I_GPG_UART1 2
#define SUN8I_R528_GPG_UART2 2
#define SUN5I_GPG_UART1 4
#define SUN6I_GPH_PWM 2