From c0c92411ce15ab58af665aebe91cdb11b882b5cc Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 24 Mar 2015 10:05:21 -0600 Subject: [PATCH] SAMV7 USB: Updates to early initialization logic --- arch/arm/src/samv7/chip/sam_usbhs.h | 4 +- arch/arm/src/samv7/sam_usbdevhs.c | 129 +++++++++++++++------------- 2 files changed, 74 insertions(+), 59 deletions(-) diff --git a/arch/arm/src/samv7/chip/sam_usbhs.h b/arch/arm/src/samv7/chip/sam_usbhs.h index d5710d8897..ba9293766d 100644 --- a/arch/arm/src/samv7/chip/sam_usbhs.h +++ b/arch/arm/src/samv7/chip/sam_usbhs.h @@ -204,7 +204,7 @@ #define USBHS_DEVCTRL_RMWKUP (1 << 9) /* Bit 9: Send Remote Wake Up */ #define USBHS_DEVCTRL_SPDCONF_SHIFT (10) /* Bits 10-11: Mode Configuration */ #define USBHS_DEVCTRL_SPDCONF_MASK (3 << USBHS_DEVCTRL_SPDCONF_SHIFT) -# define USBHS_DEVCTRL_SPDCONF_NORMAL 0 << USBHS_DEVCTRL_SPDCONF_SHIFT) +# define USBHS_DEVCTRL_SPDCONF_NORMAL (0 << USBHS_DEVCTRL_SPDCONF_SHIFT) # define USBHS_DEVCTRL_SPDCONF_LOWPOWER (1 << USBHS_DEVCTRL_SPDCONF_SHIFT) #define USBHS_DEVCTRL_LS (1 << 12) /* Bit 12: Low-Speed Mode Force */ #define USBHS_DEVCTRL_TSTJ (1 << 13) /* Bit 13: Test mode J */ @@ -739,6 +739,8 @@ #define USBHS_CTRL_FRZCLK (1 << 14) /* Bit 14: Freeze USB Clock */ #define USBHS_CTRL_USBE (1 << 15) /* Bit 15: USBHS Enable */ #define USBHS_CTRL_UIMOD (1 << 25) /* Bit 25: USBHS Mode */ +# define USBHS_CTRL_UIMOD_HOST (0 << 25) /* 0=Host mode */ +# define USBHS_CTRL_UIMOD_DEVICE (1 << 25) /* 1= Device mode */ /* General Status Register */ diff --git a/arch/arm/src/samv7/sam_usbdevhs.c b/arch/arm/src/samv7/sam_usbdevhs.c index 525be8c53d..97cc4c0ed5 100644 --- a/arch/arm/src/samv7/sam_usbdevhs.c +++ b/arch/arm/src/samv7/sam_usbdevhs.c @@ -11,6 +11,11 @@ * * Copyright (c) 2009, Atmel Corporation * + * Additional updates for the SAMV7 was taken from Atmel sample code for the + * SAMV71: + * + * Copyright (c) 2014, Atmel Corporation + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -4065,16 +4070,14 @@ static void sam_reset(struct sam_usbdev_s *priv) uint32_t regval; uint8_t epno; - /* Make sure that clocking is enabled to the USBHS peripheral. - * - * NOTE: In the Atmel example code, they also enable USB clocking - * at this point (via the BIAS in the CKGR_UCKR register). In this - * implementation, that should not be necessary here because we - * never disable BIAS to begin with. - */ + /* Make sure that clocking is enabled to the USBHS peripheral. */ sam_usbhs_enableclk(); + regval = sam_getreg(SAM_USBHS_CTRL); + regval &= ~USBHS_CTRL_FRZCLK; + sam_putreg(regval, SAM_USBHS_CTRL); + /* Tell the class driver that we are disconnected. The class driver * should then accept any new configurations. */ @@ -4121,18 +4124,29 @@ static void sam_reset(struct sam_usbdev_s *priv) priv->usbdev.speed = USB_SPEED_FULL; - /* Clear all pending interrupt status */ + /* Enable normal operational interrupts (including endpoint 0) */ - regval = USBHS_DEVINT_UPRSM | USBHS_DEVINT_EORSM | USBHS_DEVINT_WAKEUP | - USBHS_DEVINT_EORST | USBHS_DEVINT_SOF | USBHS_DEVINT_MSOF | + regval = USBHS_DEVINT_EORST | USBHS_DEVINT_WAKEUP | USBHS_DEVINT_SUSPD | + USBHS_DEVINT_SOF | USBHS_DEVINT_PEP0; +#ifdef CONFIG_USBDEV_DUALSPEED + regval |= USBHS_DEVINT_MSOF; +#endif + sam_putreg(regval, SAM_USBHS_DEVIER); + + /* Reset following interrupts flag */ + + regval = USBHS_DEVINT_EORST | USBHS_DEVINT_SOF | USBHS_DEVINT_MSOF | USBHS_DEVINT_SUSPD; sam_putreg(regval, SAM_USBHS_DEVICR); - /* Enable normal operational interrupts (including endpoint 0) */ + /* Raise the first suspend interrupt */ - regval = USBHS_DEVINT_EORSM | USBHS_DEVINT_WAKEUP | USBHS_DEVINT_SUSPD | - USBHS_DEVINT_PEP0; - sam_putreg(regval, SAM_USBHS_DEVIER); + regval = sam_getreg(SAM_USBHS_DEVIFR); + regval |= USBHS_DEVINT_SUSPD; + sam_putreg(regval, SAM_USBHS_DEVIFR); + + regval |= USBHS_DEVINT_WAKEUP; + sam_putreg(regval, SAM_USBHS_DEVIFR); sam_dumpep(priv, EP0); } @@ -4146,58 +4160,56 @@ static void sam_hw_setup(struct sam_usbdev_s *priv) uint32_t regval; int i; - /* Paragraph 32.5.1, "Power Management". The USBHS is not continuously - * clocked. For using the USBHS, the programmer must first enable the - * USBHS Clock in the Power Management Controller (PMC_PCER register). - * Then enable the PLL (PMC_UCKR register). Finally, enable BIAS in - * PMC_UCKR register. However, if the application does not require USBHS - * operations, the USBHS clock can be stopped when not needed and - * restarted later. - * - * Here, we set only the PCER. PLL configuration was performed in - * sam_clockconfig() earlier in the boot sequence. + /* Enable clocking tot he USBHS peripheral. Here, we set only the PCER. + * UPLL configuration was performed in sam_clockconfig() earlier in the + * boot sequence. */ sam_usbhs_enableclk(); - /* Reset and disable endpoints */ + /* Disable USB hardware and select device mode */ + + regval = sam_getreg(SAM_USBHS_CTRL); + regval &= ~USBHS_CTRL_USBE; + sam_putreg(regval, SAM_USBHS_CTRL); + + regval |= USBHS_CTRL_UIMOD_DEVICE; + sam_putreg(regval, SAM_USBHS_CTRL); + + /* Enable USB hardware and unfreeze clocking */ + + regval |= USBHS_CTRL_USBE; + sam_putreg(regval, SAM_USBHS_CTRL); + + regval &= ~USBHS_CTRL_FRZCLK; + sam_putreg(regval, SAM_USBHS_CTRL); + + /* Select High Speed */ + + regval = sam_getreg(SAM_USBHS_DEVCTRL); + regval |= USBHS_DEVCTRL_SPDCONF_NORMAL; + sam_putreg(regval, SAM_USBHS_DEVCTRL); + + /* Wait for UTMI clocking to be usable */ + + while ((sam_getreg(SAM_USBHS_SR) & USBHS_SR_CLKUSABLE) == 0); + + /* Make sure that we are not in Low-Speed mode */ + + regval = sam_getreg(SAM_USBHS_DEVCTRL); + regval &= ~USBHS_DEVCTRL_LS; + sam_putreg(regval, SAM_USBHS_DEVCTRL); + + /* Reset and disable all endpoints (including endpoint 0) */ sam_epset_reset(priv, SAM_EPSET_ALL); - /* Configure the pull-up on D+ and disconnect it */ + /* Disconnect the device */ regval = sam_getreg(SAM_USBHS_DEVCTRL); regval |= USBHS_DEVCTRL_DETACH; sam_putreg(regval, SAM_USBHS_DEVCTRL); - /* Reset the USBHS block - * - * Paragraph 33.5.1. "One transceiver is shared with the USB High Speed - * Device (port A). The selection between Host Port A and USB Device is - * controlled by the USBHS enable bit (EN_USBHS) located in the USBHS_CTRL - * control register. - * - * "In the case the port A is driven by the USB High Speed Device, the ... - * transceiver is automatically selected for Device operation once the - * USB High Speed Device is enabled." - */ - -#warning REVISIT -#if 0 - regval &= ~xxxx; - sam_putreg(regval, SAM_USBHS_DEVCTRL); - - regval |= xxxx; - sam_putreg(regval, SAM_USBHS_DEVCTRL); -#endif - - /* REVISIT: Per recommendations and sample code, USB clocking (as - * configured in the PMC CKGR_UCKR) is set up after reseting the UDHPS. - * However, that initialation has already been done in sam_clockconfig(). - * Also, that clocking is shared with the UHPHS USB host logic; the - * device logica cannot autonomously control USB clocking. - */ - /* Initialize DMA channels */ for (i = 1; i <= SAM_USBHS_NDMACHANNELS; i++) @@ -4256,10 +4268,11 @@ static void sam_hw_setup(struct sam_usbdev_s *priv) sam_putreg(USBHS_DEVINT_ALL, SAM_USBHS_DEVIDR); - /* The Atmel sample code disables USB clocking here (via the PMC - * CKGR_UCKR). However, we cannot really do that here because that - * clocking is also needed by the UHPHS host. - */ + /* Initialization complete... Freeze the clock */ + + regval = sam_getreg(SAM_USBHS_CTRL); + regval |= ~USBHS_CTRL_FRZCLK; + sam_putreg(regval, SAM_USBHS_CTRL); } /****************************************************************************