diff --git a/arch/riscv/dts/k230_canmv.dts b/arch/riscv/dts/k230_canmv.dts index f1d0b0dd..43d0fdc3 100755 --- a/arch/riscv/dts/k230_canmv.dts +++ b/arch/riscv/dts/k230_canmv.dts @@ -55,6 +55,10 @@ status = "okay"; }; +&usbotg0 { + status = "okay"; +}; + &usbotg1 { status = "okay"; }; diff --git a/arch/riscv/dts/k230_canmv_01studio.dts b/arch/riscv/dts/k230_canmv_01studio.dts index 1d05ee43..e0db000f 100755 --- a/arch/riscv/dts/k230_canmv_01studio.dts +++ b/arch/riscv/dts/k230_canmv_01studio.dts @@ -50,6 +50,10 @@ status = "okay"; }; +&usbotg0 { + status = "okay"; +}; + &iomux { pinctrl-names = "default"; pinctrl-0 = <&pins>; diff --git a/board/kendryte/k230_canmv/board.c b/board/kendryte/k230_canmv/board.c index 96e1b721..201d3900 100644 --- a/board/kendryte/k230_canmv/board.c +++ b/board/kendryte/k230_canmv/board.c @@ -28,23 +28,16 @@ int ddr_init_training(void) { return 0; } +int board_early_init_f(void) { + /* force set boot medium to sdio1 */ + g_boot_medium = BOOT_MEDIUM_SDIO1; + return 0; +} + #ifdef CONFIG_BOARD_LATE_INIT int board_late_init(void) { ofnode node; - node = ofnode_by_compatible(ofnode_null(), "kendryte,k230_canmv_v2"); - if (ofnode_valid(node)) { -#define SDHCI_EMMC_BASE 0x91580000 -#define SDHCI_EMMC_CTRL_R 0x52C -#define EMMC_RST_N_OE 3 -#define EMMC_RST_N 2 - u32 wifi_regon_ctrl = readl((void *)(SDHCI_EMMC_BASE + SDHCI_EMMC_CTRL_R)); - wifi_regon_ctrl |= (1 << EMMC_RST_N_OE); - wifi_regon_ctrl &= ~(1 << EMMC_RST_N); - mdelay(10); - wifi_regon_ctrl |= (1 << EMMC_RST_N); - } - node = ofnode_by_compatible(ofnode_null(), "kendryte,k230_canmv"); if (ofnode_valid(node)) { #define GPIO_BASE_ADDR0 (0x9140B000U) diff --git a/board/kendryte/k230_canmv_01studio/board.c b/board/kendryte/k230_canmv_01studio/board.c index d77092f5..028eb42e 100755 --- a/board/kendryte/k230_canmv_01studio/board.c +++ b/board/kendryte/k230_canmv_01studio/board.c @@ -29,6 +29,12 @@ int ddr_init_training(void) return 0; } +int board_early_init_f(void) { + /* force set boot medium to sdio0 */ + g_boot_medium = BOOT_MEDIUM_SDIO0; + return 0; +} + #ifdef CONFIG_BOARD_LATE_INIT int board_late_init(void) { diff --git a/cmd/Kconfig b/cmd/Kconfig index 0e0be94f..dabf1fb7 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1497,6 +1497,18 @@ config CMD_USB_MASS_STORAGE export a block device: U-Boot, the USB device, acts as a simple external hard drive plugged on the host USB port. +config CMD_KBURN + bool "kburn" + select KBURN + help + Kendryte burning protocol. + +if CMD_KBURN + config CMD_KBURN_BENCHMARK + bool "Enable benchmark command with KBURN" + default n +endif + config CMD_PVBLOCK bool "Xen para-virtualized block device" depends on XEN diff --git a/cmd/Makefile b/cmd/Makefile index 6e87522b..8f8cdc55 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -187,6 +187,8 @@ obj-$(CONFIG_CMD_W1) += w1.o obj-$(CONFIG_CMD_ZIP) += zip.o obj-$(CONFIG_CMD_ZFS) += zfs.o +obj-$(CONFIG_CMD_KBURN) += kburn.o + obj-$(CONFIG_CMD_DFU) += dfu.o obj-$(CONFIG_CMD_GPT) += gpt.o obj-$(CONFIG_CMD_MBR) += mbr.o diff --git a/cmd/kburn.c b/cmd/kburn.c new file mode 100644 index 00000000..cf59539f --- /dev/null +++ b/cmd/kburn.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Eddie Cai + */ + +#include +#include +#include +#include + +#include "kburn.h" + +static int do_kburn(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret, controller_index; + char *usb_controller; + + if (argc < 1) + return CMD_RET_USAGE; + + usb_controller = argv[1]; + controller_index = simple_strtoul(usb_controller, NULL, 0); + + ret = usb_gadget_initialize(controller_index); + if (ret) { + printf("USB init failed: %d\n", ret); + return CMD_RET_FAILURE; + } + + g_dnl_clear_detach(); + ret = g_dnl_register("usb_dnl_kburn"); + if (ret) + return CMD_RET_FAILURE; + + if (!g_dnl_board_usb_cable_connected()) { + puts("\rUSB cable not detected, Command exit.\n"); + ret = CMD_RET_FAILURE; + goto exit; + } + + while (1) { + if (g_dnl_detach()) + break; + if (ctrlc()) + break; + usb_gadget_handle_interrupts(controller_index); + } + ret = CMD_RET_SUCCESS; + +exit: + g_dnl_unregister(); + g_dnl_clear_detach(); + usb_gadget_release(controller_index); + + return ret; +} + +U_BOOT_CMD(kburn, 2, 1, do_kburn, + "Canaan usb burner protocol", + " e.g. kburn 0\n" +); + +#if defined (CONFIG_CMD_KBURN_BENCHMARK) +/*****************************************************************************/ +#include +#include +#include +#include + +int test_mmc_write_speed(int dev_num, ulong start_block, ulong block_count) +{ + struct mmc *mmc; + ulong start_time, end_time; + ulong write_size = block_count * 512; // Assuming block size is 512 bytes + char *write_buffer; + int ret; + + mmc = find_mmc_device(dev_num); + if (!mmc) { + printf("MMC device %d not found\n", dev_num); + return -1; + } + + ret = mmc_init(mmc); + if (ret) { + printf("MMC init failed\n"); + return -1; + } + + write_buffer = malloc(write_size); + if (!write_buffer) { + printf("Memory allocation failed\n"); + return -1; + } + + memset(write_buffer, 0xAA, write_size); // Fill the buffer with a pattern + + start_time = get_timer(0); // Get start time + + ret = blk_dwrite(mmc_get_blk_desc(mmc), start_block, block_count, write_buffer); + + end_time = get_timer(start_time); // Get end time + + if (ret != block_count) { + printf("MMC write failed\n"); + free(write_buffer); + return -1; + } + + printf("MMC write speed: %lu bytes/sec\n", write_size * 1000 / end_time); + + free(write_buffer); + return 0; +} + +int do_test_mmc_speed(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + int dev_num = 0; + ulong start_block = 0; + ulong block_count = 1024; // Default to 1024 blocks + + if (argc > 1) + dev_num = simple_strtol(argv[1], NULL, 10); + if (argc > 2) + start_block = simple_strtol(argv[2], NULL, 10); + if (argc > 3) + block_count = simple_strtol(argv[3], NULL, 10); + + return test_mmc_write_speed(dev_num, start_block, block_count); +} + +U_BOOT_CMD( + kburn_bench_mmc, 4, 0, do_test_mmc_speed, + "Test MMC write speed", + "[dev_num] [start_block] [block_count] - Test write speed of MMC device" +); + +/*****************************************************************************/ +#include +#include +#include +#include +#include +#include + +int test_spi_flash_write_speed(int index, ulong offset, ulong size) +{ + struct udevice *dev; + struct spi_flash *flash; + ulong start_time, end_time; + char *write_buffer; + int ret; + + ret = uclass_get_device(UCLASS_SPI_FLASH, index, &dev); + if (ret) { + printf("SPI flash device %d not found\n", index); + return -1; + } + + flash = dev_get_uclass_priv(dev); + if (!flash) { + printf("Failed to get SPI flash info\n"); + return -1; + } + + write_buffer = malloc(size); + if (!write_buffer) { + printf("Memory allocation failed\n"); + return -1; + } + + memset(write_buffer, 0xAA, size); // Fill the buffer with a pattern + + start_time = get_timer(0); // Get start time + + ret = spi_flash_erase(flash, offset, size); + ret += spi_flash_write(flash, offset, size, write_buffer); + + end_time = get_timer(start_time); // Get end time + + if (ret) { + printf("SPI flash write failed\n"); + free(write_buffer); + return -1; + } + + printf("SPI flash write speed: %lu bytes/sec\n", size * 1000 / end_time); + + free(write_buffer); + return 0; +} + +int do_test_spi_flash_speed(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + int index = 0; + ulong offset = 0; + ulong size = 1024 * 1024; // Default to 1MB + + if (argc > 1) + index = simple_strtol(argv[1], NULL, 10); + if (argc > 2) + offset = simple_strtol(argv[2], NULL, 10); + if (argc > 3) + size = simple_strtol(argv[3], NULL, 10); + + return test_spi_flash_write_speed(index, offset, size); +} + +U_BOOT_CMD( + kburn_bench_sf, 4, 0, do_test_spi_flash_speed, + "Test SPI flash write speed", + "[index] [offset] [size] - Test write speed of SPI flash device" +); +/*****************************************************************************/ + +#endif // CONFIG_CMD_KBURN_BENCHMARK diff --git a/configs/k230_canmv_01studio_burntool_defconfig b/configs/k230_canmv_01studio_burntool_defconfig new file mode 100755 index 00000000..30f4148e --- /dev/null +++ b/configs/k230_canmv_01studio_burntool_defconfig @@ -0,0 +1,123 @@ +CONFIG_RISCV=y +CONFIG_SYS_TEXT_BASE=0x10000000 +CONFIG_SYS_MALLOC_F_LEN=0x40000 +CONFIG_NR_DRAM_BANKS=3 +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_OFFSET=0x1e0000 +CONFIG_SPL_DM_SPI=y +CONFIG_DEFAULT_DEVICE_TREE="k230_canmv_01studio" +CONFIG_SPL_TEXT_BASE=0x80300000 +CONFIG_SYS_PROMPT="K230# " +CONFIG_SPL_MMC=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x30000 +CONFIG_SPL_SIZE_LIMIT=0x80000 +CONFIG_SPL=y +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI=y +CONFIG_SYS_LOAD_ADDR=0xc000000 +CONFIG_BUILD_TARGET="u-boot.bin" +CONFIG_TARGET_K230_CANMV_01STUDIO=y +CONFIG_ARCH_RV64I=y +# CONFIG_SPL_SMP is not set +CONFIG_SHOW_REGS=y +CONFIG_SYS_MEMTEST_END=0x100000 +CONFIG_CC_OPTIMIZE_FOR_DEBUG=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_TIMESTAMP=y +CONFIG_FIT_SIGNATURE=y +CONFIG_SPL_FIT=y +# CONFIG_SPL_LOAD_FIT is not set +CONFIG_LEGACY_IMAGE_FORMAT=y +CONFIG_BOOTDELAY=0 +CONFIG_BOOTCOMMAND="kburn 0" +CONFIG_LOGLEVEL=7 +CONFIG_SYS_STDIO_DEREGISTER=y +# CONFIG_SYS_DEVICE_NULLDEV is not set +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_BOARD_LATE_INIT=y +CONFIG_SPL_MAX_SIZE=0x80000 +CONFIG_SPL_BSS_START_ADDR=0x80380000 +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1000 +CONFIG_SPL_ENV_SUPPORT=y +CONFIG_SPL_MMC_WRITE=y +CONFIG_SPL_MTD_SUPPORT=y +CONFIG_SPL_NAND_SUPPORT=y +CONFIG_SPL_DM_SPI_FLASH=y +# CONFIG_SPL_SPI_FLASH_TINY is not set +CONFIG_SPL_SPI_LOAD=y +CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000 +CONFIG_SPL_YMODEM_SUPPORT=y +# CONFIG_CMD_CPU is not set +CONFIG_CMD_BOOTMETH=y +CONFIG_SYS_BOOTM_LEN=0x8000000 +CONFIG_CMD_ERASEENV=y +CONFIG_CMD_MD5SUM=y +CONFIG_MD5SUM_VERIFY=y +CONFIG_CMD_MEMTEST=y +CONFIG_SYS_ALT_MEMTEST=y +CONFIG_CMD_GPT=y +CONFIG_CMD_MMC=y +CONFIG_CMD_MTD=y +# CONFIG_CMD_PINMUX is not set +CONFIG_CMD_SF_TEST=y +CONFIG_CMD_USB=y +CONFIG_CMD_KBURN=y +# CONFIG_SPL_DOS_PARTITION is not set +CONFIG_PARTITION_TYPE_GUID=y +CONFIG_OF_EMBED=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_ENV_SECT_SIZE_AUTO=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_PROT_UDP=y +CONFIG_BOOTP_SERVERIP=y +CONFIG_SPL_DM_DEVICE_REMOVE=y +CONFIG_SPL_CLK=y +CONFIG_DM_KEYBOARD=y +CONFIG_KBURN_MMC=y +CONFIG_MMC=y +CONFIG_MMC_HS200_SUPPORT=y +CONFIG_SPL_MMC_HS200_SUPPORT=y +CONFIG_MMC_DW=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_SDMA=y +CONFIG_MMC_SDHCI_SNPS=y +CONFIG_DM_MTD=y +CONFIG_MTD_SPI_NAND=y +CONFIG_SPI_FLASH_SFDP_SUPPORT=y +CONFIG_SPI_FLASH_SOFT_RESET=y +CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y +CONFIG_PINCTRL=y +CONFIG_SPL_PINCTRL=y +CONFIG_SPL_PINCONF=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_DESIGNWARE_SPI=y +CONFIG_USB=y +CONFIG_DM_USB_GADGET=y +CONFIG_USB_DWC2=y +CONFIG_USB_HOST_ETHER=y +CONFIG_USB_ETHER_ASIX=y +CONFIG_USB_ETHER_ASIX88179=y +CONFIG_USB_ETHER_MCS7830=y +CONFIG_USB_ETHER_RTL8152=y +CONFIG_USB_ETHER_SMSC95XX=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_MANUFACTURER="Kendryte" +CONFIG_USB_GADGET_VENDOR_NUM=0x29f1 +CONFIG_USB_GADGET_PRODUCT_NUM=0x0230 +CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_DOWNLOAD=y +CONFIG_FAT_WRITE=y +CONFIG_SPL_GZIP=y +# CONFIG_EFI_LOADER is not set diff --git a/configs/k230_canmv_burntool_defconfig b/configs/k230_canmv_burntool_defconfig new file mode 100755 index 00000000..66b6bef5 --- /dev/null +++ b/configs/k230_canmv_burntool_defconfig @@ -0,0 +1,123 @@ +CONFIG_RISCV=y +CONFIG_SYS_TEXT_BASE=0x10000000 +CONFIG_SYS_MALLOC_F_LEN=0x40000 +CONFIG_NR_DRAM_BANKS=3 +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_OFFSET=0x1e0000 +CONFIG_SPL_DM_SPI=y +CONFIG_DEFAULT_DEVICE_TREE="k230_canmv" +CONFIG_SPL_TEXT_BASE=0x80300000 +CONFIG_SYS_PROMPT="K230# " +CONFIG_SPL_MMC=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x30000 +CONFIG_SPL_SIZE_LIMIT=0x80000 +CONFIG_SPL=y +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI=y +CONFIG_SYS_LOAD_ADDR=0xc000000 +CONFIG_BUILD_TARGET="u-boot.bin" +CONFIG_TARGET_K230_CANMV=y +CONFIG_ARCH_RV64I=y +# CONFIG_SPL_SMP is not set +CONFIG_SHOW_REGS=y +CONFIG_SYS_MEMTEST_END=0x100000 +CONFIG_CC_OPTIMIZE_FOR_DEBUG=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_TIMESTAMP=y +CONFIG_FIT_SIGNATURE=y +CONFIG_SPL_FIT=y +# CONFIG_SPL_LOAD_FIT is not set +CONFIG_LEGACY_IMAGE_FORMAT=y +CONFIG_BOOTDELAY=0 +CONFIG_BOOTCOMMAND="kburn 0" +CONFIG_LOGLEVEL=7 +CONFIG_SYS_STDIO_DEREGISTER=y +# CONFIG_SYS_DEVICE_NULLDEV is not set +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_BOARD_LATE_INIT=y +CONFIG_SPL_MAX_SIZE=0x80000 +CONFIG_SPL_BSS_START_ADDR=0x80380000 +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1000 +CONFIG_SPL_ENV_SUPPORT=y +CONFIG_SPL_MMC_WRITE=y +CONFIG_SPL_MTD_SUPPORT=y +CONFIG_SPL_NAND_SUPPORT=y +CONFIG_SPL_DM_SPI_FLASH=y +# CONFIG_SPL_SPI_FLASH_TINY is not set +CONFIG_SPL_SPI_LOAD=y +CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000 +CONFIG_SPL_YMODEM_SUPPORT=y +# CONFIG_CMD_CPU is not set +CONFIG_CMD_BOOTMETH=y +CONFIG_SYS_BOOTM_LEN=0x8000000 +CONFIG_CMD_ERASEENV=y +CONFIG_CMD_MD5SUM=y +CONFIG_MD5SUM_VERIFY=y +CONFIG_CMD_MEMTEST=y +CONFIG_SYS_ALT_MEMTEST=y +CONFIG_CMD_GPT=y +CONFIG_CMD_MMC=y +CONFIG_CMD_MTD=y +# CONFIG_CMD_PINMUX is not set +CONFIG_CMD_SF_TEST=y +CONFIG_CMD_USB=y +CONFIG_CMD_KBURN=y +# CONFIG_SPL_DOS_PARTITION is not set +CONFIG_PARTITION_TYPE_GUID=y +CONFIG_OF_EMBED=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_ENV_SECT_SIZE_AUTO=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_PROT_UDP=y +CONFIG_BOOTP_SERVERIP=y +CONFIG_SPL_DM_DEVICE_REMOVE=y +CONFIG_SPL_CLK=y +CONFIG_DM_KEYBOARD=y +CONFIG_KBURN_MMC=y +CONFIG_MMC=y +CONFIG_MMC_HS200_SUPPORT=y +CONFIG_SPL_MMC_HS200_SUPPORT=y +CONFIG_MMC_DW=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_SDMA=y +CONFIG_MMC_SDHCI_SNPS=y +CONFIG_DM_MTD=y +CONFIG_MTD_SPI_NAND=y +CONFIG_SPI_FLASH_SFDP_SUPPORT=y +CONFIG_SPI_FLASH_SOFT_RESET=y +CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y +CONFIG_PINCTRL=y +CONFIG_SPL_PINCTRL=y +CONFIG_SPL_PINCONF=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_DESIGNWARE_SPI=y +CONFIG_USB=y +CONFIG_DM_USB_GADGET=y +CONFIG_USB_DWC2=y +CONFIG_USB_HOST_ETHER=y +CONFIG_USB_ETHER_ASIX=y +CONFIG_USB_ETHER_ASIX88179=y +CONFIG_USB_ETHER_MCS7830=y +CONFIG_USB_ETHER_RTL8152=y +CONFIG_USB_ETHER_SMSC95XX=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_MANUFACTURER="Kendryte" +CONFIG_USB_GADGET_VENDOR_NUM=0x29f1 +CONFIG_USB_GADGET_PRODUCT_NUM=0x0230 +CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_DOWNLOAD=y +CONFIG_FAT_WRITE=y +CONFIG_SPL_GZIP=y +# CONFIG_EFI_LOADER is not set diff --git a/configs/k230d_canmv_bpi_zero_burntool_defconfig b/configs/k230d_canmv_bpi_zero_burntool_defconfig new file mode 100755 index 00000000..60f5faf1 --- /dev/null +++ b/configs/k230d_canmv_bpi_zero_burntool_defconfig @@ -0,0 +1,123 @@ +CONFIG_RISCV=y +CONFIG_SYS_TEXT_BASE=0x10000000 +CONFIG_SYS_MALLOC_F_LEN=0x40000 +CONFIG_NR_DRAM_BANKS=3 +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_OFFSET=0x1e0000 +CONFIG_SPL_DM_SPI=y +CONFIG_DEFAULT_DEVICE_TREE="k230d_canmv_bpi_zero" +CONFIG_SPL_TEXT_BASE=0x80300000 +CONFIG_SYS_PROMPT="K230# " +CONFIG_SPL_MMC=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x30000 +CONFIG_SPL_SIZE_LIMIT=0x80000 +CONFIG_SPL=y +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI=y +CONFIG_SYS_LOAD_ADDR=0xc000000 +CONFIG_BUILD_TARGET="u-boot.bin" +CONFIG_TARGET_K230D_CANMV_BPI_ZERO=y +CONFIG_ARCH_RV64I=y +# CONFIG_SPL_SMP is not set +CONFIG_SHOW_REGS=y +CONFIG_SYS_MEMTEST_END=0x100000 +CONFIG_CC_OPTIMIZE_FOR_DEBUG=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_TIMESTAMP=y +CONFIG_FIT_SIGNATURE=y +CONFIG_SPL_FIT=y +# CONFIG_SPL_LOAD_FIT is not set +CONFIG_LEGACY_IMAGE_FORMAT=y +CONFIG_BOOTDELAY=0 +CONFIG_BOOTCOMMAND="kburn 0" +CONFIG_LOGLEVEL=7 +CONFIG_SYS_STDIO_DEREGISTER=y +# CONFIG_SYS_DEVICE_NULLDEV is not set +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_BOARD_LATE_INIT=y +CONFIG_SPL_MAX_SIZE=0x80000 +CONFIG_SPL_BSS_START_ADDR=0x80380000 +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1000 +CONFIG_SPL_ENV_SUPPORT=y +CONFIG_SPL_MMC_WRITE=y +CONFIG_SPL_MTD_SUPPORT=y +CONFIG_SPL_NAND_SUPPORT=y +CONFIG_SPL_DM_SPI_FLASH=y +# CONFIG_SPL_SPI_FLASH_TINY is not set +CONFIG_SPL_SPI_LOAD=y +CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000 +CONFIG_SPL_YMODEM_SUPPORT=y +# CONFIG_CMD_CPU is not set +CONFIG_CMD_BOOTMETH=y +CONFIG_SYS_BOOTM_LEN=0x8000000 +CONFIG_CMD_ERASEENV=y +CONFIG_CMD_MD5SUM=y +CONFIG_MD5SUM_VERIFY=y +CONFIG_CMD_MEMTEST=y +CONFIG_SYS_ALT_MEMTEST=y +CONFIG_CMD_GPT=y +CONFIG_CMD_MMC=y +CONFIG_CMD_MTD=y +# CONFIG_CMD_PINMUX is not set +CONFIG_CMD_SF_TEST=y +CONFIG_CMD_USB=y +CONFIG_CMD_KBURN=y +# CONFIG_SPL_DOS_PARTITION is not set +CONFIG_PARTITION_TYPE_GUID=y +CONFIG_OF_EMBED=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_ENV_SECT_SIZE_AUTO=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_PROT_UDP=y +CONFIG_BOOTP_SERVERIP=y +CONFIG_SPL_DM_DEVICE_REMOVE=y +CONFIG_SPL_CLK=y +CONFIG_DM_KEYBOARD=y +CONFIG_KBURN_MMC=y +CONFIG_MMC=y +CONFIG_MMC_HS200_SUPPORT=y +CONFIG_SPL_MMC_HS200_SUPPORT=y +CONFIG_MMC_DW=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_SDMA=y +CONFIG_MMC_SDHCI_SNPS=y +CONFIG_DM_MTD=y +CONFIG_MTD_SPI_NAND=y +CONFIG_SPI_FLASH_SFDP_SUPPORT=y +CONFIG_SPI_FLASH_SOFT_RESET=y +CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y +CONFIG_PINCTRL=y +CONFIG_SPL_PINCTRL=y +CONFIG_SPL_PINCONF=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_SYS_NS16550=y +CONFIG_SPI=y +CONFIG_DESIGNWARE_SPI=y +CONFIG_USB=y +CONFIG_DM_USB_GADGET=y +CONFIG_USB_DWC2=y +CONFIG_USB_HOST_ETHER=y +CONFIG_USB_ETHER_ASIX=y +CONFIG_USB_ETHER_ASIX88179=y +CONFIG_USB_ETHER_MCS7830=y +CONFIG_USB_ETHER_RTL8152=y +CONFIG_USB_ETHER_SMSC95XX=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_MANUFACTURER="Kendryte" +CONFIG_USB_GADGET_VENDOR_NUM=0x29f1 +CONFIG_USB_GADGET_PRODUCT_NUM=0x0230 +CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_DOWNLOAD=y +CONFIG_FAT_WRITE=y +CONFIG_SPL_GZIP=y +# CONFIG_EFI_LOADER is not set diff --git a/drivers/Kconfig b/drivers/Kconfig index 8b6fead3..184f0594 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -54,6 +54,8 @@ source "drivers/input/Kconfig" source "drivers/iommu/Kconfig" +source "drivers/kburn/Kconfig" + source "drivers/led/Kconfig" source "drivers/mailbox/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index eba99402..fa534f66 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_$(SPL_TPL_)SYSRESET) += sysreset/ obj-$(CONFIG_$(SPL_TPL_)FIRMWARE) +=firmware/ obj-$(CONFIG_$(SPL_TPL_)I2C) += i2c/ obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/ +obj-$(CONFIG_$(SPL_TPL_)KBURN) += kburn/ obj-$(CONFIG_$(SPL_TPL_)LED) += led/ obj-$(CONFIG_$(SPL_TPL_)MMC) += mmc/ obj-y += mtd/ diff --git a/drivers/kburn/Kconfig b/drivers/kburn/Kconfig new file mode 100644 index 00000000..09c1b239 --- /dev/null +++ b/drivers/kburn/Kconfig @@ -0,0 +1,32 @@ +menu "Kendryte burning support" + +config KBURN + bool + imply KBURN_OVER_USB if USB_GADGET + +config KBURN_OVER_USB + bool + depends on USB_GADGET + +if KBURN +config KBURN_MMC + bool "MMC backend for KBURN" + select DM_MMC + help + This option enables using KBURN to read and write to MMC based storage. + +config KBURN_SF + bool "sf(SPI Flash) backend for KBURN" + select DM_SPI_FLASH + help + This option enables using KBURN to read and write to SPI flash based + storage. + +config KBURN_MTD + bool "MTD back end for KBURN" + depends on DM_MTD + help + This option enables using KBURN to read and write to on any MTD device. + +endif +endmenu diff --git a/drivers/kburn/Makefile b/drivers/kburn/Makefile new file mode 100644 index 00000000..13b82617 --- /dev/null +++ b/drivers/kburn/Makefile @@ -0,0 +1,6 @@ + +obj-$(CONFIG_$(SPL_)KBURN) += kburn.o + +obj-$(CONFIG_$(SPL_)KBURN_MMC) += kburn_mmc.o +obj-$(CONFIG_$(SPL_)KBURN_SF) += kburn_sf.o +obj-$(CONFIG_$(SPL_)KBURN_MTD) += kburn_mtd.o diff --git a/drivers/kburn/kburn.c b/drivers/kburn/kburn.c new file mode 100644 index 00000000..b30b5bb3 --- /dev/null +++ b/drivers/kburn/kburn.c @@ -0,0 +1,87 @@ +#include +#include +#include + +#include "kburn.h" + +struct kburn * kburn_probe_media(enum KBURN_MEDIA_TYPE type) +{ + struct kburn * kburn = NULL; + +#if defined (CONFIG_KBURN_MMC) + if(KBURN_MEDIA_eMMC == type) { + kburn = kburn_mmc_probe(0); // K230 eMMC is on mmc0 + } else if (KBURN_MEDIA_SDCARD == type) { + kburn = kburn_mmc_probe(1); // K230 SD Card is on mmc1 + } else +#endif // CONFIG_KBURN_MMC +#if defined (CONFIG_KBURN_SF) + if(KBURN_MEDIA_SPI_NOR == type) { + kburn = kburn_sf_probe(); + } else +#endif // CONFIG_KBURN_SF +#if defined (CONFIG_KBURN_MTD) + if(KBURN_MEDIA_SPI_NAND == type) { + kburn = kburn_mtd_probe(); + } else +#endif // CONFIG_KBURN_MTD + { + printf("kburn probe not support type %x\n", type); + } + + if (NULL == kburn) { + printf("kburn probe failed, type %x\n", type); + } + + return kburn; +} + +int kburn_get_medium_info(struct kburn *burn) +{ + if((NULL == burn) || (NULL == burn->get_medium_info)) { + pr_err("invalid arg\n"); + return -1; + } + return burn->get_medium_info(burn); +} + +int kburn_read_medium(struct kburn *burn, u64 offset, void *buf, u64 *len) +{ + if((NULL == burn) || (NULL == burn->read_medium)) { + pr_err("invalid arg\n"); + return -1; + } + return burn->read_medium(burn, offset, buf, len); +} + +int kburn_write_medium(struct kburn *burn, u64 offset, const void *buf, u64 *len) +{ + if((NULL == burn) || (NULL == burn->write_medium)) { + pr_err("invalid arg\n"); + return -1; + } + return burn->write_medium(burn, offset, buf, len); +} + +int kburn_erase_medium(struct kburn *burn, u64 offset, u64 *len) +{ + if((NULL == burn) || (NULL == burn->erase_medium)) { + pr_err("invalid arg\n"); + return -1; + } + return burn->erase_medium(burn, offset, len); +} + +void kburn_destory(struct kburn *burn) +{ + if((NULL == burn) || (NULL == burn->destory)) { + pr_err("invalid arg\n"); + return; + } + + if(0x00 != burn->destory(burn)) { + pr_err("destory kburn failed.\n"); + } + + free(burn); +} diff --git a/drivers/kburn/kburn_mmc.c b/drivers/kburn/kburn_mmc.c new file mode 100644 index 00000000..9b00d582 --- /dev/null +++ b/drivers/kburn/kburn_mmc.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define MMC_OP_READ 0x01 +#define MMC_OP_WRITE 0x02 +#define MMC_OP_ERASE 0x03 + +struct kburn_mmc_priv { + struct mmc *mmc; + struct blk_desc *desc; + int dev_num; +}; + +static int mmc_get_medium_info(struct kburn *burn) +{ + struct kburn_mmc_priv *priv = (struct kburn_mmc_priv *)(burn->dev_priv); + + struct mmc *mmc = priv->mmc; + struct blk_desc *desc = priv->desc; + + // if (NULL == (mmc = find_mmc_device(priv->dev_num))) { + // pr_err("Device MMC %d - not found!", priv->dev_num); + // return 1; + // } + + // if (NULL == (desc = mmc_get_blk_desc(mmc))) { + // pr_err("Device MMC %d - get desc failed", priv->dev_num); + // return 2; + // } + + burn->medium_info.valid = 1; + burn->medium_info.wp = mmc_getwp(mmc); + + burn->medium_info.capacity = (u64)desc->lba * (u64)desc->blksz; + burn->medium_info.erase_size = (u64)mmc->erase_grp_size * (u64)desc->blksz; + burn->medium_info.blk_size = desc->blksz; + burn->medium_info.timeout_ms = 1000; + burn->medium_info.type = KBURN_MEDIA_eMMC; + + pr_info("Device MMC %d capacity %lld, erase size %lld, blk_sz %lld\n", \ + priv->dev_num, burn->medium_info.capacity, burn->medium_info.erase_size, burn->medium_info.blk_size); + + return 0; +} + +static u64 mmc_op(int op, struct kburn *burn, u64 offset, void *buf, u64 *len) +{ + struct kburn_mmc_priv *priv = (struct kburn_mmc_priv *)(burn->dev_priv); + + // struct mmc *mmc = priv->mmc; + struct blk_desc *desc = priv->desc; + + u32 blk_start, blk_count, n = 0; + + // if (NULL == (mmc = find_mmc_device(priv->dev_num))) { + // pr_err("Device MMC %d - not found!", priv->dev_num); + // return 1; + // } + + // if (mmc_getwp(mmc) == 1) { + // pr_err("Error: card is write protected!\n"); + // return 2; + // } + + // if (NULL == (desc = mmc_get_blk_desc(mmc))) { + // pr_err("Device MMC %d - get desc failed", priv->dev_num); + // return 3; + // } + + /* + * We must ensure that we work in lba_blk_size chunks, so ALIGN + * this value. + */ + *len = ALIGN(*len, desc->blksz); + + blk_start = (u32)lldiv(offset, desc->blksz); + blk_count = *len / desc->blksz; + + if (blk_start + blk_count > desc->lba) { + puts("Request would exceed designated area!\n"); + return 4; + } + + if(MMC_OP_READ == op) { + n = blk_dread(desc, blk_start, blk_count, buf); + } else if(MMC_OP_WRITE == op) { + n = blk_dwrite(desc, blk_start, blk_count, buf); + } else if(MMC_OP_ERASE == op) { + n = blk_derase(desc, blk_start, blk_count); + } + + if (n != blk_count) { + pr_err("MMC operation failed"); + + return 5; + } + + return 0; +} + +static int mmc_read_medium(struct kburn *burn, u64 offset, void *buf, u64 *len) +{ + return mmc_op(MMC_OP_READ, burn, offset, buf, len); +} + +static int mmc_write_medium(struct kburn *burn, u64 offset, const void *buf, u64 *len) +{ + return mmc_op(MMC_OP_WRITE, burn, offset, (void *)buf, len); +} + +static int mmc_erase_medium(struct kburn *burn, u64 offset, u64 *len) +{ + return mmc_op(MMC_OP_ERASE, burn, offset, NULL, len); +} + +static int mmc_destory(struct kburn *burn) +{ + return 0; +} + +struct kburn *kburn_mmc_probe(uint8_t bus) +{ + struct uclass *uc; + struct udevice *dev, *dev_bus; + + struct mmc *mmc; + struct blk_desc *desc; + + struct kburn *burner; + struct kburn_mmc_priv *priv; + + int ret; + + ret = uclass_get(UCLASS_MMC, &uc); + if(ret) { + pr_err("can not get mmc uclass\n"); + return NULL; + } + + uclass_foreach_dev(dev, uc) { + if(NULL != (mmc = mmc_get_mmc_dev(dev))) { + if(0x00 == mmc_init(mmc)) { + if(0xFF != bus) { + dev_bus = dev_get_parent(dev); + if(dev_seq(dev_bus) != bus) { + continue; + } + } + break; + } + } + } + + if (NULL == mmc) { + pr_err("can not find mmc device\n"); + return NULL; + } + + if (NULL == (desc = mmc_get_blk_desc(mmc))) { + pr_err("Device MMC %d - get desc failed", mmc_get_blk_desc(mmc)->devnum); + return NULL; + } + + // we find a mmc device, and init it. + burner = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*burner) + sizeof(*priv)); + if(NULL == burner) { + pr_err("memaligin failed\n"); + return NULL; + } + memset(burner, 0, sizeof(*burner)); + priv = (struct kburn_mmc_priv *)((char *)burner + sizeof(*burner)); + + priv->mmc = mmc; + priv->desc = desc; + priv->dev_num = mmc_get_blk_desc(mmc)->devnum; + + pr_info("probe mmc succ, dev %d\n", priv->dev_num); + + burner->type = KBURN_MEDIA_eMMC; + burner->dev_priv = (void *)priv; + + burner->get_medium_info = mmc_get_medium_info; + burner->read_medium = mmc_read_medium; + burner->write_medium = mmc_write_medium; + burner->erase_medium = mmc_erase_medium; + burner->destory = mmc_destory; + + return burner; +} diff --git a/drivers/kburn/kburn_mtd.c b/drivers/kburn/kburn_mtd.c new file mode 100644 index 00000000..5c3a275b --- /dev/null +++ b/drivers/kburn/kburn_mtd.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +struct kburn_mtd_priv { + struct mtd_info *mtd; + int dev_num; +}; + +static int mtd_get_medium_info(struct kburn *burn) +{ + struct kburn_mtd_priv *priv = (struct kburn_mtd_priv *)(burn->dev_priv); + struct mtd_info *mtd = priv->mtd; + + burn->medium_info.valid = 1; + burn->medium_info.wp = 0; + + burn->medium_info.capacity = mtd->size; + burn->medium_info.erase_size = mtd->erasesize; + burn->medium_info.blk_size = mtd->writesize; + burn->medium_info.timeout_ms = 5000; + burn->medium_info.type = KBURN_MEDIA_SPI_NAND; + + pr_info("Device %s %d capacity %lld, erase size %lld, blk_sz %lld\n", \ + mtd->name, priv->dev_num, burn->medium_info.capacity, burn->medium_info.erase_size, burn->medium_info.blk_size); + + return 0; +} + +static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size) +{ + return !do_div(size, mtd->writesize); +} + +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size) +{ + return !do_div(size, mtd->erasesize); +} + +/* Logic taken from cmd/mtd.c:mtd_oob_write_is_empty() */ +static bool mtd_page_is_empty(struct mtd_oob_ops *op) +{ + int i; + + for (i = 0; i < op->len; i++) + if (op->datbuf[i] != 0xff) + return false; + + /* oob is not used, with MTD_OPS_AUTO_OOB & ooblen=0 */ + + return true; +} + +static int mtd_read_medium(struct kburn *burn, u64 offset, void *buf, u64 *len) +{ + pr_err("TODO\n"); + return -1; +} + +static int mtd_erase_medium(struct kburn *burn, u64 offset, u64 *len) +{ + struct kburn_mtd_priv *priv = (struct kburn_mtd_priv *)(burn->dev_priv); + struct mtd_info *mtd = priv->mtd; + + struct erase_info erase_op = {}; + u64 off, size; + int ret = 0; + + off = offset; + size = *len; + + if (!mtd_is_aligned_with_block_size(mtd, off)) { + pr_err("Offset not aligned with a block (0x%x)\n", + mtd->erasesize); + return -1; + } + + if (!mtd_is_aligned_with_block_size(mtd, size)) { + pr_err("Size not a multiple of a block (0x%x)\n", + mtd->erasesize); + return -1; + } + + pr_info("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n", + off, off + size - 1, mtd_div_by_eb(size, mtd)); + + erase_op.mtd = mtd; + erase_op.addr = off; + erase_op.len = mtd->erasesize; + erase_op.scrub = false; + + while (size) { + ret = mtd_erase(mtd, &erase_op); + + if (ret) { + /* Abort if its not a bad block error */ + if (ret != -EIO) + break; + pr_info("Skipping bad block at 0x%08llx\n", + erase_op.addr); + } + + size -= mtd->erasesize; + erase_op.addr += mtd->erasesize; + } + + if (ret && ret != -EIO) { + pr_err("Erase mtd failed. %d\n", ret); + return -1; + } + + return 0; +} + +static int mtd_write_medium(struct kburn *burn, u64 offset, const void *buf, u64 *len) +{ + struct kburn_mtd_priv *priv = (struct kburn_mtd_priv *)(burn->dev_priv); + struct mtd_info *mtd = priv->mtd; + + struct mtd_oob_ops io_op = {}; + + int ret = -1; + u64 off = offset, size= *len, remaining = *len; + u64 lock_ofs = offset, lock_len = *len; + + bool has_pages = mtd->type == MTD_NANDFLASH || + mtd->type == MTD_MLCNANDFLASH; + + if (!mtd_is_aligned_with_min_io_size(mtd, off)) { + pr_err("Offset not aligned with a page (0x%x)\n", + mtd->writesize); + return -1; + } + + if (!mtd_is_aligned_with_min_io_size(mtd, size)) { + pr_err("Size not on a page boundary (0x%x), rounding to 0x%llx\n", + mtd->writesize, size); + return -1; + } + + pr_debug("Unlocking the mtd device\n"); + ret = mtd_unlock(mtd, lock_ofs, lock_len); + if (ret && ret != -EOPNOTSUPP) { + printf("MTD device unlock failed\n"); + return -1; + } + + if(0x00 != mtd_erase_medium(burn, offset, &size)) { + printf("MTD device erase failed\n"); + mtd_lock(mtd, lock_ofs, lock_len); + return -1; + } + + io_op.mode = MTD_OPS_AUTO_OOB; + io_op.len = size; + if (has_pages && io_op.len > mtd->writesize) + io_op.len = mtd->writesize; + io_op.ooblen = 0; + io_op.datbuf = buf; + io_op.oobbuf = NULL; + + /* Search for the first good block after the given offset */ + while (mtd_block_isbad(mtd, off)) + off += mtd->erasesize; + + /* Loop over the pages to do the actual read/write */ + while (remaining) { + /* Skip the block if it is bad */ + if (mtd_is_aligned_with_block_size(mtd, off) && + mtd_block_isbad(mtd, off)) { + off += mtd->erasesize; + continue; + } + + if(has_pages && mtd_page_is_empty(&io_op)) { + ret = 0; + io_op.retlen = mtd->writesize; + io_op.oobretlen = mtd->oobsize; + } else { + ret = mtd_write_oob(mtd, off, &io_op); + } + + if (ret) { + pr_err("Failure while writing at offset 0x%llx\n", off); + break; + } + + off += io_op.retlen; + remaining -= io_op.retlen; + io_op.datbuf += io_op.retlen; + io_op.len = remaining; + if (has_pages && io_op.len > mtd->writesize) + io_op.len = mtd->writesize; + } + + mtd_lock(mtd, lock_ofs, lock_len); + + if (ret) { + printf("mtd write on %s failed with error %d\n", mtd->name, ret); + return -1; + } + + return 0; +} + +static int mtd_destory(struct kburn *burn) +{ + return 0; +} + +struct kburn *kburn_mtd_probe(void) +{ + struct udevice *ud_mtd, *ud_mtd_parent; + + struct kburn *burner; + struct kburn_mtd_priv *priv; + + if(0x00 != uclass_first_device_err(UCLASS_MTD, &ud_mtd)) { + pr_err("can not found mtd device"); + return NULL; + } + ud_mtd_parent = dev_get_parent(ud_mtd); + + burner = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*burner) + sizeof(*priv)); + if(NULL == burner) { + pr_err("memaligin failed\n"); + return NULL; + } + memset(burner, 0, sizeof(*burner)); + + priv = (struct kburn_mtd_priv *)((char *)burner + sizeof(*burner)); + priv->mtd = dev_get_uclass_priv(ud_mtd); + priv->dev_num = dev_seq(ud_mtd_parent); + + burner->type = KBURN_MEDIA_SPI_NAND; + burner->dev_priv = (void *)priv; + + burner->get_medium_info = mtd_get_medium_info; + burner->read_medium = mtd_read_medium; + burner->write_medium = mtd_write_medium; + burner->erase_medium = mtd_erase_medium; + burner->destory = mtd_destory; + + return burner; +} diff --git a/drivers/kburn/kburn_sf.c b/drivers/kburn/kburn_sf.c new file mode 100644 index 00000000..5e9caf2a --- /dev/null +++ b/drivers/kburn/kburn_sf.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +struct kburn_sf_priv { + struct spi_flash *flash; + int dev_num; +}; + +static int sf_get_medium_info(struct kburn *burn) +{ + struct kburn_sf_priv *priv = (struct kburn_sf_priv *)(burn->dev_priv); + struct spi_flash *flash = priv->flash; + + burn->medium_info.valid = 1; + burn->medium_info.wp = 0; + + burn->medium_info.capacity = flash->size; + burn->medium_info.erase_size = flash->erase_size; + burn->medium_info.blk_size = flash->page_size; + burn->medium_info.timeout_ms = 5000; + burn->medium_info.type = KBURN_MEDIA_SPI_NOR; + + pr_info("Device SPI-FLASH %d capacity %lld, erase size %lld, blk_sz %lld\n", \ + priv->dev_num, burn->medium_info.capacity, burn->medium_info.erase_size, burn->medium_info.blk_size); + + return 0; +} + +static int sf_read_medium(struct kburn *burn, u64 offset, void *buf, u64 *len) +{ + pr_err("TODO"); + return -1; +} + +static bool sf_page_is_empty(const void *buf, u64 size) +{ + if(((0x00 == (((u64)buf) & 0x07))) && (0x00 == (size % 8))) { + const u64 *pdata = (u64*)buf; + const u64 *pend = pdata + (size / 8); + + do { + if(0xFFFFFFFFFFFFFFFFULL != pdata[0]) { + return false; + } + } while(pdata++ < pend); + } else { + const u8 *pdata = (u8*)buf; + const u8 *pend = pdata + size; + + do { + if(0xFF != pdata[0]) { + return false; + } + } while(pdata++ < pend); + } + + return true; +} + +static bool sf_is_aligned_with_min_io_size(struct spi_flash *flash, u64 size) +{ + return !do_div(size, flash->erase_size); +} + +static bool sf_is_aligned_with_block_size(struct spi_flash *flash, u64 size) +{ + return !do_div(size, flash->page_size); +} + +static int sf_write_medium(struct kburn *burn, u64 offset, const void *buf, u64 *len) +{ + struct kburn_sf_priv *priv = (struct kburn_sf_priv *)(burn->dev_priv); + struct spi_flash *flash = priv->flash; + + int rc; + const void *buffer = buf; + u64 off = offset; + u64 size = *len; + u64 remaining, send_len; + + pr_debug("sf write offset %lld, size %lld\n", offset, size); + + if (!sf_is_aligned_with_min_io_size(flash, off)) { + pr_err("Offset not aligned with a block (0x%x)\n", + flash->erase_size); + return -1; + } + + if (!sf_is_aligned_with_block_size(flash, size)) { + pr_err("Size not a multiple of a block (0x%x)\n", + flash->erase_size); + return -1; + } + + if(0x00 != (rc = spi_flash_erase(flash, (u32)offset, size))) { + pr_err("sf write, erase %lld failed, %d\n", offset, rc); + return -1; + } + + pr_info("Erasing 0x%08llx ... 0x%08llx\n", + off, off + size - 1); + + remaining = size; + send_len = remaining > 4096 ? 4096 : remaining; + + while(remaining) { + if(sf_page_is_empty(buffer, send_len)) { + off += send_len; + buffer += send_len; + remaining -= send_len; + send_len = remaining > 4096 ? 4096 : remaining; + continue; + } + + if(0x00 != (rc = spi_flash_write(flash, (u32)off, (size_t)send_len, buffer))) { + pr_err("sf wrtie failed %llx, err %d\n", off, rc); + return -1; + } + + off += send_len; + buffer += send_len; + remaining -= send_len; + send_len = remaining > 4096 ? 4096 : remaining; + } + + if(0x00 != rc) { + return -1; + } + + return 0; +} + +static int sf_erase_medium(struct kburn *burn, u64 offset, u64 *len) +{ + struct kburn_sf_priv *priv = (struct kburn_sf_priv *)(burn->dev_priv); + struct spi_flash *flash = priv->flash; + + pr_info("erase medium start, offset %lld, size %lld\n", offset, *len); + + int rc = spi_flash_erase(flash, (u32)offset, (size_t)*len); + + pr_info("erase medium done, result %d\n", rc); + + return rc; +} + +static int sf_destory(struct kburn *burn) +{ + return 0; +} + +struct kburn *kburn_sf_probe(void) +{ + struct udevice *ud_sf, *ud_sf_parent; + + struct kburn *burner; + struct kburn_sf_priv *priv; + + if(0x00 != uclass_first_device_err(UCLASS_SPI_FLASH, &ud_sf)) { + pr_err("can not found spi flash device"); + return NULL; + } + ud_sf_parent = dev_get_parent(ud_sf); + + // we find a sf device, and init it. + burner = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*burner) + sizeof(*priv)); + if(NULL == burner) { + pr_err("memaligin failed\n"); + return NULL; + } + memset(burner, 0, sizeof(*burner)); + + priv = (struct kburn_sf_priv *)((char *)burner + sizeof(*burner)); + priv->flash = dev_get_uclass_priv(ud_sf); + priv->dev_num = dev_seq(ud_sf_parent); + + burner->type = KBURN_MEDIA_SPI_NOR; + burner->dev_priv = (void *)priv; + + burner->get_medium_info = sf_get_medium_info; + burner->read_medium = sf_read_medium; + burner->write_medium = sf_write_medium; + burner->erase_medium = sf_erase_medium; + burner->destory = sf_destory; + + return burner; +} diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index dd09ee01..5d5a611a 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o obj-$(CONFIG_USB_FUNCTION_SDP) += f_sdp.o obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o obj-$(CONFIG_USB_FUNCTION_ACM) += f_acm.o +obj-$(CONFIG_KBURN_OVER_USB) += f_kburn.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index 9ca6f423..0cc38cca 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -264,7 +264,7 @@ struct dwc2_usbotg_reg { | INT_RESET | INT_SUSPEND | INT_OTG) #define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE) #define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE) -#define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\ +#define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR8\ | GBL_INT_UNMASK) /* Device Endpoint X Transfer Size Register (DIEPTSIZX) */ diff --git a/drivers/usb/gadget/f_kburn.c b/drivers/usb/gadget/f_kburn.c new file mode 100644 index 00000000..db654842 --- /dev/null +++ b/drivers/usb/gadget/f_kburn.c @@ -0,0 +1,763 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kburn.h" + +static void tx_done_handler(struct usb_ep *ep, struct usb_request *req); +static void rx_command_handler(struct usb_ep *ep, struct usb_request *req); + +enum kburn_pkt_cmd { + KBURN_CMD_NONE = 0, + + KBURN_CMD_DEV_PROBE = 0x10, + KBURN_CMD_DEV_GET_INFO = 0x11, + + KBURN_CMD_WRITE_LBA = 0x20, + KBURN_CMD_ERASE_LBA = 0x21, + + KBURN_CMD_MAX, +}; + +enum kburn_pkt_result { + KBURN_RESULT_NONE = 0, + + KBURN_RESULT_OK = 1, + KBURN_RESULT_ERROR = 2, + + KBURN_RESULT_ERROR_MSG = 0xFF, + + KBURN_RESULT_MAX, +}; + +#define KBUNR_USB_PKT_SIZE (64) + +struct kburn_usb_pkt { + uint16_t cmd; + uint16_t result; /* only valid in csw */ + uint8_t data_size; + uint8_t data[0]; +}; + +struct kburn_pkt_handler_t { + enum kburn_pkt_cmd cmd; + /* call back function to handle rockusb command */ + void (*cb)(struct usb_ep *ep, struct usb_request *req); +}; + +struct kburn_usb_t { + struct usb_function usb_function; + struct usb_ep *in_ep, *out_ep; + struct usb_request *in_req, *out_req; + + struct kburn *burner; + + u64 offset; + u64 dl_size; + u64 dl_bytes; + u64 ul_size; + u64 ul_bytes; + + void *buf; + void *buf_head; +}; + +static struct usb_endpoint_descriptor hs_ep_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN | 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor hs_ep_out = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT | 2, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor fs_ep_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN | 3, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), +}; + +static struct usb_endpoint_descriptor fs_ep_out = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT | 4, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), +}; + +static struct usb_interface_descriptor interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x01, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = KBURN_USB_INTF_CLASS, + .bInterfaceSubClass = KBURN_USB_INTF_SUBCLASS, + .bInterfaceProtocol = KBURN_USB_INTF_PROTOCOL, +}; + +static struct usb_descriptor_header *kburn_fs_function[] = { + (struct usb_descriptor_header *)&interface_desc, + (struct usb_descriptor_header *)&fs_ep_in, + (struct usb_descriptor_header *)&fs_ep_out, +}; + +static struct usb_descriptor_header *kburn_hs_function[] = { + (struct usb_descriptor_header *)&interface_desc, + (struct usb_descriptor_header *)&hs_ep_in, + (struct usb_descriptor_header *)&hs_ep_out, + NULL, +}; + +static const char kburn_name[] = "Canaan KBURN"; + +static struct usb_string kburn_string_defs[] = { + [0].s = kburn_name, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_kburn = { + .language = 0x0409, /* en-us */ + .strings = kburn_string_defs, +}; + +static struct usb_gadget_strings *kburn_strings[] = { + &stringtab_kburn, + NULL, +}; + +static struct kburn_usb_t *s_kburn = NULL; + +static inline struct kburn_usb_t *func_to_kburn(struct usb_function *f) +{ + return container_of(f, struct kburn_usb_t, usb_function); +} + +struct kburn_usb_t *get_kburn_usb(void) +{ + struct kburn_usb_t *kburn_usb = s_kburn; + + if (!kburn_usb) { + kburn_usb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*kburn_usb)); + if (!kburn_usb) + return NULL; + + s_kburn = kburn_usb; + memset(kburn_usb, 0, sizeof(*kburn_usb)); + } + + if (!kburn_usb->buf_head) { + kburn_usb->buf_head = memalign(CONFIG_SYS_CACHELINE_SIZE, KBURN_USB_BUFFER_SIZE); + if (!kburn_usb->buf_head) + return NULL; + + kburn_usb->buf = kburn_usb->buf_head; + memset(kburn_usb->buf_head, 0, KBURN_USB_BUFFER_SIZE); + } + + return kburn_usb; +} + +static struct usb_endpoint_descriptor *kburn_ep_desc( +struct usb_gadget *g, +struct usb_endpoint_descriptor *fs, +struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + +static int kburn_bind(struct usb_configuration *c, struct usb_function *f) +{ + int id; + struct usb_gadget *gadget = c->cdev->gadget; + struct kburn_usb_t *f_kburn = func_to_kburn(f); + + id = usb_interface_id(c, f); + if (id < 0) + return id; + interface_desc.bInterfaceNumber = id; + + id = usb_string_id(c->cdev); + if (id < 0) + return id; + + kburn_string_defs[0].id = id; + interface_desc.iInterface = id; + + usb_gadget_vbus_draw(gadget, 500); + + f_kburn->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in); + if (!f_kburn->in_ep) + return -ENODEV; + f_kburn->in_ep->driver_data = c->cdev; + + f_kburn->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out); + if (!f_kburn->out_ep) + return -ENODEV; + f_kburn->out_ep->driver_data = c->cdev; + + return 0; +} + +static void kburn_unbind(struct usb_configuration *c, struct usb_function *f) +{ + /* clear the configuration*/ + memset(s_kburn, 0, sizeof(*s_kburn)); +} + +static int kburn_handle_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct usb_gadget *gadget = f->config->cdev->gadget; + struct usb_request *req = f->config->cdev->req; + + u16 w_index = get_unaligned_le16(&ctrl->wIndex); + u16 w_value = get_unaligned_le16(&ctrl->wValue); + u16 w_length = get_unaligned_le16(&ctrl->wLength); + u8 req_type = ctrl->bRequestType & USB_TYPE_MASK; + + int value = 0; + + printf("w_index 0x%x, w_value 0x%x, w_length %d, req_type %x\n", \ + w_index, w_value, w_length, req_type); + + if (USB_TYPE_VENDOR == (req_type & USB_TYPE_VENDOR)) { + if ((0x00 == w_index) && (0x000 == w_value)) { + const char *mark = "Uboot Stage for K230"; + + strncpy(req->buf, mark, w_length); + value = strlen(mark); + } + } + + if (value >= 0) { + req->length = value; + req->zero = value < w_length; + value = usb_ep_queue(gadget->ep0, req, 0); + if (value < 0) { + debug("ep_queue --> %d\n", value); + req->status = 0; + } + } + + return value; +} + +static struct usb_request *kburn_start_ep(struct usb_ep *ep) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, 0); + if (!req) + return NULL; + + req->length = KBURN_USB_EP_BUFFER_SZIE; + req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, KBURN_USB_EP_BUFFER_SZIE); + if (!req->buf) { + usb_ep_free_request(ep, req); + return NULL; + } + memset(req->buf, 0, req->length); + + return req; +} + +static void kburn_disable(struct usb_function *f) +{ + struct kburn_usb_t *f_kburn = func_to_kburn(f); + + usb_ep_disable(f_kburn->out_ep); + usb_ep_disable(f_kburn->in_ep); + + if (f_kburn->out_req) { + free(f_kburn->out_req->buf); + usb_ep_free_request(f_kburn->out_ep, f_kburn->out_req); + f_kburn->out_req = NULL; + } + + if (f_kburn->in_req) { + free(f_kburn->in_req->buf); + usb_ep_free_request(f_kburn->in_ep, f_kburn->in_req); + f_kburn->in_req = NULL; + } + + if (f_kburn->buf_head) { + free(f_kburn->buf_head); + f_kburn->buf_head = NULL; + f_kburn->buf = NULL; + } + + if(f_kburn->burner) { + kburn_destory(f_kburn->burner); + f_kburn->burner = NULL; + } +} + +static int kburn_set_alt(struct usb_function *f, unsigned interface, unsigned alt) +{ + int ret; + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_gadget *gadget = cdev->gadget; + struct kburn_usb_t *f_kburn = func_to_kburn(f); + const struct usb_endpoint_descriptor *d; + + printf("%s: func: %s intf: %d alt: %d\n", + __func__, f->name, interface, alt); + + d = kburn_ep_desc(gadget, &fs_ep_out, &hs_ep_out); + ret = usb_ep_enable(f_kburn->out_ep, d); + if (ret) { + printf("failed to enable out ep\n"); + return ret; + } + + f_kburn->out_req = kburn_start_ep(f_kburn->out_ep); + if (!f_kburn->out_req) { + printf("failed to alloc out req\n"); + ret = -EINVAL; + goto err; + } + f_kburn->out_req->complete = rx_command_handler; + + d = kburn_ep_desc(gadget, &fs_ep_in, &hs_ep_in); + ret = usb_ep_enable(f_kburn->in_ep, d); + if (ret) { + printf("failed to enable in ep\n"); + goto err; + } + + f_kburn->in_req = kburn_start_ep(f_kburn->in_ep); + if (!f_kburn->in_req) { + printf("failed alloc req in\n"); + ret = -EINVAL; + goto err; + } + f_kburn->in_req->complete = tx_done_handler; + + ret = usb_ep_queue(f_kburn->out_ep, f_kburn->out_req, 0); + if (ret) + goto err; + + return 0; + +err: + kburn_disable(f); + + return ret; +} + +static int kburn_add(struct usb_configuration *c) +{ + int status; + + struct kburn_usb_t *kburn_usb = get_kburn_usb(); + + kburn_usb->usb_function.name = "f_kburn"; + kburn_usb->usb_function.strings = kburn_strings; + kburn_usb->usb_function.descriptors = kburn_fs_function; + kburn_usb->usb_function.hs_descriptors = kburn_hs_function; + kburn_usb->usb_function.ss_descriptors = NULL; + + kburn_usb->usb_function.bind = kburn_bind; + kburn_usb->usb_function.unbind = kburn_unbind; + kburn_usb->usb_function.set_alt = kburn_set_alt; + kburn_usb->usb_function.disable = kburn_disable; + + kburn_usb->usb_function.setup = kburn_handle_setup; + + // kburn_usb->usb_function.get_alt = kburn_get_alt; + // kburn_usb->usb_function.suspend = kburn_suspend; + // kburn_usb->usb_function.resume = kburn_resume; + + status = usb_add_function(c, &kburn_usb->usb_function); + if (status) { + free(kburn_usb->buf_head); + free(kburn_usb); + s_kburn = NULL; + } + + return status; +} + +DECLARE_GADGET_BIND_CALLBACK(usb_dnl_kburn, kburn_add); + +static void kburn_print_pkt(struct kburn_usb_pkt *pkt) +{ + printf("cmd 0x%04x, result 0x%04x, size %d, data: ", pkt->cmd, pkt->result, pkt->data_size); + for(int i = 0; i < pkt->data_size; i++) { + printf("%02x ", pkt->data[i]); + } + printf("\n"); +} + +// User can not direct call this. +static int kburn_tx_write(const char *buffer, unsigned int buffer_size) +{ + struct usb_request *in_req = s_kburn->in_req; + int ret; + + memcpy(in_req->buf, buffer, buffer_size); + in_req->length = buffer_size; + debug("Transferring 0x%x bytes\n", buffer_size); + usb_ep_dequeue(s_kburn->in_ep, in_req); + ret = usb_ep_queue(s_kburn->in_ep, in_req, 0); + if (ret) + printf("Error %d on queue\n", ret); + return 0; +} + +static int kburn_tx_result(uint16_t cmd, uint16_t result, uint8_t *data, uint8_t data_size) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct kburn_usb_pkt, csw, KBUNR_USB_PKT_SIZE); + + if(data_size > (KBUNR_USB_PKT_SIZE - sizeof(struct kburn_usb_pkt))) { + printf("tx too many data\n"); + return -1; + } + + csw->cmd = 0x8000 | cmd; + csw->result = result; + csw->data_size = data_size; + if(data_size) { + memcpy(csw->data, data, data_size); + } + + return kburn_tx_write((char *)csw, KBUNR_USB_PKT_SIZE); +} + +#define kburn_tx_string_result(c, r, d) kburn_tx_result(c, r, d, strlen(d)) + +static int kburn_tx_error_string(char *msg) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct kburn_usb_pkt, csw, KBUNR_USB_PKT_SIZE); + + int msg_len = strlen(msg); + + if(msg_len > (KBUNR_USB_PKT_SIZE - sizeof(struct kburn_usb_pkt))) { + printf("tx err msg too long\n"); + return -1; + } + + csw->cmd = 0x8000 | KBURN_CMD_NONE; + csw->result = KBURN_RESULT_ERROR_MSG; + csw->data_size = msg_len; + memcpy(csw->data, msg, msg_len); + + return kburn_tx_write((char *)csw, KBUNR_USB_PKT_SIZE); +} + +static void tx_done_handler(struct usb_ep *ep, struct usb_request *req) +{ + int status = req->status; + + if (!status) + return; + + printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual); +} + +static const struct kburn_pkt_handler_t pkt_handlers[]; + +static void rx_command_handler(struct usb_ep *ep, struct usb_request *req) +{ + void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; + + ALLOC_CACHE_ALIGN_BUFFER(struct kburn_usb_pkt, cbw, KBUNR_USB_PKT_SIZE); + char *cmdbuf = req->buf; + int i; + + if (req->status || req->length == 0) + return; + + memcpy((char *)cbw, req->buf, KBUNR_USB_PKT_SIZE); + + kburn_print_pkt(cbw); + + for (i = 0; pkt_handlers[i].cb; i++) { + if (pkt_handlers[i].cmd == cbw->cmd) { + func_cb = pkt_handlers[i].cb; + break; + } + } + + if (!func_cb) { + printf("unknown command: %s\n", (char *)req->buf); + kburn_tx_error_string("FAILunknown command"); + } else { + if (req->actual < req->length) { + u8 *buf = (u8 *)req->buf; + + buf[req->actual] = 0; + func_cb(ep, req); + } else { + puts("buffer overflow\n"); + kburn_tx_error_string("FAILbuffer overflow"); + } + } + + *cmdbuf = '\0'; + req->actual = 0; + usb_ep_queue(ep, req, 0); +} + +static void cb_probe_device(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct kburn_usb_pkt, cbw, KBUNR_USB_PKT_SIZE); + + struct kburn_usb_t *kburn_usb = get_kburn_usb(); + + uint8_t index = 0; + enum KBURN_MEDIA_TYPE type = KBURN_MEDIA_NONE; + uint64_t result[1] = {KBURN_USB_EP_BUFFER_SZIE}; + + memcpy((char *)cbw, req->buf, KBUNR_USB_PKT_SIZE); + + if(cbw->data_size != 2) { + kburn_tx_string_result(KBURN_CMD_DEV_PROBE, KBURN_RESULT_ERROR_MSG, "ERROR DATA SIZE"); + return; + } + + type = cbw->data[0]; + index = cbw->data[1]; + if(kburn_usb->burner) { + kburn_destory(kburn_usb->burner); + kburn_usb->burner = NULL; + } + kburn_usb->burner = kburn_probe_media(type); + + if (kburn_usb->burner) { + kburn_tx_result(KBURN_CMD_DEV_PROBE, KBURN_RESULT_OK, (uint8_t *)&result[0], sizeof(result)); + } else { + kburn_tx_string_result(KBURN_CMD_DEV_PROBE, KBURN_RESULT_ERROR_MSG, "PROBE FAILED"); + } +} + +static void cb_get_device_info(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct kburn_usb_pkt, cbw, KBUNR_USB_PKT_SIZE); + memcpy((char *)cbw, req->buf, KBUNR_USB_PKT_SIZE); + + struct kburn_usb_t *kburn_usb = get_kburn_usb(); + int result = -1; + + if(kburn_usb->burner) { + result = kburn_get_medium_info(kburn_usb->burner); + + kburn_tx_result(KBURN_CMD_DEV_GET_INFO, 0x00 == result ? KBURN_RESULT_OK : KBURN_RESULT_ERROR, \ + (uint8_t *)&kburn_usb->burner->medium_info, sizeof(kburn_usb->burner->medium_info)); + } else { + kburn_tx_string_result(KBURN_CMD_DEV_GET_INFO, KBURN_RESULT_ERROR_MSG, "RUNTIME ERROR"); + } +} + +static unsigned int rx_bytes_expected(struct usb_ep *ep) +{ + struct kburn_usb_t *kburn_usb = get_kburn_usb(); + u64 rx_remain = kburn_usb->dl_size - kburn_usb->dl_bytes; + u64 rem; + u64 maxpacket = ep->maxpacket; + + if (rx_remain <= 0) { + return 0; + } else if (rx_remain > KBURN_USB_EP_BUFFER_SZIE) { + return KBURN_USB_EP_BUFFER_SZIE; + } + + rem = rx_remain % maxpacket; + if (rem > 0) { + rx_remain = rx_remain + (maxpacket - rem); + } + + return (unsigned int)rx_remain; +} + +static void rx_write_lba_handler(struct usb_ep *ep, struct usb_request *req) +{ + struct kburn_usb_t *kburn_usb = get_kburn_usb(); + unsigned int transfer_size = 0; + const unsigned char *buffer = req->buf; + unsigned int buffer_size = req->actual; + + transfer_size = kburn_usb->dl_size - kburn_usb->dl_bytes; + + if (req->status != 0) { + printf("Bad status: %d\n", req->status); + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_ERROR_MSG, "ERROR STATUS"); + return; + } + + if (buffer_size < transfer_size) + transfer_size = buffer_size; + + memcpy((void *)kburn_usb->buf, buffer, transfer_size); + kburn_usb->dl_bytes += transfer_size; + + u64 xfer_size = transfer_size; + int result = kburn_write_medium(kburn_usb->burner, kburn_usb->offset, kburn_usb->buf, &xfer_size); + if((0x00 != result) || (xfer_size != transfer_size)) { + printf("write failed %d, %lld != %d\n", result, xfer_size, transfer_size); + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_ERROR_MSG, "WRITE ERROR"); + return; + } + + kburn_usb->offset += transfer_size; + + if (kburn_usb->dl_bytes >= kburn_usb->dl_size) { + req->complete = rx_command_handler; + req->length = KBURN_USB_EP_BUFFER_SZIE; + kburn_usb->buf = kburn_usb->buf_head; + + printf("write 0x%llx bytes done\n", kburn_usb->dl_size); + kburn_usb->dl_size = 0; + + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_OK, "WRITE DONE"); + } else { + req->length = rx_bytes_expected(ep); + if (kburn_usb->buf == kburn_usb->buf_head) + kburn_usb->buf = kburn_usb->buf_head + KBURN_USB_EP_BUFFER_SZIE; + else + kburn_usb->buf = kburn_usb->buf_head; + + // printf("remain %x bytes\n", req->length); + } + + req->actual = 0; + usb_ep_queue(ep, req, 0); +} + +static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct kburn_usb_pkt, cbw, KBUNR_USB_PKT_SIZE); + + struct kburn_usb_t *kburn_usb = get_kburn_usb(); + + u64 offset, size; + + memcpy((char *)cbw, req->buf, KBUNR_USB_PKT_SIZE); + + if(cbw->data_size != 16) { + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_ERROR_MSG, "ERROR DATA SIZE"); + return; + } + + offset = get_unaligned_le64(&cbw->data[0]); + size = get_unaligned_le64(&cbw->data[8]); + + if(0x01 != kburn_usb->burner->medium_info.valid) { + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_ERROR_MSG, "MEDIUM INFO INVALID"); + return; + } + + if(0x00 == size) { + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_ERROR_MSG, "DATA SIZE INVALID"); + return; + } + + if ((offset + size) > kburn_usb->burner->medium_info.capacity) { + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_ERROR_MSG, "DATA SIZE EXCEED"); + return; + } + + kburn_usb->offset = offset; + kburn_usb->dl_size = size; + kburn_usb->dl_bytes = 0; + + printf("require write %llx bytes to offset %llx\n", kburn_usb->dl_size, kburn_usb->offset); + + kburn_tx_string_result(KBURN_CMD_WRITE_LBA, KBURN_RESULT_OK, "START DL"); + + req->complete = rx_write_lba_handler; + req->length = rx_bytes_expected(ep); +} + +static void cb_erase_lba(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct kburn_usb_pkt, cbw, KBUNR_USB_PKT_SIZE); + + struct kburn_usb_t *kburn_usb = get_kburn_usb(); + + int result = -1; + uint8_t data[16]; + + u64 offset, size; + + memcpy((char *)cbw, req->buf, KBUNR_USB_PKT_SIZE); + + if(cbw->data_size != 16) { + kburn_tx_string_result(KBURN_CMD_ERASE_LBA, KBURN_RESULT_ERROR_MSG, "ERROR DATA SIZE"); + return; + } + + offset = get_unaligned_le64(&cbw->data[0]); + size = get_unaligned_le64(&cbw->data[8]); + + if(kburn_usb->burner) { + if(0x00 != size) { + result = kburn_erase_medium(kburn_usb->burner, offset, &size); + } + put_unaligned_le64(offset, &data[0]); + put_unaligned_le64(size, &data[8]); + + kburn_tx_result(KBURN_CMD_ERASE_LBA, 0x00 == result ? KBURN_RESULT_OK : KBURN_RESULT_ERROR, data, sizeof(data)); + } else { + kburn_tx_string_result(KBURN_CMD_ERASE_LBA, KBURN_RESULT_ERROR_MSG, "RUNTIME ERROR"); + } +} + +static void cb_not_support(struct usb_ep *ep, struct usb_request *req) +{ + kburn_tx_error_string("NOT SUPPORT FUNC"); +} + +static const struct kburn_pkt_handler_t pkt_handlers[] = { + { + .cmd = KBURN_CMD_NONE, + .cb = cb_not_support, + }, + { + .cmd = KBURN_CMD_MAX, + .cb = cb_not_support, + }, + { + .cmd = KBURN_CMD_DEV_PROBE, + .cb = cb_probe_device, + }, + { + .cmd = KBURN_CMD_DEV_GET_INFO, + .cb = cb_get_device_info, + }, + { + .cmd = KBURN_CMD_WRITE_LBA, + .cb = cb_write_lba, + }, + { + .cmd = KBURN_CMD_ERASE_LBA, + .cb = cb_erase_lba, + }, + { + // end of table + .cb = NULL, + } +}; diff --git a/include/kburn.h b/include/kburn.h new file mode 100644 index 00000000..e13c60d7 --- /dev/null +++ b/include/kburn.h @@ -0,0 +1,78 @@ +#ifndef __KD_BURNER_H__ +#define __KD_BURNER_H__ + +#include + +#if defined(CONFIG_KBURN_OVER_USB) && (0x00 != CONFIG_KBURN_OVER_USB) + +#define KBURN_USB_INTF_CLASS (0xFF) +#define KBURN_USB_INTF_SUBCLASS (0x02) +#define KBURN_USB_INTF_PROTOCOL (0x00) + +#define KBURN_USB_EP_BUFFER_SZIE (512 * 1024) +#define KBURN_USB_BUFFER_SIZE (KBURN_USB_EP_BUFFER_SZIE * 2) + +#endif + +enum KBURN_MEDIA_TYPE { + KBURN_MEDIA_NONE = 0x00, + KBURN_MEDIA_eMMC = 0x01, + KBURN_MEDIA_SDCARD = 0x02, // SD Card is eMMC too. + KBURN_MEDIA_SPI_NAND = 0x03, + KBURN_MEDIA_SPI_NOR = 0x04, + KBURN_MEDIA_OTP = 0x05, +}; + +struct kburn_medium_info { + u64 capacity; + u64 blk_size; + u64 erase_size; + u64 timeout_ms:32; + u64 wp:8; + u64 type:7; + u64 valid:1; +}; + +struct kburn { + enum KBURN_MEDIA_TYPE type; + struct kburn_medium_info medium_info; + void *dev_priv; + + int (*get_medium_info)(struct kburn *burn); + + int (*read_medium)(struct kburn *burn, + u64 offset, void *buf, u64 *len); + + int (*write_medium)(struct kburn *burn, + u64 offset, const void *buf, u64 *len); + + int (*erase_medium)(struct kburn *burn, u64 offset, u64 *len); + + int (*destory)(struct kburn *burn); +}; + +struct kburn * kburn_probe_media(enum KBURN_MEDIA_TYPE type); + +int kburn_get_medium_info(struct kburn *burn); + +int kburn_read_medium(struct kburn *burn, u64 offset, void *buf, u64 *len); + +int kburn_write_medium(struct kburn *burn, u64 offset, const void *buf, u64 *len); + +int kburn_erase_medium(struct kburn *burn, u64 offset, u64 *len); + +void kburn_destory(struct kburn *burn); + +#if defined (CONFIG_KBURN_MMC) +struct kburn *kburn_mmc_probe(uint8_t index); +#endif // CONFIG_KBURN_MMC + +#if defined (CONFIG_KBURN_SF) +struct kburn *kburn_sf_probe(void); +#endif // CONFIG_KBURN_SF + +#if defined (CONFIG_KBURN_MTD) +struct kburn *kburn_mtd_probe(void); +#endif // CONFIG_KBURN_MTD + +#endif // __KD_BURNER_H__