Merge branch 'master' of git://git.denx.de/u-boot-usb

- Mostly DFU fixes and r8152 fixes
This commit is contained in:
Tom Rini 2020-09-03 09:48:28 -04:00
commit 9bfb567e5f
39 changed files with 1867 additions and 101 deletions

View file

@ -187,6 +187,12 @@ int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
return 0;
}
#define SDPV_BCD_DEVICE 0x500
int g_dnl_get_board_bcd_device_number(int gcnum)
{
return SDPV_BCD_DEVICE;
}
#endif
#if defined(CONFIG_SPL_MMC_SUPPORT)

View file

@ -5,6 +5,7 @@
#include <common.h>
#include <cpu_func.h>
#include <fastboot.h>
#include <init.h>
#include <net.h>
#include <asm/arch/boot.h>
@ -153,8 +154,11 @@ int board_late_init(void)
#if CONFIG_IS_ENABLED(FASTBOOT)
static unsigned int reboot_reason = REBOOT_REASON_NORMAL;
int fastboot_set_reboot_flag()
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER)
return -ENOTSUPP;
reboot_reason = REBOOT_REASON_BOOTLOADER;
printf("Using reboot reason: 0x%x\n", reboot_reason);

View file

@ -6,6 +6,7 @@
#include <clk.h>
#include <cpu_func.h>
#include <dm.h>
#include <fastboot.h>
#include <init.h>
#include <log.h>
#include <ram.h>
@ -152,8 +153,11 @@ int board_usb_init(int index, enum usb_init_type init)
#endif /* CONFIG_USB_GADGET */
#if CONFIG_IS_ENABLED(FASTBOOT)
int fastboot_set_reboot_flag(void)
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER)
return -ENOTSUPP;
printf("Setting reboot to fastboot flag ...\n");
/* Set boot mode to fastboot */
writel(BOOT_FASTBOOT, CONFIG_ROCKCHIP_BOOT_MODE_REG);

View file

@ -8,6 +8,7 @@
#include <config.h>
#include <common.h>
#include <env.h>
#include <fastboot.h>
#include <init.h>
#include <linux/ctype.h>
#include <linux/usb/musb.h>
@ -163,8 +164,11 @@ void get_board_serial(struct tag_serialnr *serialnr)
omap_die_id_get_board_serial(serialnr);
}
int fastboot_set_reboot_flag(void)
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER)
return -ENOTSUPP;
return omap_reboot_mode_store("b");
}

View file

@ -9,6 +9,7 @@
#include <common.h>
#include <dm.h>
#include <env.h>
#include <fastboot.h>
#include <init.h>
#include <linux/ctype.h>
#include <linux/usb/musb.h>
@ -175,8 +176,11 @@ void reset_misc(void)
omap_reboot_mode_store(reboot_mode);
}
int fastboot_set_reboot_flag(void)
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER)
return -ENOTSUPP;
return omap_reboot_mode_store("b");
}

View file

@ -9,6 +9,7 @@
#include <common.h>
#include <env.h>
#include <fastboot.h>
#include <fdt_support.h>
#include <image.h>
#include <init.h>
@ -1172,8 +1173,11 @@ int board_fit_config_name_match(const char *name)
#endif
#if CONFIG_IS_ENABLED(FASTBOOT) && !CONFIG_IS_ENABLED(ENV_IS_NOWHERE)
int fastboot_set_reboot_flag(void)
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER)
return -ENOTSUPP;
printf("Setting reboot to fastboot flag ...\n");
env_set("dofastboot", "1");
env_save();

View file

@ -12,6 +12,7 @@
#include <common.h>
#include <env.h>
#include <fdt_support.h>
#include <fastboot.h>
#include <image.h>
#include <init.h>
#include <spl.h>
@ -1050,8 +1051,11 @@ int board_fit_config_name_match(const char *name)
#endif
#if CONFIG_IS_ENABLED(FASTBOOT) && !CONFIG_IS_ENABLED(ENV_IS_NOWHERE)
int fastboot_set_reboot_flag(void)
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER)
return -ENOTSUPP;
printf("Setting reboot to fastboot flag ...\n");
env_set("dofastboot", "1");
env_save();

View file

@ -170,7 +170,7 @@ static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag,
goto cleanup_ums_init;
}
rc = fsg_init(ums, ums_count);
rc = fsg_init(ums, ums_count, controller_index);
if (rc) {
pr_err("fsg_init failed\n");
rc = CMD_RET_FAILURE;

View file

@ -19,6 +19,8 @@ static int spl_sdp_load_image(struct spl_image_info *spl_image,
usb_gadget_initialize(controller_index);
board_usb_init(0, USB_INIT_DEVICE);
g_dnl_clear_detach();
ret = g_dnl_register("usb_dnl_sdp");
if (ret) {

View file

@ -24,6 +24,7 @@
#include <net.h>
#include <net/tftp.h>
#include <malloc.h>
#include <mapmem.h>
#include <dfu.h>
#include <errno.h>
#include <mtd/cfi_flash.h>
@ -280,7 +281,7 @@ int update_tftp(ulong addr, char *interface, char *devstring)
}
got_update_file:
fit = (void *)addr;
fit = map_sysmem(addr, 0);
if (!fit_check_format((void *)fit)) {
printf("Bad FIT format of the update file, aborting "
@ -309,8 +310,7 @@ got_update_file:
printf("\n");
if (update_fit_getparams(fit, noffset, &update_addr,
&update_fladdr, &update_size)) {
printf("Error: can't get update parameteres, "
"aborting\n");
printf("Error: can't get update parameters, aborting\n");
ret = 1;
goto next_node;
}

View file

@ -10,25 +10,34 @@ CONFIG_FIT_SIGNATURE=y
CONFIG_FIT_VERBOSE=y
CONFIG_FIT_BEST_MATCH=y
CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_USE_PREBOOT=y
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_PCI_INIT_R=y
CONFIG_CMD_BOOTEFI_SELFTEST=y
CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_DFU=y
CONFIG_CMD_MTD=y
CONFIG_CMD_PCI=y
CONFIG_CMD_USB=y
CONFIG_CMD_MTDPARTS=y
CONFIG_OF_BOARD=y
CONFIG_ENV_IS_IN_FLASH=y
CONFIG_ENV_ADDR=0x4000000
CONFIG_SCSI_AHCI=y
CONFIG_AHCI_PCI=y
CONFIG_BLK=y
CONFIG_DFU_TFTP=y
CONFIG_DFU_RAM=y
CONFIG_DFU_MTD=y
# CONFIG_MMC is not set
CONFIG_MTD=y
CONFIG_DM_MTD=y
CONFIG_MTD_NOR_FLASH=y
CONFIG_FLASH_CFI_DRIVER=y
CONFIG_CFI_FLASH=y
CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
CONFIG_FLASH_CFI_MTD=y
CONFIG_SYS_FLASH_CFI=y
CONFIG_DM_ETH=y
CONFIG_E1000=y

View file

@ -13,25 +13,34 @@ CONFIG_FIT_SIGNATURE=y
CONFIG_FIT_VERBOSE=y
CONFIG_FIT_BEST_MATCH=y
CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_USE_PREBOOT=y
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_PCI_INIT_R=y
CONFIG_CMD_BOOTEFI_SELFTEST=y
CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_DFU=y
CONFIG_CMD_MTD=y
CONFIG_CMD_PCI=y
CONFIG_CMD_USB=y
CONFIG_CMD_MTDPARTS=y
CONFIG_OF_BOARD=y
CONFIG_ENV_IS_IN_FLASH=y
CONFIG_ENV_ADDR=0x4000000
CONFIG_SCSI_AHCI=y
CONFIG_AHCI_PCI=y
CONFIG_BLK=y
CONFIG_DFU_TFTP=y
CONFIG_DFU_RAM=y
CONFIG_DFU_MTD=y
# CONFIG_MMC is not set
CONFIG_MTD=y
CONFIG_DM_MTD=y
CONFIG_MTD_NOR_FLASH=y
CONFIG_FLASH_CFI_DRIVER=y
CONFIG_CFI_FLASH=y
CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
CONFIG_FLASH_CFI_MTD=y
CONFIG_SYS_FLASH_CFI=y
CONFIG_DM_ETH=y
CONFIG_E1000=y

View file

@ -85,6 +85,25 @@ for example::
fastboot_partition_alias_boot=LNX
Raw partition descriptors
^^^^^^^^^^^^^^^^^^^^^^^^^
In cases where no partition table is present, a raw partition descriptor can be
defined, specifying the offset, size, and optionally the MMC hardware partition
number for a given partition name.
This is useful when using fastboot to flash files (e.g. SPL or U-Boot) to a
specific offset in the eMMC boot partition, without having to update the entire
boot partition.
To define a raw partition descriptor, add an environment variable similar to::
fastboot_raw_partition_<raw partition name>=<offset> <size> [mmcpart <num>]
for example::
fastboot_raw_partition_boot=0x100 0x1f00 mmcpart 1
Variable overrides
^^^^^^^^^^^^^^^^^^

View file

@ -71,6 +71,7 @@ config DFU_SF_PART
config DFU_MTD
bool "MTD back end for DFU"
depends on DM_MTD
depends on CMD_MTDPARTS
help
This option enables using DFU to read and write to on any MTD device.

View file

@ -10,6 +10,7 @@
#include <common.h>
#include <malloc.h>
#include <mapmem.h>
#include <errno.h>
#include <dfu.h>
@ -27,9 +28,9 @@ static int dfu_transfer_medium_ram(enum dfu_op op, struct dfu_entity *dfu,
}
if (op == DFU_OP_WRITE)
memcpy(dfu->data.ram.start + offset, buf, *len);
memcpy(map_sysmem(dfu->data.ram.start + offset, 0), buf, *len);
else
memcpy(buf, dfu->data.ram.start + offset, *len);
memcpy(buf, map_sysmem(dfu->data.ram.start + offset, 0), *len);
return 0;
}
@ -73,7 +74,7 @@ int dfu_fill_entity_ram(struct dfu_entity *dfu, char *devstr, char *s)
}
dfu->layout = DFU_RAM_ADDR;
dfu->data.ram.start = (void *)simple_strtoul(argv[1], NULL, 16);
dfu->data.ram.start = simple_strtoul(argv[1], NULL, 16);
dfu->data.ram.size = simple_strtoul(argv[2], NULL, 16);
dfu->write_medium = dfu_write_medium_ram;

View file

@ -165,6 +165,18 @@ config FASTBOOT_CMD_OEM_FORMAT
relies on the env variable partitions to contain the list of
partitions as required by the gpt command.
config FASTBOOT_USE_BCB_SET_REBOOT_FLAG
bool "Use BCB by fastboot to set boot reason"
depends on CMD_BCB && !ARCH_MESON && !ARCH_ROCKCHIP && !TARGET_KC1 && \
!TARGET_SNIPER && !TARGET_AM57XX_EVM && !TARGET_DRA7XX_EVM
default y
help
Fastboot could implement setting of reboot reason in a generic fashion
via BCB commands. BCB commands are able to write reboot reason into
command field of boot control block. In general case it is sufficient
implementation if your platform supports BCB commands and doesn't
require any specific reboot reason handling.
endif # FASTBOOT
endmenu

View file

@ -5,3 +5,4 @@ obj-y += fb_getvar.o
obj-y += fb_command.o
obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o
obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
obj-$(CONFIG_FASTBOOT_USE_BCB_SET_REBOOT_FLAG) += fb_bcb_impl.o

View file

@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2020 GlobalLogic.
* Roman Kovalivskyi <roman.kovalivskyi@globallogic.com>
*/
#include <common.h>
#include <fastboot.h>
/**
* fastboot_set_reboot_flag() - Set flag to indicate reboot-bootloader
*
* Set flag which indicates that we should reboot into the bootloader
* following the reboot that fastboot executes after this function.
*
* This function should be overridden in your board file with one
* which sets whatever flag your board specific Android bootloader flow
* requires in order to re-enter the bootloader.
*/
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
char cmd[64];
if (reason >= FASTBOOT_REBOOT_REASONS_COUNT)
return -EINVAL;
snprintf(cmd, sizeof(cmd), "bcb load %d misc",
CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (run_command(cmd, 0))
return -ENODEV;
snprintf(cmd, sizeof(cmd), "bcb set command %s",
fastboot_boot_cmds[reason]);
if (run_command(cmd, 0))
return -ENOEXEC;
if (run_command("bcb store", 0))
return -EIO;
return 0;
}

View file

@ -37,6 +37,8 @@ static void flash(char *, char *);
static void erase(char *, char *);
#endif
static void reboot_bootloader(char *, char *);
static void reboot_fastbootd(char *, char *);
static void reboot_recovery(char *, char *);
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
static void oem_format(char *, char *);
#endif
@ -79,6 +81,14 @@ static const struct {
.command = "reboot-bootloader",
.dispatch = reboot_bootloader
},
[FASTBOOT_COMMAND_REBOOT_FASTBOOTD] = {
.command = "reboot-fastboot",
.dispatch = reboot_fastbootd
},
[FASTBOOT_COMMAND_REBOOT_RECOVERY] = {
.command = "reboot-recovery",
.dispatch = reboot_recovery
},
[FASTBOOT_COMMAND_SET_ACTIVE] = {
.command = "set_active",
.dispatch = okay
@ -307,12 +317,40 @@ static void erase(char *cmd_parameter, char *response)
*/
static void reboot_bootloader(char *cmd_parameter, char *response)
{
if (fastboot_set_reboot_flag())
if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
fastboot_fail("Cannot set reboot flag", response);
else
fastboot_okay(NULL, response);
}
/**
* reboot_fastbootd() - Sets reboot fastboot flag.
*
* @cmd_parameter: Pointer to command parameter
* @response: Pointer to fastboot response buffer
*/
static void reboot_fastbootd(char *cmd_parameter, char *response)
{
if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
fastboot_fail("Cannot set fastboot flag", response);
else
fastboot_okay(NULL, response);
}
/**
* reboot_recovery() - Sets reboot recovery flag.
*
* @cmd_parameter: Pointer to command parameter
* @response: Pointer to fastboot response buffer
*/
static void reboot_recovery(char *cmd_parameter, char *response)
{
if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
fastboot_fail("Cannot set recovery flag", response);
else
fastboot_okay(NULL, response);
}
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
/**
* oem_format() - Execute the OEM format command

View file

@ -88,7 +88,7 @@ void fastboot_okay(const char *reason, char *response)
* which sets whatever flag your board specific Android bootloader flow
* requires in order to re-enter the bootloader.
*/
int __weak fastboot_set_reboot_flag(void)
int __weak fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
return -ENOSYS;
}

View file

@ -95,7 +95,7 @@ static const struct {
*
* @param[in] part_name Info for which partition name to look for
* @param[in,out] response Pointer to fastboot response buffer
* @param[out] size If not NULL, will contain partition size (in blocks)
* @param[out] size If not NULL, will contain partition size
* @return Partition number or negative value on error
*/
static int getvar_get_part_info(const char *part_name, char *response,
@ -109,7 +109,7 @@ static int getvar_get_part_info(const char *part_name, char *response,
r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
response);
if (r >= 0 && size)
*size = part_info.size;
*size = part_info.size * part_info.blksz;
# elif CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
struct part_info *part_info;

View file

@ -50,6 +50,48 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc,
return ret;
}
static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
const char *name, struct disk_partition *info, int *mmcpart)
{
/* strlen("fastboot_raw_partition_") + PART_NAME_LEN + 1 */
char env_desc_name[23 + PART_NAME_LEN + 1];
char *raw_part_desc;
const char *argv[2];
const char **parg = argv;
/* check for raw partition descriptor */
strcpy(env_desc_name, "fastboot_raw_partition_");
strncat(env_desc_name, name, PART_NAME_LEN);
raw_part_desc = strdup(env_get(env_desc_name));
if (raw_part_desc == NULL)
return -ENODEV;
/*
* parse partition descriptor
*
* <lba_start> <lba_size> [mmcpart <num>]
*/
for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) {
*parg = strsep(&raw_part_desc, " ");
if (*parg == NULL) {
pr_err("Invalid number of arguments.\n");
return -ENODEV;
}
}
info->start = simple_strtoul(argv[0], NULL, 0);
info->size = simple_strtoul(argv[1], NULL, 0);
info->blksz = dev_desc->blksz;
strncpy((char *)info->name, name, PART_NAME_LEN);
if (raw_part_desc) {
if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0)
*mmcpart = simple_strtoul(raw_part_desc, NULL, 0);
}
return 0;
}
/**
* fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE
*
@ -376,7 +418,8 @@ int fastboot_mmc_get_part_info(const char *part_name,
struct blk_desc **dev_desc,
struct disk_partition *part_info, char *response)
{
int r;
int r = 0;
int mmcpart;
*dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!*dev_desc) {
@ -388,11 +431,13 @@ int fastboot_mmc_get_part_info(const char *part_name,
return -ENOENT;
}
if (raw_part_get_info_by_name(*dev_desc, part_name, part_info, &mmcpart) < 0) {
r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info);
if (r < 0) {
fastboot_fail("partition not found", response);
return r;
}
}
return r;
}
@ -410,6 +455,7 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
{
struct blk_desc *dev_desc;
struct disk_partition info;
int mmcpart = 0;
dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
@ -482,7 +528,13 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
}
#endif
if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) {
if (blk_dselect_hwpart(dev_desc, mmcpart)) {
pr_err("Failed to select hwpart\n");
fastboot_fail("Failed to select hwpart", response);
return;
}
} else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
pr_err("cannot find partition: '%s'\n", cmd);
fastboot_fail("cannot find partition", response);
return;
@ -524,11 +576,11 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
*/
void fastboot_mmc_erase(const char *cmd, char *response)
{
int ret;
struct blk_desc *dev_desc;
struct disk_partition info;
lbaint_t blks, blks_start, blks_size, grp_size;
struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
int mmcpart = 0;
if (mmc == NULL) {
pr_err("invalid mmc device\n");
@ -562,8 +614,13 @@ void fastboot_mmc_erase(const char *cmd, char *response)
}
#endif
ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info);
if (ret < 0) {
if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) {
if (blk_dselect_hwpart(dev_desc, mmcpart)) {
pr_err("Failed to select hwpart\n");
fastboot_fail("Failed to select hwpart", response);
return;
}
} else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
pr_err("cannot find partition: '%s'\n", cmd);
fastboot_fail("cannot find partition", response);
return;

View file

@ -68,6 +68,8 @@ static const struct r8152_version r8152_versions[] = {
{ 0x5c20, RTL_VER_05, 1 },
{ 0x5c30, RTL_VER_06, 1 },
{ 0x4800, RTL_VER_07, 0 },
{ 0x6000, RTL_VER_08, 1 },
{ 0x6010, RTL_VER_09, 1 },
};
static
@ -331,6 +333,12 @@ void sram_write(struct r8152 *tp, u16 addr, u16 data)
ocp_reg_write(tp, OCP_SRAM_DATA, data);
}
static u16 sram_read(struct r8152 *tp, u16 addr)
{
ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
return ocp_reg_read(tp, OCP_SRAM_DATA);
}
int r8152_wait_for_bit(struct r8152 *tp, bool ocp_reg, u16 type, u16 index,
const u32 mask, bool set, unsigned int timeout)
{
@ -467,12 +475,56 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp)
{
u32 ocp_data = tp->coalesce / 8;
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, ocp_data);
switch (tp->version) {
case RTL_VER_03:
case RTL_VER_04:
case RTL_VER_05:
case RTL_VER_06:
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
ocp_data);
break;
case RTL_VER_08:
case RTL_VER_09:
/* The RTL8153B uses USB_RX_EXTRA_AGGR_TMR for rx timeout
* primarily. For USB_RX_EARLY_TIMEOUT, we fix it to 1264ns.
*/
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
RX_AUXILIARY_TIMER / 8);
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR,
ocp_data);
break;
default:
debug("** %s Invalid Device\n", __func__);
break;
}
}
static void r8153_set_rx_early_size(struct r8152 *tp)
{
u32 ocp_data = (RTL8152_AGG_BUF_SZ - RTL8153_RMS) / 4;
u32 ocp_data = (RTL8152_AGG_BUF_SZ - RTL8153_RMS -
sizeof(struct rx_desc));
switch (tp->version) {
case RTL_VER_03:
case RTL_VER_04:
case RTL_VER_05:
case RTL_VER_06:
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
ocp_data / 4);
break;
case RTL_VER_08:
case RTL_VER_09:
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
ocp_data / 8);
break;
default:
debug("** %s Invalid Device\n", __func__);
break;
}
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data);
}
@ -540,6 +592,19 @@ static void r8153_u1u2en(struct r8152 *tp, bool enable)
usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
}
static void r8153b_u1u2en(struct r8152 *tp, bool enable)
{
u16 ocp_data;
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG);
if (enable)
ocp_data |= LPM_U1U2_EN;
else
ocp_data &= ~LPM_U1U2_EN;
ocp_write_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG, ocp_data);
}
static void r8153_u2p3en(struct r8152 *tp, bool enable)
{
u32 ocp_data;
@ -568,6 +633,17 @@ static void r8153_power_cut_en(struct r8152 *tp, bool enable)
ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
}
static void rtl_reset_bmu(struct r8152 *tp)
{
u8 ocp_data;
ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_BMU_RESET);
ocp_data &= ~(BMU_RESET_EP_IN | BMU_RESET_EP_OUT);
ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
ocp_data |= BMU_RESET_EP_IN | BMU_RESET_EP_OUT;
ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
}
static int r8152_read_mac(struct r8152 *tp, unsigned char *macaddr)
{
int ret;
@ -773,6 +849,71 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
sram_write(tp, SRAM_10M_AMP2, 0x0208);
}
static u32 r8152_efuse_read(struct r8152 *tp, u8 addr)
{
u32 ocp_data;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD, EFUSE_READ_CMD | addr);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD);
ocp_data = (ocp_data & EFUSE_DATA_BIT16) << 9; /* data of bit16 */
ocp_data |= ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_DATA);
return ocp_data;
}
static void r8153b_hw_phy_cfg(struct r8152 *tp)
{
u32 ocp_data;
u16 data;
data = r8152_mdio_read(tp, MII_BMCR);
if (data & BMCR_PDOWN) {
data &= ~BMCR_PDOWN;
r8152_mdio_write(tp, MII_BMCR, data);
}
/* U1/U2/L1 idle timer. 500 us */
ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
r8153b_firmware(tp);
data = sram_read(tp, SRAM_GREEN_CFG);
data |= R_TUNE_EN;
sram_write(tp, SRAM_GREEN_CFG, data);
data = ocp_reg_read(tp, OCP_NCTL_CFG);
data |= PGA_RETURN_EN;
ocp_reg_write(tp, OCP_NCTL_CFG, data);
/* ADC Bias Calibration:
* read efuse offset 0x7d to get a 17-bit data. Remove the dummy/fake
* bit (bit3) to rebuild the real 16-bit data. Write the data to the
* ADC ioffset.
*/
ocp_data = r8152_efuse_read(tp, 0x7d);
ocp_data = ((ocp_data & 0x1fff0) >> 1) | (ocp_data & 0x7);
if (ocp_data != 0xffff)
ocp_reg_write(tp, OCP_ADC_IOFFSET, ocp_data);
/* ups mode tx-link-pulse timing adjustment:
* rg_saw_cnt = OCP reg 0xC426 Bit[13:0]
* swr_cnt_1ms_ini = 16000000 / rg_saw_cnt
*/
ocp_data = ocp_reg_read(tp, 0xc426);
ocp_data &= 0x3fff;
if (ocp_data) {
u32 swr_cnt_1ms_ini;
swr_cnt_1ms_ini = (16000000 / ocp_data) & SAW_CNT_1MS_MASK;
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG);
ocp_data = (ocp_data & ~SAW_CNT_1MS_MASK) | swr_cnt_1ms_ini;
ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CFG, ocp_data);
}
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
ocp_data |= PFM_PWM_SWITCH;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
}
static void r8153_first_init(struct r8152 *tp)
{
u32 ocp_data;
@ -786,6 +927,7 @@ static void r8153_first_init(struct r8152 *tp)
r8153_hw_phy_cfg(tp);
rtl8152_nic_reset(tp);
rtl_reset_bmu(tp);
ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
ocp_data &= ~NOW_IS_OOB;
@ -832,6 +974,7 @@ static void r8153_enter_oob(struct r8152 *tp)
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
rtl_disable(tp);
rtl_reset_bmu(tp);
rtl8152_reinit_ll(tp);
@ -873,6 +1016,7 @@ static void rtl8153_disable(struct r8152 *tp)
{
r8153_disable_aldps(tp);
rtl_disable(tp);
rtl_reset_bmu(tp);
}
static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
@ -933,7 +1077,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
return -EINVAL;
}
bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
}
if (tp->supports_gmii)
@ -977,6 +1121,16 @@ static void rtl8153_down(struct r8152 *tp)
r8153_enter_oob(tp);
}
static void rtl8153b_up(struct r8152 *tp)
{
r8153_first_init(tp);
}
static void rtl8153b_down(struct r8152 *tp)
{
r8153_enter_oob(tp);
}
static void r8152b_get_version(struct r8152 *tp)
{
u32 ocp_data;
@ -1140,6 +1294,60 @@ static void r8153_init(struct r8152 *tp)
rtl_tally_reset(tp);
}
static void r8153b_init(struct r8152 *tp)
{
u32 ocp_data;
int i;
r8153_disable_aldps(tp);
r8153b_u1u2en(tp, false);
r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_BOOT_CTRL,
AUTOLOAD_DONE, 1, R8152_WAIT_TIMEOUT);
for (i = 0; i < R8152_WAIT_TIMEOUT; i++) {
ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK;
if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN)
break;
mdelay(1);
}
r8153_u2p3en(tp, false);
/* MSC timer = 0xfff * 8ms = 32760 ms */
ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
r8153_power_cut_en(tp, false);
/* MAC clock speed down */
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2);
ocp_data |= MAC_CLK_SPDWN_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3);
ocp_data &= ~PLA_MCU_SPDWN_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, ocp_data);
if (tp->version == RTL_VER_09) {
/* Disable Test IO for 32QFN */
if (ocp_read_byte(tp, MCU_TYPE_PLA, 0xdc00) & BIT(5)) {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
ocp_data |= TEST_IO_OFF;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
}
}
/* rx aggregation */
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
rtl_tally_reset(tp);
r8153b_hw_phy_cfg(tp);
r8152b_enable_fc(tp);
}
static void rtl8152_unload(struct r8152 *tp)
{
if (tp->version != RTL_VER_01)
@ -1180,6 +1388,15 @@ static int rtl_ops_init(struct r8152 *tp)
ops->unload = rtl8153_unload;
break;
case RTL_VER_08:
case RTL_VER_09:
ops->init = r8153b_init;
ops->enable = rtl8153_enable;
ops->disable = rtl8153_disable;
ops->up = rtl8153b_up;
ops->down = rtl8153b_down;
break;
default:
ret = -ENODEV;
printf("r8152 Unknown Device\n");

View file

@ -26,6 +26,8 @@
#define PLA_TEREDO_TIMER 0xd2cc
#define PLA_REALWOW_TIMER 0xd2e8
#define PLA_EXTRA_STATUS 0xd398
#define PLA_EFUSE_DATA 0xdd00
#define PLA_EFUSE_CMD 0xdd02
#define PLA_LEDSEL 0xdd90
#define PLA_LED_FEATURE 0xdd92
#define PLA_PHYAR 0xde00
@ -76,8 +78,10 @@
#define USB_CSR_DUMMY2 0xb466
#define USB_DEV_STAT 0xb808
#define USB_CONNECT_TIMER 0xcbf8
#define USB_MSC_TIMER 0xcbfc
#define USB_BURST_SIZE 0xcfc0
#define USB_FW_FIX_EN1 0xcfcc
#define USB_LPM_CONFIG 0xcfd8
#define USB_USB_CTRL 0xd406
#define USB_PHY_CTRL 0xd408
#define USB_TX_AGG 0xd40a
@ -85,25 +89,23 @@
#define USB_USB_TIMER 0xd428
#define USB_RX_EARLY_TIMEOUT 0xd42c
#define USB_RX_EARLY_SIZE 0xd42e
#define USB_PM_CTRL_STATUS 0xd432
#define USB_PM_CTRL_STATUS 0xd432 /* RTL8153A */
#define USB_RX_EXTRA_AGGR_TMR 0xd432 /* RTL8153B */
#define USB_TX_DMA 0xd434
#define USB_TOLERANCE 0xd490
#define USB_LPM_CTRL 0xd41a
#define USB_BMU_RESET 0xd4b0
#define USB_U1U2_TIMER 0xd4da
#define USB_UPS_CTRL 0xd800
#define USB_MISC_0 0xd81a
#define USB_POWER_CUT 0xd80a
#define USB_MISC_0 0xd81a
#define USB_AFE_CTRL2 0xd824
#define USB_UPS_CFG 0xd842
#define USB_WDT11_CTRL 0xe43c
#define USB_BP_BA 0xfc26
#define USB_BP_0 0xfc28
#define USB_BP_1 0xfc2a
#define USB_BP_2 0xfc2c
#define USB_BP_3 0xfc2e
#define USB_BP_4 0xfc30
#define USB_BP_5 0xfc32
#define USB_BP_6 0xfc34
#define USB_BP_7 0xfc36
#define USB_BP_EN 0xfc38
#define USB_BP_BA PLA_BP_BA
#define USB_BP(n) (0xfc28 + 2 * (n))
#define USB_BP_EN PLA_BP_EN /* RTL8153A */
#define USB_BP2_EN 0xfc48
/* OCP Registers */
#define OCP_ALDPS_CONFIG 0x2010
@ -114,6 +116,7 @@
#define OCP_EEE_AR 0xa41a
#define OCP_EEE_DATA 0xa41c
#define OCP_PHY_STATUS 0xa420
#define OCP_NCTL_CFG 0xa42c
#define OCP_POWER_CFG 0xa430
#define OCP_EEE_CFG 0xa432
#define OCP_SRAM_ADDR 0xa436
@ -123,9 +126,11 @@
#define OCP_EEE_ADV 0xa5d0
#define OCP_EEE_LPABLE 0xa5d2
#define OCP_PHY_STATE 0xa708 /* nway state for 8153 */
#define OCP_ADC_IOFFSET 0xbcfc
#define OCP_ADC_CFG 0xbc06
/* SRAM Register */
#define SRAM_GREEN_CFG 0x8011
#define SRAM_LPF_CFG 0x8012
#define SRAM_10M_AMP1 0x8080
#define SRAM_10M_AMP2 0x8082
@ -207,6 +212,7 @@
/* PLA_PHY_PWR */
#define PLA_PHY_PWR_LLR (LINK_LIST_READY << 24)
#define PLA_PHY_PWR_TXEMP (TXFIFO_EMPTY << 24)
#define TEST_IO_OFF BIT(4)
/* PLA_MISC_1 */
#define RXDY_GATED_EN 0x0008
@ -230,6 +236,10 @@
/* PLA_BDC_CR */
#define ALDPS_PROXY_MODE 0x0001
/* PLA_EFUSE_CMD */
#define EFUSE_READ_CMD BIT(15)
#define EFUSE_DATA_BIT16 BIT(7)
/* PLA_CONFIG34 */
#define LINK_ON_WAKE_EN 0x0010
#define LINK_OFF_WAKE_EN 0x0008
@ -255,8 +265,10 @@
/* PLA_MAC_PWR_CTRL2 */
#define EEE_SPDWN_RATIO 0x8007
#define MAC_CLK_SPDWN_EN BIT(15)
/* PLA_MAC_PWR_CTRL3 */
#define PLA_MCU_SPDWN_EN BIT(14)
#define PKT_AVAIL_SPDWN_EN 0x0100
#define SUSPEND_SPDWN_EN 0x0004
#define U1U2_SPDWN_EN 0x0002
@ -312,6 +324,9 @@
/* USB_FW_FIX_EN1 */
#define FW_IP_RESET_EN BIT(9)
/* USB_LPM_CONFIG */
#define LPM_U1U2_EN BIT(0)
/* USB_TX_AGG */
#define TX_AGG_MAX_THRESHOLD 0x03
@ -320,10 +335,17 @@
#define RX_THR_HIGH 0x7a120180
#define RX_THR_SLOW 0xffff0180
/* USB_RX_EARLY_TIMEOUT */
#define RX_AUXILIARY_TIMER 1264
/* USB_TX_DMA */
#define TEST_MODE_DISABLE 0x00000001
#define TX_SIZE_ADJUST1 0x00000100
/* USB_BMU_RESET */
#define BMU_RESET_EP_IN 0x01
#define BMU_RESET_EP_OUT 0x02
/* USB_UPS_CTRL */
#define POWER_CUT 0x0100
@ -366,6 +388,9 @@
#define SEN_VAL_NORMAL 0xa000
#define SEL_RXIDLE 0x0100
/* USB_UPS_CFG */
#define SAW_CNT_1MS_MASK 0x0fff
/* OCP_ALDPS_CONFIG */
#define ENPWRSAVE 0x8000
#define ENPDNPS 0x0200
@ -377,6 +402,9 @@
#define PHY_STAT_LAN_ON 3
#define PHY_STAT_PWRDN 5
/* OCP_NCTL_CFG */
#define PGA_RETURN_EN BIT(1)
/* OCP_POWER_CFG */
#define EEE_CLKDIV_EN 0x8000
#define EN_ALDPS 0x0004
@ -429,6 +457,10 @@
#define ADC_EN 0x0080
#define EN_EMI_L 0x0040
/* SRAM_GREEN_CFG */
#define GREEN_ETH_EN BIT(15)
#define R_TUNE_EN BIT(11)
/* SRAM_LPF_CFG */
#define LPF_AUTO_TUNE 0x8000
@ -573,6 +605,8 @@ enum rtl_version {
RTL_VER_05,
RTL_VER_06,
RTL_VER_07,
RTL_VER_08,
RTL_VER_09,
RTL_VER_MAX
};
@ -640,4 +674,5 @@ int r8152_wait_for_bit(struct r8152 *tp, bool ocp_reg, u16 type, u16 index,
void r8152b_firmware(struct r8152 *tp);
void r8153_firmware(struct r8152 *tp);
void r8153b_firmware(struct r8152 *tp);
#endif

View file

@ -729,28 +729,161 @@ static u16 r8153_pla_patch_d_bp[] = {
0xfc2e, 0x0000, 0xfc30, 0x0000, 0xfc32, 0x0000, 0xfc34, 0x0000,
0xfc36, 0x0000, 0xfc38, 0x0007 };
static void rtl_clear_bp(struct r8152 *tp)
static u8 usb_patch2_b[] = {
0x10, 0xe0, 0x26, 0xe0, 0x3a, 0xe0, 0x58, 0xe0,
0x6c, 0xe0, 0x85, 0xe0, 0xa5, 0xe0, 0xbe, 0xe0,
0xd8, 0xe0, 0xdb, 0xe0, 0xf3, 0xe0, 0xf5, 0xe0,
0xf7, 0xe0, 0xf9, 0xe0, 0xfb, 0xe0, 0xfd, 0xe0,
0x16, 0xc0, 0x00, 0x75, 0xd1, 0x49, 0x0d, 0xf0,
0x0f, 0xc0, 0x0f, 0xc5, 0x00, 0x1e, 0x08, 0x9e,
0x0c, 0x9d, 0x0c, 0xc6, 0x0a, 0x9e, 0x8f, 0x1c,
0x0e, 0x8c, 0x0e, 0x74, 0xcf, 0x49, 0xfe, 0xf1,
0x02, 0xc0, 0x00, 0xb8, 0x96, 0x31, 0x00, 0xdc,
0x24, 0xe4, 0x80, 0x02, 0x34, 0xd3, 0xff, 0xc3,
0x60, 0x72, 0xa1, 0x49, 0x0d, 0xf0, 0xf8, 0xc3,
0xf8, 0xc2, 0x00, 0x1c, 0x68, 0x9c, 0xf6, 0xc4,
0x6a, 0x9c, 0x6c, 0x9a, 0x8f, 0x1c, 0x6e, 0x8c,
0x6e, 0x74, 0xcf, 0x49, 0xfe, 0xf1, 0x04, 0xc0,
0x02, 0xc2, 0x00, 0xba, 0xa8, 0x28, 0xf8, 0xc7,
0xea, 0xc0, 0x00, 0x75, 0xd1, 0x49, 0x15, 0xf0,
0x19, 0xc7, 0x17, 0xc2, 0xec, 0x9a, 0x00, 0x19,
0xee, 0x89, 0xee, 0x71, 0x9f, 0x49, 0xfe, 0xf1,
0xea, 0x71, 0x9f, 0x49, 0x0a, 0xf0, 0xd9, 0xc2,
0xec, 0x9a, 0x00, 0x19, 0xe8, 0x99, 0x81, 0x19,
0xee, 0x89, 0xee, 0x71, 0x9f, 0x49, 0xfe, 0xf1,
0x06, 0xc3, 0x02, 0xc2, 0x00, 0xba, 0xf0, 0x1d,
0x4c, 0xe8, 0x00, 0xdc, 0x00, 0xd4, 0xcb, 0xc0,
0x00, 0x75, 0xd1, 0x49, 0x0d, 0xf0, 0xc4, 0xc0,
0xc4, 0xc5, 0x00, 0x1e, 0x08, 0x9e, 0xc2, 0xc6,
0x0a, 0x9e, 0x0c, 0x9d, 0x8f, 0x1c, 0x0e, 0x8c,
0x0e, 0x74, 0xcf, 0x49, 0xfe, 0xf1, 0x04, 0xc0,
0x02, 0xc1, 0x00, 0xb9, 0xc4, 0x16, 0x20, 0xd4,
0xb6, 0xc0, 0x00, 0x75, 0xd1, 0x48, 0x00, 0x9d,
0xe5, 0xc7, 0xaf, 0xc2, 0xec, 0x9a, 0x00, 0x19,
0xe8, 0x9a, 0x81, 0x19, 0xee, 0x89, 0xee, 0x71,
0x9f, 0x49, 0xfe, 0xf1, 0x2c, 0xc1, 0xec, 0x99,
0x81, 0x19, 0xee, 0x89, 0xee, 0x71, 0x9f, 0x49,
0xfe, 0xf1, 0x04, 0xc3, 0x02, 0xc2, 0x00, 0xba,
0x96, 0x1c, 0xc0, 0xd4, 0xc0, 0x88, 0x1e, 0xc6,
0xc0, 0x70, 0x8f, 0x49, 0x0e, 0xf0, 0x8f, 0x48,
0x93, 0xc6, 0xca, 0x98, 0x11, 0x18, 0xc8, 0x98,
0x16, 0xc0, 0xcc, 0x98, 0x8f, 0x18, 0xce, 0x88,
0xce, 0x70, 0x8f, 0x49, 0xfe, 0xf1, 0x0b, 0xe0,
0x43, 0xc6, 0x00, 0x18, 0xc8, 0x98, 0x0b, 0xc0,
0xcc, 0x98, 0x81, 0x18, 0xce, 0x88, 0xce, 0x70,
0x8f, 0x49, 0xfe, 0xf1, 0x02, 0xc0, 0x00, 0xb8,
0xf2, 0x19, 0x40, 0xd3, 0x20, 0xe4, 0x33, 0xc2,
0x40, 0x71, 0x91, 0x48, 0x40, 0x99, 0x30, 0xc2,
0x00, 0x19, 0x48, 0x99, 0xf8, 0xc1, 0x4c, 0x99,
0x81, 0x19, 0x4e, 0x89, 0x4e, 0x71, 0x9f, 0x49,
0xfe, 0xf1, 0x0b, 0xc1, 0x4c, 0x99, 0x81, 0x19,
0x4e, 0x89, 0x4e, 0x71, 0x9f, 0x49, 0xfe, 0xf1,
0x02, 0x71, 0x02, 0xc2, 0x00, 0xba, 0x0e, 0x34,
0x24, 0xe4, 0x19, 0xc2, 0x40, 0x71, 0x91, 0x48,
0x40, 0x99, 0x16, 0xc2, 0x00, 0x19, 0x48, 0x99,
0xde, 0xc1, 0x4c, 0x99, 0x81, 0x19, 0x4e, 0x89,
0x4e, 0x71, 0x9f, 0x49, 0xfe, 0xf1, 0xf1, 0xc1,
0x4c, 0x99, 0x81, 0x19, 0x4e, 0x89, 0x4e, 0x71,
0x9f, 0x49, 0xfe, 0xf1, 0x02, 0x71, 0x02, 0xc2,
0x00, 0xba, 0x60, 0x33, 0x34, 0xd3, 0x00, 0xdc,
0x1e, 0x89, 0x02, 0xc0, 0x00, 0xb8, 0xfa, 0x12,
0x18, 0xc0, 0x00, 0x65, 0xd1, 0x49, 0x0e, 0xf0,
0x11, 0xc0, 0x11, 0xc5, 0x00, 0x1e, 0x08, 0x9e,
0x0c, 0x9d, 0x0e, 0xc6, 0x0a, 0x9e, 0x8f, 0x1c,
0x0e, 0x8c, 0x0e, 0x74, 0xcf, 0x49, 0xfe, 0xf1,
0x04, 0xc0, 0x02, 0xc2, 0x00, 0xba, 0xa0, 0x41,
0x06, 0xd4, 0x00, 0xdc, 0x24, 0xe4, 0x80, 0x02,
0x34, 0xd3, 0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00,
0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00, 0x02, 0xc0,
0x00, 0xb8, 0x00, 0x00, 0x02, 0xc0, 0x00, 0xb8,
0x00, 0x00, 0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00,
0x02, 0xc0, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00 };
static u16 r8153b_usb_patch_b_bp[] = {
0xfc26, 0xa000, 0xfc28, 0x2a20, 0xfc2a, 0x28a6, 0xfc2c, 0x1dee,
0xfc2e, 0x16c2, 0xfc30, 0x1c94, 0xfc32, 0x19f0, 0xfc34, 0x340c,
0xfc36, 0x335e, 0xfc38, 0x12f8, 0xfc3a, 0x419e, 0xfc3c, 0x0000,
0xfc3e, 0x0000, 0xfc40, 0x0000, 0xfc42, 0x0000, 0xfc44, 0x0000,
0xfc46, 0x0000, 0xfc48, 0x03ff };
static u8 pla_patch2_b[] = {
0x05, 0xe0, 0x1b, 0xe0, 0x2c, 0xe0, 0x60, 0xe0,
0x73, 0xe0, 0x15, 0xc6, 0xc2, 0x64, 0xd2, 0x49,
0x06, 0xf1, 0xc4, 0x48, 0xc5, 0x48, 0xc6, 0x48,
0xc7, 0x48, 0x05, 0xe0, 0x44, 0x48, 0x45, 0x48,
0x46, 0x48, 0x47, 0x48, 0xc2, 0x8c, 0xc0, 0x64,
0x46, 0x48, 0xc0, 0x8c, 0x05, 0xc5, 0x02, 0xc4,
0x00, 0xbc, 0x18, 0x02, 0x06, 0xdc, 0xb0, 0xc0,
0x10, 0xc5, 0xa0, 0x77, 0xa0, 0x74, 0x46, 0x48,
0x47, 0x48, 0xa0, 0x9c, 0x0b, 0xc5, 0xa0, 0x74,
0x44, 0x48, 0x43, 0x48, 0xa0, 0x9c, 0x05, 0xc5,
0xa0, 0x9f, 0x02, 0xc5, 0x00, 0xbd, 0x3c, 0x03,
0x1c, 0xe8, 0x20, 0xe8, 0xd4, 0x49, 0x04, 0xf1,
0xd5, 0x49, 0x20, 0xf1, 0x28, 0xe0, 0x2a, 0xc7,
0xe0, 0x75, 0xda, 0x49, 0x14, 0xf0, 0x27, 0xc7,
0xe0, 0x75, 0xdc, 0x49, 0x10, 0xf1, 0x24, 0xc7,
0xe0, 0x75, 0x25, 0xc7, 0xe0, 0x74, 0x2c, 0x40,
0x0a, 0xfa, 0x1f, 0xc7, 0xe4, 0x75, 0xd0, 0x49,
0x09, 0xf1, 0x1c, 0xc5, 0xe6, 0x9d, 0x11, 0x1d,
0xe4, 0x8d, 0x04, 0xe0, 0x16, 0xc7, 0x00, 0x1d,
0xe4, 0x8d, 0xe0, 0x8e, 0x11, 0x1d, 0xe0, 0x8d,
0x07, 0xe0, 0x0c, 0xc7, 0xe0, 0x75, 0xda, 0x48,
0xe0, 0x9d, 0x0b, 0xc7, 0xe4, 0x8e, 0x02, 0xc4,
0x00, 0xbc, 0x28, 0x03, 0x02, 0xc4, 0x00, 0xbc,
0x14, 0x03, 0x12, 0xe8, 0x4e, 0xe8, 0x1c, 0xe6,
0x20, 0xe4, 0x80, 0x02, 0xa4, 0xc0, 0x12, 0xc2,
0x40, 0x73, 0xb0, 0x49, 0x08, 0xf0, 0xb8, 0x49,
0x06, 0xf0, 0xb8, 0x48, 0x40, 0x9b, 0x0b, 0xc2,
0x40, 0x76, 0x05, 0xe0, 0x02, 0x61, 0x02, 0xc3,
0x00, 0xbb, 0x0a, 0x0a, 0x02, 0xc3, 0x00, 0xbb,
0x1a, 0x0a, 0x98, 0xd3, 0x1e, 0xfc, 0xfe, 0xc0,
0x02, 0x62, 0xa0, 0x48, 0x02, 0x8a, 0x00, 0x72,
0xa0, 0x49, 0x11, 0xf0, 0x13, 0xc1, 0x20, 0x62,
0x2e, 0x21, 0x2f, 0x25, 0x00, 0x71, 0x9f, 0x24,
0x0a, 0x40, 0x09, 0xf0, 0x00, 0x71, 0x18, 0x48,
0xa0, 0x49, 0x03, 0xf1, 0x9f, 0x48, 0x02, 0xe0,
0x1f, 0x48, 0x00, 0x99, 0x02, 0xc2, 0x00, 0xba,
0xda, 0x0e, 0x08, 0xe9 };
static u16 r8153b_pla_patch_b_bp[] = {
0xfc26, 0x8000, 0xfc28, 0x0216, 0xfc2a, 0x0332, 0xfc2c, 0x030c,
0xfc2e, 0x0a08, 0xfc30, 0x0ec0, 0xfc32, 0x0000, 0xfc34, 0x0000,
0xfc36, 0x0000, 0xfc38, 0x001e };
static void rtl_clear_bp(struct r8152 *tp, u16 type)
{
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
u8 zeros[16] = {0};
switch (tp->version) {
case RTL_VER_01:
case RTL_VER_02:
case RTL_VER_07:
break;
case RTL_VER_03:
case RTL_VER_04:
case RTL_VER_05:
case RTL_VER_06:
ocp_write_byte(tp, type, PLA_BP_EN, 0);
break;
case RTL_VER_08:
case RTL_VER_09:
default:
if (type == MCU_TYPE_USB) {
ocp_write_byte(tp, MCU_TYPE_USB, USB_BP2_EN, 0);
generic_ocp_write(tp, USB_BP(8), 0xff, sizeof(zeros),
zeros, type);
} else {
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
}
break;
}
generic_ocp_write(tp, USB_BP(0), 0xff, sizeof(zeros), zeros, type);
mdelay(6);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
}
static void r8153_clear_bp(struct r8152 *tp)
{
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
rtl_clear_bp(tp);
ocp_write_word(tp, type, PLA_BP_BA, 0);
}
static void r8152b_set_dq_desc(struct r8152 *tp)
@ -826,7 +959,7 @@ void r8152b_firmware(struct r8152 *tp)
int i;
r8152b_set_dq_desc(tp);
rtl_clear_bp(tp);
rtl_clear_bp(tp, MCU_TYPE_PLA);
generic_ocp_write(tp, 0xf800, 0x3f,
sizeof(r8152b_pla_patch_a),
@ -847,7 +980,7 @@ void r8152b_firmware(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, 0xb098, 0x0200);
ocp_write_word(tp, MCU_TYPE_PLA, 0xb092, 0x7030);
} else if (tp->version == RTL_VER_02) {
rtl_clear_bp(tp);
rtl_clear_bp(tp, MCU_TYPE_PLA);
generic_ocp_write(tp, 0xf800, 0xff,
sizeof(r8152b_pla_patch_a2),
@ -866,8 +999,6 @@ void r8153_firmware(struct r8152 *tp)
int i;
if (tp->version == RTL_VER_03) {
r8153_clear_bp(tp);
r8153_pre_ram_code(tp, 0x7000);
for (i = 0; i < ARRAY_SIZE(r8153_ram_code_a); i += 2)
@ -887,7 +1018,8 @@ void r8153_firmware(struct r8152 *tp)
r8153_post_ram_code(tp);
r8153_wdt1_end(tp);
r8153_clear_bp(tp);
rtl_clear_bp(tp, MCU_TYPE_USB);
ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
generic_ocp_write(tp, 0xf800, 0xff,
@ -904,6 +1036,8 @@ void r8153_firmware(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, 0xd38e, 0x0082);
}
rtl_clear_bp(tp, MCU_TYPE_PLA);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
generic_ocp_write(tp, 0xf800, 0xff,
sizeof(r8153_pla_patch_b),
@ -932,7 +1066,8 @@ void r8153_firmware(struct r8152 *tp)
r8153_post_ram_code(tp);
r8153_wdt1_end(tp);
r8153_clear_bp(tp);
rtl_clear_bp(tp, MCU_TYPE_USB);
ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
generic_ocp_write(tp, 0xf800, 0xff,
@ -951,6 +1086,8 @@ void r8153_firmware(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x00ef);
}
rtl_clear_bp(tp, MCU_TYPE_PLA);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
generic_ocp_write(tp, 0xf800, 0xff,
sizeof(r8153_pla_patch_c),
@ -985,7 +1122,7 @@ void r8153_firmware(struct r8152 *tp)
r8153_post_ram_code(tp);
r8153_clear_bp(tp);
rtl_clear_bp(tp, MCU_TYPE_USB);
ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
generic_ocp_write(tp, 0xf800, 0xff, sizeof(usb_patch_d),
@ -996,6 +1133,8 @@ void r8153_firmware(struct r8152 *tp)
r8153_usb_patch_d_bp[i],
r8153_usb_patch_d_bp[i+1]);
rtl_clear_bp(tp, MCU_TYPE_PLA);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
generic_ocp_write(tp, 0xf800, 0xff, sizeof(pla_patch_d),
pla_patch_d, MCU_TYPE_PLA);
@ -1014,3 +1153,42 @@ void r8153_firmware(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
}
}
void r8153b_firmware(struct r8152 *tp)
{
u32 ocp_data;
int i;
if (tp->version != RTL_VER_09)
return;
rtl_clear_bp(tp, MCU_TYPE_USB);
ocp_write_word(tp, MCU_TYPE_USB, USB_BP_EN, 0x0000);
generic_ocp_write(tp, 0xe600, 0xff, sizeof(usb_patch2_b),
usb_patch2_b, MCU_TYPE_USB);
for (i = 0; i < ARRAY_SIZE(r8153b_usb_patch_b_bp); i += 2)
ocp_write_word(tp, MCU_TYPE_USB,
r8153b_usb_patch_b_bp[i],
r8153b_usb_patch_b_bp[i + 1]);
rtl_clear_bp(tp, MCU_TYPE_PLA);
ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, 0x0000);
generic_ocp_write(tp, 0xf800, 0xff, sizeof(pla_patch2_b),
pla_patch2_b, MCU_TYPE_PLA);
for (i = 0; i < ARRAY_SIZE(r8153b_pla_patch_b_bp); i += 2)
ocp_write_word(tp, MCU_TYPE_PLA,
r8153b_pla_patch_b_bp[i],
r8153b_pla_patch_b_bp[i + 1]);
ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1);
ocp_data |= FW_IP_RESET_EN;
ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data);
}

View file

@ -105,6 +105,12 @@ config CI_UDC
Say Y here to enable device controller functionality of the
ChipIdea driver.
config USB_GADGET_MAX3420
bool "MAX3420 USB Over SPI"
depends on DM_SPI
help
MAX3420, from MAXIM, implements USB-over-SPI Full-Speed device controller.
config USB_GADGET_VBUS_DRAW
int "Maximum VBUS Power usage (2-500 mA)"
range 2 500

View file

@ -20,6 +20,7 @@ obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o
obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o
obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o
obj-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
obj-$(CONFIG_USB_GADGET_MAX3420) += max3420_udc.o
obj-$(CONFIG_CI_UDC) += ci_udc.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o

View file

@ -1053,6 +1053,13 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
free(controller.items_mem);
free(controller.epts);
#if CONFIG_IS_ENABLED(DM_USB)
usb_remove_ehci_gadget(&controller.ctrl);
#else
usb_lowlevel_stop(0);
controller.ctrl = NULL;
#endif
return 0;
}

View file

@ -441,8 +441,6 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
req->length = rx_bytes_expected(ep);
}
fastboot_tx_write_str(response);
if (!strncmp("OKAY", response, 4)) {
switch (cmd) {
case FASTBOOT_COMMAND_BOOT:
@ -455,11 +453,15 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
case FASTBOOT_COMMAND_REBOOT:
case FASTBOOT_COMMAND_REBOOT_BOOTLOADER:
case FASTBOOT_COMMAND_REBOOT_FASTBOOTD:
case FASTBOOT_COMMAND_REBOOT_RECOVERY:
fastboot_func->in_req->complete = compl_do_reset;
break;
}
}
fastboot_tx_write_str(response);
*cmdbuf = '\0';
req->actual = 0;
usb_ep_queue(ep, req, 0);

View file

@ -435,6 +435,7 @@ static void set_bulk_out_req_length(struct fsg_common *common,
static struct ums *ums;
static int ums_count;
static struct fsg_common *the_fsg_common;
static unsigned int controller_index;
static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
{
@ -679,7 +680,7 @@ static int sleep_thread(struct fsg_common *common)
k = 0;
}
usb_gadget_handle_interrupts(0);
usb_gadget_handle_interrupts(controller_index);
}
common->thread_wakeup_needed = 0;
return rc;
@ -2764,10 +2765,11 @@ int fsg_add(struct usb_configuration *c)
return fsg_bind_config(c->cdev, c, fsg_common);
}
int fsg_init(struct ums *ums_devs, int count)
int fsg_init(struct ums *ums_devs, int count, unsigned int controller_idx)
{
ums = ums_devs;
ums_count = count;
controller_index = controller_idx;
return 0;
}

View file

@ -71,6 +71,10 @@ struct hid_report {
#define SDP_COMMAND_LEN 16
#define SDP_HID_PACKET_SIZE_EP1 1024
#define SDP_EXIT 1
struct sdp_command {
u16 cmd;
u32 addr;
@ -82,8 +86,10 @@ struct sdp_command {
enum sdp_state {
SDP_STATE_IDLE,
SDP_STATE_RX_CMD,
SDP_STATE_RX_DCD_DATA,
SDP_STATE_RX_FILE_DATA,
SDP_STATE_RX_FILE_DATA_BUSY,
SDP_STATE_TX_SEC_CONF,
SDP_STATE_TX_SEC_CONF_BUSY,
SDP_STATE_TX_REGISTER,
@ -114,8 +120,12 @@ struct f_sdp {
/* EP1 IN */
struct usb_ep *in_ep;
struct usb_request *in_req;
/* EP1 OUT */
struct usb_ep *out_ep;
struct usb_request *out_req;
bool configuration_done;
bool ep_int_enable;
};
static struct f_sdp *sdp_func;
@ -129,7 +139,7 @@ static struct usb_interface_descriptor sdp_intf_runtime = {
.bLength = sizeof(sdp_intf_runtime),
.bDescriptorType = USB_DT_INTERFACE,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
@ -159,10 +169,49 @@ static struct usb_endpoint_descriptor in_desc = {
.bInterval = 1,
};
static struct usb_endpoint_descriptor out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
.bEndpointAddress = 1 | USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = 64,
.bInterval = 1,
};
static struct usb_endpoint_descriptor in_hs_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
.bEndpointAddress = 1 | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = 512,
.bInterval = 3,
};
static struct usb_endpoint_descriptor out_hs_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
.bEndpointAddress = 1 | USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = SDP_HID_PACKET_SIZE_EP1,
.bInterval = 3,
};
static struct usb_descriptor_header *sdp_runtime_descs[] = {
(struct usb_descriptor_header *)&sdp_intf_runtime,
(struct usb_descriptor_header *)&sdp_hid_desc,
(struct usb_descriptor_header *)&in_desc,
(struct usb_descriptor_header *)&out_desc,
NULL,
};
static struct usb_descriptor_header *sdp_runtime_hs_descs[] = {
(struct usb_descriptor_header *)&sdp_intf_runtime,
(struct usb_descriptor_header *)&sdp_hid_desc,
(struct usb_descriptor_header *)&in_hs_desc,
(struct usb_descriptor_header *)&out_hs_desc,
NULL,
};
@ -328,7 +377,7 @@ static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req)
int status = req->status;
u8 *data = req->buf;
u8 report = data[0];
int datalen = req->length - 1;
int datalen = req->actual - 1;
if (status != 0) {
pr_err("Status: %d\n", status);
@ -351,13 +400,15 @@ static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req)
sdp->dnl_bytes_remaining -= datalen;
}
if (sdp->state == SDP_STATE_RX_FILE_DATA) {
if (sdp->state == SDP_STATE_RX_FILE_DATA_BUSY) {
memcpy(sdp_ptr(sdp->dnl_address), req->buf + 1, datalen);
sdp->dnl_address += datalen;
}
if (sdp->dnl_bytes_remaining)
if (sdp->dnl_bytes_remaining) {
sdp->state = SDP_STATE_RX_FILE_DATA;
return;
}
#ifndef CONFIG_SPL_BUILD
env_set_hex("filesize", sdp->dnl_bytes);
@ -365,7 +416,7 @@ static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req)
printf("done\n");
switch (sdp->state) {
case SDP_STATE_RX_FILE_DATA:
case SDP_STATE_RX_FILE_DATA_BUSY:
sdp->state = SDP_STATE_TX_SEC_CONF;
break;
case SDP_STATE_RX_DCD_DATA:
@ -446,10 +497,12 @@ static int sdp_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
case 1:
value = SDP_COMMAND_LEN + 1;
req->complete = sdp_rx_command_complete;
sdp_func->ep_int_enable = false;
break;
case 2:
value = len;
req->complete = sdp_rx_data_complete;
sdp_func->state = SDP_STATE_RX_FILE_DATA_BUSY;
break;
}
}
@ -480,16 +533,29 @@ static int sdp_bind(struct usb_configuration *c, struct usb_function *f)
return id;
sdp_intf_runtime.bInterfaceNumber = id;
struct usb_ep *ep;
struct usb_ep *ep_in, *ep_out;
/* allocate instance-specific endpoints */
ep = usb_ep_autoconfig(gadget, &in_desc);
if (!ep) {
ep_in = usb_ep_autoconfig(gadget, &in_desc);
if (!ep_in) {
rv = -ENODEV;
goto error;
}
sdp->in_ep = ep; /* Store IN EP for enabling @ setup */
ep_out = usb_ep_autoconfig(gadget, &out_desc);
if (!ep_out) {
rv = -ENODEV;
goto error;
}
if (gadget_is_dualspeed(gadget)) {
/* Assume endpoint addresses are the same for both speeds */
in_hs_desc.bEndpointAddress = in_desc.bEndpointAddress;
out_hs_desc.bEndpointAddress = out_desc.bEndpointAddress;
}
sdp->in_ep = ep_in; /* Store IN EP for enabling @ setup */
sdp->out_ep = ep_out;
cdev->req->context = sdp;
@ -522,18 +588,29 @@ static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
}
static struct usb_request *sdp_start_ep(struct usb_ep *ep)
static struct usb_request *sdp_start_ep(struct usb_ep *ep, bool in)
{
struct usb_request *req;
req = alloc_ep_req(ep, 64);
if (in)
req = alloc_ep_req(ep, 65);
else
req = alloc_ep_req(ep, 2048);
/*
* OUT endpoint request length should be an integral multiple of
* maxpacket size 1024, else we break on certain controllers like
* DWC3 that expect bulk OUT requests to be divisible by maxpacket size.
*/
debug("%s: ep:%p req:%p\n", __func__, ep, req);
if (!req)
return NULL;
memset(req->buf, 0, req->length);
if (in)
req->complete = sdp_tx_complete;
else
req->complete = sdp_rx_command_complete;
return req;
}
@ -541,20 +618,32 @@ static int sdp_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_sdp *sdp = func_to_sdp(f);
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_gadget *gadget = cdev->gadget;
int result;
debug("%s: intf: %d alt: %d\n", __func__, intf, alt);
if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) {
result = usb_ep_enable(sdp->in_ep, &in_hs_desc);
result |= usb_ep_enable(sdp->out_ep, &out_hs_desc);
} else {
result = usb_ep_enable(sdp->in_ep, &in_desc);
result |= usb_ep_enable(sdp->out_ep, &out_desc);
}
if (result)
return result;
sdp->in_req = sdp_start_ep(sdp->in_ep);
sdp->in_req = sdp_start_ep(sdp->in_ep, true);
sdp->in_req->context = sdp;
sdp->out_req = sdp_start_ep(sdp->out_ep, false);
sdp->out_req->context = sdp;
sdp->in_ep->driver_data = cdev; /* claim */
sdp->out_ep->driver_data = cdev; /* claim */
sdp->altsetting = alt;
sdp->state = SDP_STATE_IDLE;
sdp->ep_int_enable = true;
return 0;
}
@ -571,11 +660,18 @@ static void sdp_disable(struct usb_function *f)
struct f_sdp *sdp = func_to_sdp(f);
usb_ep_disable(sdp->in_ep);
usb_ep_disable(sdp->out_ep);
if (sdp->in_req) {
free(sdp->in_req);
free(sdp->in_req->buf);
usb_ep_free_request(sdp->in_ep, sdp->in_req);
sdp->in_req = NULL;
}
if (sdp->out_req) {
free(sdp->out_req->buf);
usb_ep_free_request(sdp->out_ep, sdp->out_req);
sdp->out_req = NULL;
}
}
static int sdp_bind_config(struct usb_configuration *c)
@ -591,7 +687,7 @@ static int sdp_bind_config(struct usb_configuration *c)
memset(sdp_func, 0, sizeof(*sdp_func));
sdp_func->usb_function.name = "sdp";
sdp_func->usb_function.hs_descriptors = sdp_runtime_descs;
sdp_func->usb_function.hs_descriptors = sdp_runtime_hs_descs;
sdp_func->usb_function.descriptors = sdp_runtime_descs;
sdp_func->usb_function.bind = sdp_bind;
sdp_func->usb_function.unbind = sdp_unbind;
@ -641,8 +737,7 @@ static u32 sdp_jump_imxheader(void *address)
}
#ifdef CONFIG_SPL_BUILD
#ifdef CONFIG_SPL_LOAD_FIT
static ulong sdp_fit_read(struct spl_load_info *load, ulong sector,
static ulong sdp_load_read(struct spl_load_info *load, ulong sector,
ulong count, void *buf)
{
debug("%s: sector %lx, count %lx, buf %lx\n",
@ -650,10 +745,35 @@ static ulong sdp_fit_read(struct spl_load_info *load, ulong sector,
memcpy(buf, (void *)(load->dev + sector), count);
return count;
}
#endif
static ulong search_fit_header(ulong p, int size)
{
int i;
for (i = 0; i < size; i += 4) {
if (genimg_get_format((const void *)(p + i)) == IMAGE_FORMAT_FIT)
return p + i;
}
return 0;
}
static ulong search_container_header(ulong p, int size)
{
int i;
u8 *hdr;
for (i = 0; i < size; i += 4) {
hdr = (u8 *)(p + i);
if (*(hdr + 3) == 0x87 && *hdr == 0)
if (*(hdr + 1) != 0 || *(hdr + 2) != 0)
return p + i;
}
return 0;
}
#endif
static void sdp_handle_in_ep(struct spl_image_info *spl_image)
static int sdp_handle_in_ep(struct spl_image_info *spl_image)
{
u8 *data = sdp_func->in_req->buf;
u32 status;
@ -705,6 +825,15 @@ static void sdp_handle_in_ep(struct spl_image_info *spl_image)
/* If imx header fails, try some U-Boot specific headers */
if (status) {
#ifdef CONFIG_SPL_BUILD
if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER))
sdp_func->jmp_address = (u32)search_container_header((ulong)sdp_func->jmp_address, sdp_func->dnl_bytes);
else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT))
sdp_func->jmp_address = (u32)search_fit_header((ulong)sdp_func->jmp_address, sdp_func->dnl_bytes);
if (sdp_func->jmp_address == 0)
panic("Error in search header, failed to jump\n");
printf("Found header at 0x%08x\n", sdp_func->jmp_address);
image_header_t *header =
sdp_ptr(sdp_func->jmp_address);
#ifdef CONFIG_SPL_LOAD_FIT
@ -714,13 +843,23 @@ static void sdp_handle_in_ep(struct spl_image_info *spl_image)
debug("Found FIT\n");
load.dev = header;
load.bl_len = 1;
load.read = sdp_fit_read;
load.read = sdp_load_read;
spl_load_simple_fit(spl_image, &load, 0,
header);
return;
return SDP_EXIT;
}
#endif
if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
struct spl_load_info load;
load.dev = header;
load.bl_len = 1;
load.read = sdp_load_read;
spl_load_imx_container(spl_image, &load, 0);
return SDP_EXIT;
}
/* In SPL, allow jumps to U-Boot images */
struct spl_image_info spl_image = {};
spl_parse_image_header(&spl_image, header);
@ -743,6 +882,29 @@ static void sdp_handle_in_ep(struct spl_image_info *spl_image)
default:
break;
};
return 0;
}
static void sdp_handle_out_ep(void)
{
int rc;
if (sdp_func->state == SDP_STATE_IDLE) {
sdp_func->out_req->complete = sdp_rx_command_complete;
rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
if (rc)
printf("error in submission: %s\n",
sdp_func->out_ep->name);
sdp_func->state = SDP_STATE_RX_CMD;
} else if (sdp_func->state == SDP_STATE_RX_FILE_DATA) {
sdp_func->out_req->complete = sdp_rx_data_complete;
rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
if (rc)
printf("error in submission: %s\n",
sdp_func->out_ep->name);
sdp_func->state = SDP_STATE_RX_FILE_DATA_BUSY;
}
}
#ifndef CONFIG_SPL_BUILD
@ -751,6 +913,7 @@ int sdp_handle(int controller_index)
int spl_sdp_handle(int controller_index, struct spl_image_info *spl_image)
#endif
{
int flag = 0;
printf("SDP: handle requests...\n");
while (1) {
if (ctrlc()) {
@ -758,19 +921,19 @@ int spl_sdp_handle(int controller_index, struct spl_image_info *spl_image)
return -EINVAL;
}
#ifdef CONFIG_SPL_BUILD
if (spl_image->flags & SPL_FIT_FOUND)
if (flag == SDP_EXIT)
return 0;
#endif
WATCHDOG_RESET();
usb_gadget_handle_interrupts(controller_index);
#ifdef CONFIG_SPL_BUILD
sdp_handle_in_ep(spl_image);
flag = sdp_handle_in_ep(spl_image);
#else
sdp_handle_in_ep(NULL);
flag = sdp_handle_in_ep(NULL);
#endif
if (sdp_func->ep_int_enable)
sdp_handle_out_ep();
}
}

View file

@ -155,6 +155,12 @@
#define gadget_is_cdns3(g) 0
#endif
#ifdef CONFIG_USB_GADGET_MAX3420
#define gadget_is_max3420(g) (!strcmp("max3420-udc", (g)->name))
#else
#define gadget_is_max3420(g) 0
#endif
/**
* usb_gadget_controller_number - support bcdDevice id convention
* @gadget: the controller being driven
@ -216,5 +222,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x23;
else if (gadget_is_cdns3(gadget))
return 0x24;
else if (gadget_is_max3420(gadget))
return 0x25;
return -ENOENT;
}

View file

@ -0,0 +1,875 @@
// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <asm/gpio.h>
#include <linux/list.h>
#include <linux/bitfield.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <malloc.h>
#include <spi.h>
#include <dm.h>
#include <g_dnl.h>
#define MAX3420_MAX_EPS 4
#define EP_MAX_PACKET 64 /* Same for all Endpoints */
#define EPNAME_SIZE 16 /* Buffer size for endpoint name */
#define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */
#define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */
/* SPI commands: */
#define MAX3420_SPI_ACK_MASK BIT(0)
#define MAX3420_SPI_DIR_MASK BIT(1)
#define MAX3420_SPI_REG_MASK GENMASK(7, 3)
#define MAX3420_REG_EP0FIFO 0
#define MAX3420_REG_EP1FIFO 1
#define MAX3420_REG_EP2FIFO 2
#define MAX3420_REG_EP3FIFO 3
#define MAX3420_REG_SUDFIFO 4
#define MAX3420_REG_EP0BC 5
#define MAX3420_REG_EP1BC 6
#define MAX3420_REG_EP2BC 7
#define MAX3420_REG_EP3BC 8
#define MAX3420_REG_EPSTALLS 9
#define bACKSTAT BIT(6)
#define bSTLSTAT BIT(5)
#define bSTLEP3IN BIT(4)
#define bSTLEP2IN BIT(3)
#define bSTLEP1OUT BIT(2)
#define bSTLEP0OUT BIT(1)
#define bSTLEP0IN BIT(0)
#define MAX3420_REG_CLRTOGS 10
#define bEP3DISAB BIT(7)
#define bEP2DISAB BIT(6)
#define bEP1DISAB BIT(5)
#define bCTGEP3IN BIT(4)
#define bCTGEP2IN BIT(3)
#define bCTGEP1OUT BIT(2)
#define MAX3420_REG_EPIRQ 11
#define MAX3420_REG_EPIEN 12
#define bSUDAVIRQ BIT(5)
#define bIN3BAVIRQ BIT(4)
#define bIN2BAVIRQ BIT(3)
#define bOUT1DAVIRQ BIT(2)
#define bOUT0DAVIRQ BIT(1)
#define bIN0BAVIRQ BIT(0)
#define MAX3420_REG_USBIRQ 13
#define MAX3420_REG_USBIEN 14
#define bOSCOKIRQ BIT(0)
#define bRWUDNIRQ BIT(1)
#define bBUSACTIRQ BIT(2)
#define bURESIRQ BIT(3)
#define bSUSPIRQ BIT(4)
#define bNOVBUSIRQ BIT(5)
#define bVBUSIRQ BIT(6)
#define bURESDNIRQ BIT(7)
#define MAX3420_REG_USBCTL 15
#define bHOSCSTEN BIT(7)
#define bVBGATE BIT(6)
#define bCHIPRES BIT(5)
#define bPWRDOWN BIT(4)
#define bCONNECT BIT(3)
#define bSIGRWU BIT(2)
#define MAX3420_REG_CPUCTL 16
#define bIE BIT(0)
#define MAX3420_REG_PINCTL 17
#define bEP3INAK BIT(7)
#define bEP2INAK BIT(6)
#define bEP0INAK BIT(5)
#define bFDUPSPI BIT(4)
#define bINTLEVEL BIT(3)
#define bPOSINT BIT(2)
#define bGPXB BIT(1)
#define bGPXA BIT(0)
#define MAX3420_REG_REVISION 18
#define MAX3420_REG_FNADDR 19
#define FNADDR_MASK 0x7f
#define MAX3420_REG_IOPINS 20
#define MAX3420_REG_IOPINS2 21
#define MAX3420_REG_GPINIRQ 22
#define MAX3420_REG_GPINIEN 23
#define MAX3420_REG_GPINPOL 24
#define MAX3420_REG_HIRQ 25
#define MAX3420_REG_HIEN 26
#define MAX3420_REG_MODE 27
#define MAX3420_REG_PERADDR 28
#define MAX3420_REG_HCTL 29
#define MAX3420_REG_HXFR 30
#define MAX3420_REG_HRSL 31
struct max3420_req {
struct usb_request usb_req;
struct list_head queue;
struct max3420_ep *ep;
};
struct max3420_ep {
struct max3420_udc *udc;
struct list_head queue;
char name[EPNAME_SIZE];
unsigned int maxpacket;
struct usb_ep ep_usb;
int halted;
int id;
};
struct max3420_udc {
struct max3420_ep ep[MAX3420_MAX_EPS];
struct usb_gadget_driver *driver;
bool softconnect;
struct usb_ctrlrequest setup;
struct max3420_req ep0req;
struct usb_gadget gadget;
struct spi_slave *slave;
struct udevice *dev;
u8 ep0buf[64];
int remote_wkp;
bool suspended;
};
#define to_max3420_req(r) container_of((r), struct max3420_req, usb_req)
#define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb)
#define to_udc(g) container_of((g), struct max3420_udc, gadget)
static void spi_ack_ctrl(struct max3420_udc *udc)
{
struct spi_slave *slave = udc->slave;
u8 txdata[1];
txdata[0] = FIELD_PREP(MAX3420_SPI_ACK_MASK, 1);
spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE);
}
static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int ackstat)
{
struct spi_slave *slave = udc->slave;
u8 txdata[2], rxdata[2];
txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD) |
FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0);
rxdata[0] = 0;
rxdata[1] = 0;
spi_xfer(slave, sizeof(txdata), txdata, rxdata, SPI_XFER_ONCE);
return rxdata[1];
}
static u8 spi_rd8(struct max3420_udc *udc, u8 reg)
{
return spi_rd8_ack(udc, reg, 0);
}
static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int ackstat)
{
struct spi_slave *slave = udc->slave;
u8 txdata[2];
txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR) |
FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0);
txdata[1] = val;
spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE);
}
static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val)
{
spi_wr8_ack(udc, reg, val, 0);
}
static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
{
struct spi_slave *slave = udc->slave;
u8 txdata[1];
txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD);
spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN);
spi_xfer(slave, len * 8, NULL, buf, SPI_XFER_END);
}
static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
{
struct spi_slave *slave = udc->slave;
u8 txdata[1];
txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR);
spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN);
spi_xfer(slave, len * 8, buf, NULL, SPI_XFER_END);
}
/* 0 if not-connected */
int g_dnl_board_usb_cable_connected(void)
{
return 1;
}
static void spi_max3420_enable(struct max3420_ep *ep, int enable)
{
struct max3420_udc *udc = ep->udc;
u8 epdis, epien;
if (ep->id == 0)
return;
epien = spi_rd8(udc, MAX3420_REG_EPIEN);
epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS);
if (enable) {
epdis &= ~BIT(ep->id + 4);
epien |= BIT(ep->id + 1);
} else {
epdis |= BIT(ep->id + 4);
epien &= ~BIT(ep->id + 1);
}
spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis);
spi_wr8(udc, MAX3420_REG_EPIEN, epien);
}
static int
max3420_ep_enable(struct usb_ep *_ep,
const struct usb_endpoint_descriptor *desc)
{
struct max3420_ep *ep = to_max3420_ep(_ep);
_ep->desc = desc;
_ep->maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
spi_max3420_enable(ep, 1);
return 0;
}
static void max3420_req_done(struct max3420_req *req, int status)
{
struct max3420_ep *ep = req->ep;
if (req->usb_req.status == -EINPROGRESS)
req->usb_req.status = status;
else
status = req->usb_req.status;
if (status && status != -ESHUTDOWN)
dev_err(ep->udc->dev, "%s done %p, status %d\n",
ep->ep_usb.name, req, status);
if (req->usb_req.complete)
req->usb_req.complete(&ep->ep_usb, &req->usb_req);
}
static void max3420_ep_nuke(struct max3420_ep *ep, int status)
{
struct max3420_req *req, *r;
list_for_each_entry_safe(req, r, &ep->queue, queue) {
list_del_init(&req->queue);
max3420_req_done(req, status);
}
}
static int max3420_ep_disable(struct usb_ep *_ep)
{
struct max3420_ep *ep = to_max3420_ep(_ep);
_ep->desc = NULL;
max3420_ep_nuke(ep, -ESHUTDOWN);
spi_max3420_enable(ep, 0);
return 0;
}
static struct usb_request *
max3420_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
{
struct max3420_ep *ep = to_max3420_ep(_ep);
struct max3420_req *req = kzalloc(sizeof(*req), gfp_flags);
if (!req)
return NULL;
req->ep = ep;
INIT_LIST_HEAD(&req->queue);
return &req->usb_req;
}
static void
max3420_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
{
kfree(to_max3420_req(_req));
}
static int
max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
{
struct max3420_req *req = to_max3420_req(_req);
struct max3420_ep *ep = to_max3420_ep(_ep);
_req->status = -EINPROGRESS;
_req->actual = 0;
list_add_tail(&req->queue, &ep->queue);
return 0;
}
static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct max3420_req *req = to_max3420_req(_req);
list_del_init(&req->queue);
max3420_req_done(req, -ECONNRESET);
return 0;
}
static int max3420_ep_set_halt(struct usb_ep *_ep, int halt)
{
struct max3420_ep *ep = to_max3420_ep(_ep);
struct max3420_udc *udc = ep->udc;
u8 epstalls;
if (ep->id == 0) /* can't stall EP0 */
return 0;
epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS);
if (halt) {
ep->halted = 1;
epstalls |= BIT(ep->id + 1);
} else {
u8 clrtogs;
ep->halted = 0;
epstalls &= ~BIT(ep->id + 1);
clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS);
clrtogs |= BIT(ep->id + 1);
spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs);
}
spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | bACKSTAT);
return 0;
}
static const struct usb_ep_ops max3420_ep_ops = {
.enable = max3420_ep_enable,
.disable = max3420_ep_disable,
.alloc_request = max3420_ep_alloc_request,
.free_request = max3420_ep_free_request,
.queue = max3420_ep_queue,
.dequeue = max3420_ep_dequeue,
.set_halt = max3420_ep_set_halt,
};
static void __max3420_stop(struct max3420_udc *udc)
{
u8 val;
/* Disable IRQ to CPU */
spi_wr8(udc, MAX3420_REG_CPUCTL, 0);
val = spi_rd8(udc, MAX3420_REG_USBCTL);
val |= bPWRDOWN;
val |= bHOSCSTEN;
spi_wr8(udc, MAX3420_REG_USBCTL, val);
}
static void __max3420_start(struct max3420_udc *udc)
{
u8 val;
/* configure SPI */
spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI);
/* Chip Reset */
spi_wr8(udc, MAX3420_REG_USBCTL, bCHIPRES);
mdelay(5);
spi_wr8(udc, MAX3420_REG_USBCTL, 0);
/* Poll for OSC to stabilize */
while (1) {
val = spi_rd8(udc, MAX3420_REG_USBIRQ);
if (val & bOSCOKIRQ)
break;
cond_resched();
}
/* Enable PULL-UP only when Vbus detected */
val = spi_rd8(udc, MAX3420_REG_USBCTL);
val |= bVBGATE | bCONNECT;
spi_wr8(udc, MAX3420_REG_USBCTL, val);
val = bURESDNIRQ | bURESIRQ;
spi_wr8(udc, MAX3420_REG_USBIEN, val);
/* Enable only EP0 interrupts */
val = bIN0BAVIRQ | bOUT0DAVIRQ | bSUDAVIRQ;
spi_wr8(udc, MAX3420_REG_EPIEN, val);
/* Enable IRQ to CPU */
spi_wr8(udc, MAX3420_REG_CPUCTL, bIE);
}
static int max3420_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
struct max3420_udc *udc = to_udc(gadget);
udc->driver = driver;
udc->remote_wkp = 0;
udc->softconnect = true;
__max3420_start(udc);
return 0;
}
static int max3420_udc_stop(struct usb_gadget *gadget)
{
struct max3420_udc *udc = to_udc(gadget);
udc->driver = NULL;
udc->softconnect = false;
__max3420_stop(udc);
return 0;
}
static int max3420_wakeup(struct usb_gadget *gadget)
{
struct max3420_udc *udc = to_udc(gadget);
u8 usbctl;
/* Only if wakeup allowed by host */
if (!udc->remote_wkp || !udc->suspended)
return 0;
/* Set Remote-Wakeup Signal*/
usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
usbctl |= bSIGRWU;
spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
mdelay(5);
/* Clear Remote-WkUp Signal*/
usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
usbctl &= ~bSIGRWU;
spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
udc->suspended = false;
return 0;
}
static const struct usb_gadget_ops max3420_udc_ops = {
.udc_start = max3420_udc_start,
.udc_stop = max3420_udc_stop,
.wakeup = max3420_wakeup,
};
static struct usb_endpoint_descriptor ep0_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
.wMaxPacketSize = cpu_to_le16(EP_MAX_PACKET),
};
static void max3420_getstatus(struct max3420_udc *udc)
{
struct max3420_ep *ep;
u16 status = 0;
switch (udc->setup.bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
/* Get device status */
status = 0 << USB_DEVICE_SELF_POWERED;
status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP);
break;
case USB_RECIP_INTERFACE:
if (udc->driver->setup(&udc->gadget, &udc->setup) < 0)
goto stall;
break;
case USB_RECIP_ENDPOINT:
ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK];
if (ep->halted)
status = 1 << USB_ENDPOINT_HALT;
break;
default:
goto stall;
}
status = cpu_to_le16(status);
spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2);
spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1);
return;
stall:
dev_err(udc->dev, "Can't respond to getstatus request\n");
spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
}
static void max3420_set_clear_feature(struct max3420_udc *udc)
{
int set = udc->setup.bRequest == USB_REQ_SET_FEATURE;
struct max3420_ep *ep;
int id;
switch (udc->setup.bRequestType) {
case USB_RECIP_DEVICE:
if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP)
break;
if (udc->setup.bRequest == USB_REQ_SET_FEATURE)
udc->remote_wkp = 1;
else
udc->remote_wkp = 0;
return spi_ack_ctrl(udc);
case USB_RECIP_ENDPOINT:
if (udc->setup.wValue != USB_ENDPOINT_HALT)
break;
id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[id];
max3420_ep_set_halt(&ep->ep_usb, set);
return;
default:
break;
}
dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n");
spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
}
static void max3420_handle_setup(struct max3420_udc *udc)
{
struct usb_ctrlrequest setup;
u8 addr;
spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8);
udc->setup = setup;
udc->setup.wValue = cpu_to_le16(setup.wValue);
udc->setup.wIndex = cpu_to_le16(setup.wIndex);
udc->setup.wLength = cpu_to_le16(setup.wLength);
switch (udc->setup.bRequest) {
case USB_REQ_GET_STATUS:
/* Data+Status phase form udc */
if ((udc->setup.bRequestType &
(USB_DIR_IN | USB_TYPE_MASK)) !=
(USB_DIR_IN | USB_TYPE_STANDARD)) {
break;
}
return max3420_getstatus(udc);
case USB_REQ_SET_ADDRESS:
/* Status phase from udc */
if (udc->setup.bRequestType != (USB_DIR_OUT |
USB_TYPE_STANDARD | USB_RECIP_DEVICE))
break;
addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1);
dev_dbg(udc->dev, "Assigned Address=%d/%d\n",
udc->setup.wValue, addr);
return;
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
/* Requests with no data phase, status phase from udc */
if ((udc->setup.bRequestType & USB_TYPE_MASK)
!= USB_TYPE_STANDARD)
break;
return max3420_set_clear_feature(udc);
default:
break;
}
if (udc->driver->setup(&udc->gadget, &setup) < 0) {
/* Stall EP0 */
spi_wr8(udc, MAX3420_REG_EPSTALLS,
bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
}
}
static int do_data(struct max3420_udc *udc, int ep_id, int in)
{
struct max3420_ep *ep = &udc->ep[ep_id];
struct max3420_req *req;
int done, length, psz;
void *buf;
if (list_empty(&ep->queue))
return 0;
req = list_first_entry(&ep->queue, struct max3420_req, queue);
buf = req->usb_req.buf + req->usb_req.actual;
psz = ep->ep_usb.maxpacket;
length = req->usb_req.length - req->usb_req.actual;
length = min(length, psz);
if (length == 0) {
done = 1;
goto xfer_done;
}
done = 0;
if (in) {
spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length);
if (length < psz)
done = 1;
} else {
psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id);
length = min(length, psz);
spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
if (length < ep->ep_usb.maxpacket)
done = 1;
}
req->usb_req.actual += length;
if (req->usb_req.actual == req->usb_req.length)
done = 1;
xfer_done:
if (done) {
list_del_init(&req->queue);
if (ep_id == 0)
spi_ack_ctrl(udc);
max3420_req_done(req, 0);
}
return 1;
}
static int max3420_handle_irqs(struct max3420_udc *udc)
{
u8 epien, epirq, usbirq, usbien, reg[4];
int ret = 0;
spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4);
epirq = reg[0];
epien = reg[1];
usbirq = reg[2];
usbien = reg[3];
usbirq &= usbien;
epirq &= epien;
if (epirq & bSUDAVIRQ) {
spi_wr8(udc, MAX3420_REG_EPIRQ, bSUDAVIRQ);
max3420_handle_setup(udc);
return 1;
}
if (usbirq & bVBUSIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bVBUSIRQ);
dev_dbg(udc->dev, "Cable plugged in\n");
g_dnl_clear_detach();
return 1;
}
if (usbirq & bNOVBUSIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bNOVBUSIRQ);
dev_dbg(udc->dev, "Cable pulled out\n");
g_dnl_trigger_detach();
return 1;
}
if (usbirq & bURESIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bURESIRQ);
return 1;
}
if (usbirq & bURESDNIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bURESDNIRQ);
spi_wr8(udc, MAX3420_REG_USBIEN, bURESDNIRQ | bURESIRQ);
spi_wr8(udc, MAX3420_REG_EPIEN, bSUDAVIRQ
| bIN0BAVIRQ | bOUT0DAVIRQ);
return 1;
}
if (usbirq & bSUSPIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bSUSPIRQ);
dev_dbg(udc->dev, "USB Suspend - Enter\n");
udc->suspended = true;
return 1;
}
if (usbirq & bBUSACTIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bBUSACTIRQ);
dev_dbg(udc->dev, "USB Suspend - Exit\n");
udc->suspended = false;
return 1;
}
if (usbirq & bRWUDNIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bRWUDNIRQ);
dev_dbg(udc->dev, "Asked Host to wakeup\n");
return 1;
}
if (usbirq & bOSCOKIRQ) {
spi_wr8(udc, MAX3420_REG_USBIRQ, bOSCOKIRQ);
dev_dbg(udc->dev, "Osc stabilized, start work\n");
return 1;
}
if (epirq & bOUT0DAVIRQ && do_data(udc, 0, 0)) {
spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT0DAVIRQ, 1);
ret = 1;
}
if (epirq & bIN0BAVIRQ && do_data(udc, 0, 1))
ret = 1;
if (epirq & bOUT1DAVIRQ && do_data(udc, 1, 0)) {
spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT1DAVIRQ, 1);
ret = 1;
}
if (epirq & bIN2BAVIRQ && do_data(udc, 2, 1))
ret = 1;
if (epirq & bIN3BAVIRQ && do_data(udc, 3, 1))
ret = 1;
return ret;
}
static int max3420_irq(struct max3420_udc *udc)
{
do_data(udc, 0, 1); /* get done with the EP0 ZLP */
return max3420_handle_irqs(udc);
}
static void max3420_setup_eps(struct max3420_udc *udc)
{
int i;
INIT_LIST_HEAD(&udc->gadget.ep_list);
INIT_LIST_HEAD(&udc->ep[0].ep_usb.ep_list);
for (i = 0; i < MAX3420_MAX_EPS; i++) {
struct max3420_ep *ep = &udc->ep[i];
INIT_LIST_HEAD(&ep->queue);
ep->id = i;
ep->udc = udc;
ep->ep_usb.ops = &max3420_ep_ops;
ep->ep_usb.name = ep->name;
ep->ep_usb.maxpacket = EP_MAX_PACKET;
if (i == 0) {
ep->ep_usb.desc = &ep0_desc;
snprintf(ep->name, EPNAME_SIZE, "ep0");
continue;
}
list_add_tail(&ep->ep_usb.ep_list, &udc->gadget.ep_list);
if (i == 1)
snprintf(ep->name, EPNAME_SIZE, "ep1out-bulk");
else
snprintf(ep->name, EPNAME_SIZE, "ep%din-bulk", i);
};
}
static void max3420_setup_spi(struct max3420_udc *udc)
{
u8 reg[8];
spi_claim_bus(udc->slave);
spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8);
/* configure SPI */
spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI);
}
int dm_usb_gadget_handle_interrupts(struct udevice *dev)
{
struct max3420_udc *udc = dev_get_priv(dev);
return max3420_irq(udc);
}
static int max3420_udc_probe(struct udevice *dev)
{
struct max3420_udc *udc = dev_get_priv(dev);
struct dm_spi_slave_platdata *slave_pdata;
struct udevice *bus = dev->parent;
int busnum = bus->seq;
unsigned int cs;
uint speed, mode;
struct udevice *spid;
slave_pdata = dev_get_parent_platdata(dev);
cs = slave_pdata->cs;
speed = slave_pdata->max_hz;
mode = slave_pdata->mode;
spi_get_bus_and_cs(busnum, cs, speed, mode, "spi_generic_drv",
NULL, &spid, &udc->slave);
udc->dev = dev;
udc->gadget.ep0 = &udc->ep[0].ep_usb;
udc->gadget.max_speed = USB_SPEED_FULL;
udc->gadget.speed = USB_SPEED_FULL;
udc->gadget.is_dualspeed = 0;
udc->gadget.ops = &max3420_udc_ops;
udc->gadget.name = "max3420-udc";
max3420_setup_eps(udc);
max3420_setup_spi(udc);
usb_add_gadget_udc((struct device *)dev, &udc->gadget);
return 0;
}
static int max3420_udc_remove(struct udevice *dev)
{
struct max3420_udc *udc = dev_get_priv(dev);
usb_del_gadget_udc(&udc->gadget);
spi_release_bus(udc->slave);
return 0;
}
static const struct udevice_id max3420_ids[] = {
{ .compatible = "maxim,max3421-udc" },
{ }
};
U_BOOT_DRIVER(max3420_generic_udc) = {
.name = "max3420-udc",
.id = UCLASS_USB_GADGET_GENERIC,
.of_match = max3420_ids,
.probe = max3420_udc_probe,
.remove = max3420_udc_remove,
.priv_auto_alloc_size = sizeof(struct max3420_udc),
};

View file

@ -411,6 +411,24 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
return 0;
}
int usb_remove_ehci_gadget(struct ehci_ctrl **ctlrp)
{
struct udevice *dev;
int ret;
/* Find the old device and remove it */
ret = uclass_find_device_by_seq(UCLASS_USB, 0, true, &dev);
if (ret)
return ret;
ret = device_remove(dev, DM_REMOVE_NORMAL);
if (ret)
return ret;
*ctlrp = NULL;
return 0;
}
/* returns 0 if no match, 1 if match */
static int usb_match_device(const struct usb_device_descriptor *desc,
const struct usb_device_id *id)

View file

@ -79,7 +79,7 @@ struct nand_internal_data {
};
struct ram_internal_data {
void *start;
unsigned long start;
unsigned int size;
};

View file

@ -32,6 +32,8 @@ enum {
FASTBOOT_COMMAND_CONTINUE,
FASTBOOT_COMMAND_REBOOT,
FASTBOOT_COMMAND_REBOOT_BOOTLOADER,
FASTBOOT_COMMAND_REBOOT_FASTBOOTD,
FASTBOOT_COMMAND_REBOOT_RECOVERY,
FASTBOOT_COMMAND_SET_ACTIVE,
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
FASTBOOT_COMMAND_OEM_FORMAT,
@ -40,6 +42,25 @@ enum {
FASTBOOT_COMMAND_COUNT
};
/**
* Reboot reasons
*/
enum fastboot_reboot_reason {
FASTBOOT_REBOOT_REASON_BOOTLOADER,
FASTBOOT_REBOOT_REASON_FASTBOOTD,
FASTBOOT_REBOOT_REASON_RECOVERY,
FASTBOOT_REBOOT_REASONS_COUNT
};
/**
* BCB boot commands
*/
static const char * const fastboot_boot_cmds[] = {
[FASTBOOT_REBOOT_REASON_BOOTLOADER] = "bootonce-bootloader",
[FASTBOOT_REBOOT_REASON_FASTBOOTD] = "boot-fastboot",
[FASTBOOT_REBOOT_REASON_RECOVERY] = "boot-recovery"
};
/**
* fastboot_response() - Writes a response of the form "$tag$reason".
*
@ -77,7 +98,7 @@ void fastboot_okay(const char *reason, char *response);
* which sets whatever flag your board specific Android bootloader flow
* requires in order to re-enter the bootloader.
*/
int fastboot_set_reboot_flag(void);
int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason);
/**
* fastboot_set_progress_callback() - set progress callback

View file

@ -921,6 +921,15 @@ struct ehci_ctrl;
*/
int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp);
/**
* usb_remove_ehci_gadget() - Remove a gadget USB device
*
* TODO(sjg@chromium.org): Tidy this up when USB gadgets can use driver model
*
* This provides a way to tell a controller to remove a USB device
*/
int usb_remove_ehci_gadget(struct ehci_ctrl **ctlrp);
/**
* usb_stor_reset() - Prepare to scan USB storage devices
*

View file

@ -25,7 +25,7 @@ struct ums {
struct blk_desc block_dev;
};
int fsg_init(struct ums *ums_devs, int count);
int fsg_init(struct ums *ums_devs, int count, unsigned int controller_idx);
void fsg_cleanup(void);
int fsg_main_thread(void *);
int fsg_add(struct usb_configuration *c);

View file

@ -227,6 +227,8 @@ static void fastboot_send(struct fastboot_header header, char *fastboot_data,
case FASTBOOT_COMMAND_REBOOT:
case FASTBOOT_COMMAND_REBOOT_BOOTLOADER:
case FASTBOOT_COMMAND_REBOOT_FASTBOOTD:
case FASTBOOT_COMMAND_REBOOT_RECOVERY:
do_reset(NULL, 0, 0, NULL);
break;
}