From d74a76234f1bbbb9c6266ebe55ce53be99a6df19 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Tue, 16 Jun 2020 17:09:44 +0800 Subject: eth/r8152: reset bmu after disabling Tx/Rx Reset bmu after disabling Tx/Rx. This is used to clear the FIFO of Tx/Rx. The remained data may be transferred after Tx/Rx is re-enabled. And it results in garbage data. Signed-off-by: Hayes Wang --- drivers/usb/eth/r8152.c | 14 ++++++++++++++ drivers/usb/eth/r8152.h | 7 ++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/eth/r8152.c b/drivers/usb/eth/r8152.c index 1845d957f9..8cefacbd7e 100644 --- a/drivers/usb/eth/r8152.c +++ b/drivers/usb/eth/r8152.c @@ -568,6 +568,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; @@ -786,6 +797,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 +844,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 +886,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) diff --git a/drivers/usb/eth/r8152.h b/drivers/usb/eth/r8152.h index 10e0da8eb1..4daf4ee87d 100644 --- a/drivers/usb/eth/r8152.h +++ b/drivers/usb/eth/r8152.h @@ -89,9 +89,10 @@ #define USB_TX_DMA 0xd434 #define USB_TOLERANCE 0xd490 #define USB_LPM_CTRL 0xd41a +#define USB_BMU_RESET 0xd4b0 #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_WDT11_CTRL 0xe43c #define USB_BP_BA 0xfc26 @@ -324,6 +325,10 @@ #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 -- cgit From 16b9417b6ac64e8942064960a7e9b6fc8502a0a3 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Tue, 16 Jun 2020 17:09:45 +0800 Subject: eth/r8152: reset PHY after setting it Some settings of PHY have to work after resetting PHY. Signed-off-by: Hayes Wang --- drivers/usb/eth/r8152.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/eth/r8152.c b/drivers/usb/eth/r8152.c index 8cefacbd7e..421293407f 100644 --- a/drivers/usb/eth/r8152.c +++ b/drivers/usb/eth/r8152.c @@ -947,7 +947,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) -- cgit From 9f6142aa0a456cda16aa01c3acbf3f22a7c1122f Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Tue, 16 Jun 2020 17:09:46 +0800 Subject: eth/r8152: modify rtl_clear_bp function The original rtl_clear_bp() is used to clear the firmware of both PLA and USB MCU. The new one could clear the firmware of PLA or USB independently. It is unnecessary to clear firmware, if there is no one to be updated. Besides, clear the firmware by writing the relative registers in bulk. Signed-off-by: Hayes Wang --- drivers/usb/eth/r8152.h | 13 +++-------- drivers/usb/eth/r8152_fw.c | 58 ++++++++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/eth/r8152.h b/drivers/usb/eth/r8152.h index 4daf4ee87d..710637d7a2 100644 --- a/drivers/usb/eth/r8152.h +++ b/drivers/usb/eth/r8152.h @@ -95,16 +95,9 @@ #define USB_MISC_0 0xd81a #define USB_AFE_CTRL2 0xd824 #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 /* OCP Registers */ #define OCP_ALDPS_CONFIG 0x2010 diff --git a/drivers/usb/eth/r8152_fw.c b/drivers/usb/eth/r8152_fw.c index f953b0384b..2da1f221b4 100644 --- a/drivers/usb/eth/r8152_fw.c +++ b/drivers/usb/eth/r8152_fw.c @@ -729,28 +729,30 @@ 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 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; + default: + break; + } - mdelay(6); + generic_ocp_write(tp, USB_BP(0), 0xff, sizeof(zeros), zeros, type); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); -} + mdelay(6); -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 +828,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 +849,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 +868,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 +887,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 +905,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 +935,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 +955,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 +991,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 +1002,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); -- cgit From 3a41086f6afabdeed115f33bedd66eb832dacb86 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Tue, 16 Jun 2020 17:09:47 +0800 Subject: eth/r8152: support RTL8153B/RTL8154B This is used to support RTL8153B and RTL8154B. Signed-off-by: Hayes Wang --- drivers/usb/eth/r8152.c | 207 ++++++++++++++++++++++++++++++++++++++++++++- drivers/usb/eth/r8152.h | 41 ++++++++- drivers/usb/eth/r8152_fw.c | 170 +++++++++++++++++++++++++++++++++++++ 3 files changed, 414 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/eth/r8152.c b/drivers/usb/eth/r8152.c index 421293407f..215bcbbef8 100644 --- a/drivers/usb/eth/r8152.c +++ b/drivers/usb/eth/r8152.c @@ -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; @@ -784,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; @@ -991,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; @@ -1154,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) @@ -1194,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"); diff --git a/drivers/usb/eth/r8152.h b/drivers/usb/eth/r8152.h index 710637d7a2..fa57e42502 100644 --- a/drivers/usb/eth/r8152.h +++ b/drivers/usb/eth/r8152.h @@ -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,19 +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_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 PLA_BP_BA #define USB_BP(n) (0xfc28 + 2 * (n)) -#define USB_BP_EN PLA_BP_EN +#define USB_BP_EN PLA_BP_EN /* RTL8153A */ +#define USB_BP2_EN 0xfc48 /* OCP Registers */ #define OCP_ALDPS_CONFIG 0x2010 @@ -108,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 @@ -117,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 @@ -201,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 @@ -224,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 @@ -249,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 @@ -306,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 @@ -314,6 +335,9 @@ #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 @@ -364,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 @@ -375,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 @@ -427,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 @@ -571,6 +605,8 @@ enum rtl_version { RTL_VER_05, RTL_VER_06, RTL_VER_07, + RTL_VER_08, + RTL_VER_09, RTL_VER_MAX }; @@ -638,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 diff --git a/drivers/usb/eth/r8152_fw.c b/drivers/usb/eth/r8152_fw.c index 2da1f221b4..a41abed306 100644 --- a/drivers/usb/eth/r8152_fw.c +++ b/drivers/usb/eth/r8152_fw.c @@ -729,6 +729,127 @@ static u16 r8153_pla_patch_d_bp[] = { 0xfc2e, 0x0000, 0xfc30, 0x0000, 0xfc32, 0x0000, 0xfc34, 0x0000, 0xfc36, 0x0000, 0xfc38, 0x0007 }; +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) { u8 zeros[16] = {0}; @@ -744,7 +865,17 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) 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; } @@ -1022,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); +} -- cgit From 213fa47dacf07d11f094ff58a5695cd0c425e164 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Mon, 29 Jun 2020 10:12:26 +0800 Subject: usb: gadget: Fix controller index in UMS The usb mass storage (f_mass_storage.c) uses fixed usb index 0, this causes problem while CDNS3 USB controller index is 1. Modify the API of fsg to pass the controller index. Reviewed-by: Jun Li Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/usb/gadget/f_mass_storage.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 439a31c255..45f0504b6e 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -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; } -- cgit From 1468a1cc72afa210c35a4d0ed533de29110de648 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Mon, 29 Jun 2020 10:12:59 +0800 Subject: usb: ci_udc: Add function to remove usb device When unregister gadget driver in ci_udc, the usb device is not removed or stop. This causes next "usb start" fails to work. Add a new interface "usb_remove_ehci_gadget" in usb-uclass to remove the usb device for DM driver. Using "usb_lowlevel_stop" for non-DM driver. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/usb/gadget/ci_udc.c | 7 +++++++ drivers/usb/host/usb-uclass.c | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index cdbdbcc5ca..cdb8f6fb3d 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -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; } diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index e5dda79b94..8773824e05 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -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) -- cgit From a17c0cb85e3abe8601efaadbb287116d1142fefd Mon Sep 17 00:00:00 2001 From: Filip Brozovic Date: Mon, 29 Jun 2020 13:14:37 +0200 Subject: fastboot: Support defining raw partitions without a partition table Add support for defining raw fastboot partitions in eMMC by specifying the offset and size in an environment variable. Optionally, the eMMC hardware partition number may also be specified. This makes it possible to e.g. update only part of the eMMC boot partition, instead of having to write the entire partition. Signed-off-by: Filip Brozovic --- drivers/fastboot/fb_mmc.c | 75 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index b2f8932e1c..ae8e8e512f 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -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 + * + * [mmcpart ] + */ + 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,10 +431,12 @@ int fastboot_mmc_get_part_info(const char *part_name, return -ENOENT; } - 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; + 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; -- cgit From 40c79420d0a70fe0f52f79ab9a8147a2a5e38e2c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 21 Jul 2020 20:06:31 +0200 Subject: dfu: DFU_MTD depends on CMD_MTDPARTS Function mtdparts_init() is needed for the DFU MTD driver. Signed-off-by: Heinrich Schuchardt --- drivers/dfu/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index 5d45d7d7c2..0eec00ba73 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -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. -- cgit From 73f4ebb659df4996e154b17f14866fb166447be0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 22 Jul 2020 17:46:02 +0200 Subject: dfu: fix dfu tftp on sandbox The environment variable loadaddr is in the virtual address space of the sandbox. To get the actual memory address where the FIT image has been loaded we have to convert this address according to the memory mapping of the sandbox. Equally the addresses in the *.its file have to be converted when used in the dfu_ram driver. Signed-off-by: Heinrich Schuchardt --- drivers/dfu/dfu_ram.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dfu/dfu_ram.c b/drivers/dfu/dfu_ram.c index cc98668e7a..ab0ce9e6fa 100644 --- a/drivers/dfu/dfu_ram.c +++ b/drivers/dfu/dfu_ram.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -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; -- cgit From 851737ab8922742732bea5f70407cb95cafcb3ee Mon Sep 17 00:00:00 2001 From: Roman Kovalivskyi Date: Tue, 28 Jul 2020 23:35:32 +0300 Subject: fastboot: Extend fastboot_set_reboot_flag with reboot reason Extend fastboot_set_reboot_flag arguments with reboot reason so that it could handle different reboot cases in future. Signed-off-by: Roman Kovalivskyi --- drivers/fastboot/fb_command.c | 2 +- drivers/fastboot/fb_common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 49f6a61c37..8ce5d32fb2 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -307,7 +307,7 @@ 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); diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c index c3735a44af..736ce1cd02 100644 --- a/drivers/fastboot/fb_common.c +++ b/drivers/fastboot/fb_common.c @@ -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; } -- cgit From 2b2a771b40876c3db456705d5dcc5b60249d4075 Mon Sep 17 00:00:00 2001 From: Roman Kovalivskyi Date: Tue, 28 Jul 2020 23:35:33 +0300 Subject: fastboot: Add support for 'reboot fastboot' command Android 10 adds support for dynamic partitions and in order to support this userspace fastboot must be used[1]. New tool fastbootd is included into recovery. Userspace fastboot works from recovery and is launched if: 1) - Dynamic partitioning is enabled 2) - Boot control block has 'boot-fastboot' value into command field The bootloader is expected to load and boot into the recovery image upon seeing boot-fastboot in the BCB command. Recovery then parses the BCB message and switches to fastbootd mode[2]. Please note that boot script is expected to handle 'boot-fastboot' command in BCB and load into recovery mode. Bootloader must support 'reboot fastboot' command which should reboot device into userspace fastboot to accomodate those changes[3]. Another command that bootloader must support[3] is 'reboot recovery'. This command should simply reboot device into recovery mode. [1] - https://source.android.com/devices/bootloader/fastbootd [2] - https://source.android.com/devices/bootloader/fastbootd#unified_fastboot_and_recovery [3] - https://source.android.com/devices/bootloader/fastbootd#modifications_to_the_bootloader Signed-off-by: Roman Kovalivskyi Signed-off-by: Roman Stratiienko Change-Id: I9d2bdc9a6f6f31ea98572fe155e1cc8341e9af76 --- drivers/fastboot/fb_command.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/f_fastboot.c | 2 ++ 2 files changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 8ce5d32fb2..d3c578672d 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -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 @@ -313,6 +323,34 @@ static void reboot_bootloader(char *cmd_parameter, char *response) 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 diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 384c0f6f6e..30f7a52087 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -455,6 +455,8 @@ 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; } -- cgit From 0ebf9842e56c5b8cb7cb1f990bb452cc14af6225 Mon Sep 17 00:00:00 2001 From: Roman Kovalivskyi Date: Tue, 28 Jul 2020 23:35:34 +0300 Subject: fastboot: Add default fastboot_set_reboot_flag implementation Default implementation of fastboot_set_reboot_flag function that depends on "bcb" commands could be used in general case if there are no need to make any platform-specific implementation, otherwise it could be disabled via Kconfig option FASTBOOT_USE_BCB_SET_REBOOT_FLAG. Please note that FASTBOOT_USE_BCB_SET_REBOOT_FLAG is mutually exclusive with some platforms which already have their own implementation of this function. Signed-off-by: Roman Kovalivskyi --- drivers/fastboot/Kconfig | 12 ++++++++++++ drivers/fastboot/Makefile | 1 + drivers/fastboot/fb_bcb_impl.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 drivers/fastboot/fb_bcb_impl.c (limited to 'drivers') diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index d4436dfc91..4352ba67a7 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -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 diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile index 048af5aa82..2b2c390fe4 100644 --- a/drivers/fastboot/Makefile +++ b/drivers/fastboot/Makefile @@ -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 diff --git a/drivers/fastboot/fb_bcb_impl.c b/drivers/fastboot/fb_bcb_impl.c new file mode 100644 index 0000000000..89ec3601b6 --- /dev/null +++ b/drivers/fastboot/fb_bcb_impl.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 GlobalLogic. + * Roman Kovalivskyi + */ + +#include +#include + +/** + * 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; +} -- cgit From 7ed4eac43d672b8f6cefa6bf92fcaacf7dda0f7c Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 29 Jul 2020 20:51:27 -0500 Subject: usb: max3420: add the gadget driver MAX3420 implements FullSpeed USB Device over SPI. Another version MAX3421, also implements USB Host mode. This driver should be good for the device mode of max3421 as well. Signed-off-by: Jassi Brar --- drivers/usb/gadget/Kconfig | 6 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/gadget_chips.h | 8 + drivers/usb/gadget/max3420_udc.c | 875 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 890 insertions(+) create mode 100644 drivers/usb/gadget/max3420_udc.c (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 46aa3fe954..7c0df5c264 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -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 diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 70f3bf43e7..f560068b41 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -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 diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 91b0285244..587204cfb7 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -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; } diff --git a/drivers/usb/gadget/max3420_udc.c b/drivers/usb/gadget/max3420_udc.c new file mode 100644 index 0000000000..b38b9dc68f --- /dev/null +++ b/drivers/usb/gadget/max3420_udc.c @@ -0,0 +1,875 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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), +}; -- cgit From d10d429112b78c69099c57fa219230539502e543 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 18 Aug 2020 18:16:44 +0800 Subject: f_sdp: Add high speed endpoint descriptor Add HS endpoint descriptor for SDP. So that we can use high speed endpoint, and the SDP device can send packet with 512 byte size. Signed-off-by: Ye Li Signed-off-by: Peng Fan Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/f_sdp.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index f2fe89d2a6..f971ccdeca 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -159,6 +159,16 @@ static struct usb_endpoint_descriptor in_desc = { .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 = 1, +}; + static struct usb_descriptor_header *sdp_runtime_descs[] = { (struct usb_descriptor_header *)&sdp_intf_runtime, (struct usb_descriptor_header *)&sdp_hid_desc, @@ -166,6 +176,13 @@ static struct usb_descriptor_header *sdp_runtime_descs[] = { 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, + NULL, +}; + /* This is synchronized with what the SoC implementation reports */ static struct hid_report sdp_hid_report = { .usage_page = { @@ -489,6 +506,11 @@ static int sdp_bind(struct usb_configuration *c, struct usb_function *f) goto error; } + if (gadget_is_dualspeed(gadget)) { + /* Assume endpoint addresses are the same for both speeds */ + in_hs_desc.bEndpointAddress = in_desc.bEndpointAddress; + } + sdp->in_ep = ep; /* Store IN EP for enabling @ setup */ cdev->req->context = sdp; @@ -541,11 +563,15 @@ 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); - result = usb_ep_enable(sdp->in_ep, &in_desc); + if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) + result = usb_ep_enable(sdp->in_ep, &in_hs_desc); + else + result = usb_ep_enable(sdp->in_ep, &in_desc); if (result) return result; sdp->in_req = sdp_start_ep(sdp->in_ep); @@ -591,7 +617,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; -- cgit From 5dee7f0b0233f8b4e43e1212a6a96cdee835a8e6 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 18 Aug 2020 18:16:45 +0800 Subject: f_sdp: Fix wrong usb request size Because the buffer length of sdp usb request is 65, we have to allocate 65 bytes not 64 bytes. Otherwise there is potential buffer overflow. Signed-off-by: Ye Li Signed-off-by: Peng Fan Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/f_sdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index f971ccdeca..eec7560fc2 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -548,7 +548,7 @@ static struct usb_request *sdp_start_ep(struct usb_ep *ep) { struct usb_request *req; - req = alloc_ep_req(ep, 64); + req = alloc_ep_req(ep, 65); debug("%s: ep:%p req:%p\n", __func__, ep, req); if (!req) -- cgit From b0e9f3e593c0ed1356ff05d99d7a562dc4bf228d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 18 Aug 2020 18:16:46 +0800 Subject: f_sdp: Support searching and loading FIT or container image Add support to f_sdp to search and load iMX8 container image or iMX8M FIT image by new UUU command SDPV. When using the SDPV, the uuu will continue to send out data after first level boot loader used by ROM. This means uuu won't skip to the offset of the second boot loader, and the padding data before second boot loader will be sent out. So we have to search the FIT header or container header in the buffer that SDP received. Also change to more common method to exit f_sdp handler not depending on SPL_FIT_FOUND flag because container loader won't set this. Signed-off-by: Peng Fan --- drivers/usb/gadget/f_sdp.c | 70 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index eec7560fc2..9b7372815d 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -71,6 +71,8 @@ struct hid_report { #define SDP_COMMAND_LEN 16 +#define SDP_EXIT 1 + struct sdp_command { u16 cmd; u32 addr; @@ -667,19 +669,43 @@ 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, - ulong count, void *buf) +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", __func__, sector, count, (ulong)buf); 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; @@ -731,6 +757,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 @@ -740,13 +775,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); @@ -769,6 +814,8 @@ static void sdp_handle_in_ep(struct spl_image_info *spl_image) default: break; }; + + return 0; } #ifndef CONFIG_SPL_BUILD @@ -777,6 +824,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()) { @@ -784,18 +832,16 @@ 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 } } -- cgit From 9e06c5c55a60bea001c82ad32f48177eddda0d38 Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Tue, 18 Aug 2020 18:16:48 +0800 Subject: f_sdp: Add EP1_OUT as default data receive pipe in sdp EP0 has been used to transfer file data in sdp before, but the max packetsize of ep0 is 64 bytes. So in order to improve the file transfer speed, here add the EP1_OUT interrupt endpoint which max packetsize is set to 1024 byte. After testing, it turns out that using ep1out is twice as fast as using ep0 while receiving data in sdp. Signed-off-by: Sherry Sun Reviewed-by: Ye Li Signed-off-by: Peng Fan --- drivers/usb/gadget/f_sdp.c | 123 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index 9b7372815d..c5b35945c1 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -71,6 +71,8 @@ struct hid_report { #define SDP_COMMAND_LEN 16 +#define SDP_HID_PACKET_SIZE_EP1 1024 + #define SDP_EXIT 1 struct sdp_command { @@ -84,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, @@ -116,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; @@ -131,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, @@ -161,6 +169,16 @@ 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*/ @@ -171,10 +189,21 @@ static struct usb_endpoint_descriptor in_hs_desc = { .bInterval = 1, }; +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 = 1, +}; + 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, }; @@ -182,6 +211,7 @@ 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, }; @@ -347,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); @@ -370,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); @@ -384,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: @@ -465,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; } } @@ -499,11 +533,17 @@ 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; + } + + ep_out = usb_ep_autoconfig(gadget, &out_desc); + if (!ep_out) { rv = -ENODEV; goto error; } @@ -511,9 +551,11 @@ static int sdp_bind(struct usb_configuration *c, struct usb_function *f) 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; /* Store IN EP for enabling @ setup */ + sdp->in_ep = ep_in; /* Store IN EP for enabling @ setup */ + sdp->out_ep = ep_out; cdev->req->context = sdp; @@ -546,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, 65); + 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); - req->complete = sdp_tx_complete; + if (in) + req->complete = sdp_tx_complete; + else + req->complete = sdp_rx_command_complete; return req; } @@ -570,19 +623,27 @@ static int sdp_set_alt(struct usb_function *f, unsigned intf, unsigned alt) debug("%s: intf: %d alt: %d\n", __func__, intf, alt); - if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) { result = usb_ep_enable(sdp->in_ep, &in_hs_desc); - else + 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; } @@ -599,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) @@ -818,6 +886,27 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image) 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 int sdp_handle(int controller_index) #else @@ -843,6 +932,8 @@ int spl_sdp_handle(int controller_index, struct spl_image_info *spl_image) #else flag = sdp_handle_in_ep(NULL); #endif + if (sdp_func->ep_int_enable) + sdp_handle_out_ep(); } } -- cgit From 405217a0332aa33e33fb579d75bc7f420c27bcd1 Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Tue, 18 Aug 2020 18:16:49 +0800 Subject: f_sdp: Change bInterval of interrupt endpoint to 3 Since the USB HID limits the maximum bandwidth(3072) for interrupt endpoint transfers, when the bInterval set to 1, we can only support 3 boards to run sdp at the same time. In order to support more boards, change the bInterval of interrupt endpoint to 3, which will not affect the transmission speed. Reviewed-by: Ye Li Signed-off-by: Sherry Sun Signed-off-by: Peng Fan --- drivers/usb/gadget/f_sdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index c5b35945c1..e48aa2f90d 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -186,7 +186,7 @@ static struct usb_endpoint_descriptor in_hs_desc = { .bEndpointAddress = 1 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = 512, - .bInterval = 1, + .bInterval = 3, }; static struct usb_endpoint_descriptor out_hs_desc = { @@ -196,7 +196,7 @@ static struct usb_endpoint_descriptor out_hs_desc = { .bEndpointAddress = 1 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = SDP_HID_PACKET_SIZE_EP1, - .bInterval = 1, + .bInterval = 3, }; static struct usb_descriptor_header *sdp_runtime_descs[] = { -- cgit From 64af06ce91d1b2f7819a273e56f7c41186a7588b Mon Sep 17 00:00:00 2001 From: "yurii.pidhornyi" Date: Thu, 20 Aug 2020 18:41:18 +0300 Subject: fastboot: Fix fastboot reboot fail by changing functions order It was revealed that when the fastboot_tx_write_str function is called without the previously initialized fastboot_func->in_req->complete field, a copy of in_req will be sent to the I/O requests queue without an initialized field. Moving a piece of code with the initializing of the fastboot_func->in_req->complete field above transmit_tx allows to solve this problem. Fixes: 65c96757fe9 "usb: fastboot: Convert USB f_fastboot to shared fastboot" Signed-off-by: yurii.pidhornyi --- drivers/usb/gadget/f_fastboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 30f7a52087..d1d087e12b 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -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: @@ -462,6 +460,8 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) } } + fastboot_tx_write_str(response); + *cmdbuf = '\0'; req->actual = 0; usb_ep_queue(ep, req, 0); -- cgit From 293a6dfeb96129abebf1ad927fa9aedf03a66d34 Mon Sep 17 00:00:00 2001 From: Gary Bisson Date: Thu, 27 Aug 2020 10:51:14 +0200 Subject: fastboot: getvar: fix partition-size return value The size returned by 'getvar partition-size' should be in bytes, not in blocks as fastboot uses that value to generate empty partition when running format [1]. Note that the function was already returning the proper size in bytes for NAND devices (see struct part_info details). [1] https://android.googlesource.com/platform/system/core/+/refs/heads/android10-release/fastboot/fastboot.cpp#1500 Signed-off-by: Gary Bisson --- drivers/fastboot/fb_getvar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_getvar.c b/drivers/fastboot/fb_getvar.c index 52da34b1e3..d43f2cfee6 100644 --- a/drivers/fastboot/fb_getvar.c +++ b/drivers/fastboot/fb_getvar.c @@ -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; -- cgit