main/u-boot-pinephone: upgrade to 2022.07 (MR 3263)
This commit is contained in:
parent
858c730020
commit
41fec92f75
15 changed files with 14 additions and 2150 deletions
|
@ -1,56 +0,0 @@
|
|||
From 599896bc50b4532f39105ed0c40ada838227650d Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Thu, 7 May 2020 18:50:37 -0500
|
||||
Subject: [PATCH 01/10] sunxi: DT: H6: update device tree files
|
||||
|
||||
Import updated device trees from Linux v5.9.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
arch/arm/dts/Makefile | 1 +
|
||||
arch/arm/dts/sun50i-h6-pine-h64-model-b.dts | 21 +++++++++++++++++++++
|
||||
2 files changed, 22 insertions(+)
|
||||
create mode 100644 arch/arm/dts/sun50i-h6-pine-h64-model-b.dts
|
||||
|
||||
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
|
||||
index fc16a57e60..de2e4ca66b 100644
|
||||
--- a/arch/arm/dts/Makefile
|
||||
+++ b/arch/arm/dts/Makefile
|
||||
@@ -642,6 +642,7 @@ dtb-$(CONFIG_MACH_SUN50I_H6) += \
|
||||
sun50i-h6-orangepi-lite2.dtb \
|
||||
sun50i-h6-orangepi-one-plus.dtb \
|
||||
sun50i-h6-pine-h64.dtb \
|
||||
+ sun50i-h6-pine-h64-model-b.dtb \
|
||||
sun50i-h6-tanix-tx6.dtb
|
||||
dtb-$(CONFIG_MACH_SUN50I_H616) += \
|
||||
sun50i-h616-orangepi-zero2.dtb
|
||||
diff --git a/arch/arm/dts/sun50i-h6-pine-h64-model-b.dts b/arch/arm/dts/sun50i-h6-pine-h64-model-b.dts
|
||||
new file mode 100644
|
||||
index 0000000000..f4c8966a64
|
||||
--- /dev/null
|
||||
+++ b/arch/arm/dts/sun50i-h6-pine-h64-model-b.dts
|
||||
@@ -0,0 +1,21 @@
|
||||
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
|
||||
+/*
|
||||
+ * Copyright (C) 2019 Corentin LABBE <clabbe@baylibre.com>
|
||||
+ */
|
||||
+
|
||||
+#include "sun50i-h6-pine-h64.dts"
|
||||
+
|
||||
+/ {
|
||||
+ model = "Pine H64 model B";
|
||||
+ compatible = "pine64,pine-h64-model-b", "allwinner,sun50i-h6";
|
||||
+
|
||||
+ /delete-node/ reg_gmac_3v3;
|
||||
+};
|
||||
+
|
||||
+&hdmi_connector {
|
||||
+ /delete-property/ ddc-en-gpios;
|
||||
+};
|
||||
+
|
||||
+&emac {
|
||||
+ phy-supply = <®_aldo2>;
|
||||
+};
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -8,14 +8,17 @@ Subject: [PATCH 09/10] disable bootdelay
|
|||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/configs/pinephone_defconfig b/configs/pinephone_defconfig
|
||||
index 149772749a..1683c1f032 100644
|
||||
index 9d39204a43..1f0ce680f9 100644
|
||||
--- a/configs/pinephone_defconfig
|
||||
+++ b/configs/pinephone_defconfig
|
||||
@@ -11,3 +11,4 @@ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
|
||||
@@ -11,6 +11,7 @@ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
|
||||
CONFIG_PINEPHONE_DT_SELECTION=y
|
||||
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
|
||||
CONFIG_OF_LIST="sun50i-a64-pinephone-1.1 sun50i-a64-pinephone-1.2"
|
||||
+CONFIG_BOOTDELAY=0
|
||||
--
|
||||
CONFIG_LED_STATUS=y
|
||||
CONFIG_LED_STATUS_GPIO=y
|
||||
CONFIG_LED_STATUS0=y
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,995 +0,0 @@
|
|||
From 0db85bb77ddc1dad6b2cb24b105274f6a77e4fc7 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sun, 20 Jun 2021 14:09:29 -0500
|
||||
Subject: [PATCH 02/10] tools: mkimage: Add Allwinner TOC0 support
|
||||
|
||||
Most Allwinner sunxi SoCs have separate boot ROMs in non-secure and
|
||||
secure mode. The non-secure boot ROM (NBROM) uses the existing
|
||||
sunxi_egon image type. The secure boot ROM (SBROM) uses a completely
|
||||
different image type, known as TOC0.
|
||||
|
||||
A TOC0 image is composed of a header and two or more items. These items
|
||||
include signed firmware and a key chain linking to a root-of-trust
|
||||
public key (ROTPK) hash burned to eFuses in the SoC. Signatures are made
|
||||
using RSA-2048 + SHA256.
|
||||
|
||||
This TOC0 implementation has been verified to work with the A64, H5, H6,
|
||||
and H616 SBROMs.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
common/image.c | 1 +
|
||||
include/image.h | 1 +
|
||||
include/sunxi_image.h | 191 ++++++++++++
|
||||
tools/Makefile | 3 +-
|
||||
tools/sunxi_toc0.c | 710 ++++++++++++++++++++++++++++++++++++++++++
|
||||
5 files changed, 905 insertions(+), 1 deletion(-)
|
||||
create mode 100644 tools/sunxi_toc0.c
|
||||
|
||||
diff --git a/common/image.c b/common/image.c
|
||||
index 59c52a1f9a..8f1634c120 100644
|
||||
--- a/common/image.c
|
||||
+++ b/common/image.c
|
||||
@@ -191,6 +191,7 @@ static const table_entry_t uimage_type[] = {
|
||||
{ IH_TYPE_MTKIMAGE, "mtk_image", "MediaTek BootROM loadable Image" },
|
||||
{ IH_TYPE_COPRO, "copro", "Coprocessor Image"},
|
||||
{ IH_TYPE_SUNXI_EGON, "sunxi_egon", "Allwinner eGON Boot Image" },
|
||||
+ { IH_TYPE_SUNXI_TOC0, "sunxi_toc0", "Allwinner TOC0 Boot Image" },
|
||||
{ -1, "", "", },
|
||||
};
|
||||
|
||||
diff --git a/include/image.h b/include/image.h
|
||||
index 73a763a693..7913753c01 100644
|
||||
--- a/include/image.h
|
||||
+++ b/include/image.h
|
||||
@@ -262,6 +262,7 @@ enum {
|
||||
IH_TYPE_IMX8IMAGE, /* Freescale IMX8Boot Image */
|
||||
IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/
|
||||
IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */
|
||||
+ IH_TYPE_SUNXI_TOC0, /* Allwinner TOC0 Boot Image */
|
||||
|
||||
IH_TYPE_COUNT, /* Number of image types */
|
||||
};
|
||||
diff --git a/include/sunxi_image.h b/include/sunxi_image.h
|
||||
index 5b2055c0af..bdf80ec0e0 100644
|
||||
--- a/include/sunxi_image.h
|
||||
+++ b/include/sunxi_image.h
|
||||
@@ -9,9 +9,12 @@
|
||||
*
|
||||
* Shared between mkimage and the SPL.
|
||||
*/
|
||||
+
|
||||
#ifndef SUNXI_IMAGE_H
|
||||
#define SUNXI_IMAGE_H
|
||||
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
#define BOOT0_MAGIC "eGON.BT0"
|
||||
#define BROM_STAMP_VALUE 0x5f0a6c39
|
||||
#define SPL_SIGNATURE "SPL" /* marks "sunxi" SPL header */
|
||||
@@ -79,4 +82,192 @@ struct boot_file_head {
|
||||
/* Compile time check to assure proper alignment of structure */
|
||||
typedef char boot_file_head_not_multiple_of_32[1 - 2*(sizeof(struct boot_file_head) % 32)];
|
||||
|
||||
+struct toc0_main_info {
|
||||
+ uint8_t name[8];
|
||||
+ __le32 magic;
|
||||
+ __le32 checksum;
|
||||
+ __le32 serial;
|
||||
+ __le32 status;
|
||||
+ __le32 num_items;
|
||||
+ __le32 length;
|
||||
+ uint8_t platform[4];
|
||||
+ uint8_t reserved[8];
|
||||
+ uint8_t end[4];
|
||||
+};
|
||||
+
|
||||
+#define TOC0_MAIN_INFO_NAME "TOC0.GLH"
|
||||
+#define TOC0_MAIN_INFO_MAGIC 0x89119800
|
||||
+#define TOC0_MAIN_INFO_END "MIE;"
|
||||
+
|
||||
+struct toc0_item_info {
|
||||
+ __le32 name;
|
||||
+ __le32 offset;
|
||||
+ __le32 length;
|
||||
+ __le32 status;
|
||||
+ __le32 type;
|
||||
+ __le32 load_addr;
|
||||
+ uint8_t reserved[4];
|
||||
+ uint8_t end[4];
|
||||
+};
|
||||
+
|
||||
+#define TOC0_ITEM_INFO_NAME_CERT 0x00010101
|
||||
+#define TOC0_ITEM_INFO_NAME_FIRMWARE 0x00010202
|
||||
+#define TOC0_ITEM_INFO_NAME_KEY 0x00010303
|
||||
+#define TOC0_ITEM_INFO_END "IIE;"
|
||||
+
|
||||
+struct toc0_small_tag {
|
||||
+ uint8_t tag;
|
||||
+ uint8_t length;
|
||||
+};
|
||||
+
|
||||
+typedef struct toc0_small_tag toc0_small_int;
|
||||
+typedef struct toc0_small_tag toc0_small_oct;
|
||||
+typedef struct toc0_small_tag toc0_small_seq;
|
||||
+typedef struct toc0_small_tag toc0_small_exp;
|
||||
+
|
||||
+#define TOC0_SMALL_INT(len) { 0x02, (len) }
|
||||
+#define TOC0_SMALL_SEQ(len) { 0x30, (len) }
|
||||
+#define TOC0_SMALL_EXP(tag, len) { 0xa0 | (tag), len }
|
||||
+
|
||||
+struct toc0_large_tag {
|
||||
+ uint8_t tag;
|
||||
+ uint8_t prefix;
|
||||
+ uint8_t length_hi;
|
||||
+ uint8_t length_lo;
|
||||
+};
|
||||
+
|
||||
+typedef struct toc0_large_tag toc0_large_int;
|
||||
+typedef struct toc0_large_tag toc0_large_bit;
|
||||
+typedef struct toc0_large_tag toc0_large_seq;
|
||||
+
|
||||
+#define TOC0_LARGE_INT(len) { 0x02, 0x82, (len) >> 8, (len) & 0xff }
|
||||
+#define TOC0_LARGE_BIT(len) { 0x03, 0x82, (len) >> 8, (len) & 0xff }
|
||||
+#define TOC0_LARGE_SEQ(len) { 0x30, 0x82, (len) >> 8, (len) & 0xff }
|
||||
+
|
||||
+/*
|
||||
+ * This looks somewhat like an X.509 certificate, but it is not valid BER.
|
||||
+ *
|
||||
+ * Some differences:
|
||||
+ * - Some X.509 certificate fields are missing or rearranged.
|
||||
+ * - Some sequences have the wrong tag.
|
||||
+ * - Zero-length sequences are accepted.
|
||||
+ * - Large strings and integers must be an even number of bytes long.
|
||||
+ * - Positive integers are not zero-extended to maintain their sign.
|
||||
+ *
|
||||
+ * See https://linux-sunxi.org/TOC0 for more information.
|
||||
+ */
|
||||
+struct toc0_cert_item {
|
||||
+ toc0_large_seq tag_totalSequence;
|
||||
+ struct toc0_totalSequence {
|
||||
+ toc0_large_seq tag_mainSequence;
|
||||
+ struct toc0_mainSequence {
|
||||
+ toc0_small_exp tag_explicit0;
|
||||
+ struct toc0_explicit0 {
|
||||
+ toc0_small_int tag_version;
|
||||
+ uint8_t version;
|
||||
+ } explicit0;
|
||||
+ toc0_small_int tag_serialNumber;
|
||||
+ uint8_t serialNumber;
|
||||
+ toc0_small_seq tag_signature;
|
||||
+ toc0_small_seq tag_issuer;
|
||||
+ toc0_small_seq tag_validity;
|
||||
+ toc0_small_seq tag_subject;
|
||||
+ toc0_large_seq tag_subjectPublicKeyInfo;
|
||||
+ struct toc0_subjectPublicKeyInfo {
|
||||
+ toc0_small_seq tag_algorithm;
|
||||
+ toc0_large_seq tag_publicKey;
|
||||
+ struct toc0_publicKey {
|
||||
+ toc0_large_int tag_n;
|
||||
+ uint8_t n[256];
|
||||
+ toc0_small_int tag_e;
|
||||
+ uint8_t e[3];
|
||||
+ } publicKey;
|
||||
+ } subjectPublicKeyInfo;
|
||||
+ toc0_small_exp tag_explicit3;
|
||||
+ struct toc0_explicit3 {
|
||||
+ toc0_small_seq tag_extension;
|
||||
+ struct toc0_extension {
|
||||
+ toc0_small_int tag_digest;
|
||||
+ uint8_t digest[32];
|
||||
+ } extension;
|
||||
+ } explicit3;
|
||||
+ } mainSequence;
|
||||
+ toc0_large_bit tag_sigSequence;
|
||||
+ struct toc0_sigSequence {
|
||||
+ toc0_small_seq tag_algorithm;
|
||||
+ toc0_large_bit tag_signature;
|
||||
+ uint8_t signature[256];
|
||||
+ } sigSequence;
|
||||
+ } totalSequence;
|
||||
+};
|
||||
+
|
||||
+#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
|
||||
+
|
||||
+#define TOC0_CERT_ITEM { \
|
||||
+ TOC0_LARGE_SEQ(sizeof(struct toc0_totalSequence)), \
|
||||
+ { \
|
||||
+ TOC0_LARGE_SEQ(sizeof(struct toc0_mainSequence)), \
|
||||
+ { \
|
||||
+ TOC0_SMALL_EXP(0, sizeof(struct toc0_explicit0)), \
|
||||
+ { \
|
||||
+ TOC0_SMALL_INT(sizeof_field(struct toc0_explicit0, version)), \
|
||||
+ 0, \
|
||||
+ }, \
|
||||
+ TOC0_SMALL_INT(sizeof_field(struct toc0_mainSequence, serialNumber)), \
|
||||
+ 0, \
|
||||
+ TOC0_SMALL_SEQ(0), \
|
||||
+ TOC0_SMALL_SEQ(0), \
|
||||
+ TOC0_SMALL_SEQ(0), \
|
||||
+ TOC0_SMALL_SEQ(0), \
|
||||
+ TOC0_LARGE_SEQ(sizeof(struct toc0_subjectPublicKeyInfo)), \
|
||||
+ { \
|
||||
+ TOC0_SMALL_SEQ(0), \
|
||||
+ TOC0_LARGE_SEQ(sizeof(struct toc0_publicKey)), \
|
||||
+ { \
|
||||
+ TOC0_LARGE_INT(sizeof_field(struct toc0_publicKey, n)), \
|
||||
+ {}, \
|
||||
+ TOC0_SMALL_INT(sizeof_field(struct toc0_publicKey, e)), \
|
||||
+ {}, \
|
||||
+ }, \
|
||||
+ }, \
|
||||
+ TOC0_SMALL_EXP(3, sizeof(struct toc0_explicit3)), \
|
||||
+ { \
|
||||
+ TOC0_SMALL_SEQ(sizeof(struct toc0_extension)), \
|
||||
+ { \
|
||||
+ TOC0_SMALL_INT(sizeof_field(struct toc0_extension, digest)), \
|
||||
+ {}, \
|
||||
+ }, \
|
||||
+ }, \
|
||||
+ }, \
|
||||
+ TOC0_LARGE_BIT(sizeof(struct toc0_sigSequence)), \
|
||||
+ { \
|
||||
+ TOC0_SMALL_SEQ(0), \
|
||||
+ TOC0_LARGE_BIT(sizeof_field(struct toc0_sigSequence, signature)), \
|
||||
+ {}, \
|
||||
+ }, \
|
||||
+ }, \
|
||||
+}
|
||||
+
|
||||
+struct toc0_key_item {
|
||||
+ __le32 vendor_id;
|
||||
+ __le32 key0_n_len;
|
||||
+ __le32 key0_e_len;
|
||||
+ __le32 key1_n_len;
|
||||
+ __le32 key1_e_len;
|
||||
+ __le32 sig_len;
|
||||
+ uint8_t key0[512];
|
||||
+ uint8_t key1[512];
|
||||
+ uint8_t reserved[32];
|
||||
+ uint8_t sig[256];
|
||||
+};
|
||||
+
|
||||
+#define TOC0_DEFAULT_NUM_ITEMS 3
|
||||
+#define TOC0_DEFAULT_HEADER_LEN \
|
||||
+ ALIGN( \
|
||||
+ sizeof(struct toc0_main_info) + \
|
||||
+ sizeof(struct toc0_item_info) * TOC0_DEFAULT_NUM_ITEMS + \
|
||||
+ sizeof(struct toc0_cert_item) + \
|
||||
+ sizeof(struct toc0_key_item), \
|
||||
+ 32)
|
||||
+
|
||||
#endif
|
||||
diff --git a/tools/Makefile b/tools/Makefile
|
||||
index 4a86321f64..46a4f9c0f1 100644
|
||||
--- a/tools/Makefile
|
||||
+++ b/tools/Makefile
|
||||
@@ -96,7 +96,8 @@ AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/aes/, \
|
||||
|
||||
# Cryptographic helpers that depend on openssl/libcrypto
|
||||
LIBCRYPTO_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/, \
|
||||
- fdt-libcrypto.o)
|
||||
+ fdt-libcrypto.o)\
|
||||
+ sunxi_toc0.o \
|
||||
|
||||
ROCKCHIP_OBS = lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
|
||||
|
||||
diff --git a/tools/sunxi_toc0.c b/tools/sunxi_toc0.c
|
||||
new file mode 100644
|
||||
index 0000000000..f0bf86b477
|
||||
--- /dev/null
|
||||
+++ b/tools/sunxi_toc0.c
|
||||
@@ -0,0 +1,710 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * (C) Copyright 2018 Arm Ltd.
|
||||
+ * (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org>
|
||||
+ */
|
||||
+
|
||||
+#include <assert.h>
|
||||
+#include <stdint.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <openssl/asn1t.h>
|
||||
+#include <openssl/pem.h>
|
||||
+#include <openssl/rsa.h>
|
||||
+
|
||||
+#include <image.h>
|
||||
+#include <sunxi_image.h>
|
||||
+
|
||||
+#include "imagetool.h"
|
||||
+#include "mkimage.h"
|
||||
+
|
||||
+/*
|
||||
+ * NAND requires 8K padding. For other devices, BROM requires only
|
||||
+ * 512B padding, but let's use the larger padding to cover everything.
|
||||
+ */
|
||||
+#define PAD_SIZE 8192
|
||||
+
|
||||
+#define pr_err(fmt, args...) fprintf(stderr, "TOC0 ERR: " fmt, ##args)
|
||||
+#define pr_warn(fmt, args...) fprintf(stderr, "TOC0 WRN: " fmt, ##args)
|
||||
+#define pr_info(fmt, args...) fprintf(stderr, "TOC0 INF: " fmt, ##args)
|
||||
+
|
||||
+static char *fw_key_file = "fw_key.pem";
|
||||
+static char *key_item_file = "key_item.bin";
|
||||
+static char *root_key_file = "root_key.pem";
|
||||
+
|
||||
+/*
|
||||
+ * Create a key item in @buf, containing the public keys @root_key and @fw_key,
|
||||
+ * and signed by the RSA key @root_key.
|
||||
+ */
|
||||
+static int toc0_create_key_item(uint8_t *buf, uint32_t *len,
|
||||
+ RSA *root_key, RSA *fw_key)
|
||||
+{
|
||||
+ struct toc0_key_item *key_item = (void *)buf;
|
||||
+ uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ unsigned int sig_len;
|
||||
+ int n_len, e_len;
|
||||
+
|
||||
+ /* Store key 0. */
|
||||
+ n_len = BN_bn2bin(RSA_get0_n(root_key), key_item->key0);
|
||||
+ e_len = BN_bn2bin(RSA_get0_e(root_key), key_item->key0 + n_len);
|
||||
+ if (n_len + e_len > sizeof(key_item->key0)) {
|
||||
+ pr_err("Root key is too large\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ key_item->key0_n_len = cpu_to_le32(n_len);
|
||||
+ key_item->key0_e_len = cpu_to_le32(e_len);
|
||||
+
|
||||
+ /* Store key 1. */
|
||||
+ n_len = BN_bn2bin(RSA_get0_n(fw_key), key_item->key1);
|
||||
+ e_len = BN_bn2bin(RSA_get0_e(fw_key), key_item->key1 + n_len);
|
||||
+ if (n_len + e_len > sizeof(key_item->key1)) {
|
||||
+ pr_err("Firmware key is too large\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ key_item->key1_n_len = cpu_to_le32(n_len);
|
||||
+ key_item->key1_e_len = cpu_to_le32(e_len);
|
||||
+
|
||||
+ /* Sign the key item. */
|
||||
+ key_item->sig_len = cpu_to_le32(RSA_size(root_key));
|
||||
+ SHA256(buf, key_item->sig - buf, digest);
|
||||
+ if (!RSA_sign(NID_sha256, digest, sizeof(digest),
|
||||
+ key_item->sig, &sig_len, root_key)) {
|
||||
+ pr_err("Failed to sign key item\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (sig_len != sizeof(key_item->sig)) {
|
||||
+ pr_err("Signature length mismatch\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ *len = sizeof(*key_item);
|
||||
+ ret = EXIT_SUCCESS;
|
||||
+
|
||||
+err:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Verify the key item in @buf, containing two public keys @key0 and @key1,
|
||||
+ * and signed by the RSA key @key0. If @root_key is provided, only signatures
|
||||
+ * by that key will be accepted. @key1 is returned in @key.
|
||||
+ */
|
||||
+static int toc0_verify_key_item(const uint8_t *buf, uint32_t len,
|
||||
+ RSA *root_key, RSA **fw_key)
|
||||
+{
|
||||
+ struct toc0_key_item *key_item = (void *)buf;
|
||||
+ uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ int n_len, e_len;
|
||||
+ RSA *key0 = NULL;
|
||||
+ RSA *key1 = NULL;
|
||||
+ BIGNUM *n, *e;
|
||||
+
|
||||
+ if (len < sizeof(*key_item))
|
||||
+ goto err;
|
||||
+
|
||||
+ /* Load key 0. */
|
||||
+ n_len = le32_to_cpu(key_item->key0_n_len);
|
||||
+ e_len = le32_to_cpu(key_item->key0_e_len);
|
||||
+ if (n_len + e_len > sizeof(key_item->key0))
|
||||
+ goto err;
|
||||
+ n = BN_bin2bn(key_item->key0, n_len, NULL);
|
||||
+ e = BN_bin2bn(key_item->key0 + n_len, e_len, NULL);
|
||||
+ key0 = RSA_new();
|
||||
+ if (!key0)
|
||||
+ goto err;
|
||||
+ if (!RSA_set0_key(key0, n, e, NULL))
|
||||
+ goto err;
|
||||
+
|
||||
+ /* If a root key was provided, compare it to key 0. */
|
||||
+ if (root_key && (BN_cmp(n, RSA_get0_n(root_key)) ||
|
||||
+ BN_cmp(e, RSA_get0_e(root_key)))) {
|
||||
+ pr_err("Root key mismatch\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /* Verify the key item signature. */
|
||||
+ SHA256(buf, key_item->sig - buf, digest);
|
||||
+ if (!RSA_verify(NID_sha256, digest, sizeof(digest),
|
||||
+ key_item->sig, le32_to_cpu(key_item->sig_len), key0)) {
|
||||
+ pr_err("Bad key item signature\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ if (fw_key) {
|
||||
+ /* Load key 1. */
|
||||
+ n_len = le32_to_cpu(key_item->key1_n_len);
|
||||
+ e_len = le32_to_cpu(key_item->key1_e_len);
|
||||
+ if (n_len + e_len > sizeof(key_item->key1))
|
||||
+ goto err;
|
||||
+ n = BN_bin2bn(key_item->key1, n_len, NULL);
|
||||
+ e = BN_bin2bn(key_item->key1 + n_len, e_len, NULL);
|
||||
+ key1 = RSA_new();
|
||||
+ if (!key1)
|
||||
+ goto err;
|
||||
+ if (!RSA_set0_key(key1, n, e, NULL))
|
||||
+ goto err;
|
||||
+
|
||||
+ if (*fw_key) {
|
||||
+ /* If a FW key was provided, compare it to key 1. */
|
||||
+ if (BN_cmp(n, RSA_get0_n(*fw_key)) ||
|
||||
+ BN_cmp(e, RSA_get0_e(*fw_key))) {
|
||||
+ pr_err("Firmware key mismatch\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Otherwise, send key1 back to the caller. */
|
||||
+ *fw_key = key1;
|
||||
+ key1 = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = EXIT_SUCCESS;
|
||||
+
|
||||
+err:
|
||||
+ RSA_free(key0);
|
||||
+ RSA_free(key1);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Create a certificate in @buf, describing the firmware with SHA256 digest
|
||||
+ * @digest, and signed by the RSA key @fw_key.
|
||||
+ */
|
||||
+static int toc0_create_cert_item(uint8_t *buf, uint32_t *len, RSA *fw_key,
|
||||
+ uint8_t digest[static SHA256_DIGEST_LENGTH])
|
||||
+{
|
||||
+ static const struct toc0_cert_item cert_item_template = TOC0_CERT_ITEM;
|
||||
+ struct toc0_cert_item *cert_item = (void *)buf;
|
||||
+ uint8_t cert_digest[SHA256_DIGEST_LENGTH];
|
||||
+ struct toc0_totalSequence *totalSequence;
|
||||
+ struct toc0_sigSequence *sigSequence;
|
||||
+ struct toc0_extension *extension;
|
||||
+ struct toc0_publicKey *publicKey;
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ unsigned int sig_len;
|
||||
+
|
||||
+ memcpy(cert_item, &cert_item_template, sizeof(*cert_item));
|
||||
+ *len = sizeof(*cert_item);
|
||||
+
|
||||
+ /*
|
||||
+ * Fill in the public key.
|
||||
+ *
|
||||
+ * Only 2048-bit RSA keys are supported. Since this uses a fixed-size
|
||||
+ * structure, it may fail for non-standard exponents.
|
||||
+ */
|
||||
+ totalSequence = &cert_item->totalSequence;
|
||||
+ publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey;
|
||||
+ if (BN_bn2binpad(RSA_get0_n(fw_key), publicKey->n, sizeof(publicKey->n)) < 0 ||
|
||||
+ BN_bn2binpad(RSA_get0_e(fw_key), publicKey->e, sizeof(publicKey->e)) < 0) {
|
||||
+ pr_err("Incorrect key size\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /* Fill in the firmware digest. */
|
||||
+ extension = &totalSequence->mainSequence.explicit3.extension;
|
||||
+ memcpy(&extension->digest, digest, SHA256_DIGEST_LENGTH);
|
||||
+
|
||||
+ /*
|
||||
+ * Sign the certificate.
|
||||
+ *
|
||||
+ * In older SBROM versions (and by default in newer versions),
|
||||
+ * the last 4 bytes of the certificate are not signed.
|
||||
+ *
|
||||
+ * (The buffer passed to SHA256 starts at tag_mainSequence, but
|
||||
+ * the buffer size does not include the length of that tag.)
|
||||
+ */
|
||||
+ SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence),
|
||||
+ cert_digest);
|
||||
+ sigSequence = &totalSequence->sigSequence;
|
||||
+ if (!RSA_sign(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH,
|
||||
+ sigSequence->signature, &sig_len, fw_key)) {
|
||||
+ pr_err("Failed to sign certificate\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (sig_len != sizeof(sigSequence->signature)) {
|
||||
+ pr_err("Signature length mismatch\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ ret = EXIT_SUCCESS;
|
||||
+
|
||||
+err:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Verify the certificate in @buf, describing the firmware with SHA256 digest
|
||||
+ * @digest, and signed by the RSA key contained within. If @fw_key is provided,
|
||||
+ * only that key will be accepted.
|
||||
+ *
|
||||
+ * This function is only expected to work with images created by mkimage.
|
||||
+ */
|
||||
+static int toc0_verify_cert_item(const uint8_t *buf, uint32_t len, RSA *fw_key,
|
||||
+ uint8_t digest[static SHA256_DIGEST_LENGTH])
|
||||
+{
|
||||
+ const struct toc0_cert_item *cert_item = (const void *)buf;
|
||||
+ uint8_t cert_digest[SHA256_DIGEST_LENGTH];
|
||||
+ const struct toc0_totalSequence *totalSequence;
|
||||
+ const struct toc0_sigSequence *sigSequence;
|
||||
+ const struct toc0_extension *extension;
|
||||
+ const struct toc0_publicKey *publicKey;
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ RSA *key = NULL;
|
||||
+ BIGNUM *n, *e;
|
||||
+
|
||||
+ /* Extract the public key from the certificate. */
|
||||
+ totalSequence = &cert_item->totalSequence;
|
||||
+ publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey;
|
||||
+ n = BN_bin2bn(publicKey->n, sizeof(publicKey->n), NULL);
|
||||
+ e = BN_bin2bn(publicKey->e, sizeof(publicKey->e), NULL);
|
||||
+ key = RSA_new();
|
||||
+ if (!key)
|
||||
+ goto err;
|
||||
+ if (!RSA_set0_key(key, n, e, NULL))
|
||||
+ goto err;
|
||||
+
|
||||
+ /* If a key was provided, compare it to the embedded key. */
|
||||
+ if (fw_key && (BN_cmp(RSA_get0_n(key), RSA_get0_n(fw_key)) ||
|
||||
+ BN_cmp(RSA_get0_e(key), RSA_get0_e(fw_key)))) {
|
||||
+ pr_err("Firmware key mismatch\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /* If a digest was provided, compare it to the embedded digest. */
|
||||
+ extension = &totalSequence->mainSequence.explicit3.extension;
|
||||
+ if (digest && memcmp(&extension->digest, digest, SHA256_DIGEST_LENGTH)) {
|
||||
+ pr_err("Firmware digest mismatch\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /* Verify the certificate's signature. See the comment above. */
|
||||
+ SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence),
|
||||
+ cert_digest);
|
||||
+ sigSequence = &totalSequence->sigSequence;
|
||||
+ if (!RSA_verify(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH,
|
||||
+ sigSequence->signature,
|
||||
+ sizeof(sigSequence->signature), key)) {
|
||||
+ pr_err("Bad certificate signature\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ ret = EXIT_SUCCESS;
|
||||
+
|
||||
+err:
|
||||
+ RSA_free(key);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Always create a TOC0 containing 3 items. The extra item will be ignored on
|
||||
+ * SoCs which do not support it.
|
||||
+ */
|
||||
+static int toc0_create(uint8_t *buf, uint32_t len, RSA *root_key, RSA *fw_key,
|
||||
+ uint8_t *key_item, uint32_t key_item_len,
|
||||
+ uint8_t *fw_item, uint32_t fw_item_len, uint32_t fw_addr)
|
||||
+{
|
||||
+ struct toc0_main_info *main = (void *)buf;
|
||||
+ struct toc0_item_info *item = (void *)(main + 1);
|
||||
+ uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
+ uint32_t *buf32 = (void *)buf;
|
||||
+ RSA *orig_fw_key = fw_key;
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ uint32_t checksum = 0;
|
||||
+ uint32_t item_offset;
|
||||
+ uint32_t item_length;
|
||||
+ int i;
|
||||
+
|
||||
+ /* Hash the firmware for inclusion in the certificate. */
|
||||
+ SHA256(fw_item, fw_item_len, digest);
|
||||
+
|
||||
+ /* Create the main TOC0 header, containing three items. */
|
||||
+ memcpy(main->name, TOC0_MAIN_INFO_NAME, sizeof(main->name));
|
||||
+ main->magic = cpu_to_le32(TOC0_MAIN_INFO_MAGIC);
|
||||
+ main->checksum = cpu_to_le32(BROM_STAMP_VALUE);
|
||||
+ main->num_items = cpu_to_le32(TOC0_DEFAULT_NUM_ITEMS);
|
||||
+ memcpy(main->end, TOC0_MAIN_INFO_END, sizeof(main->end));
|
||||
+
|
||||
+ /* The first item links the ROTPK to the signing key. */
|
||||
+ item_offset = sizeof(*main) + TOC0_DEFAULT_NUM_ITEMS * sizeof(*item);
|
||||
+ /* Using an existing key item avoids needing the root private key. */
|
||||
+ if (key_item) {
|
||||
+ item_length = sizeof(*key_item);
|
||||
+ if (toc0_verify_key_item(key_item, item_length,
|
||||
+ root_key, &fw_key))
|
||||
+ goto err;
|
||||
+ memcpy(buf + item_offset, key_item, item_length);
|
||||
+ } else if (toc0_create_key_item(buf + item_offset, &item_length,
|
||||
+ root_key, fw_key)) {
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ item->name = cpu_to_le32(TOC0_ITEM_INFO_NAME_KEY);
|
||||
+ item->offset = cpu_to_le32(item_offset);
|
||||
+ item->length = cpu_to_le32(item_length);
|
||||
+ memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
|
||||
+
|
||||
+ /* The second item contains a certificate signed by the firmware key. */
|
||||
+ item_offset = item_offset + item_length;
|
||||
+ if (toc0_create_cert_item(buf + item_offset, &item_length,
|
||||
+ fw_key, digest))
|
||||
+ goto err;
|
||||
+
|
||||
+ item++;
|
||||
+ item->name = cpu_to_le32(TOC0_ITEM_INFO_NAME_CERT);
|
||||
+ item->offset = cpu_to_le32(item_offset);
|
||||
+ item->length = cpu_to_le32(item_length);
|
||||
+ memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
|
||||
+
|
||||
+ /* The third item contains the actual boot code. */
|
||||
+ item_offset = ALIGN(item_offset + item_length, 32);
|
||||
+ item_length = fw_item_len;
|
||||
+ if (buf + item_offset != fw_item)
|
||||
+ memmove(buf + item_offset, fw_item, item_length);
|
||||
+
|
||||
+ item++;
|
||||
+ item->name = cpu_to_le32(TOC0_ITEM_INFO_NAME_FIRMWARE);
|
||||
+ item->offset = cpu_to_le32(item_offset);
|
||||
+ item->length = cpu_to_le32(item_length);
|
||||
+ item->load_addr = cpu_to_le32(fw_addr);
|
||||
+ memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
|
||||
+
|
||||
+ /* Pad to the required block size with 0xff to be flash-friendly. */
|
||||
+ item_offset = item_offset + item_length;
|
||||
+ item_length = ALIGN(item_offset, PAD_SIZE) - item_offset;
|
||||
+ memset(buf + item_offset, 0xff, item_length);
|
||||
+
|
||||
+ /* Fill in the total padded file length. */
|
||||
+ item_offset = item_offset + item_length;
|
||||
+ main->length = cpu_to_le32(item_offset);
|
||||
+
|
||||
+ /* Verify enough space was provided when creating the image. */
|
||||
+ assert(len >= item_offset);
|
||||
+
|
||||
+ /* Calculate the checksum. Yes, it's that simple. */
|
||||
+ for (i = 0; i < item_offset / 4; ++i)
|
||||
+ checksum += le32_to_cpu(buf32[i]);
|
||||
+ main->checksum = cpu_to_le32(checksum);
|
||||
+
|
||||
+ ret = EXIT_SUCCESS;
|
||||
+
|
||||
+err:
|
||||
+ if (fw_key != orig_fw_key)
|
||||
+ RSA_free(fw_key);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct toc0_item_info *
|
||||
+toc0_find_item(const struct toc0_main_info *main,
|
||||
+ uint32_t name, uint32_t *offset, uint32_t *length)
|
||||
+{
|
||||
+ const struct toc0_item_info *item = (void *)(main + 1);
|
||||
+ uint32_t item_offset, item_length;
|
||||
+ uint32_t num_items, main_length;
|
||||
+ int i;
|
||||
+
|
||||
+ num_items = le32_to_cpu(main->num_items);
|
||||
+ main_length = le32_to_cpu(main->length);
|
||||
+
|
||||
+ for (i = 0; i < num_items; ++i, ++item) {
|
||||
+ if (le32_to_cpu(item->name) != name)
|
||||
+ continue;
|
||||
+
|
||||
+ item_offset = le32_to_cpu(item->offset);
|
||||
+ item_length = le32_to_cpu(item->length);
|
||||
+
|
||||
+ if (item_offset > main_length ||
|
||||
+ item_length > main_length - item_offset)
|
||||
+ continue;
|
||||
+
|
||||
+ *offset = item_offset;
|
||||
+ *length = item_length;
|
||||
+
|
||||
+ return item;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int toc0_verify(const uint8_t *buf, uint32_t len, RSA *root_key)
|
||||
+{
|
||||
+ const struct toc0_main_info *main = (void *)buf;
|
||||
+ const struct toc0_item_info *item;
|
||||
+ uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
+ uint32_t main_length = le32_to_cpu(main->length);
|
||||
+ uint32_t checksum = BROM_STAMP_VALUE;
|
||||
+ uint32_t *buf32 = (void *)buf;
|
||||
+ uint32_t length, offset;
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ RSA *fw_key = NULL;
|
||||
+ int i;
|
||||
+
|
||||
+ if (len < main_length)
|
||||
+ goto err;
|
||||
+
|
||||
+ /* Verify the main header. */
|
||||
+ if (memcmp(main->name, TOC0_MAIN_INFO_NAME, sizeof(main->name)))
|
||||
+ goto err;
|
||||
+ if (le32_to_cpu(main->magic) != TOC0_MAIN_INFO_MAGIC)
|
||||
+ goto err;
|
||||
+ /* Verify the checksum without modifying the buffer. */
|
||||
+ for (i = 0; i < main_length / 4; ++i)
|
||||
+ checksum += le32_to_cpu(buf32[i]);
|
||||
+ if (checksum != 2 * le32_to_cpu(main->checksum))
|
||||
+ goto err;
|
||||
+ /* The length must be at least 512 byte aligned. */
|
||||
+ if (main_length % 512)
|
||||
+ goto err;
|
||||
+ if (memcmp(main->end, TOC0_MAIN_INFO_END, sizeof(main->end)))
|
||||
+ goto err;
|
||||
+
|
||||
+ /* Verify the key item if present. */
|
||||
+ item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_KEY, &offset, &length);
|
||||
+ if (!item)
|
||||
+ fw_key = root_key;
|
||||
+ else if (toc0_verify_key_item(buf + offset, length, root_key, &fw_key))
|
||||
+ goto err;
|
||||
+
|
||||
+ /* Hash the firmware to compare with the certificate. */
|
||||
+ item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_FIRMWARE, &offset, &length);
|
||||
+ if (!item) {
|
||||
+ pr_err("Image does not contain a firmware item\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ SHA256(buf + offset, length, digest);
|
||||
+
|
||||
+ /* Verify the certificate item. */
|
||||
+ item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_CERT, &offset, &length);
|
||||
+ if (!item) {
|
||||
+ pr_err("Image does not contain a certificate item\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (toc0_verify_cert_item(buf + offset, length, fw_key, digest))
|
||||
+ goto err;
|
||||
+
|
||||
+ ret = EXIT_SUCCESS;
|
||||
+
|
||||
+err:
|
||||
+ if (fw_key != root_key)
|
||||
+ RSA_free(fw_key);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int toc0_check_params(struct image_tool_params *params)
|
||||
+{
|
||||
+ if (!params->dflag)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (params->keydir) {
|
||||
+ asprintf(&fw_key_file, "%s/%s", params->keydir, fw_key_file);
|
||||
+ asprintf(&key_item_file, "%s/%s", params->keydir, key_item_file);
|
||||
+ asprintf(&root_key_file, "%s/%s", params->keydir, root_key_file);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int toc0_verify_header(unsigned char *buf, int image_size,
|
||||
+ struct image_tool_params *params)
|
||||
+{
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ RSA *root_key = NULL;
|
||||
+ FILE *fp;
|
||||
+
|
||||
+ /* A root public key is optional. */
|
||||
+ fp = fopen(root_key_file, "rb");
|
||||
+ if (fp) {
|
||||
+ pr_info("Verifying image with existing root key\n");
|
||||
+ root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
|
||||
+ if (!root_key)
|
||||
+ root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
|
||||
+ fclose(fp);
|
||||
+ if (!root_key) {
|
||||
+ pr_err("Failed to read public key from '%s'\n",
|
||||
+ root_key_file);
|
||||
+ goto err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = toc0_verify(buf, image_size, root_key);
|
||||
+
|
||||
+err:
|
||||
+ RSA_free(root_key);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const char *toc0_item_name(uint32_t name)
|
||||
+{
|
||||
+ if (name == TOC0_ITEM_INFO_NAME_CERT)
|
||||
+ return "Certificate";
|
||||
+ if (name == TOC0_ITEM_INFO_NAME_FIRMWARE)
|
||||
+ return "Firmware";
|
||||
+ if (name == TOC0_ITEM_INFO_NAME_KEY)
|
||||
+ return "Key";
|
||||
+ return "(unknown)";
|
||||
+}
|
||||
+
|
||||
+static void toc0_print_header(const void *buf)
|
||||
+{
|
||||
+ const struct toc0_main_info *main = buf;
|
||||
+ const struct toc0_item_info *item = (void *)(main + 1);
|
||||
+ uint32_t head_length, main_length, num_items;
|
||||
+ uint32_t item_offset, item_length, item_name;
|
||||
+ int load_addr = -1;
|
||||
+ int i;
|
||||
+
|
||||
+ num_items = le32_to_cpu(main->num_items);
|
||||
+ head_length = sizeof(*main) + num_items * sizeof(*item);
|
||||
+ main_length = le32_to_cpu(main->length);
|
||||
+
|
||||
+ printf("Allwinner TOC0 Image\n"
|
||||
+ "Size: %d bytes\n"
|
||||
+ "Contents: %d items\n"
|
||||
+ " 00000000:%08x Headers\n",
|
||||
+ main_length, num_items, head_length);
|
||||
+
|
||||
+ for (i = 0; i < num_items; ++i, ++item) {
|
||||
+ item_offset = le32_to_cpu(item->offset);
|
||||
+ item_length = le32_to_cpu(item->length);
|
||||
+ item_name = le32_to_cpu(item->name);
|
||||
+
|
||||
+ if (item_name == TOC0_ITEM_INFO_NAME_FIRMWARE)
|
||||
+ load_addr = le32_to_cpu(item->load_addr);
|
||||
+
|
||||
+ printf(" %08x:%08x %s\n",
|
||||
+ item_offset, item_length,
|
||||
+ toc0_item_name(item_name));
|
||||
+ }
|
||||
+
|
||||
+ if (num_items && item_offset + item_length < main_length) {
|
||||
+ item_offset = item_offset + item_length;
|
||||
+ item_length = main_length - item_offset;
|
||||
+
|
||||
+ printf(" %08x:%08x Padding\n",
|
||||
+ item_offset, item_length);
|
||||
+ }
|
||||
+
|
||||
+ if (load_addr != -1)
|
||||
+ printf("Load address: 0x%08x\n", load_addr);
|
||||
+}
|
||||
+
|
||||
+static void toc0_set_header(void *buf, struct stat *sbuf, int ifd,
|
||||
+ struct image_tool_params *params)
|
||||
+{
|
||||
+ uint32_t key_item_len = 0;
|
||||
+ uint8_t *key_item = NULL;
|
||||
+ int ret = EXIT_FAILURE;
|
||||
+ RSA *root_key = NULL;
|
||||
+ RSA *fw_key = NULL;
|
||||
+ FILE *fp;
|
||||
+
|
||||
+ /* Either a key item or the root private key is required. */
|
||||
+ fp = fopen(key_item_file, "rb");
|
||||
+ if (fp) {
|
||||
+ pr_info("Creating image using existing key item\n");
|
||||
+ key_item_len = sizeof(struct toc0_key_item);
|
||||
+ key_item = OPENSSL_malloc(key_item_len);
|
||||
+ if (!key_item || fread(key_item, key_item_len, 1, fp) != 1) {
|
||||
+ pr_err("Failed to read key item from '%s'\n",
|
||||
+ root_key_file);
|
||||
+ goto err;
|
||||
+ }
|
||||
+ fclose(fp);
|
||||
+ fp = NULL;
|
||||
+ }
|
||||
+
|
||||
+ fp = fopen(root_key_file, "rb");
|
||||
+ if (fp) {
|
||||
+ root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
|
||||
+ if (!root_key)
|
||||
+ root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
|
||||
+ fclose(fp);
|
||||
+ fp = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* When using an existing key item, the root key is optional. */
|
||||
+ if (!key_item && (!root_key || !RSA_get0_d(root_key))) {
|
||||
+ pr_err("Failed to read private key from '%s'\n",
|
||||
+ root_key_file);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /* The certificate/firmware private key is always required. */
|
||||
+ fp = fopen(fw_key_file, "rb");
|
||||
+ if (fp) {
|
||||
+ fw_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
|
||||
+ fclose(fp);
|
||||
+ fp = NULL;
|
||||
+ }
|
||||
+ if (!fw_key) {
|
||||
+ /* If the root key is a private key, it can be used instead. */
|
||||
+ if (root_key && RSA_get0_d(root_key)) {
|
||||
+ pr_info("Using root key as firmware key\n");
|
||||
+ fw_key = root_key;
|
||||
+ } else {
|
||||
+ pr_err("Failed to read private key from '%s'\n",
|
||||
+ fw_key_file);
|
||||
+ goto err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Warn about potential compatiblity issues. */
|
||||
+ if (key_item || fw_key != root_key)
|
||||
+ pr_warn("Only H6 supports separate root and firmware keys\n");
|
||||
+
|
||||
+ ret = toc0_create(buf, params->file_size, root_key, fw_key,
|
||||
+ key_item, key_item_len,
|
||||
+ buf + TOC0_DEFAULT_HEADER_LEN,
|
||||
+ params->orig_file_size, params->addr);
|
||||
+
|
||||
+err:
|
||||
+ OPENSSL_free(key_item);
|
||||
+ OPENSSL_free(root_key);
|
||||
+ if (fw_key != root_key)
|
||||
+ OPENSSL_free(fw_key);
|
||||
+ if (fp)
|
||||
+ fclose(fp);
|
||||
+
|
||||
+ if (ret != EXIT_SUCCESS)
|
||||
+ exit(ret);
|
||||
+}
|
||||
+
|
||||
+static int toc0_check_image_type(uint8_t type)
|
||||
+{
|
||||
+ return type == IH_TYPE_SUNXI_TOC0 ? 0 : 1;
|
||||
+}
|
||||
+
|
||||
+static int toc0_vrec_header(struct image_tool_params *params,
|
||||
+ struct image_type_params *tparams)
|
||||
+{
|
||||
+ tparams->hdr = calloc(tparams->header_size, 1);
|
||||
+
|
||||
+ /* Save off the unpadded data size for SHA256 calculation. */
|
||||
+ params->orig_file_size = params->file_size - TOC0_DEFAULT_HEADER_LEN;
|
||||
+
|
||||
+ /* Return padding to 8K blocks. */
|
||||
+ return ALIGN(params->file_size, PAD_SIZE) - params->file_size;
|
||||
+}
|
||||
+
|
||||
+U_BOOT_IMAGE_TYPE(
|
||||
+ sunxi_toc0,
|
||||
+ "Allwinner TOC0 Boot Image support",
|
||||
+ TOC0_DEFAULT_HEADER_LEN,
|
||||
+ NULL,
|
||||
+ toc0_check_params,
|
||||
+ toc0_verify_header,
|
||||
+ toc0_print_header,
|
||||
+ toc0_set_header,
|
||||
+ NULL,
|
||||
+ toc0_check_image_type,
|
||||
+ NULL,
|
||||
+ toc0_vrec_header
|
||||
+);
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
From 67097556d368d16917be3590384d8e988266aa59 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sun, 20 Jun 2021 14:23:11 -0500
|
||||
Subject: [PATCH 03/10] sunxi: Support both SPL image types
|
||||
|
||||
SPL uses the image header to detect the boot device and to find the
|
||||
offset of U-Boot proper. Since this information is stored differently in
|
||||
eGON and TOC0 image headers, add code to find the correct value based on
|
||||
the image type currently in use.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
arch/arm/include/asm/arch-sunxi/spl.h | 2 --
|
||||
arch/arm/mach-sunxi/board.c | 20 ++++++++++++++------
|
||||
include/sunxi_image.h | 14 ++++++++++++++
|
||||
3 files changed, 28 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
|
||||
index 58cdf806d9..157b11e489 100644
|
||||
--- a/arch/arm/include/asm/arch-sunxi/spl.h
|
||||
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
|
||||
@@ -19,8 +19,6 @@
|
||||
#define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10
|
||||
#define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12
|
||||
|
||||
-#define is_boot0_magic(addr) (memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0)
|
||||
-
|
||||
uint32_t sunxi_get_boot_device(void);
|
||||
|
||||
#endif
|
||||
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
|
||||
index d9b04f75fc..bbed5838c1 100644
|
||||
--- a/arch/arm/mach-sunxi/board.c
|
||||
+++ b/arch/arm/mach-sunxi/board.c
|
||||
@@ -246,10 +246,13 @@ void s_init(void)
|
||||
|
||||
static int sunxi_get_boot_source(void)
|
||||
{
|
||||
- if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
|
||||
- return SUNXI_INVALID_BOOT_SOURCE;
|
||||
+ if (is_egon_image((void *)SPL_ADDR))
|
||||
+ return ((struct boot_file_head *)SPL_ADDR)->boot_media;
|
||||
+ if (is_toc0_image((void *)SPL_ADDR))
|
||||
+ return ((struct toc0_main_info *)SPL_ADDR)->platform[0];
|
||||
|
||||
- return readb(SPL_ADDR + 0x28);
|
||||
+ /* Not a valid BROM image, so we must have been booted via FEL. */
|
||||
+ return SUNXI_INVALID_BOOT_SOURCE;
|
||||
}
|
||||
|
||||
/* The sunxi internal brom will try to loader external bootloader
|
||||
@@ -294,13 +297,18 @@ uint32_t sunxi_get_boot_device(void)
|
||||
return -1; /* Never reached */
|
||||
}
|
||||
|
||||
+#define is_toc0_magic(foo) true
|
||||
+
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
static u32 sunxi_get_spl_size(void)
|
||||
{
|
||||
- if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
|
||||
- return 0;
|
||||
+ if (is_egon_image((void *)SPL_ADDR))
|
||||
+ return ((struct boot_file_head *)SPL_ADDR)->length;
|
||||
+ if (is_toc0_image((void *)SPL_ADDR))
|
||||
+ return ((struct toc0_main_info *)SPL_ADDR)->length;
|
||||
|
||||
- return readl(SPL_ADDR + 0x10);
|
||||
+ /* Unknown size, so fall back to the default offset. */
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/include/sunxi_image.h b/include/sunxi_image.h
|
||||
index bdf80ec0e0..b0424b6b7f 100644
|
||||
--- a/include/sunxi_image.h
|
||||
+++ b/include/sunxi_image.h
|
||||
@@ -270,4 +270,18 @@ struct toc0_key_item {
|
||||
sizeof(struct toc0_key_item), \
|
||||
32)
|
||||
|
||||
+static inline bool is_egon_image(void *addr)
|
||||
+{
|
||||
+ struct boot_file_head *head = addr;
|
||||
+
|
||||
+ return memcmp(head->magic, BOOT0_MAGIC, 8) == 0;
|
||||
+}
|
||||
+
|
||||
+static inline bool is_toc0_image(void *addr)
|
||||
+{
|
||||
+ struct toc0_main_info *main = addr;
|
||||
+
|
||||
+ return memcmp(main->name, TOC0_MAIN_INFO_NAME, 8) == 0;
|
||||
+}
|
||||
+
|
||||
#endif
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
From 02794d97426245146aaec889583e3eea11e80c02 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sun, 20 Jun 2021 14:24:29 -0500
|
||||
Subject: [PATCH 04/10] sunxi: Support building a SPL as a TOC0 image
|
||||
|
||||
Now that mkimage can generate TOC0 images, and the SPL can interpret
|
||||
them, hook up the build infrastructure so the user can choose which
|
||||
image type to build.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
arch/arm/mach-sunxi/Kconfig | 2 ++
|
||||
board/sunxi/Kconfig | 24 ++++++++++++++++++++++++
|
||||
scripts/Makefile.spl | 3 ++-
|
||||
3 files changed, 28 insertions(+), 1 deletion(-)
|
||||
create mode 100644 board/sunxi/Kconfig
|
||||
|
||||
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
|
||||
index 49f94f095c..b0191d0080 100644
|
||||
--- a/arch/arm/mach-sunxi/Kconfig
|
||||
+++ b/arch/arm/mach-sunxi/Kconfig
|
||||
@@ -1091,6 +1091,8 @@ config BLUETOOTH_DT_DEVICE_FIXUP
|
||||
The used address is "bdaddr" if set, and "ethaddr" with the LSB
|
||||
flipped elsewise.
|
||||
|
||||
+source "board/sunxi/Kconfig"
|
||||
+
|
||||
endif
|
||||
|
||||
config CHIP_DIP_SCAN
|
||||
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
|
||||
new file mode 100644
|
||||
index 0000000000..c5c0929db5
|
||||
--- /dev/null
|
||||
+++ b/board/sunxi/Kconfig
|
||||
@@ -0,0 +1,24 @@
|
||||
+choice
|
||||
+ prompt "SPL Image Type"
|
||||
+ default SUNXI_SPL_IMAGE_EGON
|
||||
+
|
||||
+config SUNXI_SPL_IMAGE_EGON
|
||||
+ bool "eGON (non-secure)"
|
||||
+ help
|
||||
+ Select this option to embed the SPL binary in an eGON.BT0 image,
|
||||
+ which is compatible with the non-secure boot ROM (NBROM).
|
||||
+
|
||||
+ This is usually the correct option to choose.
|
||||
+
|
||||
+config SUNXI_SPL_IMAGE_TOC0
|
||||
+ bool "TOC0 (secure)"
|
||||
+ help
|
||||
+ Select this option to embed the SPL binary in a TOC0 image,
|
||||
+ which is compatible with the secure boot ROM (SBROM).
|
||||
+
|
||||
+endchoice
|
||||
+
|
||||
+config SUNXI_SPL_IMAGE_TYPE
|
||||
+ string
|
||||
+ default "sunxi_egon" if SUNXI_SPL_IMAGE_EGON
|
||||
+ default "sunxi_toc0" if SUNXI_SPL_IMAGE_TOC0
|
||||
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
|
||||
index 25a3e7fa52..52ead28487 100644
|
||||
--- a/scripts/Makefile.spl
|
||||
+++ b/scripts/Makefile.spl
|
||||
@@ -414,7 +414,8 @@ endif
|
||||
$(obj)/$(SPL_BIN).sfp: $(obj)/$(SPL_BIN).bin FORCE
|
||||
$(call if_changed,mkimage)
|
||||
|
||||
-MKIMAGEFLAGS_sunxi-spl.bin = -T sunxi_egon \
|
||||
+MKIMAGEFLAGS_sunxi-spl.bin = -T $(CONFIG_SUNXI_SPL_IMAGE_TYPE) \
|
||||
+ -a $(CONFIG_SPL_TEXT_BASE) \
|
||||
-n $(CONFIG_DEFAULT_DEVICE_TREE)
|
||||
|
||||
OBJCOPYFLAGS_u-boot-spl-dtb.hex := -I binary -O ihex --change-address=$(CONFIG_SPL_TEXT_BASE)
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
From 2ebd6418254742499ab6150877879536486b47b3 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sat, 17 Apr 2021 14:21:45 -0500
|
||||
Subject: [PATCH 05/10] sunxi: DT: H6: Add USB3 to Pine H64 DTS
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
arch/arm/dts/sun50i-h6-pine-h64.dts | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/dts/sun50i-h6-pine-h64.dts b/arch/arm/dts/sun50i-h6-pine-h64.dts
|
||||
index b868ad17af..73d011dc69 100644
|
||||
--- a/arch/arm/dts/sun50i-h6-pine-h64.dts
|
||||
+++ b/arch/arm/dts/sun50i-h6-pine-h64.dts
|
||||
@@ -89,6 +89,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&dwc3 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ehci0 {
|
||||
status = "okay";
|
||||
};
|
||||
@@ -332,3 +336,7 @@
|
||||
usb3_vbus-supply = <®_usb_vbus>;
|
||||
status = "okay";
|
||||
};
|
||||
+
|
||||
+&usb3phy {
|
||||
+ status = "okay";
|
||||
+};
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
From 40b65e95cfebc9d9af61d3c47562cdeb6b2a1302 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sat, 17 Apr 2021 10:43:58 -0500
|
||||
Subject: [PATCH 06/10] sunxi: Load sun8i secure monitor to SRAM A2
|
||||
|
||||
Most sun6i-derived SoCs contain SRAM A2, a secure SRAM area for ARISC
|
||||
SCP firmware. H3 has a smaller SRAM than other SoCs (A31/A33/A23/A83T).
|
||||
|
||||
On sun8i SoCs which do not have SRAM B, we can use part of this SRAM for
|
||||
the secure monitor. Follow the design of 64-bit SoCs and use the first
|
||||
part for the monitor, and the last 16 KiB for the SCP firmware. With
|
||||
this change, the monitor no longer needs to reserve a region in DRAM.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
include/configs/sun8i.h | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h
|
||||
index 27c9808a49..3466c75e28 100644
|
||||
--- a/include/configs/sun8i.h
|
||||
+++ b/include/configs/sun8i.h
|
||||
@@ -22,6 +22,13 @@
|
||||
#define CONFIG_ARMV7_SECURE_MAX_SIZE (SUNXI_SRAM_A2_SIZE - 33 * 1024)
|
||||
#endif
|
||||
|
||||
+/*
|
||||
+ * Skip the first 16 KiB of SRAM A2, which is not usable, as only certain bytes
|
||||
+ * are writable. Reserve the last 17 KiB for the resume shim and SCP firmware.
|
||||
+ */
|
||||
+#define CONFIG_ARMV7_SECURE_BASE (SUNXI_SRAM_A2_BASE + 16 * 1024)
|
||||
+#define CONFIG_ARMV7_SECURE_MAX_SIZE (SUNXI_SRAM_A2_SIZE - 33 * 1024)
|
||||
+
|
||||
/*
|
||||
* Include common sunxi configuration where most the settings are
|
||||
*/
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
From d0af5f5a4fc81e4dcd0b51ad46d8faf01b9ae168 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman <megous@megous.com>
|
||||
Date: Tue, 11 Feb 2020 14:10:05 +0100
|
||||
Subject: [PATCH 07/10] pinephone: Add volume_key environment variable
|
||||
|
||||
When the user has a volume key pressed volume_key variable will
|
||||
contain either value 'down' or 'up', otherwise it will be empty.
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
---
|
||||
board/sunxi/Makefile | 1 +
|
||||
board/sunxi/board.c | 18 ++++++++++
|
||||
board/sunxi/lradc.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
board/sunxi/lradc.h | 11 ++++++
|
||||
4 files changed, 111 insertions(+)
|
||||
create mode 100644 board/sunxi/lradc.c
|
||||
create mode 100644 board/sunxi/lradc.h
|
||||
|
||||
diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile
|
||||
index d96b7897b6..a096a5c771 100644
|
||||
--- a/board/sunxi/Makefile
|
||||
+++ b/board/sunxi/Makefile
|
||||
@@ -12,3 +12,4 @@ obj-$(CONFIG_MACH_SUN4I) += dram_sun4i_auto.o
|
||||
obj-$(CONFIG_MACH_SUN5I) += dram_sun5i_auto.o
|
||||
obj-$(CONFIG_MACH_SUN7I) += dram_sun5i_auto.o
|
||||
obj-$(CONFIG_CHIP_DIP_SCAN) += chip.o
|
||||
+obj-$(CONFIG_MACH_SUN50I) += lradc.o
|
||||
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
|
||||
index 1a46100e40..400cc938dd 100644
|
||||
--- a/board/sunxi/board.c
|
||||
+++ b/board/sunxi/board.c
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <spl.h>
|
||||
#include <sy8106a.h>
|
||||
#include <asm/setup.h>
|
||||
+#include "lradc.h"
|
||||
|
||||
#if defined CONFIG_VIDEO_LCD_PANEL_I2C && !(defined CONFIG_SPL_BUILD)
|
||||
/* So that we can use pin names in Kconfig and sunxi_name_to_gpio() */
|
||||
@@ -672,6 +673,12 @@ void sunxi_board_init(void)
|
||||
{
|
||||
int power_failed = 0;
|
||||
|
||||
+#ifdef CONFIG_MACH_SUN50I
|
||||
+ // we init the lradc in SPL to get the ADC started early to have
|
||||
+ // a valid sample when U-Boot main binary gets executed.
|
||||
+ lradc_enable();
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_SY8106A_POWER
|
||||
power_failed = sy8106a_set_vout1(CONFIG_SY8106A_VOUT1_VOLT);
|
||||
#endif
|
||||
@@ -946,6 +953,17 @@ int misc_init_r(void)
|
||||
env_set("fdtfile", str);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_MACH_SUN50I
|
||||
+ int key = lradc_get_pressed_key();
|
||||
+ if (key == KEY_VOLUMEDOWN)
|
||||
+ env_set("volume_key", "down");
|
||||
+ else if (key == KEY_VOLUMEUP)
|
||||
+ env_set("volume_key", "up");
|
||||
+
|
||||
+ // no longer needed
|
||||
+ lradc_disable();
|
||||
+#endif
|
||||
+
|
||||
setup_environment(gd->fdt_blob);
|
||||
|
||||
return 0;
|
||||
diff --git a/board/sunxi/lradc.c b/board/sunxi/lradc.c
|
||||
new file mode 100644
|
||||
index 0000000000..693b198e25
|
||||
--- /dev/null
|
||||
+++ b/board/sunxi/lradc.c
|
||||
@@ -0,0 +1,81 @@
|
||||
+#include <common.h>
|
||||
+#include <asm/io.h>
|
||||
+#include "lradc.h"
|
||||
+
|
||||
+#define LRADC_BASE 0x1c21800
|
||||
+
|
||||
+#define LRADC_CTRL (LRADC_BASE + 0x00)
|
||||
+#define LRADC_INTC (LRADC_BASE + 0x04)
|
||||
+#define LRADC_INTS (LRADC_BASE + 0x08)
|
||||
+#define LRADC_DATA0 (LRADC_BASE + 0x0c)
|
||||
+#define LRADC_DATA1 (LRADC_BASE + 0x10)
|
||||
+
|
||||
+/* LRADC_CTRL bits */
|
||||
+#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */
|
||||
+#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */
|
||||
+#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */
|
||||
+#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */
|
||||
+#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */
|
||||
+#define HOLD_KEY_EN(x) ((x) << 7)
|
||||
+#define HOLD_EN(x) ((x) << 6)
|
||||
+#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */
|
||||
+#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */
|
||||
+#define ENABLE(x) ((x) << 0)
|
||||
+
|
||||
+/* LRADC_INTC and LRADC_INTS bits */
|
||||
+#define CHAN1_KEYUP_IRQ BIT(12)
|
||||
+#define CHAN1_ALRDY_HOLD_IRQ BIT(11)
|
||||
+#define CHAN1_HOLD_IRQ BIT(10)
|
||||
+#define CHAN1_KEYDOWN_IRQ BIT(9)
|
||||
+#define CHAN1_DATA_IRQ BIT(8)
|
||||
+#define CHAN0_KEYUP_IRQ BIT(4)
|
||||
+#define CHAN0_ALRDY_HOLD_IRQ BIT(3)
|
||||
+#define CHAN0_HOLD_IRQ BIT(2)
|
||||
+#define CHAN0_KEYDOWN_IRQ BIT(1)
|
||||
+#define CHAN0_DATA_IRQ BIT(0)
|
||||
+
|
||||
+// this is for PinePhone only
|
||||
+
|
||||
+int lradc_get_pressed_key(void)
|
||||
+{
|
||||
+ uint32_t val;
|
||||
+ uint32_t vref = 3000000 * 2 / 3;
|
||||
+
|
||||
+ val = readl(LRADC_DATA0) & 0x3f;
|
||||
+ val = val * vref / 63;
|
||||
+
|
||||
+// printf("lradc=%u\n", val);
|
||||
+
|
||||
+ if (val < 200000) // 158730
|
||||
+ return KEY_VOLUMEUP;
|
||||
+ else if (val < 400000) // 349206
|
||||
+ return KEY_VOLUMEDOWN;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void lradc_enable(void)
|
||||
+{
|
||||
+ // aldo3 is always on and defaults to 3V
|
||||
+
|
||||
+ writel(0xffffffff, LRADC_INTS);
|
||||
+ writel(0, LRADC_INTC);
|
||||
+
|
||||
+ /*
|
||||
+ * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
|
||||
+ * stabilize on press, wait (1 + 1) * 4 ms for key release
|
||||
+ */
|
||||
+ writel(FIRST_CONVERT_DLY(0) | LEVELA_B_CNT(0) | HOLD_EN(0) |
|
||||
+ SAMPLE_RATE(0) | ENABLE(1), LRADC_CTRL);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+void lradc_disable(void)
|
||||
+{
|
||||
+ writel(0xffffffff, LRADC_INTS);
|
||||
+ writel(0, LRADC_INTC);
|
||||
+
|
||||
+ /* Disable lradc, leave other settings unchanged */
|
||||
+ writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
|
||||
+ SAMPLE_RATE(2), LRADC_CTRL);
|
||||
+}
|
||||
diff --git a/board/sunxi/lradc.h b/board/sunxi/lradc.h
|
||||
new file mode 100644
|
||||
index 0000000000..c908401b5b
|
||||
--- /dev/null
|
||||
+++ b/board/sunxi/lradc.h
|
||||
@@ -0,0 +1,11 @@
|
||||
+#pragma once
|
||||
+
|
||||
+enum {
|
||||
+ KEY_NONE = 0,
|
||||
+ KEY_VOLUMEDOWN = 1,
|
||||
+ KEY_VOLUMEUP = 2,
|
||||
+};
|
||||
+
|
||||
+int lradc_get_pressed_key(void);
|
||||
+void lradc_enable(void);
|
||||
+void lradc_disable(void);
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
From e7a3da0093b96d89c9d65fe8d5f1dd32f299afa1 Mon Sep 17 00:00:00 2001
|
||||
From: Marius Gripsgard <marius@ubports.com>
|
||||
Date: Tue, 5 May 2020 16:51:13 +0200
|
||||
Subject: [PATCH 08/10] Enable led on boot to notify user of boot status
|
||||
|
||||
---
|
||||
arch/arm/mach-sunxi/Kconfig | 5 +++++
|
||||
board/sunxi/board.c | 6 ++++++
|
||||
configs/pinephone_defconfig | 1 +
|
||||
3 files changed, 12 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
|
||||
index b0191d0080..7a46bb4481 100644
|
||||
--- a/arch/arm/mach-sunxi/Kconfig
|
||||
+++ b/arch/arm/mach-sunxi/Kconfig
|
||||
@@ -1,5 +1,10 @@
|
||||
if ARCH_SUNXI
|
||||
|
||||
+config PINEPHONE_LEDS
|
||||
+ bool "Notify boot status via LEDs on PinePhone"
|
||||
+ ---help---
|
||||
+ LED boot notification.
|
||||
+
|
||||
config SPL_LDSCRIPT
|
||||
default "arch/arm/cpu/armv7/sunxi/u-boot-spl.lds" if !ARM64
|
||||
|
||||
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
|
||||
index 400cc938dd..0abfa78880 100644
|
||||
--- a/board/sunxi/board.c
|
||||
+++ b/board/sunxi/board.c
|
||||
@@ -679,6 +679,12 @@ void sunxi_board_init(void)
|
||||
lradc_enable();
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_PINEPHONE_LEDS
|
||||
+ /* PD18:G PD19:R PD20:B */
|
||||
+ gpio_request(SUNXI_GPD(19), "led:red");
|
||||
+ gpio_direction_output(SUNXI_GPD(19), 1);
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_SY8106A_POWER
|
||||
power_failed = sy8106a_set_vout1(CONFIG_SY8106A_VOUT1_VOLT);
|
||||
#endif
|
||||
diff --git a/configs/pinephone_defconfig b/configs/pinephone_defconfig
|
||||
index 64e13d3132..149772749a 100644
|
||||
--- a/configs/pinephone_defconfig
|
||||
+++ b/configs/pinephone_defconfig
|
||||
@@ -2,6 +2,7 @@ CONFIG_ARM=y
|
||||
CONFIG_ARCH_SUNXI=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pinephone-1.2"
|
||||
CONFIG_SPL=y
|
||||
+CONFIG_PINEPHONE_LEDS=y
|
||||
CONFIG_MACH_SUN50I=y
|
||||
CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y
|
||||
CONFIG_DRAM_CLK=552
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
From 679af1e60220bdb31c42beb41a3a405b23f8ffee Mon Sep 17 00:00:00 2001
|
||||
From: Dalton Durst <dalton@ubports.com>
|
||||
Date: Wed, 10 Mar 2021 11:44:07 -0600
|
||||
Subject: [PATCH 10/10] Reduce DRAM speed to 528 for better compatibility with
|
||||
all PinePhones
|
||||
|
||||
---
|
||||
configs/pinephone_defconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/configs/pinephone_defconfig b/configs/pinephone_defconfig
|
||||
index 1683c1f032..4dde6fec87 100644
|
||||
--- a/configs/pinephone_defconfig
|
||||
+++ b/configs/pinephone_defconfig
|
||||
@@ -5,7 +5,7 @@ CONFIG_SPL=y
|
||||
CONFIG_PINEPHONE_LEDS=y
|
||||
CONFIG_MACH_SUN50I=y
|
||||
CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y
|
||||
-CONFIG_DRAM_CLK=552
|
||||
+CONFIG_DRAM_CLK=528
|
||||
CONFIG_DRAM_ZQ=3881949
|
||||
CONFIG_MMC_SUNXI_SLOT_EXTRA=2
|
||||
CONFIG_PINEPHONE_DT_SELECTION=y
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,354 +0,0 @@
|
|||
From b0950e4696b391578f7428337e41fa8ca14b225d Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman <megous@megous.com>
|
||||
Date: Wed, 11 Sep 2019 20:45:28 +0200
|
||||
Subject: [PATCH 27/29] mmc: sunxi: Add support for DMA transfers
|
||||
|
||||
Allwinner MMC controller supports DMA via internal DMA controller,
|
||||
use it.
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
---
|
||||
arch/arm/include/asm/arch-sunxi/mmc.h | 7 +
|
||||
drivers/mmc/sunxi_mmc.c | 204 +++++++++++++++++++++++---
|
||||
2 files changed, 192 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
|
||||
index 5daacf10eb..dc8ea6f43a 100644
|
||||
--- a/arch/arm/include/asm/arch-sunxi/mmc.h
|
||||
+++ b/arch/arm/include/asm/arch-sunxi/mmc.h
|
||||
@@ -112,6 +112,10 @@ struct sunxi_mmc {
|
||||
SUNXI_MMC_RINT_COMMAND_DONE | \
|
||||
SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE)
|
||||
|
||||
+#define SUNXI_MMC_FTRGLEVEL_BURST_SIZE(v) (((v) & 0x7) << 28)
|
||||
+#define SUNXI_MMC_FTRGLEVEL_RX_TL(v) (((v) & 0xfff) << 16)
|
||||
+#define SUNXI_MMC_FTRGLEVEL_TX_TL(v) (((v) & 0xffff) << 0)
|
||||
+
|
||||
#define SUNXI_MMC_STATUS_RXWL_FLAG (0x1 << 0)
|
||||
#define SUNXI_MMC_STATUS_TXWL_FLAG (0x1 << 1)
|
||||
#define SUNXI_MMC_STATUS_FIFO_EMPTY (0x1 << 2)
|
||||
@@ -130,6 +134,9 @@ struct sunxi_mmc {
|
||||
#define SUNXI_MMC_IDIE_TXIRQ (0x1 << 0)
|
||||
#define SUNXI_MMC_IDIE_RXIRQ (0x1 << 1)
|
||||
|
||||
+#define SUNXI_MMC_IDST_TXIRQ (0x1 << 0)
|
||||
+#define SUNXI_MMC_IDST_RXIRQ (0x1 << 1)
|
||||
+
|
||||
#define SUNXI_MMC_COMMON_CLK_GATE (1 << 16)
|
||||
#define SUNXI_MMC_COMMON_RESET (1 << 18)
|
||||
|
||||
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
|
||||
index 28af8e6ac5..47c947cdb8 100644
|
||||
--- a/drivers/mmc/sunxi_mmc.c
|
||||
+++ b/drivers/mmc/sunxi_mmc.c
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
+#include <cpu_func.h>
|
||||
#include <errno.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
@@ -27,6 +28,27 @@
|
||||
#define CCM_MMC_CTRL_MODE_SEL_NEW 0
|
||||
#endif
|
||||
|
||||
+#define DMA_CONFIG_DIC BIT(1) // flag: disable interrupt after this descriptor's buffer is processed
|
||||
+#define DMA_CONFIG_LAST BIT(2) // flag: last descriptor
|
||||
+#define DMA_CONFIG_FIRST BIT(3) // flag: first descriptor
|
||||
+#define DMA_CONFIG_CHAIN BIT(4) // flag: buf_addr_ptr2 points to next descriptor
|
||||
+#define DMA_CONFIG_ERROR BIT(30) // flag: out: error happened
|
||||
+#define DMA_CONFIG_HOLD BIT(31) // flag: desc owned by IDMAC (set to 1)
|
||||
+
|
||||
+#if defined(CONFIG_MACH_SUN50I)
|
||||
+// mmc2 on A64 only allows for 8k
|
||||
+#define DMA_BUF_MAX_SIZE (1 << 13)
|
||||
+#else
|
||||
+#define DMA_BUF_MAX_SIZE (1 << 16)
|
||||
+#endif
|
||||
+
|
||||
+struct sunxi_idma_desc {
|
||||
+ u32 config;
|
||||
+ u32 buf_size;
|
||||
+ u32 buf_addr_ptr1;
|
||||
+ u32 buf_addr_ptr2;
|
||||
+};
|
||||
+
|
||||
struct sunxi_mmc_plat {
|
||||
struct mmc_config cfg;
|
||||
struct mmc mmc;
|
||||
@@ -39,6 +61,8 @@ struct sunxi_mmc_priv {
|
||||
struct gpio_desc cd_gpio; /* Change Detect GPIO */
|
||||
struct sunxi_mmc *reg;
|
||||
struct mmc_config cfg;
|
||||
+ unsigned n_dma_descs;
|
||||
+ struct sunxi_idma_desc* dma_descs;
|
||||
};
|
||||
|
||||
#if !CONFIG_IS_ENABLED(DM_MMC)
|
||||
@@ -318,7 +342,7 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
|
||||
if (timeout_msecs < 2000)
|
||||
timeout_msecs = 2000;
|
||||
|
||||
- /* Always read / write data through the CPU */
|
||||
+ /* Read / write data through the CPU */
|
||||
setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
|
||||
|
||||
start = get_timer(0);
|
||||
@@ -328,7 +352,7 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
|
||||
|
||||
while ((status = readl(&priv->reg->status)) & status_bit) {
|
||||
if (get_timer(start) > timeout_msecs)
|
||||
- return -1;
|
||||
+ return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -360,21 +384,142 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void flush_cache_auto_align(void* buf, size_t len)
|
||||
+{
|
||||
+ uintptr_t mask = ~((uintptr_t)CONFIG_SYS_CACHELINE_SIZE - 1);
|
||||
+ uintptr_t start = (uintptr_t)buf & mask;
|
||||
+
|
||||
+ len = (len + 2 * CONFIG_SYS_CACHELINE_SIZE) & mask;
|
||||
+
|
||||
+ flush_cache(start, len);
|
||||
+}
|
||||
+
|
||||
+static int mmc_trans_data_by_dma(struct sunxi_mmc_priv *priv, struct mmc *mmc,
|
||||
+ struct mmc_data *data)
|
||||
+{
|
||||
+ const int reading = !!(data->flags & MMC_DATA_READ);
|
||||
+ uint8_t *buff = (uint8_t*)(reading ? data->dest : data->src);
|
||||
+ unsigned byte_cnt = data->blocksize * data->blocks;
|
||||
+ unsigned i, n_desc, last_block_size;
|
||||
+ u32 rval;
|
||||
+
|
||||
+ /* data pointer and transfer size needs to be aligned to 4 bytes */
|
||||
+
|
||||
+ /* Read / write data through IDMAC */
|
||||
+ clrbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
|
||||
+
|
||||
+ n_desc = byte_cnt / DMA_BUF_MAX_SIZE;
|
||||
+ last_block_size = byte_cnt % DMA_BUF_MAX_SIZE;
|
||||
+ if (last_block_size)
|
||||
+ n_desc++;
|
||||
+
|
||||
+ if (n_desc > priv->n_dma_descs)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ memset(priv->dma_descs, 0, sizeof(struct sunxi_idma_desc) * n_desc);
|
||||
+
|
||||
+ for (i = 0; i < n_desc; i++) {
|
||||
+ struct sunxi_idma_desc* desc = &priv->dma_descs[i];
|
||||
+ bool is_last = i == n_desc - 1;
|
||||
+ bool is_first = i == 0;
|
||||
+
|
||||
+ desc->config = DMA_CONFIG_CHAIN | DMA_CONFIG_HOLD
|
||||
+ | (is_last ? DMA_CONFIG_LAST : DMA_CONFIG_DIC)
|
||||
+ | (is_first ? DMA_CONFIG_FIRST : 0);
|
||||
+
|
||||
+ if (is_last && last_block_size)
|
||||
+ desc->buf_size = last_block_size;
|
||||
+ else
|
||||
+ desc->buf_size = DMA_BUF_MAX_SIZE;
|
||||
+
|
||||
+ desc->buf_addr_ptr1 = (uintptr_t)buff + i * DMA_BUF_MAX_SIZE;
|
||||
+ if (!is_last)
|
||||
+ desc->buf_addr_ptr2 = (uintptr_t)(desc + 1);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure everyhting needed for a transfer is in DRAM.
|
||||
+ */
|
||||
+
|
||||
+ flush_cache_auto_align(buff, byte_cnt);
|
||||
+ flush_cache_auto_align(priv->dma_descs,
|
||||
+ sizeof(struct sunxi_idma_desc) * n_desc);
|
||||
+
|
||||
+ dsb();
|
||||
+ isb();
|
||||
+
|
||||
+ /* dma enable */
|
||||
+ setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_DMA_RESET
|
||||
+ | SUNXI_MMC_GCTRL_DMA_ENABLE);
|
||||
+
|
||||
+ /* idma reset */
|
||||
+ writel(SUNXI_MMC_IDMAC_RESET, &priv->reg->dmac);
|
||||
+
|
||||
+ /* wait idma reset done */
|
||||
+ while (readl(&priv->reg->dmac) & SUNXI_MMC_IDMAC_RESET);
|
||||
+
|
||||
+ /* idma on */
|
||||
+ writel(SUNXI_MMC_IDMAC_ENABLE | SUNXI_MMC_IDMAC_FIXBURST,
|
||||
+ &priv->reg->dmac);
|
||||
+
|
||||
+ /* enable interrupt flags */
|
||||
+ rval = readl(&priv->reg->idie)
|
||||
+ & ~(SUNXI_MMC_IDIE_RXIRQ | SUNXI_MMC_IDIE_TXIRQ);
|
||||
+ rval |= reading ? SUNXI_MMC_IDIE_RXIRQ : SUNXI_MMC_IDIE_TXIRQ;
|
||||
+ writel(rval, &priv->reg->idie);
|
||||
+
|
||||
+ /* set address of the first descriptor */
|
||||
+ writel((uintptr_t)priv->dma_descs, &priv->reg->dlba);
|
||||
+
|
||||
+ /* set fifo fill tresholds for issuing dma */
|
||||
+
|
||||
+#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
|
||||
+ if (priv->mmc_no == 2) {
|
||||
+ // for mmc 2 we need to set this differently
|
||||
+ writel(SUNXI_MMC_FTRGLEVEL_BURST_SIZE(3) // burst-16
|
||||
+ | SUNXI_MMC_FTRGLEVEL_RX_TL(15)
|
||||
+ | SUNXI_MMC_FTRGLEVEL_TX_TL(240),
|
||||
+ &priv->reg->ftrglevel);
|
||||
+ } else {
|
||||
+ writel(SUNXI_MMC_FTRGLEVEL_BURST_SIZE(2) // burst-8
|
||||
+ | SUNXI_MMC_FTRGLEVEL_RX_TL(7)
|
||||
+ | SUNXI_MMC_FTRGLEVEL_TX_TL(248),
|
||||
+ &priv->reg->ftrglevel);
|
||||
+ }
|
||||
+#else
|
||||
+ writel(SUNXI_MMC_FTRGLEVEL_BURST_SIZE(2) // burst-8
|
||||
+ | SUNXI_MMC_FTRGLEVEL_RX_TL(7)
|
||||
+ | SUNXI_MMC_FTRGLEVEL_TX_TL(8),
|
||||
+ &priv->reg->ftrglevel);
|
||||
+#endif
|
||||
+
|
||||
+ writel(0xffffffff, &priv->reg->idst);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
|
||||
- uint timeout_msecs, uint done_bit, const char *what)
|
||||
+ uint timeout_msecs, uint done_bit, bool wait_dma,
|
||||
+ const char *what)
|
||||
{
|
||||
unsigned int status;
|
||||
unsigned long start = get_timer(0);
|
||||
+ bool dma_done = true;
|
||||
|
||||
do {
|
||||
status = readl(&priv->reg->rint);
|
||||
+
|
||||
if ((get_timer(start) > timeout_msecs) ||
|
||||
(status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
|
||||
debug("%s timeout %x\n", what,
|
||||
status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
- } while (!(status & done_bit));
|
||||
+
|
||||
+ if (wait_dma)
|
||||
+ dma_done = readl(&priv->reg->idst)
|
||||
+ & (SUNXI_MMC_IDST_TXIRQ | SUNXI_MMC_IDST_RXIRQ);
|
||||
+ } while (!(status & done_bit) || !dma_done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -388,6 +533,7 @@ static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
|
||||
int error = 0;
|
||||
unsigned int status = 0;
|
||||
unsigned int bytecnt = 0;
|
||||
+ bool usedma = false;
|
||||
|
||||
if (priv->fatal_err)
|
||||
return -1;
|
||||
@@ -424,42 +570,45 @@ static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
|
||||
cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
|
||||
writel(cmd->cmdarg, &priv->reg->arg);
|
||||
|
||||
- if (!data)
|
||||
- writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
|
||||
-
|
||||
/*
|
||||
* transfer data and check status
|
||||
* STATREG[2] : FIFO empty
|
||||
* STATREG[3] : FIFO full
|
||||
*/
|
||||
if (data) {
|
||||
- int ret = 0;
|
||||
-
|
||||
bytecnt = data->blocksize * data->blocks;
|
||||
debug("trans data %d bytes\n", bytecnt);
|
||||
- writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
|
||||
- ret = mmc_trans_data_by_cpu(priv, mmc, data);
|
||||
- if (ret) {
|
||||
- error = readl(&priv->reg->rint) &
|
||||
- SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
|
||||
- error = -ETIMEDOUT;
|
||||
- goto out;
|
||||
+
|
||||
+ if (bytecnt > 64 && !IS_ENABLED(SPL_BUILD)) {
|
||||
+ debug(" using dma %d\n", bytecnt);
|
||||
+ error = mmc_trans_data_by_dma(priv, mmc, data);
|
||||
+ writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
|
||||
+ usedma = true;
|
||||
+ } else {
|
||||
+ debug(" using pio\n");
|
||||
+ writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
|
||||
+ error = mmc_trans_data_by_cpu(priv, mmc, data);
|
||||
}
|
||||
+
|
||||
+ if (error)
|
||||
+ goto out;
|
||||
+ } else {
|
||||
+ writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
|
||||
}
|
||||
|
||||
error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
|
||||
- "cmd");
|
||||
+ false, "cmd");
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if (data) {
|
||||
- timeout_msecs = 120;
|
||||
+ timeout_msecs = 10000;
|
||||
debug("cacl timeout %x msec\n", timeout_msecs);
|
||||
error = mmc_rint_wait(priv, mmc, timeout_msecs,
|
||||
data->blocks > 1 ?
|
||||
SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
|
||||
SUNXI_MMC_RINT_DATA_OVER,
|
||||
- "data");
|
||||
+ usedma, "data");
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
@@ -491,6 +640,14 @@ static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
|
||||
debug("mmc resp 0x%08x\n", cmd->response[0]);
|
||||
}
|
||||
out:
|
||||
+ if (data && usedma) {
|
||||
+ //status = readl(®->idst);
|
||||
+ writel(0, &priv->reg->idie);
|
||||
+ writel(0xffffffff, &priv->reg->idst);
|
||||
+ writel(0, &priv->reg->dmac);
|
||||
+ clrbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_DMA_ENABLE);
|
||||
+ }
|
||||
+
|
||||
if (error < 0) {
|
||||
writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
|
||||
mmc_update_clk(priv);
|
||||
@@ -674,6 +831,15 @@ static int sunxi_mmc_probe(struct udevice *dev)
|
||||
|
||||
priv->reg = dev_read_addr_ptr(dev);
|
||||
|
||||
+ // make sure we have enough space for descritors for BLK_SIZE * b_max
|
||||
+ priv->n_dma_descs = 512 * 65536 / DMA_BUF_MAX_SIZE;
|
||||
+ priv->dma_descs = malloc(sizeof(struct sunxi_idma_desc)
|
||||
+ * priv->n_dma_descs);
|
||||
+ if (priv->dma_descs == NULL) {
|
||||
+ debug("init mmc alloc failed\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
/* We don't have a sunxi clock driver so find the clock address here */
|
||||
ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
|
||||
1, &args);
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From 1af4c86329397bc553122c650226bd5c7acb1ed0 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman <megous@megous.com>
|
||||
Date: Fri, 13 Sep 2019 22:14:43 +0200
|
||||
Subject: [PATCH 28/29] mmc: sunxi: DDR/DMA support for SPL
|
||||
|
||||
---
|
||||
drivers/mmc/sunxi_mmc.c | 16 +++++++++++++++-
|
||||
1 file changed, 15 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
|
||||
index 47c947cdb8..855dfd35d9 100644
|
||||
--- a/drivers/mmc/sunxi_mmc.c
|
||||
+++ b/drivers/mmc/sunxi_mmc.c
|
||||
@@ -579,7 +579,12 @@ static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
|
||||
bytecnt = data->blocksize * data->blocks;
|
||||
debug("trans data %d bytes\n", bytecnt);
|
||||
|
||||
- if (bytecnt > 64 && !IS_ENABLED(SPL_BUILD)) {
|
||||
+ // DMA doesn't work when the target is SRAM for some reason.
|
||||
+ int reading = !!(data->flags & MMC_DATA_READ);
|
||||
+ uint8_t* buf = (uint8_t*)(reading ? data->dest : data->src);
|
||||
+ bool is_dram = (uintptr_t)buf >= 0x4000000;
|
||||
+
|
||||
+ if (bytecnt > 64 && is_dram) {
|
||||
debug(" using dma %d\n", bytecnt);
|
||||
error = mmc_trans_data_by_dma(priv, mmc, data);
|
||||
writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
|
||||
@@ -715,10 +720,19 @@ struct mmc *sunxi_mmc_init(int sdc_no)
|
||||
|
||||
cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
|
||||
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
|
||||
+ if (sdc_no == 2)
|
||||
+ cfg->host_caps |= MMC_MODE_DDR_52MHz;
|
||||
|
||||
cfg->f_min = 400000;
|
||||
cfg->f_max = 52000000;
|
||||
|
||||
+ // enough descs for a realy big u-boot (4MiB)
|
||||
+ priv->n_dma_descs = 4*1024*1024 / DMA_BUF_MAX_SIZE;
|
||||
+ priv->dma_descs = malloc(sizeof(struct sunxi_idma_desc)
|
||||
+ * priv->n_dma_descs);
|
||||
+ if (priv->dma_descs == NULL)
|
||||
+ return NULL;
|
||||
+
|
||||
if (mmc_resource_init(sdc_no) != 0)
|
||||
return NULL;
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
From 6ad822cb4d64beda76cade8761c49b55620a8b5b Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman <megous@megous.com>
|
||||
Date: Tue, 14 Jan 2020 03:56:32 +0100
|
||||
Subject: [PATCH 29/29] spl: ARM: Enable CPU caches
|
||||
|
||||
http://u-boot.10912.n7.nabble.com/RFC-PATCH-0-3-spl-Add-D-cache-support-td274750.html
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
---
|
||||
arch/arm/lib/cache-cp15.c | 29 ++++++++++++++++++++++++
|
||||
common/spl/spl.c | 46 +++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 75 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
|
||||
index aab1bf4360..c2fe0acdc4 100644
|
||||
--- a/arch/arm/lib/cache-cp15.c
|
||||
+++ b/arch/arm/lib/cache-cp15.c
|
||||
@@ -116,6 +116,25 @@ __weak void dram_bank_mmu_setup(int bank)
|
||||
set_section_dcache(i, DCACHE_DEFAULT_OPTION);
|
||||
}
|
||||
|
||||
+#if defined(CONFIG_SPL_BUILD) && (defined(CONFIG_SPL_MAX_SIZE) || \
|
||||
+ defined(CONFIG_SPL_MAX_FOOTPRINT))
|
||||
+__weak void sram_bank_mmu_setup(phys_addr_t start, phys_addr_t size)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = start >> MMU_SECTION_SHIFT;
|
||||
+ i < (start >> MMU_SECTION_SHIFT) + (size >> MMU_SECTION_SHIFT);
|
||||
+ i++)
|
||||
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
|
||||
+ set_section_dcache(i, DCACHE_WRITETHROUGH);
|
||||
+#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
|
||||
+ set_section_dcache(i, DCACHE_WRITEALLOC);
|
||||
+#else
|
||||
+ set_section_dcache(i, DCACHE_WRITEBACK);
|
||||
+#endif
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/* to activate the MMU we need to set up virtual memory: use 1M areas */
|
||||
static inline void mmu_setup(void)
|
||||
{
|
||||
@@ -131,6 +150,16 @@ static inline void mmu_setup(void)
|
||||
dram_bank_mmu_setup(i);
|
||||
}
|
||||
|
||||
+#if defined(CONFIG_SPL_BUILD)
|
||||
+#if defined(CONFIG_SPL_MAX_SIZE)
|
||||
+ sram_bank_mmu_setup(CONFIG_SPL_TEXT_BASE,
|
||||
+ ALIGN(CONFIG_SPL_MAX_SIZE, MMU_SECTION_SIZE));
|
||||
+#elif defined(CONFIG_SPL_MAX_FOOTPRINT)
|
||||
+ sram_bank_mmu_setup(CONFIG_SPL_TEXT_BASE,
|
||||
+ ALIGN(CONFIG_SPL_MAX_FOOTPRINT, MMU_SECTION_SIZE));
|
||||
+#endif
|
||||
+#endif
|
||||
+
|
||||
#if defined(CONFIG_ARMV7_LPAE) && __LINUX_ARM_ARCH__ != 4
|
||||
/* Set up 4 PTE entries pointing to our 4 1GB page tables */
|
||||
for (i = 0; i < 4; i++) {
|
||||
diff --git a/common/spl/spl.c b/common/spl/spl.c
|
||||
index a0a608fd77..40c9022928 100644
|
||||
--- a/common/spl/spl.c
|
||||
+++ b/common/spl/spl.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <bloblist.h>
|
||||
#include <binman_sym.h>
|
||||
#include <bootstage.h>
|
||||
+#include <cpu_func.h>
|
||||
#include <dm.h>
|
||||
#include <handoff.h>
|
||||
#include <hang.h>
|
||||
@@ -636,6 +637,35 @@ void board_init_f(ulong dummy)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
|
||||
+ defined(CONFIG_ARM)
|
||||
+int reserve_mmu(void)
|
||||
+{
|
||||
+ phys_addr_t ram_top = 0;
|
||||
+ /* reserve TLB table */
|
||||
+ gd->arch.tlb_size = PGTABLE_SIZE;
|
||||
+
|
||||
+#ifdef CONFIG_SYS_SDRAM_BASE
|
||||
+ ram_top = CONFIG_SYS_SDRAM_BASE;
|
||||
+#endif
|
||||
+ ram_top += get_effective_memsize();
|
||||
+ gd->arch.tlb_addr = ram_top - gd->arch.tlb_size;
|
||||
+ debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
|
||||
+ gd->arch.tlb_addr + gd->arch.tlb_size);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+__weak int dram_init_banksize(void)
|
||||
+{
|
||||
+#if defined(CONFIG_NR_DRAM_BANKS) && defined(CONFIG_SYS_SDRAM_BASE)
|
||||
+ gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
|
||||
+ gd->bd->bi_dram[0].size = get_effective_memsize();
|
||||
+#endif
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||
{
|
||||
u32 spl_boot_list[] = {
|
||||
@@ -651,6 +681,12 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||
debug(">>" SPL_TPL_PROMPT "board_init_r()\n");
|
||||
|
||||
spl_set_bd();
|
||||
+#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
|
||||
+ defined(CONFIG_ARM)
|
||||
+ dram_init_banksize();
|
||||
+ reserve_mmu();
|
||||
+ enable_caches();
|
||||
+#endif
|
||||
|
||||
#if defined(CONFIG_SYS_SPL_MALLOC_START)
|
||||
mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
|
||||
@@ -661,6 +697,11 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||
if (spl_init())
|
||||
hang();
|
||||
}
|
||||
+ if (IS_ENABLED(CONFIG_SPL_ALLOC_BD) && spl_alloc_bd()) {
|
||||
+ puts("Cannot alloc bd\n");
|
||||
+ hang();
|
||||
+ }
|
||||
+
|
||||
#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MX6)
|
||||
/*
|
||||
* timer_init() does not exist on PPC systems. The timer is initialized
|
||||
@@ -728,6 +769,11 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||
ret);
|
||||
}
|
||||
|
||||
+#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
|
||||
+ defined(CONFIG_ARM)
|
||||
+ cleanup_before_linux();
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_CPU_V7M
|
||||
spl_image.entry_point |= 0x1;
|
||||
#endif
|
||||
--
|
||||
2.31.1
|
||||
|
|
@ -5,8 +5,8 @@
|
|||
# Co-Maintainer: Dylan Van Assche <me@dylanvanassche.be>
|
||||
# U-boot with patches to make the PinePhone boot faster and have control over the ddr clock speed
|
||||
pkgname=u-boot-pinephone
|
||||
pkgver=2021.10
|
||||
pkgrel=1
|
||||
pkgver=2022.07
|
||||
pkgrel=0
|
||||
pkgdesc="U-Boot bootloader for the PINE64 PinePhone"
|
||||
url="https://source.denx.de/u-boot"
|
||||
arch="aarch64"
|
||||
|
@ -26,22 +26,10 @@ makedepends="$depends_dev
|
|||
swig
|
||||
"
|
||||
options="!check"
|
||||
source="http://source.denx.de/u-boot/u-boot/-/archive/v$pkgver/u-boot-v$pkgver.tar.gz
|
||||
source="https://source.denx.de/u-boot/u-boot/-/archive/v$pkgver/u-boot-v$pkgver.tar.gz
|
||||
update-u-boot
|
||||
0001-sunxi-DT-H6-update-device-tree-files.patch
|
||||
0002-tools-mkimage-Add-Allwinner-TOC0-support.patch
|
||||
0003-sunxi-Support-both-SPL-image-types.patch
|
||||
0004-sunxi-Support-building-a-SPL-as-a-TOC0-image.patch
|
||||
0005-sunxi-DT-H6-Add-USB3-to-Pine-H64-DTS.patch
|
||||
0006-sunxi-Load-sun8i-secure-monitor-to-SRAM-A2.patch
|
||||
0007-pinephone-Add-volume_key-environment-variable.patch
|
||||
0008-Enable-led-on-boot-to-notify-user-of-boot-status.patch
|
||||
0009-disable-bootdelay.patch
|
||||
0010-Reduce-DRAM-speed-to-528-for-better-compatibility-wi.patch
|
||||
0011-mmc-sunxi-Add-support-for-DMA-transfers.patch
|
||||
0012-mmc-sunxi-DDR-DMA-support-for-SPL.patch
|
||||
0013-spl-ARM-Enable-CPU-caches.patch
|
||||
0014-common-expose-DRAM-clock-speed.patch
|
||||
0001-common-expose-DRAM-clock-speed.patch
|
||||
0002-disable-bootdelay.patch
|
||||
"
|
||||
builddir="$srcdir/u-boot-v$pkgver"
|
||||
install="$pkgname.post-upgrade"
|
||||
|
@ -77,20 +65,8 @@ package() {
|
|||
}
|
||||
|
||||
sha512sums="
|
||||
f97d1531946d749d3a40c4a1c60489382d0100757ac8ed4e3e18b70685ba664641cc56de1e2fef2e00efc78e6779f0f52fab2c1ff98fefac98303973572ffd69 u-boot-v2021.10.tar.gz
|
||||
7cd524d5c4b692c99d61fae4e7d99287ce4bca06884dc02b62bd69dfdf594cc9232c13c5b8dbb3aeac125bf7907591dbc6a40e2ea3e39f024bd5a5d42aeaa4cd u-boot-v2022.07.tar.gz
|
||||
d6e1ca6100fdc0ecd9559d556bb8f6699ff807a180d097808417cdacc07fc22b58f8bf33f1f104fcbb28201bd873e469f251176605bec123870ff49bde50024c update-u-boot
|
||||
4d5526a9d492a45213bee5252407061441fc2a760e9ece2651f51a628ab55aac98ce66ff397276b8f5f5bb497ec07ed0344896ae127680666324a4968cd03418 0001-sunxi-DT-H6-update-device-tree-files.patch
|
||||
edc73a3472f4fb2c02785cb07042d2547fa0cebab4bd27b15085ccdc73aa92597d1325e8f7daed1e5d2a5f0875a763bcdb7ffef6af43612c87bbe37008d6ac3e 0002-tools-mkimage-Add-Allwinner-TOC0-support.patch
|
||||
8e60a6a633126265e5f9b363144ce77beaa0460856d007570f1772783cd8e47a250441ffeec525c7f9ac030350d52d2248f4bfc0a0e975cdc1d5525b61008002 0003-sunxi-Support-both-SPL-image-types.patch
|
||||
86b5c6cb43a7bb2dd9a0434c3875114a6ff569d994c23db8da1c149556dc2042d1af7f802dee4873a39dbd2a8059a1d891476c324594c53901de7455b1fc07f3 0004-sunxi-Support-building-a-SPL-as-a-TOC0-image.patch
|
||||
6addeafd556814239a5b0ac3c7604c84b8598d62e8f9fc71f506fb8d312500328a1bd66a688173ccaa8b197e0eb6d3cf2d31c8a1029033ca9a3204ea2906f17b 0005-sunxi-DT-H6-Add-USB3-to-Pine-H64-DTS.patch
|
||||
fe38e2cd396a1ba432e2951b35dfed4aa0b481499bd4cbbba5af7111717554fa73d3f0e762be1b060651e4216a7efcd13f12ad56f2026c1dcbf575520a372aab 0006-sunxi-Load-sun8i-secure-monitor-to-SRAM-A2.patch
|
||||
127b630f1656b7a2ebb946310cf9f478ec07d2df0899635b324efab9b76cf3158bfd01901400542ab2d314e3ac3de1680dc73e03bed7de29628cb4995f97cfd4 0007-pinephone-Add-volume_key-environment-variable.patch
|
||||
034b3f8800627d9a49761ef663f794375c816b33bf88d83eb9b87a73d123004de2c418a1a02761557463bfd6e311a3b85ea8159eeb13c32882ba99668430e4ab 0008-Enable-led-on-boot-to-notify-user-of-boot-status.patch
|
||||
ee42dabe8d8dce1200babb5d5060373d80a5457ee06a8adc3b18b0b7f2b8dca183cc5480c2d833ce3df823c3061c6c9f57b8b6a5122cfec0a6d4e24f1033e65c 0009-disable-bootdelay.patch
|
||||
74747317194f46855bc553c1371a3134db9017041ca3d8afdb377ca1162805931e3c93e44728e6d8980babd5e326f1654b70c683c1ee10dbfe4ddfb88684de6b 0010-Reduce-DRAM-speed-to-528-for-better-compatibility-wi.patch
|
||||
ae2d0baf7c2048e142230741368db1d0520b1764d62e798098d2548b0ba9622f098f64edc0988db10963543ca0169ae6f3db609f436e1fd090d785274cf30283 0011-mmc-sunxi-Add-support-for-DMA-transfers.patch
|
||||
eff2901ac5e14949f326a9d8b553f6f32d7e89502929090595b360d1b76d0d3335c94d0c4960b25603f9786524baf2386251bd4a18582ed1012a6db3e5e84618 0012-mmc-sunxi-DDR-DMA-support-for-SPL.patch
|
||||
f2ee73c774758bd13872d370bc7990474adc453531dacf15664609ca0fdc2a4844d4769376c370b7d18896ac734a7080ee709066659647a4cf0368928bf5e198 0013-spl-ARM-Enable-CPU-caches.patch
|
||||
86d9587cb2b0ca99fb4090bd0daacd47c0043858654f6f7114c8d0ed6c660eb2b8bc0b37de6723e738df9b1137d62482f00764c284f4aa0a6054db9efe754db9 0014-common-expose-DRAM-clock-speed.patch
|
||||
86d9587cb2b0ca99fb4090bd0daacd47c0043858654f6f7114c8d0ed6c660eb2b8bc0b37de6723e738df9b1137d62482f00764c284f4aa0a6054db9efe754db9 0001-common-expose-DRAM-clock-speed.patch
|
||||
9b9a5bd2cb5c04715a5bb2d34bfc06e63817dba7ec40fa2b09000a0827590623e85ed5877d6b6bb39f2bb917e5e9d8e1379e3df9128e3304be06abc487c68df2 0002-disable-bootdelay.patch
|
||||
"
|
||||
|
|
Loading…
Reference in a new issue