Update for v1.0

This commit is contained in:
James Deng 2024-05-30 23:19:44 +08:00
parent d0e22fd5b0
commit c3b72c9393
49 changed files with 1914 additions and 453 deletions

View file

@ -28,7 +28,7 @@
device_type = "cpu";
reg = <0>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
@ -42,7 +42,7 @@
device_type = "cpu";
reg = <1>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu1_intc: interrupt-controller {
@ -56,7 +56,7 @@
device_type = "cpu";
reg = <2>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu2_intc: interrupt-controller {
@ -70,7 +70,7 @@
device_type = "cpu";
reg = <3>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu3_intc: interrupt-controller {
@ -84,7 +84,7 @@
device_type = "cpu";
reg = <4>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu4_intc: interrupt-controller {
@ -98,7 +98,7 @@
device_type = "cpu";
reg = <5>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu5_intc: interrupt-controller {
@ -112,7 +112,7 @@
device_type = "cpu";
reg = <6>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu6_intc: interrupt-controller {
@ -126,7 +126,7 @@
device_type = "cpu";
reg = <7>;
status = "okay";
riscv,isa = "rv64imafdcvsu_zicsr_zifencei_zicbom_zihintpause_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
riscv,isa = "rv64imafdcv_zicsr_zifencei_zicbom_zicboz_zicbop_zihintpause_zicond_zba_zbb_zbc_zbs_svpbmt_sstc_sscofpmf";
mmu-type = "riscv,sv39";
cpu7_intc: interrupt-controller {
@ -872,4 +872,20 @@
*/
<0x0 0x0 0xffffffff 0xffffff00 0x0007fff8>;
};
watchdog:watchdog@D4080000 {
compatible = "spacemit,k1x-wdt";
reg = <0x0 0xD4080000 0x0 0x1000>,
<0x0 0xD4051020 0x0 0x4>;
clocks = <&ccu CLK_WDT>;
resets = <&reset RESET_WDT>;
status = "okay";
};
wdt_reboot {
compatible = "wdt-reboot";
wdt = <&watchdog>;
status = "okay";
};
};

View file

@ -171,10 +171,10 @@
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};

View file

@ -128,10 +128,10 @@
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};

View file

@ -188,10 +188,10 @@
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};
@ -200,7 +200,6 @@
pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
bus-width = <4>;
cd-gpios = <&gpio 80 0>;
cd-inverted;
cap-sd-highspeed;
sdh-phy-module = <0>;
clk-src-freq = <204800000>;
@ -257,7 +256,7 @@
status = "okay";
};
/*&qspi {
&qspi {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_qspi>;
@ -270,7 +269,7 @@
broken-flash-reset;
status = "okay";
};
};*/
};
&efuse {
status = "okay";

View file

@ -173,10 +173,10 @@
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};

View file

@ -170,10 +170,10 @@
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};

View file

@ -121,10 +121,13 @@
&usbdrd3 {
status = "disabled";
dwc3@c0a00000 {
maximum-speed = "high-speed";
dr_mode = "peripheral";
phy_type = "utmi_wide";
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};

View file

@ -121,10 +121,10 @@
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};

View file

@ -141,10 +141,10 @@
dr_mode = "host";
phy_type = "utmi";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis_u2_susphy_quirk;
snps,dis_u3_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
};
};

View file

@ -12,6 +12,13 @@
bus = <8>;
u-boot,dm-spl;
pmic-reset {
compatible = "spacemit,spm8821-reset";
reboot-reg = <0x7e>; /* Address of the reboot register */
reboot-mask = <0x02>; /* Bit mask for triggering a reboot */
status = "okay";
};
regulators {
/* buck */
dcdc_6: DCDC_REG1 {

View file

@ -3,5 +3,5 @@
# Copyright (c) 2022-2023 Spacemit, Inc
obj-y += k1x.o
obj-$(CONFIG_SPL_BUILD) += spl.o k1x-i2c-eeprom.o
obj-$(CONFIG_SPL_BUILD) += spl.o k1x-i2c-eeprom.o k1x-tlvinfo.o
obj-$(CONFIG_SPLASH_SOURCE) +=splash.o

View file

@ -18,14 +18,23 @@ nor_rootfstype=squashfs
// eMMC/SDCard rootfs device
mmc_rootfstype=ext4
// rootfs part number must less than 99
rootfs_part_to_ul=echo "set rootfs_part to ul"; setexpr temp_num_0 ${rootfs_part} / a;\
setexpr temp_num_1 ${rootfs_part} % a;\
setenv rootfs_part ${temp_num_0}${temp_num_1};
// Get "rootfs" partition number in decimal, and set var "mmc_root"
// Variable "boot_devnum" is set during board_lat_init()
set_mmc_root=part number mmc ${boot_devnum} rootfs rootfs_part; \
setexpr rootfs_part ${rootfs_part} + 0; \
if test ${rootfs_part} > 9 ; then run rootfs_part_to_ul;fi; \
echo "get rootfs_part index:${rootfs_part}"; \
setenv mmc_root "/dev/mmcblk${boot_devnum}p${rootfs_part}";
set_nvme_root=part number nvme ${boot_devnum} rootfs rootfs_part; \
setexpr rootfs_part ${rootfs_part} + 0; \
if test ${rootfs_part} > 9 ; then run rootfs_part_to_ul;fi; \
echo "get rootfs_part index:${rootfs_part}"; \
setenv nvme_root "/dev/nvme${boot_devnum}n1p${rootfs_part}";
//override here, otherwise gen random addr and save to eeprom by uboot
@ -74,7 +83,7 @@ dtb_env=if test -n "${product_name}"; then \
elif test "${product_name}" = k1_MINI-PC; then \
setenv dtb_name ${dtb_dir}/k1-x_MINI-PC.dtb; \
else \
echo "falling to default dtb: ${dtb_dir}/${product_name}.dtb"; \
echo "match dtb by product_name: ${dtb_dir}/${product_name}.dtb"; \
setenv dtb_name ${dtb_dir}/${product_name}.dtb; \
fi; \
fi;

View file

@ -5,6 +5,8 @@
#include <asm/io.h>
#include <common.h>
#include <asm/global_data.h>
#include <stdlib.h>
#include <linux/delay.h>
DECLARE_GLOBAL_DATA_PTR;
@ -19,6 +21,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define PULL_UP BIT(14) | BIT(15) /* pull-up */
#define I2C_PIN_CONFIG(x) ((x) | EDGE_NONE | PULL_UP | PAD_1V8_DS2)
#define READ_I2C_LINE_LEN (16)
char *spacemit_i2c_eeprom[] = {
"atmel,24c02",
@ -122,3 +125,65 @@ int k1x_eeprom_init(void)
return -EINVAL;
}
int _read_from_i2c(int chip, u32 addr, u32 size, uchar *buf)
{
u32 nbytes = size;
u32 linebytes = 0;
int ret;
do {
linebytes = (nbytes > READ_I2C_LINE_LEN) ? READ_I2C_LINE_LEN : nbytes;
ret = i2c_read(chip, addr, 1, buf, linebytes);
if (ret){
pr_err("read from i2c error:%d\n", ret);
return -1;
}
buf += linebytes;
nbytes -= linebytes;
addr += linebytes;
} while (nbytes > 0);
return 0;
}
int _write_to_i2c(int chip, u32 addr, u32 size, uchar *buf)
{
uint nbytes = size;
int ret;
while (nbytes-- > 0) {
ret = i2c_write(chip, addr++, 1, buf++, 1);
if (ret){
pr_err("write to i2c error:%d\n", ret);
return -1;
}
/*
* No write delay with FRAM devices.
*/
#if !defined(CONFIG_SYS_I2C_FRAM)
udelay(11000);
#endif
}
return 0;
}
int clear_eeprom(u32 dev, u32 erase_size)
{
char *blank_buf = calloc(0, erase_size);
int chip = k1x_eeprom_init();
if (chip < 0){
pr_err("can not get i2c bus addr\n");
return -1;
}
if (_write_to_i2c(chip, 0, erase_size, blank_buf)){
pr_err("clear eeprom fail\n");
return -1;
}
free(blank_buf);
return 0;
}

View file

@ -0,0 +1,593 @@
// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
#include <asm/io.h>
#include <stdlib.h>
#include <tlv_eeprom.h>
#include <u-boot/crc.h>
#include <net.h>
#define EEPROM_SIZE (256)
#define EEPROM_SIZE_MAX_TLV_LEN (EEPROM_SIZE - sizeof(struct tlvinfo_header))
extern int k1x_eeprom_init(void);
extern int _read_from_i2c(int chip, u32 addr, u32 size, uchar *buf);
extern int _write_to_i2c(int chip, u32 addr, u32 size, uchar *buf);
/* File scope function prototypes */
static bool is_checksum_valid(u8 *eeprom);
static void update_crc(u8 *eeprom);
static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index);
static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code);
static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval);
static int set_mac(char *buf, const char *string);
static int set_date(char *buf, const char *string);
static int set_bytes(char *buf, const char *string, int *converted_accum);
static u8 tlvinfo_eeprom[EEPROM_SIZE];
static bool had_read_tlvinfo = false;
/**
* _is_valid_tlvinfo_header
*
* Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM
* data pointed to by the parameter:
* 1. First 8 bytes contain null-terminated ASCII string "TlvInfo"
* 2. Version byte is 1
* 3. Total length bytes contain value which is less than or equal
* to the allowed maximum (2048-11)
*
*/
static bool _is_valid_tlvinfo_header(struct tlvinfo_header *hdr)
{
return ((strcmp(hdr->signature, TLV_INFO_ID_STRING) == 0) &&
(hdr->version == TLV_INFO_VERSION) &&
(be16_to_cpu(hdr->totallen) <= TLV_TOTAL_LEN_MAX));
}
static inline bool is_valid_tlv(struct tlvinfo_tlv *tlv)
{
return((tlv->type != 0x00) && (tlv->type != 0xFF));
}
static inline bool is_digit(char c)
{
return (c >= '0' && c <= '9');
}
/**
* is_hex
*
* Tests if character is an ASCII hex digit
*/
static inline u8 is_hex(char p)
{
return (((p >= '0') && (p <= '9')) ||
((p >= 'A') && (p <= 'F')) ||
((p >= 'a') && (p <= 'f')));
}
/**
* is_checksum_valid
*
* Validate the checksum in the provided TlvInfo EEPROM data. First,
* verify that the TlvInfo header is valid, then make sure the last
* TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data
* and compare it to the value stored in the EEPROM CRC-32 TLV.
*/
static bool is_checksum_valid(u8 *eeprom)
{
struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom;
struct tlvinfo_tlv *eeprom_crc;
unsigned int calc_crc;
unsigned int stored_crc;
// Is the eeprom header valid?
if (!_is_valid_tlvinfo_header(eeprom_hdr)){
pr_err("%s, not valid tlv info header\n", __func__);
return false;
}
// Is the last TLV a CRC?
eeprom_crc = (struct tlvinfo_tlv *)(&eeprom[sizeof(struct tlvinfo_header) +
be16_to_cpu(eeprom_hdr->totallen) - (sizeof(struct tlvinfo_tlv) + 4)]);
if (eeprom_crc->type != TLV_CODE_CRC_32 || eeprom_crc->length != 4)
return false;
// Calculate the checksum
calc_crc = crc32(0, (void *)eeprom,
sizeof(struct tlvinfo_header) + be16_to_cpu(eeprom_hdr->totallen) - 4);
stored_crc = (eeprom_crc->value[0] << 24) |
(eeprom_crc->value[1] << 16) |
(eeprom_crc->value[2] << 8) |
eeprom_crc->value[3];
return calc_crc == stored_crc;
}
/**
* set_mac
*
* Converts a string MAC address into a binary buffer.
*
* This function takes a pointer to a MAC address string
* (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number).
* The string format is verified and then converted to binary and
* stored in a buffer.
*/
static int set_mac(char *buf, const char *string)
{
char *p = (char *)string;
int i;
int err = 0;
char *end;
if (!p) {
pr_err("ERROR: NULL mac addr string passed in.\n");
return -1;
}
if (strlen(p) != 17) {
pr_err("ERROR: MAC address strlen() != 17 -- %zu\n", strlen(p));
pr_err("ERROR: Bad MAC address format: %s\n", string);
return -1;
}
for (i = 0; i < 17; i++) {
if ((i % 3) == 2) {
if (p[i] != ':') {
err++;
pr_err("ERROR: mac: p[%i] != :, found: `%c'\n",
i, p[i]);
break;
}
continue;
} else if (!is_hex(p[i])) {
err++;
pr_err("ERROR: mac: p[%i] != hex digit, found: `%c'\n",
i, p[i]);
break;
}
}
if (err != 0) {
pr_err("ERROR: Bad MAC address format: %s\n", string);
return -1;
}
/* Convert string to binary */
for (i = 0, p = (char *)string; i < 6; i++) {
buf[i] = p ? hextoul(p, &end) : 0;
if (p)
p = (*end) ? end + 1 : end;
}
if (!is_valid_ethaddr((u8 *)buf)) {
pr_err("ERROR: MAC address must not be 00:00:00:00:00:00, a multicast address or FF:FF:FF:FF:FF:FF.\n");
pr_err("ERROR: Bad MAC address format: %s\n", string);
return -1;
}
return 0;
}
/**
* set_date
*
* Validates the format of the data string
*
* This function takes a pointer to a date string (i.e. MM/DD/YYYY hh:mm:ss)
* and validates that the format is correct. If so the string is copied
* to the supplied buffer.
*/
static int set_date(char *buf, const char *string)
{
int i;
if (!string) {
pr_err("ERROR: NULL date string passed in.\n");
return -1;
}
if (strlen(string) != 19) {
pr_err("ERROR: Date strlen() != 19 -- %zu\n", strlen(string));
pr_err("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
string);
return -1;
}
for (i = 0; string[i] != 0; i++) {
switch (i) {
case 2:
case 5:
if (string[i] != '/') {
pr_err("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
string);
return -1;
}
break;
case 10:
if (string[i] != ' ') {
pr_err("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
string);
return -1;
}
break;
case 13:
case 16:
if (string[i] != ':') {
pr_err("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
string);
return -1;
}
break;
default:
if (!is_digit(string[i])) {
pr_err("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
string);
return -1;
}
break;
}
}
strcpy(buf, string);
return 0;
}
/**
* set_bytes
*
* Converts a space-separated string of decimal numbers into a
* buffer of bytes.
*
* This function takes a pointer to a space-separated string of decimal
* numbers (i.e. "128 0x55 0321") with "C" standard radix specifiers
* and converts them to an array of bytes.
*/
static int set_bytes(char *buf, const char *string, int *converted_accum)
{
char *p = (char *)string;
int i;
uint byte;
if (!p) {
pr_err("ERROR: NULL string passed in.\n");
return -1;
}
/* Convert string to bytes */
for (i = 0, p = (char *)string; (i < TLV_VALUE_MAX_LEN) && (*p != 0);
i++) {
while ((*p == ' ') || (*p == '\t') || (*p == ',') ||
(*p == ';')) {
p++;
}
if (*p != 0) {
if (!is_digit(*p)) {
pr_err("ERROR: Non-digit found in byte string: (%s)\n",
string);
return -1;
}
byte = simple_strtoul(p, &p, 0);
if (byte >= EEPROM_SIZE) {
pr_err("ERROR: The value specified is greater than 255: (%u) in string: %s\n",
byte, string);
return -1;
}
buf[i] = byte & 0xFF;
}
}
if (i == TLV_VALUE_MAX_LEN && (*p != 0)) {
pr_err("ERROR: Trying to assign too many bytes (max: %d) in string: %s\n",
TLV_VALUE_MAX_LEN, string);
return -1;
}
*converted_accum = i;
return 0;
}
/**
* tlvinfo_find_tlv
*
* This function finds the TLV with the supplied code in the EERPOM.
* An offset from the beginning of the EEPROM is returned in the
* eeprom_index parameter if the TLV is found.
*/
static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index)
{
struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom;
struct tlvinfo_tlv *eeprom_tlv;
int eeprom_end;
// Search through the TLVs, looking for the first one which matches the
// supplied type code.
*eeprom_index = sizeof(struct tlvinfo_header);
eeprom_end = sizeof(struct tlvinfo_header) + be16_to_cpu(eeprom_hdr->totallen);
while (*eeprom_index < eeprom_end) {
eeprom_tlv = (struct tlvinfo_tlv *)(&eeprom[*eeprom_index]);
if (!is_valid_tlv(eeprom_tlv))
return false;
if (eeprom_tlv->type == tcode)
return true;
*eeprom_index += sizeof(struct tlvinfo_tlv) + eeprom_tlv->length;
}
return(false);
}
/**
* update_crc
*
* This function updates the CRC-32 TLV. If there is no CRC-32 TLV, then
* one is added. This function should be called after each update to the
* EEPROM structure, to make sure the CRC is always correct.
*/
static void update_crc(u8 *eeprom)
{
struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom;
struct tlvinfo_tlv *eeprom_crc;
unsigned int calc_crc;
int eeprom_index;
// Discover the CRC TLV
if (!tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index)) {
unsigned int totallen = be16_to_cpu(eeprom_hdr->totallen);
if ((totallen + sizeof(struct tlvinfo_tlv) + 4) > EEPROM_SIZE_MAX_TLV_LEN)
return;
eeprom_index = sizeof(struct tlvinfo_header) + totallen;
eeprom_hdr->totallen = cpu_to_be16(totallen + sizeof(struct tlvinfo_tlv) + 4);
}
eeprom_crc = (struct tlvinfo_tlv *)(&eeprom[eeprom_index]);
eeprom_crc->type = TLV_CODE_CRC_32;
eeprom_crc->length = 4;
// Calculate the checksum
calc_crc = crc32(0, (void *)eeprom,
sizeof(struct tlvinfo_header) + be16_to_cpu(eeprom_hdr->totallen) - 4);
eeprom_crc->value[0] = (calc_crc >> 24) & 0xFF;
eeprom_crc->value[1] = (calc_crc >> 16) & 0xFF;
eeprom_crc->value[2] = (calc_crc >> 8) & 0xFF;
eeprom_crc->value[3] = (calc_crc >> 0) & 0xFF;
}
static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval)
{
struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom;
struct tlvinfo_tlv *eeprom_tlv;
int new_tlv_len = 0;
u32 value;
char data[EEPROM_SIZE];
int eeprom_index;
// Encode each TLV type into the format to be stored in the EERPOM
switch (tcode) {
case TLV_CODE_PRODUCT_NAME:
case TLV_CODE_PART_NUMBER:
case TLV_CODE_SERIAL_NUMBER:
case TLV_CODE_LABEL_REVISION:
case TLV_CODE_PLATFORM_NAME:
case TLV_CODE_ONIE_VERSION:
case TLV_CODE_MANUF_NAME:
case TLV_CODE_MANUF_COUNTRY:
case TLV_CODE_VENDOR_NAME:
case TLV_CODE_DIAG_VERSION:
case TLV_CODE_SERVICE_TAG:
strncpy(data, strval, EEPROM_SIZE);
new_tlv_len = min_t(size_t, EEPROM_SIZE, strlen(strval));
break;
case TLV_CODE_DEVICE_VERSION:
value = simple_strtoul(strval, NULL, 0);
if (value >= EEPROM_SIZE) {
pr_err("ERROR: Device version must be 255 or less. Value supplied: %u",
value);
return false;
}
data[0] = value & 0xFF;
new_tlv_len = 1;
break;
case TLV_CODE_MAC_SIZE:
value = simple_strtoul(strval, NULL, 0);
if (value >= 65536) {
pr_err("ERROR: MAC Size must be 65535 or less. Value supplied: %u",
value);
return false;
}
data[0] = (value >> 8) & 0xFF;
data[1] = value & 0xFF;
new_tlv_len = 2;
break;
case TLV_CODE_MANUF_DATE:
if (set_date(data, strval) != 0)
return false;
new_tlv_len = 19;
break;
case TLV_CODE_MAC_BASE:
if (set_mac(data, strval) != 0)
return false;
new_tlv_len = 6;
break;
case TLV_CODE_CRC_32:
pr_err("WARNING: The CRC TLV is set automatically and cannot be set manually.\n");
return false;
case TLV_CODE_VENDOR_EXT:
default:
if (set_bytes(data, strval, &new_tlv_len) != 0)
return false;
break;
}
// Is there room for this TLV?
if ((be16_to_cpu(eeprom_hdr->totallen) + sizeof(struct tlvinfo_tlv) + new_tlv_len) >
EEPROM_SIZE_MAX_TLV_LEN) {
pr_err("ERROR: There is not enough room in the EERPOM to save data.\n");
return false;
}
// Add TLV at the end, overwriting CRC TLV if it exists
if (tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index))
eeprom_hdr->totallen =
cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
sizeof(struct tlvinfo_tlv) - 4);
else
eeprom_index = sizeof(struct tlvinfo_header) + be16_to_cpu(eeprom_hdr->totallen);
eeprom_tlv = (struct tlvinfo_tlv *)(&eeprom[eeprom_index]);
eeprom_tlv->type = tcode;
eeprom_tlv->length = new_tlv_len;
memcpy(eeprom_tlv->value, data, new_tlv_len);
// Update the total length and calculate (add) a new CRC-32 TLV
eeprom_hdr->totallen = cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) +
sizeof(struct tlvinfo_tlv) + new_tlv_len);
update_crc(eeprom);
return true;
}
static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code)
{
int eeprom_index;
int tlength;
struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom;
struct tlvinfo_tlv *eeprom_tlv;
// Find the TLV and then move all following TLVs "forward"
if (tlvinfo_find_tlv(eeprom, code, &eeprom_index)) {
eeprom_tlv = (struct tlvinfo_tlv *)(&eeprom[eeprom_index]);
tlength = sizeof(struct tlvinfo_tlv) + eeprom_tlv->length;
memcpy(&eeprom[eeprom_index], &eeprom[eeprom_index + tlength],
sizeof(struct tlvinfo_header) +
be16_to_cpu(eeprom_hdr->totallen) - eeprom_index -
tlength);
eeprom_hdr->totallen =
cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
tlength);
update_crc(eeprom);
return true;
}
return false;
}
static int read_tlvinfo_from_eeprom(u8 *eeprom)
{
struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom;
struct tlvinfo_tlv *eeprom_tlv = (struct tlvinfo_tlv *)(&eeprom[sizeof(struct tlvinfo_header)]);
int chip;
chip = k1x_eeprom_init();
if (chip < 0){
pr_err("can not get i2c bus addr\n");
return -1;
}
/*read tlv head info*/
if (_read_from_i2c(chip, 0, sizeof(struct tlvinfo_header), (uchar *)eeprom_hdr)){
pr_err("read tlvinfo_header from i2c fail\n");
return -1;
}
if (_is_valid_tlvinfo_header(eeprom_hdr)){
if (_read_from_i2c(chip, sizeof(struct tlvinfo_header), be16_to_cpu(eeprom_hdr->totallen),
(uchar *)eeprom_tlv)){
pr_err("read tlvinvo_tlv from i2c fail\n");
return -1;
}
}
// If the contents are invalid, start over with default contents
if (!_is_valid_tlvinfo_header(eeprom_hdr) ||
!is_checksum_valid(eeprom)) {
strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
eeprom_hdr->version = TLV_INFO_VERSION;
eeprom_hdr->totallen = cpu_to_be16(0);
pr_info("update new tlv info\n");
update_crc(eeprom);
}
return 0;
}
int get_tlvinfo_from_eeprom(int tcode, char *buf)
{
int tlv_end;
int curr_tlv;
u8 eeprom[EEPROM_SIZE];
memset(eeprom, 0, EEPROM_SIZE);
if (read_tlvinfo_from_eeprom(eeprom)){
pr_err("read tlv info fail\n");
return -1;
}
struct tlvinfo_header *eeprom_hdr = (struct tlvinfo_header *)eeprom;
struct tlvinfo_tlv *eeprom_tlv;
curr_tlv = sizeof(struct tlvinfo_header);
tlv_end = sizeof(struct tlvinfo_header) + be16_to_cpu(eeprom_hdr->totallen);
while (curr_tlv < tlv_end) {
eeprom_tlv = (struct tlvinfo_tlv *)(&eeprom[curr_tlv]);
if (!is_valid_tlv(eeprom_tlv)) {
pr_err("Invalid TLV field starting at EEPROM offset %d\n",
curr_tlv);
return -1;
}
if (eeprom_tlv->type == tcode){
memcpy(buf, eeprom_tlv->value, eeprom_tlv->length);
pr_info("get tlvinfo value:%x,%s\n", tcode, buf);
return 0;
}
curr_tlv += sizeof(struct tlvinfo_tlv) + eeprom_tlv->length;
}
pr_info("can not get tlvinfo index:%x\n", tcode);
return -1;
}
int set_val_to_tlvinfo(int tcode, char *val)
{
if (!had_read_tlvinfo){
/*read tlvinfo at first*/
read_tlvinfo_from_eeprom(tlvinfo_eeprom);
had_read_tlvinfo = true;
}
tlvinfo_delete_tlv(tlvinfo_eeprom, tcode);
if (val != NULL)
tlvinfo_add_tlv(tlvinfo_eeprom, tcode, val);
return 0;
}
int write_tlvinfo_to_eeprom(void)
{
struct tlvinfo_header *eeprom_hdr;
int eeprom_len;
int chip = k1x_eeprom_init();
if (chip < 0){
pr_err("can not get i2c bus addr\n");
return -1;
}
if (!had_read_tlvinfo){
/*read tlvinfo at first*/
read_tlvinfo_from_eeprom(tlvinfo_eeprom);
had_read_tlvinfo = true;
}
eeprom_hdr = (struct tlvinfo_header *)tlvinfo_eeprom;
update_crc(tlvinfo_eeprom);
eeprom_len = sizeof(struct tlvinfo_header) + be16_to_cpu(eeprom_hdr->totallen);
if (_write_to_i2c(chip, 0, eeprom_len, tlvinfo_eeprom)){
pr_err("write to eeprom fail\n");
return -1;
}
return 0;
}

View file

@ -32,13 +32,16 @@
#include <tlv_eeprom.h>
#include <u-boot/crc.h>
#include <fb_mtd.h>
#include <power/pmic.h>
#include <dm/device.h>
#include <dm/device-internal.h>
#include <g_dnl.h>
DECLARE_GLOBAL_DATA_PTR;
static char found_partition[64] = {0};
extern u32 ddr_cs_num;
#ifdef CONFIG_DISPLAY_SPACEMIT_HDMI
extern int is_hdmi_connected;
#endif
bool is_video_connected = false;
uint32_t reboot_config;
void refresh_config_info(u8 *eeprom_data);
int mac_read_from_buffer(u8 *eeprom_data);
@ -100,6 +103,16 @@ enum board_boot_mode get_boot_mode(void)
return get_boot_pin_select();
}
void set_serialnumber_based_on_boot_mode(void)
{
const char *s = env_get("serial#");
enum board_boot_mode boot_mode = get_boot_mode();
if (boot_mode != BOOT_MODE_USB && s) {
g_dnl_set_serialnumber((char *)s);
}
}
enum board_boot_mode get_boot_storage(void)
{
enum board_boot_mode boot_storage = get_boot_mode();
@ -218,17 +231,59 @@ void get_ddr_config_info(void)
ddr_cs_num = DDR_CS_NUM;
}
u32 get_reboot_config(void)
{
int ret;
struct udevice *dev;
u32 flag = 0;
uint8_t value;
if (reboot_config)
return reboot_config;
/* K1 has non-reset register(BOOT_CIU_DEBUG_REG0) to save boot config
before system reboot, but it will be clear when K1 power is down,
then boot config will be save in P1.
*/
flag = readl((void *)BOOT_CIU_DEBUG_REG0);
if ((BOOT_MODE_SHELL == flag) || (BOOT_MODE_USB == flag)) {
/* reset */
writel(0, (void *)BOOT_CIU_DEBUG_REG0);
reboot_config = flag;
}
else {
// select boot mode from boot strap pin
reboot_config = BOOT_MODE_BOOTSTRAP;
ret = uclass_get_device_by_driver(UCLASS_PMIC,
DM_DRIVER_GET(spacemit_pm8xx), &dev);
if (ret) {
pr_err("PMIC init failed: %d\n", ret);
return 0;
}
pmic_read(dev, P1_NON_RESET_REG, &value, 1);
pr_info("Read PMIC reg %x value %x\n", P1_NON_RESET_REG, value);
if (1 == (value & 3)) {
reboot_config = BOOT_MODE_USB;
value &= ~3;
pmic_write(dev, P1_NON_RESET_REG, &value, 1);
}
else if (2 == (value & 3)) {
reboot_config = BOOT_MODE_SHELL;
value &= ~3;
pmic_write(dev, P1_NON_RESET_REG, &value, 1);
}
}
return reboot_config;
}
void run_fastboot_command(void)
{
u32 boot_mode = get_boot_mode();
/*if define BOOT_MODE_USB flag in BOOT_CIU_DEBUG_REG0, it would excute fastboot*/
u32 cui_flasg = readl((void *)BOOT_CIU_DEBUG_REG0);
if (boot_mode == BOOT_MODE_USB || cui_flasg == BOOT_MODE_USB){
if (boot_mode == BOOT_MODE_USB || BOOT_MODE_USB == get_reboot_config()) {
/* show flash log*/
env_set("stdout", env_get("stdout_flash"));
/*would reset debug_reg0*/
writel(0, (void *)BOOT_CIU_DEBUG_REG0);
char *cmd_para = "fastboot 0";
run_command(cmd_para, 0);
@ -242,11 +297,7 @@ int run_uboot_shell(void)
{
u32 boot_mode = get_boot_mode();
/*if define BOOT_MODE_SHELL flag in BOOT_CIU_DEBUG_REG0, it would into uboot shell*/
u32 flag = readl((void *)BOOT_CIU_DEBUG_REG0);
if (boot_mode == BOOT_MODE_SHELL || flag == BOOT_MODE_SHELL){
/*would reset debug_reg0*/
writel(0, (void *)BOOT_CIU_DEBUG_REG0);
if (boot_mode == BOOT_MODE_SHELL || BOOT_MODE_SHELL == get_reboot_config()) {
return 0;
}
return 1;
@ -640,6 +691,9 @@ void set_env_ethaddr(u8 *eeprom_data) {
eth_env_set_enetaddr("ethaddr", mac_addr);
eth_env_set_enetaddr("eth1addr", mac1_addr);
/*must read before set/write to eeprom using tlv_eeprom command*/
run_command("tlv_eeprom", 0);
/* save mac address to eeprom */
snprintf(cmd_str, (sizeof(cmd_str) - 1), "tlv_eeprom set 0x24 %02x:%02x:%02x:%02x:%02x:%02x", \
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
@ -686,6 +740,9 @@ void set_dev_serial_no(uint8_t *eeprom_data)
}
pr_info("\n");
/*must read before set/write to eeprom using tlv_eeprom command*/
run_command("tlv_eeprom", 0);
/* save serial number to eeprom */
snprintf(cmd_str, (sizeof(cmd_str) - 1), "tlv_eeprom set 0x23 %02x%02x%02x%02x%02x%02x", \
sn[0], sn[1], sn[2], sn[3], sn[4], sn[5]);
@ -706,7 +763,6 @@ void refresh_config_info(u8 *eeprom_data)
struct tlvinfo_tlv *tlv_info = NULL;
char *strval;
int i;
char tmp_name[64];
const struct code_desc_info {
u8 m_code;
@ -742,15 +798,6 @@ void refresh_config_info(u8 *eeprom_data)
strval = malloc(tlv_info->length + 1);
memcpy(strval, tlv_info->value, tlv_info->length);
strval[tlv_info->length] = '\0';
/*
be compatible to previous format name,
such as: k1_deb1 -> k1-x_deb1
*/
if (info[i].m_code == TLV_CODE_PRODUCT_NAME && strncmp(strval, CONFIG_SYS_BOARD, 4)){
sprintf(tmp_name, "%s_%s", CONFIG_SYS_BOARD, &strval[3]);
strcpy(strval, tmp_name);
}
}
env_set(info[i].m_name, strval);
free(strval);
@ -809,6 +856,19 @@ int board_late_init(void)
refresh_config_info(NULL);
}
set_serialnumber_based_on_boot_mode();
#ifdef CONFIG_VIDEO_SPACEMIT
ret = uclass_probe_all(UCLASS_VIDEO);
if (ret) {
pr_info("video devices not found or not probed yet: %d\n", ret);
}
ret = uclass_probe_all(UCLASS_DISPLAY);
if (ret) {
pr_info("display devices not found or not probed yet: %d\n", ret);
}
#endif
run_fastboot_command();
run_cardfirmware_flash_command();
@ -822,11 +882,9 @@ int board_late_init(void)
/*import env.txt from bootfs*/
import_env_from_bootfs();
#ifdef CONFIG_DISPLAY_SPACEMIT_HDMI
if (is_hdmi_connected < 0) {
if (!is_video_connected) {
env_set("stdout", "serial");
}
#endif
setenv_boot_mode();
@ -969,8 +1027,18 @@ ulong board_get_usable_ram_top(ulong total_size)
#if !defined(CONFIG_SPL_BUILD)
int board_fit_config_name_match(const char *name)
{
char tmp_name[64];
char *product_name = env_get("product_name");
/*
be compatible to previous format name,
such as: k1_deb1 -> k1-x_deb1
*/
if (!strncmp(product_name, "k1_", 3)){
sprintf(tmp_name, "%s_%s", "k1-x", &product_name[3]);
product_name = tmp_name;
}
if ((NULL != product_name) && (0 == strcmp(product_name, name))) {
log_emerg("Boot from fit configuration %s\n", name);
return 0;

View file

@ -526,11 +526,21 @@ void board_init_f(ulong dummy)
int board_fit_config_name_match(const char *name)
{
char *buildin_name;
char tmp_name[64];
buildin_name = product_name;
if (NULL == buildin_name)
buildin_name = DEFAULT_PRODUCT_NAME;
/*
be compatible to previous format name,
such as: k1_deb1 -> k1-x_deb1
*/
if (!strncmp(buildin_name, "k1_", 3)){
sprintf(tmp_name, "%s_%s", "k1-x", &buildin_name[3]);
buildin_name = tmp_name;
}
if ((NULL != buildin_name) && (0 == strcmp(buildin_name, name))) {
log_emerg("Boot from fit configuration %s\n", name);
return 0;
@ -643,22 +653,12 @@ char *get_product_name(void)
{
char *name = NULL;
int eeprom_addr;
char tmp_name[64];
eeprom_addr = k1x_eeprom_init();
name = calloc(1, 64);
if ((eeprom_addr >= 0) && (NULL != name) && (0 == spacemit_eeprom_read(
eeprom_addr, name, TLV_CODE_PRODUCT_NAME))) {
pr_info("Get product name from eeprom %s\n", name);
/*
be compatible to previous format name,
such as: k1_deb1 -> k1-x_deb1
*/
if (strncmp(name, CONFIG_SYS_BOARD, 4)){
sprintf(tmp_name, "%s_%s", CONFIG_SYS_BOARD, &name[3]);
strcpy(name, tmp_name);
}
return name;
}

View file

@ -17,6 +17,10 @@
#include <linux/delay.h>
#include <linux/string.h>
#ifdef CONFIG_VIDEO_SPACEMIT
extern bool is_video_connected;
#endif
/* maximum bootmenu entries */
#define MAX_COUNT 99
@ -600,7 +604,14 @@ int menu_show(int bootdelay)
return 0;
#endif
env_set("stdout","serial,vidconsole");
#ifdef CONFIG_VIDEO_SPACEMIT
printf("menu_show:is_video_connected: %d\n", is_video_connected);
if (is_video_connected) {
env_set("stdout", "serial,vidconsole");
} else {
env_set("stdout", "serial");
}
#endif
while (1) {
ret = bootmenu_show(bootdelay);
@ -616,7 +627,8 @@ int menu_show(int bootdelay)
run_command("run bootcmd", 0);
}
} else {
}
if (ret == BOOTMENU_RET_QUIT) {
break;
}
}

View file

@ -51,98 +51,6 @@ static void free_flash_dev(struct flash_dev *fdev)
free(fdev);
}
static int _write_gpt_partition(struct flash_dev *fdev)
{
__maybe_unused char write_part_command[300] = {"\0"};
char *gpt_table_str = NULL;
u32 boot_mode = get_boot_pin_select();
if (fdev->gptinfo.gpt_table != NULL && strlen(fdev->gptinfo.gpt_table) > 0){
gpt_table_str = malloc(strlen(fdev->gptinfo.gpt_table) + 32);
if (gpt_table_str == NULL){
return -1;
}
sprintf(gpt_table_str, "env set -f partitions '%s'", fdev->gptinfo.gpt_table);
run_command(gpt_table_str, 0);
free(gpt_table_str);
}
switch(boot_mode){
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
case BOOT_MODE_EMMC:
case BOOT_MODE_SD:
sprintf(write_part_command, "gpt write mmc %x '%s'",
CONFIG_FASTBOOT_FLASH_MMC_DEV, fdev->gptinfo.gpt_table);
if (run_command(write_part_command, 0)){
printf("write gpt fail\n");
return -1;
}
break;
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_SUPPORT_BLOCK_DEV)
case BOOT_MODE_NOR:
case BOOT_MODE_NAND:
printf("write gpt to dev:%s\n", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME);
/*nvme need scan at first*/
if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)
&& nvme_scan_namespace()){
printf("can not can nvme devices!\n");
return -1;
}
sprintf(write_part_command, "gpt write %s %x '%s'",
CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX,
fdev->gptinfo.gpt_table);
if (run_command(write_part_command, 0)){
printf("write gpt fail\n");
return -1;
}
break;
#endif
default:
break;
}
return 0;
}
static int _write_mtd_partition(char mtd_table[128])
{
#ifdef CONFIG_MTD
struct mtd_info *mtd;
char mtd_ids[36] = {"\0"};
char mtd_parts[128] = {"\0"};
mtd_probe_devices();
/*
try to find the first mtd device, it there have mutil mtd device such as nand and nor,
it only use the first one.
*/
mtd_for_each_device(mtd) {
if (!mtd_is_partition(mtd))
break;
}
if (mtd == NULL){
printf("can not get mtd device\n");
return -1;
}
/*to mtd device, it should write mtd table to env.*/
sprintf(mtd_ids, "%s=spi-dev", mtd->name);
sprintf(mtd_parts, "spi-dev:%s", mtd_table);
env_set("mtdids", mtd_ids);
env_set("mtdparts", mtd_parts);
#endif
return 0;
}
/* Initialize the mmc device given its number */
static int init_mmc_device(int dev_num)
{
@ -899,11 +807,13 @@ static int parse_flash_config(struct flash_dev *fdev)
}
if (fdev->gptinfo.gpt_table != NULL && strlen(fdev->gptinfo.gpt_table) > 1 && fdev->gptinfo.fastboot_flash_gpt){
_write_gpt_partition(fdev);
if (_write_gpt_partition(fdev))
return -1;
}
if (fdev->mtd_table != NULL && strlen(fdev->mtd_table) > 1){
_write_mtd_partition(fdev->mtd_table);
if (_write_mtd_partition(fdev))
return -1;
}
/*set partition to env*/

View file

@ -59,6 +59,7 @@ CONFIG_SYS_SPL_MALLOC_SIZE=0x2000000
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION=y
CONFIG_SPL_ENV_SUPPORT=y
CONFIG_SPL_I2C=y
CONFIG_SPL_MMC_WRITE=y
CONFIG_SPL_MTD_SUPPORT=y
CONFIG_SPL_DM_SPI_FLASH=y
CONFIG_SPL_DM_RESET=y
@ -81,6 +82,8 @@ CONFIG_SYS_PBSIZE=276
CONFIG_CMD_TLV_EEPROM=y
CONFIG_SYS_BOOTM_LEN=0xa000000
CONFIG_CMD_EEPROM=y
CONFIG_CMD_MD5SUM=y
CONFIG_CMD_ZIP=y
CONFIG_CMD_CLK=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_GPIO_READ=y
@ -93,6 +96,7 @@ CONFIG_CMD_MTD=y
CONFIG_CMD_PART=y
# CONFIG_CMD_SCSI is not set
CONFIG_CMD_USB=y
CONFIG_CMD_WDT=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_TFTPPUT=y
CONFIG_CMD_TFTPSRV=y
@ -152,6 +156,9 @@ CONFIG_FASTBOOT_MMC_BOOT2_NAME="fsbl_1"
CONFIG_FASTBOOT_CMD_OEM_READ=y
CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV=y
CONFIG_FASTBOOT_CMD_OEM_CONFIG_ACCESS=y
CONFIG_SPL_FASTBOOT_CMD_OEM_CONFIG_ACCESS=y
CONFIG_FASTBOOT_CMD_OEM_ERASE=y
CONFIG_SPL_FASTBOOT_CMD_OEM_ERASE=y
CONFIG_FASTBOOT_CMD_OEM_ENV_ACCESS=y
CONFIG_SPL_FASTBOOT_CMD_OEM_ENV_ACCESS=y
CONFIG_K1X_GPIO=y
@ -180,6 +187,7 @@ CONFIG_MMC_SDHCI_K1X=y
CONFIG_DM_MTD=y
# CONFIG_MTD_NOR_FLASH is not set
CONFIG_MTD_SPI_NAND=y
CONFIG_SPI_FLASH_GIGADEVICE=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SPI_FLASH_FM=y
CONFIG_SPINOR_BLOCK_SUPPORT=y
@ -201,6 +209,7 @@ CONFIG_DM_PMIC=y
CONFIG_PMIC_SPM8XX=y
CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_SPM8XX=y
CONFIG_DM_REGULATOR_SPACEMIT_HUB=y
CONFIG_SPL_SPACEMIT_POWER=y
CONFIG_RESET_SPACEMIT_K1X=y
# CONFIG_SCSI is not set
@ -212,6 +221,7 @@ CONFIG_SPI=y
CONFIG_K1X_QSPI=y
# CONFIG_SYSRESET_SBI is not set
# CONFIG_SYSRESET_SYSCON is not set
CONFIG_SYSRESET_WATCHDOG=y
CONFIG_SYSRESET_SPACEMIT=y
CONFIG_TIMER_EARLY=y
CONFIG_USB=y
@ -227,6 +237,7 @@ CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VENDOR_NUM=0x361C
CONFIG_USB_GADGET_PRODUCT_NUM=0x1001
CONFIG_USB2_K1X_CI=y
# CONFIG_USB_SET_SERIAL_NUMBER is not set
CONFIG_DM_VIDEO=y
CONFIG_VIDEO_PCI_DEFAULT_FB_SIZE=0x8000000
CONFIG_VIDEO_COPY=y
@ -242,6 +253,8 @@ CONFIG_BMP_32BPP=y
CONFIG_VIDEO_SPACEMIT=y
CONFIG_DISPLAY_SPACEMIT_HDMI=y
CONFIG_DISPLAY_SPACEMIT_MIPI=y
CONFIG_WDT=y
CONFIG_WDT_SPACEMIT=y
CONFIG_JFFS2_NOR=y
CONFIG_JFFS2_USE_MTD_READ=y
CONFIG_UBIFS_SILENCE_MSG=y

View file

@ -26,7 +26,9 @@ configure)
FSBL=/dev/mmcblk0p1
FSBL_SEEK=0
ENV=/dev/mmcblk0p2
ENV_SEEK=0
UBOOT=/dev/mmcblk0p4
UBOOT_SEEK=0
;;
"/dev/mmcblk2"*)
BOOTINFO_FILE=bootinfo_emmc.bin
@ -34,13 +36,26 @@ configure)
FSBL=/dev/mmcblk2boot0
FSBL_SEEK=512
ENV=/dev/mmcblk2p2
ENV_SEEK=0
UBOOT=/dev/mmcblk2p4
UBOOT_SEEK=0
if [ -e $BOOTINFO ]; then
echo 0 | tee /sys/block/mmcblk2boot0/force_ro
else
exit 0
fi
;;
"/dev/nvme0n1"*)
BOOTINFO_FILE=bootinfo_spinor.bin
BOOTINFO=/dev/mtdblock0
FSBL=/dev/mtdblock0
FSBL_SEEK=$((128 * 1024))
ENV=/dev/mtdblock0
ENV_SEEK=$((384 * 1024))
UBOOT=/dev/mtdblock0
# 以KB为单位
UBOOT_SEEK=640
;;
*)
echo "Unsupported root=$ROOT"
exit 0
@ -65,8 +80,8 @@ configure)
# 此前已经做了所有检查
dd if=/usr/lib/u-boot/$target/$BOOTINFO_FILE of=$BOOTINFO && sync
dd if=/usr/lib/u-boot/$target/FSBL.bin of=$FSBL seek=$FSBL_SEEK bs=1 && sync
dd if=/usr/lib/u-boot/$target/env.bin of=$ENV bs=1 && sync
dd if=/usr/lib/u-boot/$target/u-boot.itb of=$UBOOT bs=1M && sync
dd if=/usr/lib/u-boot/$target/env.bin of=$ENV seek=$ENV_SEEK bs=1 && sync
dd if=/usr/lib/u-boot/$target/u-boot.itb of=$UBOOT seek=$UBOOT_SEEK bs=1K && sync
;;
esac

View file

@ -261,9 +261,9 @@ static SPACEMIT_CCU_GATE_NO_PARENT(usb30_clk, "usb30_clk", NULL,
0);
static const char * const qspi_parent_names[] = {"clk_dummy", "clk_dummy", "clk_dummy",
"clk_dummy", "clk_dummy", "pll1_d23_106p8"};
static SPACEMIT_CCU_DIV_MFC_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names,
static SPACEMIT_CCU_DIV_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names,
BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
9, 3, BIT(12),
9, 3,
6, 3, BIT(4), BIT(4), 0x0,
0);
static SPACEMIT_CCU_GATE_NO_PARENT(qspi_bus_clk, "qspi_bus_clk", NULL,

View file

@ -275,6 +275,24 @@ config FASTBOOT_CMD_OEM_CONFIG_ACCESS
Add support for the "oem config:read/write/flush" command from a fastboot client. This command
include configuration read, write and flush operation.
config SPL_FASTBOOT_CMD_OEM_CONFIG_ACCESS
bool "Enable the 'oem config' command in SPL"
help
Add support for the "oem config:read/write/flush" command from a fastboot client. This command
include configuration read, write and flush operation.
config FASTBOOT_CMD_OEM_ERASE
bool "Enable the 'oem erase' command"
help
Add support for the "oem erase:[eeprom, emmc]" command from a fastboot client. This command
include configuration eeprom or emmc.
config SPL_FASTBOOT_CMD_OEM_ERASE
bool "Enable the 'oem erase' command in SPL"
help
Add support for the "oem erase:[eeprom, emmc]" command from a fastboot client. This command
include configuration eeprom or emmc.
config FASTBOOT_CMD_OEM_ENV_ACCESS
bool "Enable the 'oem env' command"
help

View file

@ -9,5 +9,5 @@ obj-$(CONFIG_$(SPL_)FASTBOOT_FLASH_NAND) += fb_nand.o
obj-$(CONFIG_$(SPL_)FASTBOOT_FLASH_MTD) += fb_mtd.o
obj-$(CONFIG_$(SPL_)FASTBOOT_MULTI_FLASH_OPTION_MMC) += fb_mmc.o
obj-$(CONFIG_$(SPL_)FASTBOOT_MULTI_FLASH_OPTION_MTD) += fb_mtd.o
obj-$(CONFIG_FASTBOOT_MULTI_FLASH_OPTION_MTD) += fb_mtd.o
obj-$(CONFIG_$(SPL_)FASTBOOT_SUPPORT_BLOCK_DEV) += fb_blk.o

View file

@ -182,7 +182,7 @@ void fastboot_blk_flash_write(const char *cmd, void *download_buffer,
/*save crc value to compare after flash image*/
u64 compare_val = 0;
/*use for gzip image*/
static u32 __maybe_unused part_offset_t = 0;
static ulong __maybe_unused part_offset_t = 0;
static char __maybe_unused part_name_t[20] = "";
unsigned long __maybe_unused src_len = ~0UL;
bool gzip_image = false;
@ -218,7 +218,7 @@ void fastboot_blk_flash_write(const char *cmd, void *download_buffer,
if (fastboot_blk_get_part_info(cmd, &dev_desc, &info, response) < 0)
return;
if (gzip_parse_header((uchar *)download_buffer, src_len) >= 0) {
if (check_gzip_format((uchar *)download_buffer, src_len) >= 0) {
/*is gzip data and equal part name*/
gzip_image = true;
if (strcmp(cmd, part_name_t)){

View file

@ -69,6 +69,10 @@ static void oem_read(char *cmd_parameter, char *response);
static void oem_config(char *cmd_parameter, char *response);
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ERASE)
static void oem_erase(char *cmd_parameter, char *response);
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
static void oem_env(char *cmd_parameter, char *response);
#endif
@ -167,6 +171,12 @@ static const struct {
.dispatch = oem_config,
},
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ERASE)
[FASTBOOT_COMMAND_OEM_ERASE] = {
.command = "oem erase",
.dispatch = oem_erase,
},
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
[FASTBOOT_COMMAND_ENV_ACCESS] = {
.command = "oem env",
@ -817,6 +827,20 @@ static void oem_config(char *cmd_parameter, char *response)
}
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ERASE)
/**
* oem_erase() - Execute the OEM erase command
*
* @cmd_parameter: Pointer to command parameter
* @response: Pointer to fastboot response buffer
*/
static void oem_erase(char *cmd_parameter, char *response)
{
clear_storage_data(cmd_parameter, response);
return;
}
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
void fastboot_env_access(char *operation, char *env, char *response);
/**

View file

@ -524,7 +524,7 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
/*save crc value to compare after flash image*/
u64 compare_val = 0;
/*use for gzip image*/
static u32 __maybe_unused part_offset_t = 0;
static ulong __maybe_unused part_offset_t = 0;
static char __maybe_unused part_name_t[20] = "";
unsigned long __maybe_unused src_len = ~0UL;
bool gzip_image = false;
@ -670,7 +670,7 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
fastboot_mmc_get_part_info(cmd, &dev_desc, &info, response) < 0)
return;
if (gzip_parse_header((uchar *)download_buffer, src_len) >= 0) {
if (check_gzip_format((uchar *)download_buffer, src_len) >= 0) {
/*is gzip data and equal part name*/
gzip_image = true;
if (strcmp(cmd, part_name_t)){

View file

@ -24,6 +24,8 @@ struct fb_mtd_sparse {
struct part_info *part;
};
static bool unlock_flag = false;
static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
{
return !do_div(size, mtd->writesize);
@ -362,14 +364,6 @@ void fastboot_mtd_flash_write(const char *cmd, void *download_buffer,
response, fdev);
return;
}
/*flash env*/
/*if (strcmp(cmd, "env") == 0) {*/
/* printf("flash env \n");*/
/* fastboot_oem_flash_env(cmd, fastboot_buf_addr, download_bytes,*/
/* response, fdev);*/
/* return;*/
/*}*/
#endif
ret = fb_mtd_lookup(cmd, &mtd, &part);
@ -380,6 +374,12 @@ void fastboot_mtd_flash_write(const char *cmd, void *download_buffer,
return;
}
/*unlock nor flash protect*/
if (!unlock_flag && mtd->type == MTD_NORFLASH){
run_commandf("sf probe;sf protect unlock 0 0x%x", mtd->size);
unlock_flag = true;
}
if (need_erase) {
/*must erase at first when write data to mtd devices*/
printf("Erasing MTD partition %s\n", part->name);
@ -492,6 +492,12 @@ void fastboot_mtd_flash_erase(const char *cmd, char *response)
return;
}
/*unlock nor flash protect*/
if (!unlock_flag && mtd->type == MTD_NORFLASH){
run_commandf("sf probe;sf protect unlock 0 0x%x", mtd->size);
unlock_flag = true;
}
ret = _fb_mtd_erase(mtd, 0);
if (ret) {
pr_err("failed erasing from device %s", mtd->name);

View file

@ -35,32 +35,38 @@
#define EMMC_MAX_BLK_WRITE 16384
#if CONFIG_IS_ENABLED(SPACEMIT_FLASH)
static int _write_gpt_partition(struct flash_dev *fdev, char *response)
int _write_gpt_partition(struct flash_dev *fdev)
{
__maybe_unused char write_part_command[300] = {"\0"};
char *gpt_table_str = NULL;
int ret = 0;
u32 boot_mode = get_boot_pin_select();
if (fdev->gptinfo.gpt_table != NULL && strlen(fdev->gptinfo.gpt_table) > 0){
gpt_table_str = malloc(strlen(fdev->gptinfo.gpt_table) + 32);
if (gpt_table_str == NULL){
pr_err("malloc size fail\n");
return -1;
}
sprintf(gpt_table_str, "env set -f partitions '%s'", fdev->gptinfo.gpt_table);
run_command(gpt_table_str, 0);
free(gpt_table_str);
} else{
pr_info("parse gpt table is NULL, do nothing");
return 0;
}
memset(gpt_table_str, 0, strlen(fdev->gptinfo.gpt_table) + 32);
switch(boot_mode){
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
case BOOT_MODE_EMMC:
case BOOT_MODE_SD:
sprintf(write_part_command, "gpt write mmc %x '%s'",
sprintf(gpt_table_str, "gpt write mmc %x '%s'",
CONFIG_FASTBOOT_FLASH_MMC_DEV, fdev->gptinfo.gpt_table);
if (run_command(write_part_command, 0)){
fastboot_fail("write gpt fail", response);
return -1;
if (run_command(gpt_table_str, 0)){
pr_err("write gpt fail");
ret = -1;
goto err;
}
break;
#endif
@ -73,26 +79,31 @@ static int _write_gpt_partition(struct flash_dev *fdev, char *response)
/*nvme need scan at first*/
if (!strncmp("nvme", CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, 4)
&& nvme_scan_namespace()){
fastboot_fail("can not can nvme devices!", response);
return -1;
pr_err("can not can nvme devices!");
ret = -1;
goto err;
}
sprintf(write_part_command, "gpt write %s %x '%s'",
sprintf(gpt_table_str, "gpt write %s %x '%s'",
CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_NAME, CONFIG_FASTBOOT_SUPPORT_BLOCK_DEV_INDEX,
fdev->gptinfo.gpt_table);
if (run_command(write_part_command, 0)){
fastboot_fail("write gpt fail", response);
return -1;
if (run_command(gpt_table_str, 0)){
pr_err("write gpt fail");
ret = -1;
goto err;
}
break;
#endif
default:
break;
pr_err("no dev to write gpt table, check your env\n");
ret = -1;
goto err;
}
pr_info("parse gpt/mtd table okay");
err:
free(gpt_table_str);
fastboot_okay("parse gpt/mtd table okay", response);
return 0;
return ret;
}
int _clear_env_part(void *download_buffer, u32 download_bytes,
@ -152,12 +163,18 @@ int _clear_env_part(void *download_buffer, u32 download_bytes,
return 0;
}
static int _write_mtd_partition(char mtd_table[128], char *response)
int _write_mtd_partition(struct flash_dev *fdev)
{
#ifdef CONFIG_MTD
struct mtd_info *mtd;
char mtd_ids[36] = {"\0"};
char mtd_parts[128] = {"\0"};
char *mtd_parts = NULL;
mtd_parts = malloc(strlen(fdev->mtd_table) + 32);
if (mtd_parts == NULL){
pr_err("malloc size fail\n");
return -1;
}
mtd_probe_devices();
@ -171,18 +188,20 @@ static int _write_mtd_partition(char mtd_table[128], char *response)
}
if (mtd == NULL){
fastboot_fail("can not get mtd device", response);
pr_err("can not get mtd device");
free(mtd_parts);
return -1;
}
/*to mtd device, it should write mtd table to env.*/
sprintf(mtd_ids, "%s=spi-dev", mtd->name);
sprintf(mtd_parts, "spi-dev:%s", mtd_table);
sprintf(mtd_parts, "spi-dev:%s", fdev->mtd_table);
env_set("mtdids", mtd_ids);
env_set("mtdparts", mtd_parts);
#endif
fastboot_okay("parse gpt/mtd table okay", response);
pr_info("parse gpt/mtd table okay");
return 0;
}
@ -256,8 +275,10 @@ int _parse_flash_config(struct flash_dev *fdev, void *load_flash_addr)
/*init and would remalloc while size is increasing*/
combine_str = malloc(combine_len);
memset(combine_str, '\0', combine_len);
if (combine_str == NULL)
return -1;
memset(combine_str, '\0', combine_len);
json_root = cJSON_Parse(load_flash_addr);
if (!json_root){
pr_err("can not parse json, check your flash_config.cfg is json format or not\n");
@ -461,11 +482,17 @@ void fastboot_oem_flash_gpt(const char *cmd, void *download_buffer, u32 download
}
if (strlen(fdev->gptinfo.gpt_table) > 0 && fdev->gptinfo.fastboot_flash_gpt){
_write_gpt_partition(fdev, response);
if (_write_gpt_partition(fdev)){
fastboot_fail("write gpt tabel fail", response);
return;
}
}
if (strlen(fdev->mtd_table) > 0){
_write_mtd_partition(fdev->mtd_table, response);
if (_write_mtd_partition(fdev)){
fastboot_fail("write mtd tabel fail", response);
return;
}
}
/*set partition to env*/
@ -833,6 +860,14 @@ void fastboot_oem_flash_bootinfo(const char *cmd, void *download_buffer,
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
#if defined(CONFIG_SPL_BUILD)
extern int get_tlvinfo_from_eeprom(int tcode, char *buf);
extern int set_val_to_tlvinfo(int tcode, char *valvoid);
extern int write_tlvinfo_to_eeprom(void);
#else
static bool tlvinfo_init = false;
#endif
struct oem_config_info
{
const char *name;
@ -844,6 +879,7 @@ const struct oem_config_info config_info[] = {
{ "product_name", TLV_CODE_PRODUCT_NAME, 16, NULL },
{ "serial#", TLV_CODE_SERIAL_NUMBER, 12, NULL },
{ "ethaddr", TLV_CODE_MAC_BASE, 17, NULL },
{ "ethsize", TLV_CODE_MAC_SIZE, 6, NULL },/*size must equal or less than 65535*/
{ "manufacture_date", TLV_CODE_MANUF_DATE, 19, NULL },
{ "device_version", TLV_CODE_DEVICE_VERSION, 3, NULL },
{ "manufacturer", TLV_CODE_MANUF_NAME, 32, NULL },
@ -856,39 +892,18 @@ const struct oem_config_info config_info[] = {
static int write_config_info_to_eeprom(uint32_t id, char *value)
{
char *cmd_str;
cmd_str = malloc(256);
if (NULL == cmd_str) {
pr_err("malloc buffer for cmd string fail\n");
return -1;
#if defined(CONFIG_SPL_BUILD)
if (set_val_to_tlvinfo(id, value) == 0)
#else
if (!tlvinfo_init){
run_command("tlv_eeprom", 0);
tlvinfo_init = true;
}
pr_info("write data to EEPROM, ID:%d, string:%s\n", id, value);
/* read eeprom */
sprintf(cmd_str, "tlv_eeprom read");
if (run_command(cmd_str, 0)) {
free(cmd_str);
pr_err("tlv_eeprom read fail\n");
return 1;
}
// update eeprom data, need add '' for value string that may have space inside
sprintf(cmd_str, "tlv_eeprom set %d '%s'", id, value);
if (run_command(cmd_str, 0)) {
free(cmd_str);
pr_err("tlv_eeprom set %s to %d fail\n", value, id);
return 2;
}
if (run_command("tlv_eeprom write", 0)) {
free(cmd_str);
pr_err("tlv_eeprom write fail\n");
return 3;
}
free(cmd_str);
if (run_commandf("tlv_eeprom set 0x%x %s", id, value) == 0)
#endif
return 0;
else
return -1;
}
#if CONFIG_IS_ENABLED(SPACEMIT_K1X_EFUSE)
@ -936,58 +951,33 @@ static struct oem_config_info* get_config_info(char *key)
static void read_oem_configuration(char *config, char *response)
{
char *key;
struct oem_config_info* info;
char *ack, *value, *temp;
int i = 0, j;
char *ack;
ack = malloc(256);
ack = calloc(0, 256);
if (NULL == ack) {
pr_err("malloc buffer for ack fail\n");
return;
}
temp = malloc(256);
if (NULL == temp) {
free(ack);
pr_err("malloc buffer for temp fail\n");
return;
}
memset(ack, 0, 256);
key = strsep(&config, ",");
while (NULL != key) {
pr_debug("try to find config info for %s\n", key);
info = get_config_info(key);
if (NULL != info) {
value = env_get(key);
if (NULL != info->convert)
value = info->convert(value);
// make sure value string is NOT exceed temp buffer
if ((NULL != value) && (strlen(value) < 128)) {
memset(temp, 0, 256);
sprintf(temp, "%s", value);
j = strlen(temp);
if ((i + j) < 256) {
// add comma between two info dictionary
if (0 != i)
ack[i++] = ',';
memcpy(ack + i, temp, j);
i += j;
}
}
}
key = strsep(&config, ",");
}
if (0 != i) {
info = get_config_info(config);
if (NULL != info){
pr_info("%s, %x, \n", info->name, info->id);
#if defined(CONFIG_SPL_BUILD)
if (get_tlvinfo_from_eeprom(info->id, ack) == 0){
#else
char *tmp_str = env_get(info->name);
if (tmp_str != NULL){
strcpy(ack, tmp_str);
#endif
fastboot_okay(ack, response);
} else {
fastboot_fail("NOT exist", response);
}else{
fastboot_fail("key NOT exist", response);
}
}else{
fastboot_fail("key NOT exist", response);
}
free(ack);
free(temp);
}
static void write_oem_configuration(char *config, char *response)
@ -1020,15 +1010,23 @@ static void write_oem_configuration(char *config, char *response)
}
}
if (0 == ret)
if (ret){
fastboot_fail("write key fail", response);
return;
}
#if defined(CONFIG_SPL_BUILD)
if (0 == write_tlvinfo_to_eeprom())
#else
if (!tlvinfo_init){
run_command("tlv_eeprom", 0);
tlvinfo_init = true;
}
if (run_command("tlv_eeprom write", 0) == 0)
#endif
fastboot_okay(NULL, response);
else
fastboot_fail("NOT exist", response);
}
static void flush_oem_configuration(char *config, char *response)
{
fastboot_okay(NULL, response);
fastboot_fail("write fail", response);
}
/**
@ -1047,12 +1045,10 @@ void fastboot_config_access(char *operation, char *config, char *response)
read_oem_configuration(config, response);
else if (0 == strcmp(operation, "write"))
write_oem_configuration(config, response);
else if (0 == strcmp(operation, "flush"))
flush_oem_configuration(config, response);
else
fastboot_fail("NOT support", response);
}
#endif
#endif /*CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)*/
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
#if defined(CONFIG_SPL_BUILD)
@ -1146,3 +1142,169 @@ void fastboot_env_access(char *operation, char *env, char *response)
fastboot_fail("NOT support", response);
}
#endif
#define GZIP_HEADER_HEAD_CRC 2
#define GZIP_HEADER_EXTRA_FIELD 4
#define GZIP_HEADER_ORIG_NAME 8
#define GZIP_HEADER_COMMENT 0x10
#define GZIP_HEADER_RESERVED 0xe0
#define GZIP_HEADER_DEFLATED 8
int check_gzip_format(const unsigned char *src, unsigned long len)
{
int i, flags;
/* skip header */
i = 10;
flags = src[3];
if (src[2] != GZIP_HEADER_DEFLATED || (flags & GZIP_HEADER_RESERVED) != 0) {
pr_info("is not gzipped data\n");
return (-1);
}
if ((flags & GZIP_HEADER_EXTRA_FIELD) != 0)
i = 12 + src[10] + (src[11] << 8);
if ((flags & GZIP_HEADER_ORIG_NAME) != 0)
while (src[i++] != 0)
;
if ((flags & GZIP_HEADER_COMMENT) != 0)
while (src[i++] != 0)
;
if ((flags & GZIP_HEADER_HEAD_CRC) != 0)
i += 2;
if (i >= len) {
pr_info("gunzip out of data in header\n");
return (-1);
}
return i;
}
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ERASE)
/*boot0,boot1 would erase 128KB size*/
#define ERASE_BOOT_SIZE (0x100)
int clear_emmc(lbaint_t blkcnt)
{
struct blk_desc *dev_desc;
struct mmc *mmc;
u32 n;
mmc_init_device(MMC_DEV_EMMC);
mmc = find_mmc_device(MMC_DEV_EMMC);
if (!mmc){
pr_err("can not get mmc dev\n");
return -1;
}
if (mmc_init(mmc)){
pr_err("can not init mmc\n");
return -1;
}
dev_desc = mmc_get_blk_desc(mmc);
if (!dev_desc){
pr_err("can not get blk dev of emmc\n");
return -1;
}
n = blk_derase(dev_desc, 0, blkcnt);
if (n != blkcnt){
pr_err("erase size %lx fail\n", blkcnt);
return -1;
}
/* erase boot0/boot1 partition*/
if (mmc_set_part_conf(mmc, 0, 0, 1) ||
ERASE_BOOT_SIZE != blk_derase(dev_desc, 0, ERASE_BOOT_SIZE)){
pr_err("erase boot0 fail\n");
return -1;
}
if (mmc_set_part_conf(mmc, 0, 0, 2) ||
ERASE_BOOT_SIZE != blk_derase(dev_desc, 0, ERASE_BOOT_SIZE)){
pr_err("erase boot1 fail\n");
return -1;
}
return 0;
}
int clear_mtd(char *mtd_dev, u32 erase_size)
{
static struct mtd_info *mtd = NULL;
int ret;
if (mtd == NULL){
pr_info("mtd is not init\n");
mtd_probe_devices();
}
mtd = get_mtd_device_nm(mtd_dev);
if (IS_ERR_OR_NULL(mtd)){
pr_info("MTD device %s not found\n", mtd_dev);
return -1;
}
erase_size = round_up(erase_size, mtd->erasesize);
ret = _fb_mtd_erase(mtd, erase_size);
if (ret)
return -1;
return 0;
}
#define DEFAULT_EEPROM_ERASE_SIZE (256)
#define DEFAULT_EEPROM_DEV (0)
#define DEFAULT_EMMC_ERASE_SIZE (0x10000000)
#define DEFAULT_MTD_ERASE_SIZE (0x100000)
void clear_storage_data(char *cmd_parameter, char *response)
{
char *cmd_str, *operation;
u32 erase_size;
cmd_str = cmd_parameter;
operation = strsep(&cmd_str, " ");
if (cmd_str != NULL){
pr_info("get erase size:%s\n", cmd_str);
erase_size = hextoul(cmd_str, NULL);
}else {
pr_info("has not define erase size, use default size\n");
erase_size = 0;
}
if (!strncmp("eeprom", operation, 6)){
erase_size = (erase_size == 0) ? DEFAULT_EEPROM_ERASE_SIZE : erase_size;
pr_info("erase eeprom, erase size:%x\n", erase_size);
#if defined(CONFIG_SPL_BUILD)
if (clear_eeprom(DEFAULT_EEPROM_DEV, erase_size))
#else
if (run_command("tlv_eeprom;tlv_eeprom erase;tlv_eeprom write", 0))
#endif
fastboot_fail("erase eeprom fail", response);
else
fastboot_okay(NULL, response);
return;
} else if (!strncmp("emmc", operation, 4)){
erase_size = (erase_size == 0) ? DEFAULT_EMMC_ERASE_SIZE : erase_size;
pr_info("erase emmc, erase size:%x\n", erase_size);
if (clear_emmc(erase_size/512))
fastboot_fail("erase emmc fail", response);
else
fastboot_okay(NULL, response);
return;
}
erase_size = (erase_size == 0) ? DEFAULT_MTD_ERASE_SIZE : erase_size;
if (!strncmp("nor", operation, 3)){
if (clear_mtd("nor0", erase_size))
fastboot_fail("erase nor fail", response);
else
fastboot_okay(NULL, response);
return;
} else if (!strncmp("nand", operation, 4)){
if (clear_mtd("spi-nand0", erase_size))
fastboot_fail("erase nand fail", response);
else
fastboot_okay(NULL, response);
return;
}
fastboot_response("FAIL", response, "not support erase operation:%s", operation);
return;
}
#endif /*CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ERASE)*/

View file

@ -533,7 +533,7 @@ static int do_del_mtd_partitions(struct mtd_info *master)
debug("Deleting %s MTD partition\n", slave->name);
ret = del_mtd_device(slave);
if (ret < 0) {
pr_err("Error when deleting partition \"%s\" (%d)\n",
pr_debug("Error when deleting partition \"%s\" (%d)\n",
slave->name, ret);
err = ret;
continue;

View file

@ -3837,6 +3837,128 @@ void spi_nor_set_fixups(struct spi_nor *nor)
#endif /* SPI_FLASH_MACRONIX */
}
/*clear CMP and LB in order to unlock the protect area*/
static int generic_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
int ret;
u8 val[1] = {0};
/*if not define SPI_NOR_HAS_LOCK flag, it should not clear the protect bit*/
if (!(nor->info->flags & SPI_NOR_HAS_LOCK))
return 0;
/*read register 1*/
ret = nor->read_reg(nor, SPINOR_OP_RDSR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error %d reading CR\n", ret);
return ret;
}
/*clear block protect bit at register 1*/
val[0] &= ~(SR_BP0 | SR_BP1 | SR_BP2 | SR_TB | SR_SP);
write_enable(nor);
ret = nor->write_reg(nor, SPINOR_OP_WRSR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error while writing configuration register\n");
return ret;
}
ret = spi_nor_wait_till_ready(nor);
if (ret) {
dev_dbg(nor->dev, "timeout while writing configuration register\n");
return ret;
}
/*read register 2*/
ret = nor->read_reg(nor, SPINOR_OP_RDCR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error %d reading CR\n", ret);
return ret;
}
/*write register 2*/
val[0] &= ~(SR_LB1 | SR_LB2 | SR_LB3 | SR_CMP);
write_enable(nor);
ret = nor->write_reg(nor, SPINOR_OP_WDCR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error while writing configuration register\n");
return -EINVAL;
}
ret = spi_nor_wait_till_ready(nor);
if (ret) {
dev_dbg(nor->dev, "timeout while writing configuration register\n");
return ret;
}
return 0;
}
/* set protect area */
static int generic_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
/* TODO: should protect area by offset and len*/
int ret;
u8 val[1] = {0};
/*if not define SPI_NOR_HAS_LOCK flag, it should not clear the protect bit*/
if (!(nor->info->flags & SPI_NOR_HAS_LOCK))
return 0;
/*if unlock size is not equal to all size, return*/
if (nor->size != len && ofs != 0)
return 0;
/*read register 1*/
ret = nor->read_reg(nor, SPINOR_OP_RDSR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error %d reading CR\n", ret);
return ret;
}
/*clear block protect bit at register 1*/
val[0] &= ~(SR_BP0 | SR_BP1 | SR_BP2);
write_enable(nor);
ret = nor->write_reg(nor, SPINOR_OP_WRSR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error while writing configuration register\n");
return ret;
}
ret = spi_nor_wait_till_ready(nor);
if (ret) {
dev_dbg(nor->dev, "timeout while writing configuration register\n");
return ret;
}
/*read register 2*/
ret = nor->read_reg(nor, SPINOR_OP_RDCR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error %d reading CR\n", ret);
return ret;
}
/*write register 2*/
val[0] |= SR_CMP;
write_enable(nor);
ret = nor->write_reg(nor, SPINOR_OP_WDCR, val, 1);
if (ret < 0) {
dev_dbg(nor->dev, "error while writing configuration register\n");
return -EINVAL;
}
ret = spi_nor_wait_till_ready(nor);
if (ret) {
dev_dbg(nor->dev, "timeout while writing configuration register\n");
return ret;
}
return 0;
}
int spi_nor_scan(struct spi_nor *nor)
{
struct spi_nor_flash_parameter params;
@ -3940,6 +4062,12 @@ int spi_nor_scan(struct spi_nor *nor)
}
#endif
/* if not define flash_unlock, use generic clear func*/
if (!nor->flash_unlock){
nor->flash_unlock = generic_unlock;
nor->flash_lock = generic_lock;
}
if (info->flags & USE_FSR)
nor->flags |= SNOR_F_USE_FSR;
if (info->flags & SPI_NOR_HAS_TB)

View file

@ -82,7 +82,9 @@ static const struct pmic_child_info pmic_children_info[] = {
static int pm8xx_bind(struct udevice *dev)
{
ofnode regulators_node;
ofnode pmic_reset_node;
int children;
int ret;
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
@ -97,6 +99,15 @@ static int pm8xx_bind(struct udevice *dev)
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
pmic_reset_node = dev_read_subnode(dev, "pmic-reset");
if (ofnode_valid(pmic_reset_node) && ofnode_is_available(pmic_reset_node)) {
debug("Binding pmic-reset node\n");
ret = device_bind_driver_to_node(dev, "pmic_sysreset", "pmic_sysreset", pmic_reset_node, NULL);
if (ret) {
debug("Failed to bind pmic_sysreset driver: %d\n", ret);
}
}
/* Always return success for this device */
return 0;
}

View file

@ -405,7 +405,6 @@ config DM_REGULATOR_SPM8XX
config DM_REGULATOR_SPACEMIT_HUB
tristate "Spacemit onboard USB hub regulator wrapper support"
default SOC_SPACEMIT_K1X
depends on DM_REGULATOR
help
Say Y here if you want to support onboard usb hubs on Spacemit

View file

@ -408,7 +408,7 @@ static void spacemit_reset_set(struct reset_ctl *rst,
u32 value;
struct spacemit_reset *reset = dev_get_priv(rst->dev);
pr_info("[RESET]spacemit_reset_set assert=%d, id=%d \r\n", assert, id);
pr_debug("[RESET]spacemit_reset_set assert=%d, id=%d \r\n", assert, id);
value = spacemit_reset_read(reset, id);
if(assert == true) {
value &= ~ reset->signals[id].mask;

View file

@ -275,10 +275,12 @@ static void qspi_set_func_clk(struct k1x_qspi *qspi)
clk_disable(&qspi->bus_clk);
clk_disable(&qspi->clk);
reset_deassert_bulk(&qspi->resets);
clk_enable(&qspi->bus_clk);
clk_set_rate(&qspi->clk, qspi->max_hz);
clk_enable(&qspi->clk);
clk_enable(&qspi->bus_clk);
reset_deassert_bulk(&qspi->resets);
dev_info(qspi->dev, "bus clock: %dHz, PMUap reg[0x%08x]:0x%08x\n",
qspi->max_hz, qspi->pmuap_reg, readl((void __iomem *)((unsigned long)qspi->pmuap_reg)));
}
static int qspi_reset(struct k1x_qspi *qspi)

View file

@ -8,91 +8,77 @@
#include <errno.h>
#include <sysreset.h>
#include <asm/io.h>
#include <linux/err.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <power/pmic.h>
/*wdt*/
#define K1X_WDT_REG (0xd4080000)
#define K1X_WDT_ENABLE (0xd4080000 + 0xb8)
#define K1X_WDT_TIMEOUT (0xd4080000 + 0xbc)
#define K1X_WDT_RESET (0xd4080000 + 0xc8)
#define K1X_WDT_STATUS (0xd4080000 + 0xc0)
#define K1X_WDT_WSAR (0xd4080000 + 0x00b4)
#define K1X_WDT_WFAR (0xd4080000 + 0x00b0)
struct pmic_sysreset_data {
u32 reboot_reg;
u32 reboot_mask;
int type;
};
#define WDT_CLEAR_STATUS (0x0)
#define WDT_RESET_ENABLE (0x1)
#define WDT_ENABLE (0x3)
#define WDT_TIMEOUT (0x1)
#define K1X_WDT_START_REG (0xd4051020)
#define K1X_WDT_START_ENABLE (BIT(4))
#define K1X_WDT_CLK_RESET_REG (0xd4050200)
#define K1X_WDT_MPU_REG (0xd4051024)
#define K1X_WDT_CLK_RESET_ENABLE (0x3)
#define K1X_WDT_CLK_RESET_FLAG (BIT(2))
#define K1X_WDT_CLK_ENABLE_MPU (BIT(19))
static void spa_wdt_write_access(void)
{
writel(0xbaba, (void *)K1X_WDT_WFAR);
writel(0xeb10, (void *)K1X_WDT_WSAR);
}
static void spa_wdt_write(u32 val, void *reg)
{
spa_wdt_write_access();
writel(val, reg);
}
static void enable_wdt(void)
{
u32 reg;
/*enable wdt clk reset*/
reg = readl((void *)K1X_WDT_MPU_REG);
writel(K1X_WDT_CLK_ENABLE_MPU | reg, (void *)K1X_WDT_MPU_REG);
reg = readl((void *)K1X_WDT_CLK_RESET_REG);
writel(K1X_WDT_CLK_RESET_ENABLE | reg, (void *)K1X_WDT_CLK_RESET_REG);
reg = readl((void *)K1X_WDT_CLK_RESET_REG);
writel((~K1X_WDT_CLK_RESET_FLAG) & reg,(void *)K1X_WDT_CLK_RESET_REG);
/*set watch dog*/
spa_wdt_write(WDT_CLEAR_STATUS, (void *)K1X_WDT_STATUS);
spa_wdt_write(WDT_TIMEOUT, (void *)K1X_WDT_TIMEOUT);
spa_wdt_write(WDT_ENABLE, (void *)K1X_WDT_ENABLE);
spa_wdt_write(WDT_RESET_ENABLE, (void *)K1X_WDT_RESET);
reg = readl((void*)K1X_WDT_START_REG);
writel(K1X_WDT_START_ENABLE | reg, (void *)K1X_WDT_START_REG);
}
static int spacemit_sysreset_request(struct udevice *dev, enum sysreset_t type)
{
enable_wdt();
/*wait for reset*/
mdelay(5000);
/*if reset success, it would never return*/
return -EINPROGRESS;
}
static int spacemit_sysreset_probe(struct udevice *dev)
{
static int pmic_sysreboot_types(const char *compat) {
if (!strcmp(compat, "spacemit,spm8821-reset"))
return 1;
return 0;
}
static int pmic_sysreset_request(struct udevice *dev, enum sysreset_t type)
{
struct pmic_sysreset_data *data = dev_get_priv(dev);
struct udevice *pmic_dev;
int ret, value;
static struct sysreset_ops spacemit_sysreset = {
.request = spacemit_sysreset_request,
ret = uclass_get_device(UCLASS_PMIC, 0, &pmic_dev);
if (ret) {
pr_err("Failed to find PMIC device\n");
return ret;
}
switch (data->type) {
case 1:
value = pmic_reg_read(pmic_dev, data->reboot_reg);
if (ret) {
pr_err("Failed to read reboot register for spm8821: %d\n", ret);
return ret;
}
value |= data->reboot_mask;
ret = pmic_reg_write(pmic_dev, data->reboot_reg, value);
if (ret) {
pr_err("Failed to write reboot register for spm8821: %d\n", ret);
return ret;
}
break;
default:
pr_err("Unsupported PMIC type for sysreset\n");
return -ENOSYS;
}
mdelay(100);
return -EINPROGRESS;
}
static int pmic_sysreset_probe(struct udevice *dev)
{
struct pmic_sysreset_data *data = dev_get_priv(dev);
const char *compat = dev_read_string(dev, "compatible");
data->reboot_reg = dev_read_u32_default(dev, "reboot-reg", 0);
data->reboot_mask = dev_read_u32_default(dev, "reboot-mask", 0);
data->type = pmic_sysreboot_types(compat);
return 0;
}
static struct sysreset_ops pmic_sysreset_ops = {
.request = pmic_sysreset_request,
};
U_BOOT_DRIVER(spacemit_sysreset) = {
.name = "spacemit_sysreset",
U_BOOT_DRIVER(pmic_sysreset) = {
.name = "pmic_sysreset",
.id = UCLASS_SYSRESET,
.ops = &spacemit_sysreset,
.probe = spacemit_sysreset_probe,
.priv_auto = sizeof(struct pmic_sysreset_data),
.ops = &pmic_sysreset_ops,
.probe = pmic_sysreset_probe,
};

View file

@ -263,4 +263,10 @@ config USBNET_HOST_ADDR
endif # USB_ETHER
config USB_SET_SERIAL_NUMBER
bool "set serial number while binding usb fastboot device"
default y
help
enable to set serial number while binding fastboot devices
endif # USB_GADGET

View file

@ -262,9 +262,10 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
}
s = env_get("serial#");
#ifdef CONFIG_USB_SET_SERIAL_NUMBER
if (s)
g_dnl_set_serialnumber((char *)s);
#endif
return 0;
}

View file

@ -220,7 +220,9 @@ static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev)
static int on_serialno(const char *name, const char *value, enum env_op op,
int flags)
{
#ifdef CONFIG_USB_SET_SERIAL_NUMBER
g_dnl_set_serialnumber((char *)value);
#endif
return 0;
}
U_BOOT_ENV_CALLBACK(serialno, on_serialno);

View file

@ -406,7 +406,10 @@ static int lcd_bl_enable(struct video_tx_device *dev, bool enable)
video_tx_get_drvdata(dev);
struct spacemit_panel_priv *priv = video_tx_client->priv;
if (enable)
dm_gpio_set_value(&priv->bl, 1);
else
dm_gpio_set_value(&priv->bl, 0);
return 0;
}

View file

@ -29,6 +29,8 @@
#include "spacemit_dpu.h"
extern bool is_video_connected;
DECLARE_GLOBAL_DATA_PTR;
struct fb_info fbi = {0};
@ -342,8 +344,10 @@ static int spacemit_display_init(struct udevice *dev, ulong fbbase, ofnode ep_no
ret = spacemit_panel_init();
if (ret) {
pr_info("%s: Failed to init panel\n", __func__);
is_video_connected = false;
return ret;
}
is_video_connected = true;
spacemit_mode = &fbi.mode;
uc_priv->xsize = spacemit_mode->xres;

View file

@ -25,7 +25,7 @@
#define SPACEMIT_HDMI_PHY_STATUS 0xC
#define SPACEMIT_HDMI_PHY_HPD 0x1000
int is_hdmi_connected;
extern bool is_video_connected;
static int hdmi_get_plug_in_status(struct dw_hdmi *hdmi)
{
@ -57,48 +57,213 @@ static int hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi)
return -1;
}
enum bit_depth{
EIGHT_BPP = 0,
TEN_BPP = 1,
TWELVE_BPP =2,
};
int power_of_two(int n) {
int result = 1;
for (int i = 0; i < n; ++i) {
result <<= 1;
}
return result;
}
int pll8_bit_5_6 (int bit_clock, int n){
int ret = 0;
bit_clock = bit_clock / n;
if (bit_clock < 425)
ret = 3;
else if (bit_clock < 850)
ret = 2;
else if (bit_clock < 1700)
ret = 1;
else
ret = 0;
return ret;
}
int pll6_bit_4_5 (int bit_clock, int n){
int ret = 0;
bit_clock = bit_clock / n;
if (bit_clock <= 337)
ret = 0;
else if (bit_clock < 425)
ret = 1;
else if (bit_clock < 675)
ret = 0;
else if (bit_clock < 850)
ret = 1;
else if (bit_clock < 1350)
ret = 0;
else if (bit_clock < 1700)
ret = 1;
else
ret = 0;
return ret;
}
int pll5_bit_0_2 (int bit_clock, int n){
int value = bit_clock * power_of_two(pll8_bit_5_6(bit_clock, n)) / n;
int ret;
if (value < 1830)
ret = 0;
else if (value < 2030)
ret = 1;
else if (value < 2275)
ret = 2;
else if (value < 2520)
ret = 3;
else if (value < 2765)
ret = 4;
else if (value < 3015)
ret = 5;
else if (value < 3260)
ret = 6;
else
ret = 7;
return ret;
}
int PLL9_BIT0_1[3] = {0x0, 0x1, 0x2};
void pll_reg_cal(int bit_clock, int ref_clock, int n, int *integer_part, u32 *hmdi_e8_reg) {
long long int_para = 1000000000;
long long value = (power_of_two(pll8_bit_5_6(bit_clock, n))) * bit_clock * int_para / (n * (pll6_bit_4_5(bit_clock, n) + 1) * ref_clock);
long long integer = (power_of_two(pll8_bit_5_6(bit_clock, n)))* bit_clock / (n * (pll6_bit_4_5(bit_clock, n) + 1) * ref_clock) * int_para;
long long fraction = value - integer;
bool negative = false;
int bit = 0;
int frac_20bit = 0;
int pll2_reg = 0;
int pll1_reg = 0;
int pll0_reg = 0;
negative = fraction > 500000000 ? true : false;
fraction = negative ? 1000000000 - fraction : fraction;
*integer_part = negative ? integer/int_para + 1 : integer/int_para;
for (int i = 0; i < 20; i++){
if (bit >= int_para) {
frac_20bit |= 1 << (19 - i);
fraction -= int_para;
}
fraction *= 2;
bit = fraction;
}
if (!negative){
pll2_reg = ((frac_20bit & 0xF0000) >> 16) | (1 << 5);
} else {
frac_20bit = (~frac_20bit + 1) & 0xfffff;
pll2_reg = 0x10 | ((frac_20bit & 0xF0000) >> 16) | (1 << 5);
}
pll1_reg = (frac_20bit & 0xFF00) >> 8;
pll0_reg = frac_20bit & 0xFF;
*hmdi_e8_reg = (0x20 << 24) | (pll2_reg << 16) | (pll1_reg << 8) | pll0_reg;
}
int pll_reg (void __iomem *hdmi_addr, int pixel_clock, int bit_depth) {
int pll9_reg = 0, pll8_reg = 0, pll7_reg = 0, pll6_reg = 0, pll5_reg = 0, pll4_reg = 0;
int n = 100;
int ref_clock = 24;
int hdmi_ec_reg = 0;
int hdmi_f0_reg = 0;
int hdmi_e8_reg = 0;
int pow = 0;
int bit_clock = bit_depth == EIGHT_BPP ? pixel_clock : pixel_clock * 125 / 100;
int integer_part = 0;
pll_reg_cal(bit_clock, ref_clock, n, &integer_part, &hdmi_e8_reg);
pll9_reg = 2 << 2 | PLL9_BIT0_1[bit_depth];
pll8_reg = (0 << 7) | (pll8_bit_5_6(bit_clock, n) << 5) | 1;
pll7_reg = 0x50;
pll6_reg = 0xD | (pll6_bit_4_5(bit_clock, n) << 4) | (2 << 6);
pll5_reg = 0x40 | pll5_bit_0_2(bit_clock, n);
pow = (pll8_bit_5_6(bit_clock, n));
pll4_reg = integer_part;
hdmi_ec_reg = (pll7_reg << 24) | (pll6_reg << 16) | (pll5_reg << 8) | pll4_reg;
hdmi_f0_reg = (pll9_reg << 8) | pll8_reg;
writel(hdmi_e8_reg, hdmi_addr + 0xe8);
writel(hdmi_ec_reg, hdmi_addr + 0xec);
writel(hdmi_f0_reg, hdmi_addr + 0xf0);
return 0;
}
void hdmi_write_bits(void __iomem *hdmi_addr, u16 offset, u32 value, u32 mask, u32 shifts)
{
u32 reg_val;
reg_val = readl(hdmi_addr + (offset));
reg_val &= ~(mask << shifts);
reg_val |= (value << shifts);
writel(reg_val, hdmi_addr + (offset));
}
void hdmi_init (void __iomem *hdmi_addr, int pixel_clock, int bit_depth){
u32 value = 0;
int color_depth = bit_depth == EIGHT_BPP ? 4 : 5;
u32 good_phase = 0x00;
u32 bias_current = 0x01;
u32 bias_risistor = 0x07;
// hdmi phy config
writel(0x20200000, hdmi_addr + 0xe8);
writel(0x508d425a, hdmi_addr + 0xec);
writel(0x861, hdmi_addr + 0xf0);
writel(0xAE5C410F, hdmi_addr + 0xe0);
hdmi_write_bits(hdmi_addr, 0xe0, bias_current, 0x03, 29);
hdmi_write_bits(hdmi_addr, 0xe0, bias_risistor, 0x0F, 18);
hdmi_write_bits(hdmi_addr, 0xe0, good_phase, 0x03, 14);
value = 0x0000000d | (color_depth << 4);
writel(value, hdmi_addr + 0x34);
pll_reg(hdmi_addr, pixel_clock, bit_depth);
writel(0x00, hdmi_addr + 0xe4);
writel(0x03, hdmi_addr + 0xe4);
value = readl(hdmi_addr + 0xe4);
pr_debug("%s() hdmi pll lock status 0x%x\n", __func__, value);
// while ( (value & 0x10000) != 0) {
// value = readl(hdmi->regs + 0xe4);
// }
udelay(100);
value = 0x1C208000 | bit_depth;
writel(value, hdmi_addr + 0x28);
}
static int hdmi_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
{
void __iomem *hdmi_addr;
hdmi_addr = ioremap(0xC0400500, 0x200);
u32 value;
u32 pixel_clock = 148500;
int bit_depth = EIGHT_BPP;
// hdmi phy param config
#if 0
writel(0x4d, hdmi_addr + 0x34);
writel(0x20200000, hdmi_addr + 0xe8);
writel(0x509D453E, hdmi_addr + 0xec);
writel(0x821, hdmi_addr + 0xf0);
writel(0x3, hdmi_addr + 0xe4);
udelay(2);
value = readl(hdmi_addr + 0xe4);
pr_debug("%s() hdmi 0xe4 0x%x\n", __func__, value);
writel(0x30184000, hdmi_addr + 0x28);
#else
writel(0xEE40410F, hdmi_addr + 0xe0);
writel(0x0000005d, hdmi_addr + 0x34);
writel(0x2022C000, hdmi_addr + 0xe8);
writel(0x508D414D, hdmi_addr + 0xec);
writel(0x00000901, hdmi_addr + 0xf0);
writel(0x3, hdmi_addr + 0xe4);
udelay(2);
value = readl(hdmi_addr + 0xe4);
pr_debug("%s() hdmi 0xe4 0x%x\n", __func__, value);
writel(0x3018C001, hdmi_addr + 0x28);
#endif
udelay(1000);
hdmi_init(hdmi_addr, pixel_clock, bit_depth);
return 0;
}
@ -140,42 +305,43 @@ static int spacemit_hdmi_probe(struct udevice *dev)
return ret;
}
ret = reset_get_by_name(dev, "hdmi_reset", &priv->hdmi_reset);
if (ret) {
pr_err("reset_get_by_name hdmi reset failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->hdmi_reset);
if (ret) {
pr_err("reset_assert hdmi reset failed: %d\n", ret);
return ret;
}
ret = clk_enable(&priv->hdmi_mclk);
if (ret < 0) {
pr_err("clk_enable hdmi mclk failed: %d\n", ret);
return ret;
}
ret = reset_get_by_name(dev, "hdmi_reset", &priv->hdmi_reset);
if (ret) {
pr_err("reset_get_by_name hdmi reset failed: %d\n", ret);
ret = clk_set_rate(&priv->hdmi_mclk, 491520000);
if (ret < 0) {
pr_err("clk_set_rate mipi dsi mclk failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->hdmi_reset);
if (ret) {
pr_err("reset_assert hdmi reset failed: %d\n", ret);
goto free_reset;
}
rate = clk_get_rate(&priv->hdmi_mclk);
pr_debug("%s clk_get_rate hdmi mclk %ld\n", __func__, rate);
priv->hdmi.ioaddr = (ulong)priv->base;
priv->hdmi.reg_io_width = 4;
ret = hdmi_phy_wait_for_hpd(&priv->hdmi);
is_hdmi_connected = ret;
if (ret < 0) {
pr_info("hdmi can not get hpd signal\n");
is_video_connected = (ret >= 0);
if (!is_video_connected) {
pr_info("HDMI cannot get HPD signal\n");
return ret;
}
return ret;
free_reset:
clk_disable(&priv->hdmi_mclk);
return 0;
}

View file

@ -170,6 +170,30 @@ static int spacemit_mipi_dsi_probe(struct udevice *dev)
return ret;
}
ret = reset_deassert(&priv->dsi_reset);
if (ret) {
pr_err("reset_assert dsi_reset failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->mclk_reset);
if (ret) {
pr_err("reset_assert mclk_reset failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->esc_reset);
if (ret) {
pr_err("reset_assert esc_reset failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->lcd_reset);
if (ret) {
pr_err("reset_assert lcd_reset failed: %d\n", ret);
return ret;
}
ret = clk_enable(&priv->pxclk);
if (ret < 0) {
pr_err("clk_enable mipi dsi pxclk failed: %d\n", ret);
@ -206,7 +230,7 @@ static int spacemit_mipi_dsi_probe(struct udevice *dev)
return ret;
}
ret = clk_set_rate(&priv->mclk, 307200000);
ret = clk_set_rate(&priv->mclk, 491520000);
if (ret < 0) {
pr_err("clk_set_rate mipi dsi mclk failed: %d\n", ret);
return ret;
@ -239,30 +263,6 @@ static int spacemit_mipi_dsi_probe(struct udevice *dev)
rate = clk_get_rate(&priv->bitclk);
pr_debug("%s clk_get_rate bitclk rate = %ld\n", __func__, rate);
ret = reset_deassert(&priv->dsi_reset);
if (ret) {
pr_err("reset_assert dsi_reset failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->mclk_reset);
if (ret) {
pr_err("reset_assert mclk_reset failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->esc_reset);
if (ret) {
pr_err("reset_assert esc_reset failed: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->lcd_reset);
if (ret) {
pr_err("reset_assert lcd_reset failed: %d\n", ret);
return ret;
}
return 0;
}

View file

@ -90,6 +90,14 @@ config WDT_APPLE
The watchdog will perform a full SoC reset resulting in a
reboot of the entire system.
config WDT_SPACEMIT
bool "SPACEMIT watchdog timer support"
depends on WDT
help
Enable support for the watchdog timer on SPACEMIT SoCs.
The watchdog will perform a full SoC reset resulting in a
reboot of the entire system.
config WDT_ARMADA_37XX
bool "Marvell Armada 37xx watchdog timer support"
depends on WDT && ARMADA_3700

View file

@ -43,3 +43,4 @@ obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o
obj-$(CONFIG_WDT_SPACEMIT) += spacemit_wdt.o

View file

@ -0,0 +1,199 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <wdt.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <clk.h>
#include <reset-uclass.h>
/* Register offsets relative to the base address of the WDT */
#define WDT_ENABLE_OFFSET 0xB8
#define WDT_TIMEOUT_OFFSET 0xBC
#define WDT_RESET_OFFSET 0xC8
#define WDT_STATUS_OFFSET 0xC0
#define WDT_WSAR_OFFSET 0xB4
#define WDT_WFAR_OFFSET 0xB0
/* Watchdog Timer Control Bits */
#define WDT_CLEAR_STATUS 0x0
#define WDT_RESET_ENABLE 0x1
#define WDT_ENABLE 0x3
#define WDT_TIMEOUT 0x1
/* WDT Start Register and its enable bit */
#define WDT_START_ENABLE BIT(4)
#define WDT_CLK_FREQ 256
struct spacemit_wdt_priv {
struct clk clk;
struct reset_ctl reset;
fdt_addr_t base;
fdt_addr_t start_reg;
};
static void spa_wdt_write_access(fdt_addr_t base)
{
writel(0xbaba, (void *)(base + WDT_WFAR_OFFSET));
writel(0xeb10, (void *)(base + WDT_WSAR_OFFSET));
}
static void spa_wdt_write(u32 val, void *reg, fdt_addr_t base)
{
spa_wdt_write_access(base);
writel(val, reg);
}
static int initialize_wdt(struct udevice *dev, u64 timeout_ms)
{
struct spacemit_wdt_priv *priv = dev_get_priv(dev);
if (!priv) {
pr_err("Failed to get private data\n");
return -ENODEV;
}
int ret;
u64 counter = (timeout_ms * WDT_CLK_FREQ) / 1000;
// Enable the clock
ret = clk_enable(&priv->clk);
if (ret) {
pr_err("Failed to enable clock: %d\n", ret);
return ret;
}
// Deassert the reset
ret = reset_deassert(&priv->reset);
if (ret) {
pr_err("Failed to deassert reset: %d\n", ret);
return ret;
}
u32 timeout_val = readl((void *)(priv->base + WDT_TIMEOUT_OFFSET));
/* Set watchdog timer parameters */
spa_wdt_write(WDT_CLEAR_STATUS, (void *)(priv->base + WDT_STATUS_OFFSET), priv->base);
spa_wdt_write(counter, (void *)(priv->base + WDT_TIMEOUT_OFFSET), priv->base);
spa_wdt_write(WDT_ENABLE, (void *)(priv->base + WDT_ENABLE_OFFSET), priv->base);
spa_wdt_write(WDT_RESET_ENABLE, (void *)(priv->base + WDT_RESET_OFFSET), priv->base);
timeout_val = readl((void *)(priv->base + WDT_TIMEOUT_OFFSET));
return 0;
}
static int spacemit_wdt_reset(struct udevice *dev)
{
struct spacemit_wdt_priv *priv = dev_get_priv(dev);
if (!priv) {
pr_err("Failed to get private data\n");
return -ENODEV;
}
/* Clear watchdog timer status only, do not set timeout */
spa_wdt_write(WDT_CLEAR_STATUS, (void *)(priv->base + WDT_STATUS_OFFSET), priv->base);
spa_wdt_write(WDT_RESET_ENABLE, (void *)(priv->base + WDT_RESET_OFFSET), priv->base);
return 0;
}
static int spacemit_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
{
struct spacemit_wdt_priv *priv = dev_get_priv(dev);
if (!priv) {
pr_err("Failed to get private data\n");
return -ENODEV;
}
int ret = initialize_wdt(dev, timeout_ms);
if (ret) {
return ret;
}
/* Start watchdog timer */
u32 reg = readl((void*)priv->start_reg);
writel(WDT_START_ENABLE | reg, (void *)priv->start_reg);
return 0;
}
static int spacemit_wdt_stop(struct udevice *dev)
{
struct spacemit_wdt_priv *priv = dev_get_priv(dev);
if (!priv) {
pr_err("Failed to get private data\n");
return -ENODEV;
}
// Stop the watchdog timer by clearing the enable bit.
spa_wdt_write(0x0, (void *)(priv->base + WDT_ENABLE_OFFSET), priv->base);
return 0;
}
static int spacemit_wdt_expire_now(struct udevice *dev, ulong flags)
{
initialize_wdt(dev, 0);
return 0;
}
static int spacemit_wdt_probe(struct udevice *dev)
{
int ret;
struct spacemit_wdt_priv *priv = malloc(sizeof(*priv));
if (!priv)
return -ENOMEM;
dev->priv_ = priv;
/* Retrieve and store the reset reference */
ret = reset_get_by_index(dev, 0, &priv->reset);
if (ret) {
pr_err("Failed to get the first reset control: %d\n", ret);
return ret;
}
/* Retrieve and store the clock reference */
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret) {
pr_err("Failed to get the first clock source: %d\n", ret);
return ret;
}
priv->base = dev_read_addr(dev);
if (priv->base == FDT_ADDR_T_NONE) {
pr_err("Failed to get WDT base address\n");
return -EINVAL;
}
priv->start_reg = dev_read_addr_index(dev, 1);
if (priv->start_reg == FDT_ADDR_T_NONE) {
pr_err("Failed to get Watchdog start register address\n");
return -EINVAL;
}
dev->priv_ = priv;
return 0;
}
static struct wdt_ops spacemit_wdt_ops = {
.start = spacemit_wdt_start,
.stop = spacemit_wdt_stop,
.reset = spacemit_wdt_reset,
.expire_now = spacemit_wdt_expire_now,
};
static const struct udevice_id spacemit_wdt_ids[] = {
{ .compatible = "spacemit,k1x-wdt" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(spacemit_wdt) = {
.name = "spacemit_wdt",
.id = UCLASS_WDT,
.of_match = spacemit_wdt_ids,
.probe = spacemit_wdt_probe,
.ops = &spacemit_wdt_ops,
};

View file

@ -68,6 +68,9 @@
#define BOOT_CIU_DEBUG_REG1 (BOOT_CIU_REG + 0x0394)
#define BOOT_CIU_DEBUG_REG2 (BOOT_CIU_REG + 0x0398)
// non-reset register in P1
#define P1_NON_RESET_REG (0xAB)
#define K1_EFUSE_USER_BANK0 8
#define K1_DEFALT_PMIC_TYPE 0
#define K1_DEFALT_EEPROM_I2C_INDEX 2
@ -91,6 +94,7 @@ enum board_boot_mode {
BOOT_MODE_NOR,
BOOT_MODE_SD,
BOOT_MODE_SHELL = 0x55f,
BOOT_MODE_BOOTSTRAP,
};
struct ddr_training_info_t {
@ -114,7 +118,12 @@ struct boot_storage_op
};
#endif
#if defined(CONFIG_SPL_BUILD)
#define MMC_DEV_EMMC (1)
#else
#define MMC_DEV_EMMC (2)
#endif
#define MMC_DEV_SD (0)
#define BOOTFS_NAME ("bootfs")

View file

@ -51,6 +51,9 @@ enum {
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
FASTBOOT_COMMAND_CONFIG_ACCESS,
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ERASE)
FASTBOOT_COMMAND_OEM_ERASE,
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_ENV_ACCESS)
FASTBOOT_COMMAND_ENV_ACCESS,
#endif

View file

@ -284,5 +284,10 @@ int flash_mmc_boot_op(struct blk_desc *dev_desc, void *buffer,
char *parse_mtdparts_and_find_bootfs(void);
int get_partition_index_by_name(const char *part_name, int *part_index);
int check_gzip_format(const unsigned char *src, unsigned long len);
int clear_eeprom(u32 dev, u32 erase_size);
void clear_storage_data(char *cmd_parameter, char *response);
int _write_gpt_partition(struct flash_dev *fdev);
int _write_mtd_partition(struct flash_dev *fdev);
#endif

View file

@ -65,6 +65,7 @@
#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */
#define SPINOR_OP_RDSFDP 0x5a /* Read SFDP */
#define SPINOR_OP_RDCR 0x35 /* Read configuration register */
#define SPINOR_OP_WDCR 0x31 /* Write configuration register */
#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */
#define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */
#define SPINOR_OP_RDEAR 0xc8 /* Read Extended Address Register */
@ -161,11 +162,18 @@
#define SR_BP1 BIT(3) /* Block protect 1 */
#define SR_BP2 BIT(4) /* Block protect 2 */
#define SR_TB BIT(5) /* Top/Bottom protect */
#define SR_SP BIT(6) /* sector protect */
#define SR_SRWD BIT(7) /* SR write protect */
/* Spansion/Cypress specific status bits */
#define SR_E_ERR BIT(5)
#define SR_P_ERR BIT(6)
/* Register 2 bits. */
#define SR_LB1 BIT(3)
#define SR_LB2 BIT(4)
#define SR_LB3 BIT(5)
#define SR_CMP BIT(6)
#define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
/* Enhanced Volatile Configuration Register bits */