aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/atsam/Kconfig1
-rw-r--r--src/atsam/Makefile4
-rw-r--r--src/atsam/main.c37
-rw-r--r--src/atsam/sam3_usb.c229
-rw-r--r--src/atsam/sam4_usb.c23
5 files changed, 268 insertions, 26 deletions
diff --git a/src/atsam/Kconfig b/src/atsam/Kconfig
index 65c53e97..9aec3821 100644
--- a/src/atsam/Kconfig
+++ b/src/atsam/Kconfig
@@ -52,7 +52,6 @@ config CLOCK_FREQ
default 60000000 if MACH_SAM4E # 120000000/2
config USBSERIAL
- depends on MACH_SAM4
bool "Use USB for communication (instead of serial)"
default y
config SERIAL
diff --git a/src/atsam/Makefile b/src/atsam/Makefile
index fca614f3..76f7d86f 100644
--- a/src/atsam/Makefile
+++ b/src/atsam/Makefile
@@ -31,7 +31,9 @@ CFLAGS_klipper.elf += $(eflags-y) --specs=nano.specs --specs=nosys.specs
src-y += atsam/main.c atsam/gpio.c atsam/i2c.c atsam/spi.c
src-y += generic/crc16_ccitt.c generic/alloc.c
src-y += generic/armcm_irq.c generic/timer_irq.c
-src-$(CONFIG_USBSERIAL) += atsam/sam4_usb.c generic/usb_cdc.c
+usbserial-$(CONFIG_MACH_SAM3X) := atsam/sam3_usb.c
+usbserial-$(CONFIG_MACH_SAM4) := atsam/sam4_usb.c
+src-$(CONFIG_USBSERIAL) += $(usbserial-y) generic/usb_cdc.c
src-$(CONFIG_SERIAL) += atsam/serial.c generic/serial_irq.c
src-$(CONFIG_MACH_SAM3X) += atsam/adc.c atsam/timer.c
src-$(CONFIG_MACH_SAM4S) += atsam/adc.c atsam/sam4s_timer.c
diff --git a/src/atsam/main.c b/src/atsam/main.c
index 1b9375db..7dba4a2d 100644
--- a/src/atsam/main.c
+++ b/src/atsam/main.c
@@ -5,6 +5,7 @@
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "board/irq.h" // irq_disable
+#include "board/usb_cdc.h" // usb_request_bootloader
#include "command.h" // DECL_CONSTANT
#include "internal.h" // WDT
#include "sched.h" // sched_main
@@ -33,7 +34,7 @@ DECL_INIT(watchdog_init);
/****************************************************************
- * misc functions
+ * Peripheral clocks
****************************************************************/
// Check if a peripheral clock has been enabled
@@ -56,6 +57,11 @@ enable_pclock(uint32_t id)
PMC->PMC_PCER1 = 1 << (id - 32);
}
+
+/****************************************************************
+ * Resets
+ ****************************************************************/
+
void
command_reset(uint32_t *args)
{
@@ -67,6 +73,35 @@ command_reset(uint32_t *args)
}
DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset");
+#if CONFIG_MACH_SAM3X || CONFIG_MACH_SAM4S
+#define EFC_HW EFC0
+#elif CONFIG_MACH_SAM4E
+#define EFC_HW EFC
+#endif
+
+void noinline __aligned(16) // align for predictable flash code access
+usb_request_bootloader(void)
+{
+ irq_disable();
+ // Request boot from ROM (instead of boot from flash)
+ while ((EFC_HW->EEFC_FSR & EEFC_FSR_FRDY) == 0)
+ ;
+ EFC_HW->EEFC_FCR = (EEFC_FCR_FCMD_CGPB | EEFC_FCR_FARG(1)
+ | EEFC_FCR_FKEY_PASSWD);
+ while ((EFC_HW->EEFC_FSR & EEFC_FSR_FRDY) == 0)
+ ;
+ // Reboot
+ RSTC->RSTC_CR = ((0xA5 << RSTC_CR_KEY_Pos) | RSTC_CR_PROCRST
+ | RSTC_CR_PERRST);
+ for (;;)
+ ;
+}
+
+
+/****************************************************************
+ * Startup
+ ****************************************************************/
+
// Main entry point
int
main(void)
diff --git a/src/atsam/sam3_usb.c b/src/atsam/sam3_usb.c
new file mode 100644
index 00000000..d9101478
--- /dev/null
+++ b/src/atsam/sam3_usb.c
@@ -0,0 +1,229 @@
+// Hardware interface to USB on SAM3X
+//
+// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include <string.h> // NULL
+#include "board/usb_cdc.h" // usb_notify_ep0
+#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN
+#include "internal.h" // UOTGHS
+#include "sched.h" // DECL_INIT
+
+#define EP_SIZE(s) ((s)==64 ? UOTGHS_DEVEPTCFG_EPSIZE_64_BYTE : \
+ ((s)==32 ? UOTGHS_DEVEPTCFG_EPSIZE_32_BYTE : \
+ ((s)==16 ? UOTGHS_DEVEPTCFG_EPSIZE_16_BYTE : \
+ UOTGHS_DEVEPTCFG_EPSIZE_8_BYTE)))
+
+#define usb_fifo(ep) ((void*)UOTGHS_RAM_ADDR + ((ep) * 0x8000))
+
+static void
+usb_write_packet(uint32_t ep, const uint8_t *data, uint32_t len)
+{
+ uint8_t *dest = usb_fifo(ep);
+ while (len--)
+ *dest++ = *data++;
+}
+
+static void
+usb_read_packet(uint32_t ep, uint8_t *data, uint32_t len)
+{
+ uint8_t *src = usb_fifo(ep);
+ while (len--)
+ *data++ = *src++;
+}
+
+int_fast8_t
+usb_read_bulk_out(void *data, uint_fast8_t max_len)
+{
+ uint32_t eps = UOTGHS->UOTGHS_DEVEPTISR[USB_CDC_EP_BULK_OUT];
+ if (!(eps & UOTGHS_DEVEPTISR_RXOUTI)) {
+ // No data ready
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << USB_CDC_EP_BULK_OUT;
+ return -1;
+ }
+ uint32_t len = (eps&UOTGHS_DEVEPTISR_BYCT_Msk) >> UOTGHS_DEVEPTISR_BYCT_Pos;
+ usb_read_packet(USB_CDC_EP_BULK_OUT, data, len > max_len ? max_len : len);
+ UOTGHS->UOTGHS_DEVEPTICR[USB_CDC_EP_BULK_OUT] = UOTGHS_DEVEPTICR_RXOUTIC;
+ UOTGHS->UOTGHS_DEVEPTIDR[USB_CDC_EP_BULK_OUT] = UOTGHS_DEVEPTIDR_FIFOCONC;
+ return len;
+}
+
+int_fast8_t
+usb_send_bulk_in(void *data, uint_fast8_t len)
+{
+ uint32_t eps = UOTGHS->UOTGHS_DEVEPTISR[USB_CDC_EP_BULK_IN];
+ if (!(eps & UOTGHS_DEVEPTISR_TXINI)) {
+ // Buffer full
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << USB_CDC_EP_BULK_IN;
+ return -1;
+ }
+ usb_write_packet(USB_CDC_EP_BULK_IN, data, len);
+ UOTGHS->UOTGHS_DEVEPTICR[USB_CDC_EP_BULK_IN] = UOTGHS_DEVEPTICR_TXINIC;
+ UOTGHS->UOTGHS_DEVEPTIDR[USB_CDC_EP_BULK_IN] = UOTGHS_DEVEPTIDR_FIFOCONC;
+ return len;
+}
+
+int_fast8_t
+usb_read_ep0(void *data, uint_fast8_t max_len)
+{
+ uint32_t eps = UOTGHS->UOTGHS_DEVEPTISR[0];
+ if (eps & UOTGHS_DEVEPTISR_RXSTPI)
+ return -2;
+ if (!(eps & UOTGHS_DEVEPTISR_RXOUTI)) {
+ // Not ready to receive data
+ UOTGHS->UOTGHS_DEVEPTIER[0] = UOTGHS_DEVEPTIER_RXOUTES;
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << 0;
+ return -1;
+ }
+ usb_read_packet(0, data, max_len);
+ if (UOTGHS->UOTGHS_DEVEPTISR[0] & UOTGHS_DEVEPTISR_RXSTPI)
+ return -2;
+ UOTGHS->UOTGHS_DEVEPTICR[0] = UOTGHS_DEVEPTICR_RXOUTIC;
+ return max_len;
+}
+
+int_fast8_t
+usb_read_ep0_setup(void *data, uint_fast8_t max_len)
+{
+ uint32_t eps = UOTGHS->UOTGHS_DEVEPTISR[0];
+ if (!(eps & UOTGHS_DEVEPTISR_RXSTPI)) {
+ // No data ready to read
+ UOTGHS->UOTGHS_DEVEPTIDR[0] = (UOTGHS_DEVEPTIDR_TXINEC
+ | UOTGHS_DEVEPTIDR_RXOUTEC);
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << 0;
+ return -1;
+ }
+ usb_read_packet(0, data, max_len);
+ UOTGHS->UOTGHS_DEVEPTICR[0] = (UOTGHS_DEVEPTICR_RXSTPIC
+ | UOTGHS_DEVEPTICR_RXOUTIC);
+ return max_len;
+}
+
+int_fast8_t
+usb_send_ep0(const void *data, uint_fast8_t len)
+{
+ uint32_t eps = UOTGHS->UOTGHS_DEVEPTISR[0];
+ if (eps & (UOTGHS_DEVEPTISR_RXSTPI | UOTGHS_DEVEPTISR_RXOUTI))
+ return -2;
+ if (!(eps & UOTGHS_DEVEPTISR_TXINI)) {
+ // Not ready to send
+ UOTGHS->UOTGHS_DEVEPTIER[0] = (UOTGHS_DEVEPTIER_TXINES
+ | UOTGHS_DEVEPTIER_RXOUTES);
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << 0;
+ return -1;
+ }
+ usb_write_packet(0, data, len);
+ UOTGHS->UOTGHS_DEVEPTICR[0] = UOTGHS_DEVEPTICR_TXINIC;
+ return len;
+}
+
+void
+usb_stall_ep0(void)
+{
+ UOTGHS->UOTGHS_DEVEPTIER[0] = UOTGHS_DEVEPTIER_STALLRQS;
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << 0;
+}
+
+static uint8_t set_address;
+
+void
+usb_set_address(uint_fast8_t addr)
+{
+ set_address = addr | UOTGHS_DEVCTRL_ADDEN;
+ usb_send_ep0(NULL, 0);
+ UOTGHS->UOTGHS_DEVEPTIER[0] = UOTGHS_DEVEPTIER_TXINES;
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << 0;
+}
+
+void
+usb_set_configure(void)
+{
+ UOTGHS->UOTGHS_DEVEPT = ((UOTGHS_DEVEPT_EPEN0 << 0)
+ | (UOTGHS_DEVEPT_EPEN0 << USB_CDC_EP_BULK_OUT)
+ | (UOTGHS_DEVEPT_EPEN0 << USB_CDC_EP_BULK_IN)
+ | (UOTGHS_DEVEPT_EPEN0 << USB_CDC_EP_ACM));
+
+ UOTGHS->UOTGHS_DEVEPTCFG[USB_CDC_EP_BULK_OUT] = (
+ EP_SIZE(USB_CDC_EP_BULK_OUT_SIZE)
+ | UOTGHS_DEVEPTCFG_EPTYPE_BLK | UOTGHS_DEVEPTCFG_EPBK_2_BANK
+ | UOTGHS_DEVEPTCFG_ALLOC);
+ UOTGHS->UOTGHS_DEVEPTIER[USB_CDC_EP_BULK_OUT] = UOTGHS_DEVEPTIER_RXOUTES;
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << USB_CDC_EP_BULK_OUT;
+
+ UOTGHS->UOTGHS_DEVEPTCFG[USB_CDC_EP_BULK_IN] = (
+ EP_SIZE(USB_CDC_EP_BULK_IN_SIZE) | UOTGHS_DEVEPTCFG_EPDIR_IN
+ | UOTGHS_DEVEPTCFG_EPTYPE_BLK | UOTGHS_DEVEPTCFG_EPBK_2_BANK
+ | UOTGHS_DEVEPTCFG_ALLOC);
+ UOTGHS->UOTGHS_DEVEPTIER[USB_CDC_EP_BULK_IN] = UOTGHS_DEVEPTIER_TXINES;
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << USB_CDC_EP_BULK_IN;
+
+ UOTGHS->UOTGHS_DEVEPTCFG[USB_CDC_EP_ACM] = (
+ EP_SIZE(USB_CDC_EP_ACM_SIZE) | UOTGHS_DEVEPTCFG_EPDIR_IN
+ | UOTGHS_DEVEPTCFG_EPTYPE_INTRPT | UOTGHS_DEVEPTCFG_EPBK_2_BANK
+ | UOTGHS_DEVEPTCFG_ALLOC);
+}
+
+// Configure endpoint 0 after usb reset completes
+static void
+handle_end_reset(void)
+{
+ UOTGHS->UOTGHS_DEVEPT = UOTGHS_DEVEPT_EPEN0 << 0;
+ UOTGHS->UOTGHS_DEVEPTCFG[0] = (
+ EP_SIZE(USB_CDC_EP0_SIZE)
+ | UOTGHS_DEVEPTCFG_EPTYPE_CTRL | UOTGHS_DEVEPTCFG_EPBK_1_BANK
+ | UOTGHS_DEVEPTCFG_ALLOC);
+ UOTGHS->UOTGHS_DEVEPTIER[0] = UOTGHS_DEVEPTIER_RXSTPES;
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << 0;
+
+ UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVICR_EORSTC;
+}
+
+void
+usbserial_init(void)
+{
+ // Setup USB clock
+ enable_pclock(ID_UOTGHS);
+ PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(3) | CKGR_UCKR_UPLLEN;
+ while (!(PMC->PMC_SR & PMC_SR_LOCKU))
+ ;
+ PMC->PMC_USB = PMC_USB_USBS | PMC_USB_USBDIV(0);
+ PMC->PMC_SCER = PMC_SCER_UOTGCLK;
+
+ // Enable USB
+ UOTGHS->UOTGHS_CTRL = (UOTGHS_CTRL_UIMOD | UOTGHS_CTRL_OTGPADE
+ | UOTGHS_CTRL_USBE);
+ UOTGHS->UOTGHS_DEVCTRL = UOTGHS_DEVCTRL_SPDCONF_FORCED_FS;
+
+ // Enable interrupts
+ NVIC_SetPriority(UOTGHS_IRQn, 1);
+ NVIC_EnableIRQ(UOTGHS_IRQn);
+ UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_EORSTES;
+}
+DECL_INIT(usbserial_init);
+
+void __visible
+UOTGHS_Handler(void)
+{
+ uint32_t s = UOTGHS->UOTGHS_DEVISR;
+ if (s & UOTGHS_DEVISR_EORST) {
+ handle_end_reset();
+ return;
+ }
+ UOTGHS->UOTGHS_DEVIDR = s;
+ if (s & (UOTGHS_DEVISR_PEP_0 << 0)) {
+ usb_notify_ep0();
+
+ if (set_address
+ && (UOTGHS->UOTGHS_DEVEPTISR[0] & UOTGHS_DEVEPTISR_TXINI)) {
+ // Ack from set_address command sent - now update address
+ UOTGHS->UOTGHS_DEVCTRL = (set_address
+ | UOTGHS_DEVCTRL_SPDCONF_FORCED_FS);
+ set_address = 0;
+ }
+ }
+ if (s & (UOTGHS_DEVISR_PEP_0 << USB_CDC_EP_BULK_OUT))
+ usb_notify_bulk_out();
+ if (s & (UOTGHS_DEVISR_PEP_0 << USB_CDC_EP_BULK_IN))
+ usb_notify_bulk_in();
+}
diff --git a/src/atsam/sam4_usb.c b/src/atsam/sam4_usb.c
index ecf8e544..a615ffa5 100644
--- a/src/atsam/sam4_usb.c
+++ b/src/atsam/sam4_usb.c
@@ -159,29 +159,6 @@ usb_set_configure(void)
UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG;
}
-#if CONFIG_MACH_SAM4S8C
-#define EFC_HW EFC0
-#elif CONFIG_MACH_SAM4E8E
-#define EFC_HW EFC
-#endif
-
-void noinline __aligned(16) // align for predictable flash code access
-usb_request_bootloader(void)
-{
- irq_disable();
- // Request boot from ROM (instead of boot from flash)
- while ((EFC_HW->EEFC_FSR & EEFC_FSR_FRDY) == 0)
- ;
- EFC_HW->EEFC_FCR = (EEFC_FCR_FCMD_CGPB | EEFC_FCR_FARG(1)
- | EEFC_FCR_FKEY_PASSWD);
- while ((EFC_HW->EEFC_FSR & EEFC_FSR_FRDY) == 0)
- ;
- // Reboot
- RSTC->RSTC_CR = RSTC_CR_KEY(0xA5) | RSTC_CR_PROCRST | RSTC_CR_PERRST;
- for (;;)
- ;
-}
-
void
usbserial_init(void)
{