/* * Renesas USB3.0 Peripheral driver (USB gadget) * * Copyright (C) 2015 Renesas Electronics Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. */ #include #include #include #include #include #include #include #include #include #include #include #include /* register definitions */ #define USB3_AXI_INT_STA 0x008 #define USB3_AXI_INT_ENA 0x00c #define USB3_DMA_INT_STA 0x010 #define USB3_DMA_INT_ENA 0x014 #define USB3_USB_COM_CON 0x200 #define USB3_USB20_CON 0x204 #define USB3_USB30_CON 0x208 #define USB3_USB_STA 0x210 #define USB3_DRD_CON 0x218 #define USB3_USB_INT_STA_1 0x220 #define USB3_USB_INT_STA_2 0x224 #define USB3_USB_INT_ENA_1 0x228 #define USB3_USB_INT_ENA_2 0x22c #define USB3_STUP_DAT_0 0x230 #define USB3_STUP_DAT_1 0x234 #define USB3_P0_MOD 0x280 #define USB3_P0_CON 0x288 #define USB3_P0_STA 0x28c #define USB3_P0_INT_STA 0x290 #define USB3_P0_INT_ENA 0x294 #define USB3_P0_LNG 0x2a0 #define USB3_P0_READ 0x2a4 #define USB3_P0_WRITE 0x2a8 #define USB3_PIPE_COM 0x2b0 #define USB3_PN_MOD 0x2c0 #define USB3_PN_RAMMAP 0x2c4 #define USB3_PN_CON 0x2c8 #define USB3_PN_STA 0x2cc #define USB3_PN_INT_STA 0x2d0 #define USB3_PN_INT_ENA 0x2d4 #define USB3_PN_LNG 0x2e0 #define USB3_PN_READ 0x2e4 #define USB3_PN_WRITE 0x2e8 #define USB3_SSIFCMD 0x340 /* AXI_INT_ENA and AXI_INT_STA */ #define AXI_INT_DMAINT BIT(31) #define AXI_INT_EPCINT BIT(30) /* LCLKSEL */ #define LCLKSEL_LSEL BIT(18) /* USB_COM_CON */ #define USB_COM_CON_CONF BIT(24) #define USB_COM_CON_SPD_MODE BIT(17) #define USB_COM_CON_EP0_EN BIT(16) #define USB_COM_CON_DEV_ADDR_SHIFT 8 #define USB_COM_CON_DEV_ADDR_MASK GENMASK(14, USB_COM_CON_DEV_ADDR_SHIFT) #define USB_COM_CON_DEV_ADDR(n) (((n) << USB_COM_CON_DEV_ADDR_SHIFT) & \ USB_COM_CON_DEV_ADDR_MASK) #define USB_COM_CON_RX_DETECTION BIT(1) #define USB_COM_CON_PIPE_CLR BIT(0) /* USB20_CON */ #define USB20_CON_B2_PUE BIT(31) #define USB20_CON_B2_SUSPEND BIT(24) #define USB20_CON_B2_CONNECT BIT(17) #define USB20_CON_B2_TSTMOD_SHIFT 8 #define USB20_CON_B2_TSTMOD_MASK GENMASK(10, USB20_CON_B2_TSTMOD_SHIFT) #define USB20_CON_B2_TSTMOD(n) (((n) << USB20_CON_B2_TSTMOD_SHIFT) & \ USB20_CON_B2_TSTMOD_MASK) #define USB20_CON_B2_TSTMOD_EN BIT(0) /* USB30_CON */ #define USB30_CON_POW_SEL_SHIFT 24 #define USB30_CON_POW_SEL_MASK GENMASK(26, USB30_CON_POW_SEL_SHIFT) #define USB30_CON_POW_SEL_IN_U3 BIT(26) #define USB30_CON_POW_SEL_IN_DISCON 0 #define USB30_CON_POW_SEL_P2_TO_P0 BIT(25) #define USB30_CON_POW_SEL_P0_TO_P3 BIT(24) #define USB30_CON_POW_SEL_P0_TO_P2 0 #define USB30_CON_B3_PLLWAKE BIT(23) #define USB30_CON_B3_CONNECT BIT(17) #define USB30_CON_B3_HOTRST_CMP BIT(1) /* USB_STA */ #define USB_STA_SPEED_MASK (BIT(2) | BIT(1)) #define USB_STA_SPEED_HS BIT(2) #define USB_STA_SPEED_FS BIT(1) #define USB_STA_SPEED_SS 0 #define USB_STA_VBUS_STA BIT(0) /* DRD_CON */ #define DRD_CON_PERI_CON BIT(24) /* USB_INT_ENA_1 and USB_INT_STA_1 */ #define USB_INT_1_B3_PLLWKUP BIT(31) #define USB_INT_1_B3_LUPSUCS BIT(30) #define USB_INT_1_B3_DISABLE BIT(27) #define USB_INT_1_B3_WRMRST BIT(21) #define USB_INT_1_B3_HOTRST BIT(20) #define USB_INT_1_B2_USBRST BIT(12) #define USB_INT_1_B2_L1SPND BIT(11) #define USB_INT_1_B2_SPND BIT(9) #define USB_INT_1_B2_RSUM BIT(8) #define USB_INT_1_SPEED BIT(1) #define USB_INT_1_VBUS_CNG BIT(0) /* USB_INT_ENA_2 and USB_INT_STA_2 */ #define USB_INT_2_PIPE(n) BIT(n) /* P0_MOD */ #define P0_MOD_DIR BIT(6) /* P0_CON and PN_CON */ #define PX_CON_BYTE_EN_MASK (BIT(10) | BIT(9)) #define PX_CON_BYTE_EN_SHIFT 9 #define PX_CON_BYTE_EN_BYTES(n) (((n) << PX_CON_BYTE_EN_SHIFT) & \ PX_CON_BYTE_EN_MASK) #define PX_CON_SEND BIT(8) /* P0_CON */ #define P0_CON_ST_RES_MASK (BIT(27) | BIT(26)) #define P0_CON_ST_RES_FORCE_STALL BIT(27) #define P0_CON_ST_RES_NORMAL BIT(26) #define P0_CON_ST_RES_FORCE_NRDY 0 #define P0_CON_OT_RES_MASK (BIT(25) | BIT(24)) #define P0_CON_OT_RES_FORCE_STALL BIT(25) #define P0_CON_OT_RES_NORMAL BIT(24) #define P0_CON_OT_RES_FORCE_NRDY 0 #define P0_CON_IN_RES_MASK (BIT(17) | BIT(16)) #define P0_CON_IN_RES_FORCE_STALL BIT(17) #define P0_CON_IN_RES_NORMAL BIT(16) #define P0_CON_IN_RES_FORCE_NRDY 0 #define P0_CON_RES_WEN BIT(7) #define P0_CON_BCLR BIT(1) /* P0_STA and PN_STA */ #define PX_STA_BUFSTS BIT(0) /* P0_INT_ENA and P0_INT_STA */ #define P0_INT_STSED BIT(18) #define P0_INT_STSST BIT(17) #define P0_INT_SETUP BIT(16) #define P0_INT_RCVNL BIT(8) #define P0_INT_ERDY BIT(7) #define P0_INT_FLOW BIT(6) #define P0_INT_STALL BIT(2) #define P0_INT_NRDY BIT(1) #define P0_INT_BFRDY BIT(0) #define P0_INT_ALL_BITS (P0_INT_STSED | P0_INT_SETUP | P0_INT_BFRDY) /* PN_MOD */ #define PN_MOD_DIR BIT(6) #define PN_MOD_TYPE_SHIFT 4 #define PN_MOD_TYPE_MASK GENMASK(5, PN_MOD_TYPE_SHIFT) #define PN_MOD_TYPE(n) (((n) << PN_MOD_TYPE_SHIFT) & \ PN_MOD_TYPE_MASK) #define PN_MOD_EPNUM_MASK GENMASK(3, 0) #define PN_MOD_EPNUM(n) ((n) & PN_MOD_EPNUM_MASK) /* PN_RAMMAP */ #define PN_RAMMAP_RAMAREA_SHIFT 29 #define PN_RAMMAP_RAMAREA_MASK GENMASK(31, PN_RAMMAP_RAMAREA_SHIFT) #define PN_RAMMAP_RAMAREA_16KB BIT(31) #define PN_RAMMAP_RAMAREA_8KB (BIT(30) | BIT(29)) #define PN_RAMMAP_RAMAREA_4KB BIT(30) #define PN_RAMMAP_RAMAREA_2KB BIT(29) #define PN_RAMMAP_RAMAREA_1KB 0 #define PN_RAMMAP_MPKT_SHIFT 16 #define PN_RAMMAP_MPKT_MASK GENMASK(26, PN_RAMMAP_MPKT_SHIFT) #define PN_RAMMAP_MPKT(n) (((n) << PN_RAMMAP_MPKT_SHIFT) & \ PN_RAMMAP_MPKT_MASK) #define PN_RAMMAP_RAMIF_SHIFT 14 #define PN_RAMMAP_RAMIF_MASK GENMASK(15, PN_RAMMAP_RAMIF_SHIFT) #define PN_RAMMAP_RAMIF(n) (((n) << PN_RAMMAP_RAMIF_SHIFT) & \ PN_RAMMAP_RAMIF_MASK) #define PN_RAMMAP_BASEAD_MASK GENMASK(13, 0) #define PN_RAMMAP_BASEAD(offs) (((offs) >> 3) & PN_RAMMAP_BASEAD_MASK) #define PN_RAMMAP_DATA(area, ramif, basead) ((PN_RAMMAP_##area) | \ (PN_RAMMAP_RAMIF(ramif)) | \ (PN_RAMMAP_BASEAD(basead))) /* PN_CON */ #define PN_CON_EN BIT(31) #define PN_CON_DATAIF_EN BIT(30) #define PN_CON_RES_MASK (BIT(17) | BIT(16)) #define PN_CON_RES_FORCE_STALL BIT(17) #define PN_CON_RES_NORMAL BIT(16) #define PN_CON_RES_FORCE_NRDY 0 #define PN_CON_LAST BIT(11) #define PN_CON_RES_WEN BIT(7) #define PN_CON_CLR BIT(0) /* PN_INT_STA and PN_INT_ENA */ #define PN_INT_LSTTR BIT(4) #define PN_INT_BFRDY BIT(0) /* USB3_SSIFCMD */ #define SSIFCMD_URES_U2 BIT(9) #define SSIFCMD_URES_U1 BIT(8) #define SSIFCMD_UDIR_U2 BIT(7) #define SSIFCMD_UDIR_U1 BIT(6) #define SSIFCMD_UREQ_U2 BIT(5) #define SSIFCMD_UREQ_U1 BIT(4) #define USB3_EP0_SS_MAX_PACKET_SIZE 512 #define USB3_EP0_HSFS_MAX_PACKET_SIZE 64 #define USB3_EP0_BUF_SIZE 8 #define USB3_MAX_NUM_PIPES 30 #define USB3_WAIT_US 3 struct renesas_usb3; struct renesas_usb3_request { struct usb_request req; struct list_head queue; }; #define USB3_EP_NAME_SIZE 8 struct renesas_usb3_ep { struct usb_ep ep; struct renesas_usb3 *usb3; int num; char ep_name[USB3_EP_NAME_SIZE]; struct list_head queue; u32 rammap_val; bool dir_in; bool halt; bool wedge; bool started; }; struct renesas_usb3_priv { int ramsize_per_ramif; /* unit = bytes */ int num_ramif; int ramsize_per_pipe; /* unit = bytes */ bool workaround_for_vbus; /* if true, don't check vbus signal */ }; struct renesas_usb3 { void __iomem *reg; struct usb_gadget gadget; struct usb_gadget_driver *driver; struct renesas_usb3_ep *usb3_ep; int num_usb3_eps; spinlock_t lock; int disabled_count; struct usb_request *ep0_req; u16 test_mode; u8 ep0_buf[USB3_EP0_BUF_SIZE]; bool softconnect; bool workaround_for_vbus; }; #define gadget_to_renesas_usb3(_gadget) \ container_of(_gadget, struct renesas_usb3, gadget) #define renesas_usb3_to_gadget(renesas_usb3) (&renesas_usb3->gadget) #define usb3_to_dev(_usb3) (_usb3->gadget.dev.parent) #define usb_ep_to_usb3_ep(_ep) container_of(_ep, struct renesas_usb3_ep, ep) #define usb3_ep_to_usb3(_usb3_ep) (_usb3_ep->usb3) #define usb_req_to_usb3_req(_req) container_of(_req, \ struct renesas_usb3_request, req) #define usb3_get_ep(usb3, n) ((usb3)->usb3_ep + (n)) #define usb3_for_each_ep(usb3_ep, usb3, i) \ for ((i) = 0, usb3_ep = usb3_get_ep(usb3, (i)); \ (i) < (usb3)->num_usb3_eps; \ (i)++, usb3_ep = usb3_get_ep(usb3, (i))) static const char udc_name[] = "renesas_usb3"; static void usb3_write(struct renesas_usb3 *usb3, u32 data, u32 offs) { iowrite32(data, usb3->reg + offs); } static u32 usb3_read(struct renesas_usb3 *usb3, u32 offs) { return ioread32(usb3->reg + offs); } static void usb3_set_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs) { u32 val = usb3_read(usb3, offs); val |= bits; usb3_write(usb3, val, offs); } static void usb3_clear_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs) { u32 val = usb3_read(usb3, offs); val &= ~bits; usb3_write(usb3, val, offs); } static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask, u32 expected) { int i; for (i = 0; i < USB3_WAIT_US; i++) { if ((usb3_read(usb3, reg) & mask) == expected) return 0; udelay(1); } dev_dbg(usb3_to_dev(usb3), "%s: timed out (%8x, %08x, %08x)\n", __func__, reg, mask, expected); return -EBUSY; } static void usb3_enable_irq_1(struct renesas_usb3 *usb3, u32 bits) { usb3_set_bit(usb3, bits, USB3_USB_INT_ENA_1); } static void usb3_disable_irq_1(struct renesas_usb3 *usb3, u32 bits) { usb3_clear_bit(usb3, bits, USB3_USB_INT_ENA_1); } static void usb3_enable_pipe_irq(struct renesas_usb3 *usb3, int num) { usb3_set_bit(usb3, USB_INT_2_PIPE(num), USB3_USB_INT_ENA_2); } static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num) { usb3_clear_bit(usb3, USB_INT_2_PIPE(num), USB3_USB_INT_ENA_2); } static void usb3_init_axi_bridge(struct renesas_usb3 *usb3) { /* Set AXI_INT */ usb3_write(usb3, ~0, USB3_DMA_INT_STA); usb3_write(usb3, 0, USB3_DMA_INT_ENA); usb3_set_bit(usb3, AXI_INT_DMAINT | AXI_INT_EPCINT, USB3_AXI_INT_ENA); } static void usb3_init_epc_registers(struct renesas_usb3 *usb3) { /* FIXME: How to change host / peripheral mode as well? */ usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON); usb3_write(usb3, ~0, USB3_USB_INT_STA_1); usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG); } static bool usb3_wakeup_usb2_phy(struct renesas_usb3 *usb3) { if (!(usb3_read(usb3, USB3_USB20_CON) & USB20_CON_B2_SUSPEND)) return true; /* already waked it up */ usb3_clear_bit(usb3, USB20_CON_B2_SUSPEND, USB3_USB20_CON); usb3_enable_irq_1(usb3, USB_INT_1_B2_RSUM); return false; } static void usb3_usb2_pullup(struct renesas_usb3 *usb3, int pullup) { u32 bits = USB20_CON_B2_PUE | USB20_CON_B2_CONNECT; if (usb3->softconnect && pullup) usb3_set_bit(usb3, bits, USB3_USB20_CON); else usb3_clear_bit(usb3, bits, USB3_USB20_CON); } static void usb3_set_test_mode(struct renesas_usb3 *usb3) { u32 val = usb3_read(usb3, USB3_USB20_CON); val &= ~USB20_CON_B2_TSTMOD_MASK; val |= USB20_CON_B2_TSTMOD(usb3->test_mode); usb3_write(usb3, val | USB20_CON_B2_TSTMOD_EN, USB3_USB20_CON); if (!usb3->test_mode) usb3_clear_bit(usb3, USB20_CON_B2_TSTMOD_EN, USB3_USB20_CON); } static void usb3_start_usb2_connection(struct renesas_usb3 *usb3) { usb3->disabled_count++; usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON); usb3_set_bit(usb3, USB_COM_CON_SPD_MODE, USB3_USB_COM_CON); usb3_usb2_pullup(usb3, 1); } static int usb3_is_usb3_phy_in_u3(struct renesas_usb3 *usb3) { return usb3_read(usb3, USB3_USB30_CON) & USB30_CON_POW_SEL_IN_U3; } static bool usb3_wakeup_usb3_phy(struct renesas_usb3 *usb3) { if (!usb3_is_usb3_phy_in_u3(usb3)) return true; /* already waked it up */ usb3_set_bit(usb3, USB30_CON_B3_PLLWAKE, USB3_USB30_CON); usb3_enable_irq_1(usb3, USB_INT_1_B3_PLLWKUP); return false; } static u16 usb3_feature_get_un_enabled(struct renesas_usb3 *usb3) { u32 mask_u2 = SSIFCMD_UDIR_U2 | SSIFCMD_UREQ_U2; u32 mask_u1 = SSIFCMD_UDIR_U1 | SSIFCMD_UREQ_U1; u32 val = usb3_read(usb3, USB3_SSIFCMD); u16 ret = 0; /* Enables {U2,U1} if the bits of UDIR and UREQ are set to 0 */ if (!(val & mask_u2)) ret |= 1 << USB_DEV_STAT_U2_ENABLED; if (!(val & mask_u1)) ret |= 1 << USB_DEV_STAT_U1_ENABLED; return ret; } static void usb3_feature_u2_enable(struct renesas_usb3 *usb3, bool enable) { u32 bits = SSIFCMD_UDIR_U2 | SSIFCMD_UREQ_U2; /* Enables U2 if the bits of UDIR and UREQ are set to 0 */ if (enable) usb3_clear_bit(usb3, bits, USB3_SSIFCMD); else usb3_set_bit(usb3, bits, USB3_SSIFCMD); } static void usb3_feature_u1_enable(struct renesas_usb3 *usb3, bool enable) { u32 bits = SSIFCMD_UDIR_U1 | SSIFCMD_UREQ_U1; /* Enables U1 if the bits of UDIR and UREQ are set to 0 */ if (enable) usb3_clear_bit(usb3, bits, USB3_SSIFCMD); else usb3_set_bit(usb3, bits, USB3_SSIFCMD); } static void usb3_start_operation_for_usb3(struct renesas_usb3 *usb3) { usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON); usb3_clear_bit(usb3, USB_COM_CON_SPD_MODE, USB3_USB_COM_CON); usb3_set_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON); } static void usb3_start_usb3_connection(struct renesas_usb3 *usb3) { usb3_start_operation_for_usb3(usb3); usb3_set_bit(usb3, USB_COM_CON_RX_DETECTION, USB3_USB_COM_CON); usb3_enable_irq_1(usb3, USB_INT_1_B3_LUPSUCS | USB_INT_1_B3_DISABLE | USB_INT_1_SPEED); } static void usb3_stop_usb3_connection(struct renesas_usb3 *usb3) { usb3_clear_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON); } static void usb3_transition_to_default_state(struct renesas_usb3 *usb3, bool is_usb3) { usb3_set_bit(usb3, USB_INT_2_PIPE(0), USB3_USB_INT_ENA_2); usb3_write(usb3, P0_INT_ALL_BITS, USB3_P0_INT_STA); usb3_set_bit(usb3, P0_INT_ALL_BITS, USB3_P0_INT_ENA); if (is_usb3) usb3_enable_irq_1(usb3, USB_INT_1_B3_WRMRST | USB_INT_1_B3_HOTRST); else usb3_enable_irq_1(usb3, USB_INT_1_B2_SPND | USB_INT_1_B2_L1SPND | USB_INT_1_B2_USBRST); } static void usb3_connect(struct renesas_usb3 *usb3) { if (usb3_wakeup_usb3_phy(usb3)) usb3_start_usb3_connection(usb3); } static void usb3_reset_epc(struct renesas_usb3 *usb3) { usb3_clear_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); usb3_clear_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON); usb3_set_bit(usb3, USB_COM_CON_PIPE_CLR, USB3_USB_COM_CON); usb3->test_mode = 0; usb3_set_test_mode(usb3); } static void usb3_disconnect(struct renesas_usb3 *usb3) { usb3->disabled_count = 0; usb3_usb2_pullup(usb3, 0); usb3_clear_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON); usb3_reset_epc(usb3); if (usb3->driver) usb3->driver->disconnect(&usb3->gadget); } static void usb3_check_vbus(struct renesas_usb3 *usb3) { if (usb3->workaround_for_vbus) { usb3_connect(usb3); } else { if (usb3_read(usb3, USB3_USB_STA) & USB_STA_VBUS_STA) usb3_connect(usb3); else usb3_disconnect(usb3); } } static void renesas_usb3_init_controller(struct renesas_usb3 *usb3) { usb3_init_axi_bridge(usb3); usb3_init_epc_registers(usb3); usb3_check_vbus(usb3); } static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3) { usb3_disconnect(usb3); usb3_write(usb3, 0, USB3_P0_INT_ENA); usb3_write(usb3, 0, USB3_PN_INT_ENA); usb3_write(usb3, 0, USB3_USB_INT_ENA_1); usb3_write(usb3, 0, USB3_USB_INT_ENA_2); usb3_write(usb3, 0, USB3_AXI_INT_ENA); } static void usb3_irq_epc_int_1_pll_wakeup(struct renesas_usb3 *usb3) { usb3_disable_irq_1(usb3, USB_INT_1_B3_PLLWKUP); usb3_clear_bit(usb3, USB30_CON_B3_PLLWAKE, USB3_USB30_CON); usb3_start_usb3_connection(usb3); } static void usb3_irq_epc_int_1_linkup_success(struct renesas_usb3 *usb3) { usb3_transition_to_default_state(usb3, true); } static void usb3_irq_epc_int_1_resume(struct renesas_usb3 *usb3) { usb3_disable_irq_1(usb3, USB_INT_1_B2_RSUM); usb3_start_usb2_connection(usb3); usb3_transition_to_default_state(usb3, false); } static void usb3_irq_epc_int_1_disable(struct renesas_usb3 *usb3) { usb3_stop_usb3_connection(usb3); if (usb3_wakeup_usb2_phy(usb3)) usb3_irq_epc_int_1_resume(usb3); } static void usb3_irq_epc_int_1_bus_reset(struct renesas_usb3 *usb3) { usb3_reset_epc(usb3); if (usb3->disabled_count < 3) usb3_start_usb3_connection(usb3); else usb3_start_usb2_connection(usb3); } static void usb3_irq_epc_int_1_vbus_change(struct renesas_usb3 *usb3) { usb3_check_vbus(usb3); } static void usb3_irq_epc_int_1_hot_reset(struct renesas_usb3 *usb3) { usb3_reset_epc(usb3); usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON); /* This bit shall be set within 12ms from the start of HotReset */ usb3_set_bit(usb3, USB30_CON_B3_HOTRST_CMP, USB3_USB30_CON); } static void usb3_irq_epc_int_1_warm_reset(struct renesas_usb3 *usb3) { usb3_reset_epc(usb3); usb3_set_bit(usb3, USB_COM_CON_EP0_EN, USB3_USB_COM_CON); usb3_start_operation_for_usb3(usb3); usb3_enable_irq_1(usb3, USB_INT_1_SPEED); } static void usb3_irq_epc_int_1_speed(struct renesas_usb3 *usb3) { u32 speed = usb3_read(usb3, USB3_USB_STA) & USB_STA_SPEED_MASK; switch (speed) { case USB_STA_SPEED_SS: usb3->gadget.speed = USB_SPEED_SUPER; break; case USB_STA_SPEED_HS: usb3->gadget.speed = USB_SPEED_HIGH; break; case USB_STA_SPEED_FS: usb3->gadget.speed = USB_SPEED_FULL; break; default: usb3->gadget.speed = USB_SPEED_UNKNOWN; break; } } static void usb3_irq_epc_int_1(struct renesas_usb3 *usb3, u32 int_sta_1) { if (int_sta_1 & USB_INT_1_B3_PLLWKUP) usb3_irq_epc_int_1_pll_wakeup(usb3); if (int_sta_1 & USB_INT_1_B3_LUPSUCS) usb3_irq_epc_int_1_linkup_success(usb3); if (int_sta_1 & USB_INT_1_B3_HOTRST) usb3_irq_epc_int_1_hot_reset(usb3); if (int_sta_1 & USB_INT_1_B3_WRMRST) usb3_irq_epc_int_1_warm_reset(usb3); if (int_sta_1 & USB_INT_1_B3_DISABLE) usb3_irq_epc_int_1_disable(usb3); if (int_sta_1 & USB_INT_1_B2_USBRST) usb3_irq_epc_int_1_bus_reset(usb3); if (int_sta_1 & USB_INT_1_B2_RSUM) usb3_irq_epc_int_1_resume(usb3); if (int_sta_1 & USB_INT_1_SPEED) usb3_irq_epc_int_1_speed(usb3); if (int_sta_1 & USB_INT_1_VBUS_CNG) usb3_irq_epc_int_1_vbus_change(usb3); } static struct renesas_usb3_request *__usb3_get_request(struct renesas_usb3_ep *usb3_ep) { return list_first_entry_or_null(&usb3_ep->queue, struct renesas_usb3_request, queue); } static struct renesas_usb3_request *usb3_get_request(struct renesas_usb3_ep *usb3_ep) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); struct renesas_usb3_request *usb3_req; unsigned long flags; spin_lock_irqsave(&usb3->lock, flags); usb3_req = __usb3_get_request(usb3_ep); spin_unlock_irqrestore(&usb3->lock, flags); return usb3_req; } static void usb3_request_done(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req, int status) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); unsigned long flags; dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n", usb3_ep->num, usb3_req->req.length, usb3_req->req.actual, status); usb3_req->req.status = status; spin_lock_irqsave(&usb3->lock, flags); usb3_ep->started = false; list_del_init(&usb3_req->queue); spin_unlock_irqrestore(&usb3->lock, flags); usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req); } static void usb3_irq_epc_pipe0_status_end(struct renesas_usb3 *usb3) { struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0); struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep); if (usb3_req) usb3_request_done(usb3_ep, usb3_req, 0); if (usb3->test_mode) usb3_set_test_mode(usb3); } static void usb3_get_setup_data(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0); u32 *data = (u32 *)ctrl; *data++ = usb3_read(usb3, USB3_STUP_DAT_0); *data = usb3_read(usb3, USB3_STUP_DAT_1); /* update this driver's flag */ usb3_ep->dir_in = !!(ctrl->bRequestType & USB_DIR_IN); } static void usb3_set_p0_con_update_res(struct renesas_usb3 *usb3, u32 res) { u32 val = usb3_read(usb3, USB3_P0_CON); val &= ~(P0_CON_ST_RES_MASK | P0_CON_OT_RES_MASK | P0_CON_IN_RES_MASK); val |= res | P0_CON_RES_WEN; usb3_write(usb3, val, USB3_P0_CON); } static void usb3_set_p0_con_for_ctrl_read_data(struct renesas_usb3 *usb3) { usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_NRDY | P0_CON_OT_RES_FORCE_STALL | P0_CON_IN_RES_NORMAL); } static void usb3_set_p0_con_for_ctrl_read_status(struct renesas_usb3 *usb3) { usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_NORMAL | P0_CON_OT_RES_FORCE_STALL | P0_CON_IN_RES_NORMAL); } static void usb3_set_p0_con_for_ctrl_write_data(struct renesas_usb3 *usb3) { usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_NRDY | P0_CON_OT_RES_NORMAL | P0_CON_IN_RES_FORCE_STALL); } static void usb3_set_p0_con_for_ctrl_write_status(struct renesas_usb3 *usb3) { usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_NORMAL | P0_CON_OT_RES_NORMAL | P0_CON_IN_RES_FORCE_STALL); } static void usb3_set_p0_con_for_no_data(struct renesas_usb3 *usb3) { usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_NORMAL | P0_CON_OT_RES_FORCE_STALL | P0_CON_IN_RES_FORCE_STALL); } static void usb3_set_p0_con_stall(struct renesas_usb3 *usb3) { usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_STALL | P0_CON_OT_RES_FORCE_STALL | P0_CON_IN_RES_FORCE_STALL); } static void usb3_set_p0_con_stop(struct renesas_usb3 *usb3) { usb3_set_p0_con_update_res(usb3, P0_CON_ST_RES_FORCE_NRDY | P0_CON_OT_RES_FORCE_NRDY | P0_CON_IN_RES_FORCE_NRDY); } static int usb3_pn_change(struct renesas_usb3 *usb3, int num) { if (num == 0 || num > usb3->num_usb3_eps) return -ENXIO; usb3_write(usb3, num, USB3_PIPE_COM); return 0; } static void usb3_set_pn_con_update_res(struct renesas_usb3 *usb3, u32 res) { u32 val = usb3_read(usb3, USB3_PN_CON); val &= ~PN_CON_RES_MASK; val |= res & PN_CON_RES_MASK; val |= PN_CON_RES_WEN; usb3_write(usb3, val, USB3_PN_CON); } static void usb3_pn_start(struct renesas_usb3 *usb3) { usb3_set_pn_con_update_res(usb3, PN_CON_RES_NORMAL); } static void usb3_pn_stop(struct renesas_usb3 *usb3) { usb3_set_pn_con_update_res(usb3, PN_CON_RES_FORCE_NRDY); } static void usb3_pn_stall(struct renesas_usb3 *usb3) { usb3_set_pn_con_update_res(usb3, PN_CON_RES_FORCE_STALL); } static int usb3_pn_con_clear(struct renesas_usb3 *usb3) { usb3_set_bit(usb3, PN_CON_CLR, USB3_PN_CON); return usb3_wait(usb3, USB3_PN_CON, PN_CON_CLR, 0); } static bool usb3_is_transfer_complete(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req) { struct usb_request *req = &usb3_req->req; if ((!req->zero && req->actual == req->length) || (req->actual % usb3_ep->ep.maxpacket) || (req->length == 0)) return true; else return false; } static int usb3_wait_pipe_status(struct renesas_usb3_ep *usb3_ep, u32 mask) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); u32 sta_reg = usb3_ep->num ? USB3_PN_STA : USB3_P0_STA; return usb3_wait(usb3, sta_reg, mask, mask); } static void usb3_set_px_con_send(struct renesas_usb3_ep *usb3_ep, int bytes, bool last) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); u32 con_reg = usb3_ep->num ? USB3_PN_CON : USB3_P0_CON; u32 val = usb3_read(usb3, con_reg); val |= PX_CON_SEND | PX_CON_BYTE_EN_BYTES(bytes); val |= (usb3_ep->num && last) ? PN_CON_LAST : 0; usb3_write(usb3, val, con_reg); } static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req, u32 fifo_reg) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); int i; int len = min_t(unsigned, usb3_req->req.length - usb3_req->req.actual, usb3_ep->ep.maxpacket); u8 *buf = usb3_req->req.buf + usb3_req->req.actual; u32 tmp = 0; bool is_last; if (usb3_wait_pipe_status(usb3_ep, PX_STA_BUFSTS) < 0) return -EBUSY; /* Update gadget driver parameter */ usb3_req->req.actual += len; /* Write data to the register */ if (len >= 4) { iowrite32_rep(usb3->reg + fifo_reg, buf, len / 4); buf += (len / 4) * 4; len %= 4; /* update len to use usb3_set_pX_con_send() */ } if (len) { for (i = 0; i < len; i++) tmp |= buf[i] << (8 * i); usb3_write(usb3, tmp, fifo_reg); } is_last = usb3_is_transfer_complete(usb3_ep, usb3_req); /* Send the data */ usb3_set_px_con_send(usb3_ep, len, is_last); return is_last ? 0 : -EAGAIN; } static u32 usb3_get_received_length(struct renesas_usb3_ep *usb3_ep) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); u32 lng_reg = usb3_ep->num ? USB3_PN_LNG : USB3_P0_LNG; return usb3_read(usb3, lng_reg); } static int usb3_read_pipe(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req, u32 fifo_reg) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); int i; int len = min_t(unsigned, usb3_req->req.length - usb3_req->req.actual, usb3_get_received_length(usb3_ep)); u8 *buf = usb3_req->req.buf + usb3_req->req.actual; u32 tmp = 0; if (!len) return 0; /* Update gadget driver parameter */ usb3_req->req.actual += len; /* Read data from the register */ if (len >= 4) { ioread32_rep(usb3->reg + fifo_reg, buf, len / 4); buf += (len / 4) * 4; len %= 4; } if (len) { tmp = usb3_read(usb3, fifo_reg); for (i = 0; i < len; i++) buf[i] = (tmp >> (8 * i)) & 0xff; } return usb3_is_transfer_complete(usb3_ep, usb3_req) ? 0 : -EAGAIN; } static void usb3_set_status_stage(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); if (usb3_ep->dir_in) { usb3_set_p0_con_for_ctrl_read_status(usb3); } else { if (!usb3_req->req.length) usb3_set_p0_con_for_no_data(usb3); else usb3_set_p0_con_for_ctrl_write_status(usb3); } } static void usb3_p0_xfer(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req) { int ret = -EAGAIN; if (usb3_ep->dir_in) ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_P0_WRITE); else ret = usb3_read_pipe(usb3_ep, usb3_req, USB3_P0_READ); if (!ret) usb3_set_status_stage(usb3_ep, usb3_req); } static void usb3_start_pipe0(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); if (usb3_ep->started) return; usb3_ep->started = true; if (usb3_ep->dir_in) { usb3_set_bit(usb3, P0_MOD_DIR, USB3_P0_MOD); usb3_set_p0_con_for_ctrl_read_data(usb3); } else { usb3_clear_bit(usb3, P0_MOD_DIR, USB3_P0_MOD); usb3_set_p0_con_for_ctrl_write_data(usb3); } usb3_p0_xfer(usb3_ep, usb3_req); } static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); struct renesas_usb3_request *usb3_req_first = usb3_get_request(usb3_ep); unsigned long flags; int ret = -EAGAIN; u32 enable_bits = 0; if (usb3_ep->halt || usb3_ep->started) return; if (usb3_req != usb3_req_first) return; spin_lock_irqsave(&usb3->lock, flags); if (usb3_pn_change(usb3, usb3_ep->num) < 0) goto out; usb3_ep->started = true; usb3_pn_start(usb3); if (usb3_ep->dir_in) { ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_PN_WRITE); enable_bits |= PN_INT_LSTTR; } if (ret < 0) enable_bits |= PN_INT_BFRDY; if (enable_bits) { usb3_set_bit(usb3, enable_bits, USB3_PN_INT_ENA); usb3_enable_pipe_irq(usb3, usb3_ep->num); } out: spin_unlock_irqrestore(&usb3->lock, flags); } static int renesas_usb3_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep); struct renesas_usb3_request *usb3_req = usb_req_to_usb3_req(_req); struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); unsigned long flags; dev_dbg(usb3_to_dev(usb3), "ep_queue: ep%2d, %u\n", usb3_ep->num, _req->length); _req->status = -EINPROGRESS; _req->actual = 0; spin_lock_irqsave(&usb3->lock, flags); list_add_tail(&usb3_req->queue, &usb3_ep->queue); spin_unlock_irqrestore(&usb3->lock, flags); if (!usb3_ep->num) usb3_start_pipe0(usb3_ep, usb3_req); else usb3_start_pipen(usb3_ep, usb3_req); return 0; } static void usb3_set_device_address(struct renesas_usb3 *usb3, u16 addr) { /* DEV_ADDR bit field is cleared by WarmReset, HotReset and BusReset */ usb3_set_bit(usb3, USB_COM_CON_DEV_ADDR(addr), USB3_USB_COM_CON); } static bool usb3_std_req_set_address(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { if (ctrl->wValue >= 128) return true; /* stall */ usb3_set_device_address(usb3, ctrl->wValue); usb3_set_p0_con_for_no_data(usb3); return false; } static void usb3_pipe0_internal_xfer(struct renesas_usb3 *usb3, void *tx_data, size_t len, void (*complete)(struct usb_ep *ep, struct usb_request *req)) { struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0); if (tx_data) memcpy(usb3->ep0_buf, tx_data, min_t(size_t, len, USB3_EP0_BUF_SIZE)); usb3->ep0_req->buf = &usb3->ep0_buf; usb3->ep0_req->length = len; usb3->ep0_req->complete = complete; renesas_usb3_ep_queue(&usb3_ep->ep, usb3->ep0_req, GFP_ATOMIC); } static void usb3_pipe0_get_status_completion(struct usb_ep *ep, struct usb_request *req) { } static bool usb3_std_req_get_status(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { bool stall = false; struct renesas_usb3_ep *usb3_ep; int num; u16 status = 0; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: if (usb3->gadget.is_selfpowered) status |= 1 << USB_DEVICE_SELF_POWERED; if (usb3->gadget.speed == USB_SPEED_SUPER) status |= usb3_feature_get_un_enabled(usb3); break; case USB_RECIP_INTERFACE: break; case USB_RECIP_ENDPOINT: num = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; usb3_ep = usb3_get_ep(usb3, num); if (usb3_ep->halt) status |= 1 << USB_ENDPOINT_HALT; break; default: stall = true; break; } if (!stall) { status = cpu_to_le16(status); dev_dbg(usb3_to_dev(usb3), "get_status: req = %p\n", usb_req_to_usb3_req(usb3->ep0_req)); usb3_pipe0_internal_xfer(usb3, &status, sizeof(status), usb3_pipe0_get_status_completion); } return stall; } static bool usb3_std_req_feature_device(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl, bool set) { bool stall = true; u16 w_value = le16_to_cpu(ctrl->wValue); switch (w_value) { case USB_DEVICE_TEST_MODE: if (!set) break; usb3->test_mode = le16_to_cpu(ctrl->wIndex) >> 8; stall = false; break; case USB_DEVICE_U1_ENABLE: case USB_DEVICE_U2_ENABLE: if (usb3->gadget.speed != USB_SPEED_SUPER) break; if (w_value == USB_DEVICE_U1_ENABLE) usb3_feature_u1_enable(usb3, set); if (w_value == USB_DEVICE_U2_ENABLE) usb3_feature_u2_enable(usb3, set); stall = false; break; default: break; } return stall; } static int usb3_set_halt_p0(struct renesas_usb3_ep *usb3_ep, bool halt) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); if (unlikely(usb3_ep->num)) return -EINVAL; usb3_ep->halt = halt; if (halt) usb3_set_p0_con_stall(usb3); else usb3_set_p0_con_stop(usb3); return 0; } static int usb3_set_halt_pn(struct renesas_usb3_ep *usb3_ep, bool halt, bool is_clear_feature) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); unsigned long flags; spin_lock_irqsave(&usb3->lock, flags); if (!usb3_pn_change(usb3, usb3_ep->num)) { usb3_ep->halt = halt; if (halt) { usb3_pn_stall(usb3); } else if (!is_clear_feature || !usb3_ep->wedge) { usb3_pn_con_clear(usb3); usb3_set_bit(usb3, PN_CON_EN, USB3_PN_CON); usb3_pn_stop(usb3); } } spin_unlock_irqrestore(&usb3->lock, flags); return 0; } static int usb3_set_halt(struct renesas_usb3_ep *usb3_ep, bool halt, bool is_clear_feature) { int ret = 0; if (halt && usb3_ep->started) return -EAGAIN; if (usb3_ep->num) ret = usb3_set_halt_pn(usb3_ep, halt, is_clear_feature); else ret = usb3_set_halt_p0(usb3_ep, halt); return ret; } static bool usb3_std_req_feature_endpoint(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl, bool set) { int num = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; struct renesas_usb3_ep *usb3_ep; struct renesas_usb3_request *usb3_req; if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT) return true; /* stall */ usb3_ep = usb3_get_ep(usb3, num); usb3_set_halt(usb3_ep, set, true); /* Restarts a queue if clear feature */ if (!set) { usb3_ep->started = false; usb3_req = usb3_get_request(usb3_ep); if (usb3_req) usb3_start_pipen(usb3_ep, usb3_req); } return false; } static bool usb3_std_req_feature(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl, bool set) { bool stall = false; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: stall = usb3_std_req_feature_device(usb3, ctrl, set); break; case USB_RECIP_INTERFACE: break; case USB_RECIP_ENDPOINT: stall = usb3_std_req_feature_endpoint(usb3, ctrl, set); break; default: stall = true; break; } if (!stall) usb3_set_p0_con_for_no_data(usb3); return stall; } static void usb3_pipe0_set_sel_completion(struct usb_ep *ep, struct usb_request *req) { /* TODO */ } static bool usb3_std_req_set_sel(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { u16 w_length = le16_to_cpu(ctrl->wLength); if (w_length != 6) return true; /* stall */ dev_dbg(usb3_to_dev(usb3), "set_sel: req = %p\n", usb_req_to_usb3_req(usb3->ep0_req)); usb3_pipe0_internal_xfer(usb3, NULL, 6, usb3_pipe0_set_sel_completion); return false; } static bool usb3_std_req_set_configuration(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { if (ctrl->wValue > 0) usb3_set_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); else usb3_clear_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); return false; } /** * usb3_handle_standard_request - handle some standard requests * @usb3: the renesas_usb3 pointer * @ctrl: a pointer of setup data * * Returns true if this function handled a standard request */ static bool usb3_handle_standard_request(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { bool ret = false; bool stall = false; if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (ctrl->bRequest) { case USB_REQ_SET_ADDRESS: stall = usb3_std_req_set_address(usb3, ctrl); ret = true; break; case USB_REQ_GET_STATUS: stall = usb3_std_req_get_status(usb3, ctrl); ret = true; break; case USB_REQ_CLEAR_FEATURE: stall = usb3_std_req_feature(usb3, ctrl, false); ret = true; break; case USB_REQ_SET_FEATURE: stall = usb3_std_req_feature(usb3, ctrl, true); ret = true; break; case USB_REQ_SET_SEL: stall = usb3_std_req_set_sel(usb3, ctrl); ret = true; break; case USB_REQ_SET_ISOCH_DELAY: /* This hardware doesn't support Isochronous xfer */ stall = true; ret = true; break; case USB_REQ_SET_CONFIGURATION: usb3_std_req_set_configuration(usb3, ctrl); break; default: break; } } if (stall) usb3_set_p0_con_stall(usb3); return ret; } static int usb3_p0_con_clear_buffer(struct renesas_usb3 *usb3) { usb3_set_bit(usb3, P0_CON_BCLR, USB3_P0_CON); return usb3_wait(usb3, USB3_P0_CON, P0_CON_BCLR, 0); } static void usb3_irq_epc_pipe0_setup(struct renesas_usb3 *usb3) { struct usb_ctrlrequest ctrl; struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0); /* Call giveback function if previous transfer is not completed */ if (usb3_ep->started) usb3_request_done(usb3_ep, usb3_get_request(usb3_ep), -ECONNRESET); usb3_p0_con_clear_buffer(usb3); usb3_get_setup_data(usb3, &ctrl); if (!usb3_handle_standard_request(usb3, &ctrl)) if (usb3->driver->setup(&usb3->gadget, &ctrl) < 0) usb3_set_p0_con_stall(usb3); } static void usb3_irq_epc_pipe0_bfrdy(struct renesas_usb3 *usb3) { struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, 0); struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep); if (!usb3_req) return; usb3_p0_xfer(usb3_ep, usb3_req); } static void usb3_irq_epc_pipe0(struct renesas_usb3 *usb3) { u32 p0_int_sta = usb3_read(usb3, USB3_P0_INT_STA); p0_int_sta &= usb3_read(usb3, USB3_P0_INT_ENA); usb3_write(usb3, p0_int_sta, USB3_P0_INT_STA); if (p0_int_sta & P0_INT_STSED) usb3_irq_epc_pipe0_status_end(usb3); if (p0_int_sta & P0_INT_SETUP) usb3_irq_epc_pipe0_setup(usb3); if (p0_int_sta & P0_INT_BFRDY) usb3_irq_epc_pipe0_bfrdy(usb3); } static void usb3_request_done_pipen(struct renesas_usb3 *usb3, struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req, int status) { usb3_pn_stop(usb3); usb3_disable_pipe_irq(usb3, usb3_ep->num); usb3_request_done(usb3_ep, usb3_req, status); /* get next usb3_req */ usb3_req = usb3_get_request(usb3_ep); if (usb3_req) usb3_start_pipen(usb3_ep, usb3_req); } static void usb3_irq_epc_pipen_lsttr(struct renesas_usb3 *usb3, int num) { struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, num); struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep); if (!usb3_req) return; if (usb3_ep->dir_in) { dev_dbg(usb3_to_dev(usb3), "%s: len = %u, actual = %u\n", __func__, usb3_req->req.length, usb3_req->req.actual); usb3_request_done_pipen(usb3, usb3_ep, usb3_req, 0); } } static void usb3_irq_epc_pipen_bfrdy(struct renesas_usb3 *usb3, int num) { struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, num); struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep); if (!usb3_req) return; if (usb3_ep->dir_in) { /* Do not stop the IN pipe here to detect LSTTR interrupt */ if (!usb3_write_pipe(usb3_ep, usb3_req, USB3_PN_WRITE)) usb3_clear_bit(usb3, PN_INT_BFRDY, USB3_PN_INT_ENA); } else { if (!usb3_read_pipe(usb3_ep, usb3_req, USB3_PN_READ)) usb3_request_done_pipen(usb3, usb3_ep, usb3_req, 0); } } static void usb3_irq_epc_pipen(struct renesas_usb3 *usb3, int num) { u32 pn_int_sta; if (usb3_pn_change(usb3, num) < 0) return; pn_int_sta = usb3_read(usb3, USB3_PN_INT_STA); pn_int_sta &= usb3_read(usb3, USB3_PN_INT_ENA); usb3_write(usb3, pn_int_sta, USB3_PN_INT_STA); if (pn_int_sta & PN_INT_LSTTR) usb3_irq_epc_pipen_lsttr(usb3, num); if (pn_int_sta & PN_INT_BFRDY) usb3_irq_epc_pipen_bfrdy(usb3, num); } static void usb3_irq_epc_int_2(struct renesas_usb3 *usb3, u32 int_sta_2) { int i; for (i = 0; i < usb3->num_usb3_eps; i++) { if (int_sta_2 & USB_INT_2_PIPE(i)) { if (!i) usb3_irq_epc_pipe0(usb3); else usb3_irq_epc_pipen(usb3, i); } } } static void usb3_irq_epc(struct renesas_usb3 *usb3) { u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1); u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2); int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1); if (int_sta_1) { usb3_write(usb3, int_sta_1, USB3_USB_INT_STA_1); usb3_irq_epc_int_1(usb3, int_sta_1); } int_sta_2 &= usb3_read(usb3, USB3_USB_INT_ENA_2); if (int_sta_2) usb3_irq_epc_int_2(usb3, int_sta_2); } static irqreturn_t renesas_usb3_irq(int irq, void *_usb3) { struct renesas_usb3 *usb3 = _usb3; irqreturn_t ret = IRQ_NONE; u32 axi_int_sta = usb3_read(usb3, USB3_AXI_INT_STA); if (axi_int_sta & AXI_INT_EPCINT) { usb3_irq_epc(usb3); ret = IRQ_HANDLED; } return ret; } static void usb3_write_pn_mod(struct renesas_usb3_ep *usb3_ep, const struct usb_endpoint_descriptor *desc) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); u32 val = 0; val |= usb3_ep->dir_in ? PN_MOD_DIR : 0; val |= PN_MOD_TYPE(usb_endpoint_type(desc)); val |= PN_MOD_EPNUM(usb_endpoint_num(desc)); usb3_write(usb3, val, USB3_PN_MOD); } static u32 usb3_calc_ramarea(int ram_size) { WARN_ON(ram_size > SZ_16K); if (ram_size <= SZ_1K) return PN_RAMMAP_RAMAREA_1KB; else if (ram_size <= SZ_2K) return PN_RAMMAP_RAMAREA_2KB; else if (ram_size <= SZ_4K) return PN_RAMMAP_RAMAREA_4KB; else if (ram_size <= SZ_8K) return PN_RAMMAP_RAMAREA_8KB; else return PN_RAMMAP_RAMAREA_16KB; } static u32 usb3_calc_rammap_val(struct renesas_usb3_ep *usb3_ep, const struct usb_endpoint_descriptor *desc) { return usb3_ep->rammap_val | PN_RAMMAP_MPKT(usb_endpoint_maxp(desc)); } static int usb3_enable_pipe_n(struct renesas_usb3_ep *usb3_ep, const struct usb_endpoint_descriptor *desc) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); unsigned long flags; usb3_ep->dir_in = usb_endpoint_dir_in(desc); spin_lock_irqsave(&usb3->lock, flags); if (!usb3_pn_change(usb3, usb3_ep->num)) { usb3_write_pn_mod(usb3_ep, desc); usb3_write(usb3, usb3_calc_rammap_val(usb3_ep, desc), USB3_PN_RAMMAP); usb3_pn_con_clear(usb3); usb3_set_bit(usb3, PN_CON_EN, USB3_PN_CON); } spin_unlock_irqrestore(&usb3->lock, flags); return 0; } static int usb3_disable_pipe_n(struct renesas_usb3_ep *usb3_ep) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); unsigned long flags; usb3_ep->halt = false; spin_lock_irqsave(&usb3->lock, flags); if (!usb3_pn_change(usb3, usb3_ep->num)) { usb3_write(usb3, 0, USB3_PN_RAMMAP); usb3_clear_bit(usb3, PN_CON_EN, USB3_PN_CON); } spin_unlock_irqrestore(&usb3->lock, flags); return 0; } /*------- usb_ep_ops -----------------------------------------------------*/ static int renesas_usb3_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep); return usb3_enable_pipe_n(usb3_ep, desc); } static int renesas_usb3_ep_disable(struct usb_ep *_ep) { struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep); struct renesas_usb3_request *usb3_req; do { usb3_req = usb3_get_request(usb3_ep); if (!usb3_req) break; usb3_request_done(usb3_ep, usb3_req, -ESHUTDOWN); } while (1); return usb3_disable_pipe_n(usb3_ep); } static struct usb_request *__renesas_usb3_ep_alloc_request(gfp_t gfp_flags) { struct renesas_usb3_request *usb3_req; usb3_req = kzalloc(sizeof(struct renesas_usb3_request), gfp_flags); if (!usb3_req) return NULL; INIT_LIST_HEAD(&usb3_req->queue); return &usb3_req->req; } static void __renesas_usb3_ep_free_request(struct usb_request *_req) { struct renesas_usb3_request *usb3_req = usb_req_to_usb3_req(_req); kfree(usb3_req); } static struct usb_request *renesas_usb3_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { return __renesas_usb3_ep_alloc_request(gfp_flags); } static void renesas_usb3_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) { __renesas_usb3_ep_free_request(_req); } static int renesas_usb3_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) { struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep); struct renesas_usb3_request *usb3_req = usb_req_to_usb3_req(_req); struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); dev_dbg(usb3_to_dev(usb3), "ep_dequeue: ep%2d, %u\n", usb3_ep->num, _req->length); usb3_request_done_pipen(usb3, usb3_ep, usb3_req, -ECONNRESET); return 0; } static int renesas_usb3_ep_set_halt(struct usb_ep *_ep, int value) { return usb3_set_halt(usb_ep_to_usb3_ep(_ep), !!value, false); } static int renesas_usb3_ep_set_wedge(struct usb_ep *_ep) { struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep); usb3_ep->wedge = true; return usb3_set_halt(usb3_ep, true, false); } static void renesas_usb3_ep_fifo_flush(struct usb_ep *_ep) { struct renesas_usb3_ep *usb3_ep = usb_ep_to_usb3_ep(_ep); struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); unsigned long flags; if (usb3_ep->num) { spin_lock_irqsave(&usb3->lock, flags); if (!usb3_pn_change(usb3, usb3_ep->num)) { usb3_pn_con_clear(usb3); usb3_set_bit(usb3, PN_CON_EN, USB3_PN_CON); } spin_unlock_irqrestore(&usb3->lock, flags); } else { usb3_p0_con_clear_buffer(usb3); } } static struct usb_ep_ops renesas_usb3_ep_ops = { .enable = renesas_usb3_ep_enable, .disable = renesas_usb3_ep_disable, .alloc_request = renesas_usb3_ep_alloc_request, .free_request = renesas_usb3_ep_free_request, .queue = renesas_usb3_ep_queue, .dequeue = renesas_usb3_ep_dequeue, .set_halt = renesas_usb3_ep_set_halt, .set_wedge = renesas_usb3_ep_set_wedge, .fifo_flush = renesas_usb3_ep_fifo_flush, }; /*------- usb_gadget_ops -------------------------------------------------*/ static int renesas_usb3_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct renesas_usb3 *usb3; if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) return -EINVAL; usb3 = gadget_to_renesas_usb3(gadget); /* hook up the driver */ usb3->driver = driver; renesas_usb3_init_controller(usb3); return 0; } static int renesas_usb3_stop(struct usb_gadget *gadget) { struct renesas_usb3 *usb3 = gadget_to_renesas_usb3(gadget); unsigned long flags; spin_lock_irqsave(&usb3->lock, flags); usb3->softconnect = false; usb3->gadget.speed = USB_SPEED_UNKNOWN; usb3->driver = NULL; renesas_usb3_stop_controller(usb3); spin_unlock_irqrestore(&usb3->lock, flags); return 0; } static int renesas_usb3_get_frame(struct usb_gadget *_gadget) { return -EOPNOTSUPP; } static int renesas_usb3_pullup(struct usb_gadget *gadget, int is_on) { struct renesas_usb3 *usb3 = gadget_to_renesas_usb3(gadget); usb3->softconnect = !!is_on; return 0; } static int renesas_usb3_set_selfpowered(struct usb_gadget *gadget, int is_self) { gadget->is_selfpowered = !!is_self; return 0; } static const struct usb_gadget_ops renesas_usb3_gadget_ops = { .get_frame = renesas_usb3_get_frame, .udc_start = renesas_usb3_start, .udc_stop = renesas_usb3_stop, .pullup = renesas_usb3_pullup, .set_selfpowered = renesas_usb3_set_selfpowered, }; /*------- platform_driver ------------------------------------------------*/ static int renesas_usb3_remove(struct platform_device *pdev) { struct renesas_usb3 *usb3 = platform_get_drvdata(pdev); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); usb_del_gadget_udc(&usb3->gadget); __renesas_usb3_ep_free_request(usb3->ep0_req); return 0; } static int renesas_usb3_init_ep(struct renesas_usb3 *usb3, struct device *dev, const struct renesas_usb3_priv *priv) { struct renesas_usb3_ep *usb3_ep; int i; /* calculate num_usb3_eps from renesas_usb3_priv */ usb3->num_usb3_eps = priv->ramsize_per_ramif * priv->num_ramif * 2 / priv->ramsize_per_pipe + 1; if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES) usb3->num_usb3_eps = USB3_MAX_NUM_PIPES; usb3->usb3_ep = devm_kzalloc(dev, sizeof(*usb3_ep) * usb3->num_usb3_eps, GFP_KERNEL); if (!usb3->usb3_ep) return -ENOMEM; dev_dbg(dev, "%s: num_usb3_eps = %d\n", __func__, usb3->num_usb3_eps); /* * This driver prepares pipes as the followings: * - odd pipes = IN pipe * - even pipes = OUT pipe (except pipe 0) */ usb3_for_each_ep(usb3_ep, usb3, i) { snprintf(usb3_ep->ep_name, sizeof(usb3_ep->ep_name), "ep%d", i); usb3_ep->usb3 = usb3; usb3_ep->num = i; usb3_ep->ep.name = usb3_ep->ep_name; usb3_ep->ep.ops = &renesas_usb3_ep_ops; INIT_LIST_HEAD(&usb3_ep->queue); INIT_LIST_HEAD(&usb3_ep->ep.ep_list); if (!i) { /* for control pipe */ usb3->gadget.ep0 = &usb3_ep->ep; usb_ep_set_maxpacket_limit(&usb3_ep->ep, USB3_EP0_HSFS_MAX_PACKET_SIZE); usb3_ep->ep.caps.type_control = true; usb3_ep->ep.caps.dir_in = true; usb3_ep->ep.caps.dir_out = true; continue; } /* for bulk or interrupt pipe */ usb_ep_set_maxpacket_limit(&usb3_ep->ep, ~0); list_add_tail(&usb3_ep->ep.ep_list, &usb3->gadget.ep_list); usb3_ep->ep.caps.type_bulk = true; usb3_ep->ep.caps.type_int = true; if (i & 1) usb3_ep->ep.caps.dir_in = true; else usb3_ep->ep.caps.dir_out = true; } return 0; } static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev, const struct renesas_usb3_priv *priv) { struct renesas_usb3_ep *usb3_ep; int i; u32 ramif[2], basead[2]; /* index 0 = for IN pipes */ u32 *cur_ramif, *cur_basead; u32 val; memset(ramif, 0, sizeof(ramif)); memset(basead, 0, sizeof(basead)); /* * This driver prepares pipes as the followings: * - all pipes = the same size as "ramsize_per_pipe" * Please refer to the "Method of Specifying RAM Mapping" */ usb3_for_each_ep(usb3_ep, usb3, i) { if (!i) continue; /* out of scope if ep num = 0 */ if (usb3_ep->ep.caps.dir_in) { cur_ramif = &ramif[0]; cur_basead = &basead[0]; } else { cur_ramif = &ramif[1]; cur_basead = &basead[1]; } if (*cur_basead > priv->ramsize_per_ramif) continue; /* out of memory for IN or OUT pipe */ /* calculate rammap_val */ val = PN_RAMMAP_RAMIF(*cur_ramif); val |= usb3_calc_ramarea(priv->ramsize_per_pipe); val |= PN_RAMMAP_BASEAD(*cur_basead); usb3_ep->rammap_val = val; dev_dbg(dev, "ep%2d: val = %08x, ramif = %d, base = %x\n", i, val, *cur_ramif, *cur_basead); /* update current ramif */ if (*cur_ramif + 1 == priv->num_ramif) { *cur_ramif = 0; *cur_basead += priv->ramsize_per_pipe; } else { (*cur_ramif)++; } } } static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795 = { .ramsize_per_ramif = SZ_16K, .num_ramif = 2, .ramsize_per_pipe = SZ_4K, .workaround_for_vbus = true, }; static const struct of_device_id usb3_of_match[] = { { .compatible = "renesas,r8a7795-usb3-peri", .data = &renesas_usb3_priv_r8a7795, }, { }, }; MODULE_DEVICE_TABLE(of, usb3_of_match); static int renesas_usb3_probe(struct platform_device *pdev) { struct renesas_usb3 *usb3; struct resource *res; const struct of_device_id *match; int irq, ret; const struct renesas_usb3_priv *priv; match = of_match_node(usb3_of_match, pdev->dev.of_node); if (!match) return -ENODEV; priv = match->data; irq = platform_get_irq(pdev, 0); if (irq < 0) return -ENODEV; usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL); if (!usb3) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); usb3->reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(usb3->reg)) return PTR_ERR(usb3->reg); platform_set_drvdata(pdev, usb3); spin_lock_init(&usb3->lock); usb3->gadget.ops = &renesas_usb3_gadget_ops; usb3->gadget.name = udc_name; usb3->gadget.max_speed = USB_SPEED_SUPER; INIT_LIST_HEAD(&usb3->gadget.ep_list); ret = renesas_usb3_init_ep(usb3, &pdev->dev, priv); if (ret < 0) return ret; renesas_usb3_init_ram(usb3, &pdev->dev, priv); ret = devm_request_irq(&pdev->dev, irq, renesas_usb3_irq, 0, dev_name(&pdev->dev), usb3); if (ret < 0) return ret; /* for ep0 handling */ usb3->ep0_req = __renesas_usb3_ep_alloc_request(GFP_KERNEL); if (!usb3->ep0_req) return -ENOMEM; ret = usb_add_gadget_udc(&pdev->dev, &usb3->gadget); if (ret < 0) goto err_add_udc; usb3->workaround_for_vbus = priv->workaround_for_vbus; pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); dev_info(&pdev->dev, "probed\n"); return 0; err_add_udc: __renesas_usb3_ep_free_request(usb3->ep0_req); return ret; } static struct platform_driver renesas_usb3_driver = { .probe = renesas_usb3_probe, .remove = renesas_usb3_remove, .driver = { .name = (char *)udc_name, .of_match_table = of_match_ptr(usb3_of_match), }, }; module_platform_driver(renesas_usb3_driver); MODULE_DESCRIPTION("Renesas USB3.0 Peripheral driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yoshihiro Shimoda "); MODULE_ALIAS("platform:renesas_usb3");