Signed-off-by: Antony Pavlov <[email protected]>
---
 arch/arm/Kconfig                |   1 +
 arch/arm/boards/ezzy-4/Makefile |   3 +
 arch/arm/boards/ezzy-4/usbio.c  | 449 ++++++++++++++++++++++++++++++++
 arch/arm/cpu/uncompress.c       |   7 +
 arch/arm/include/asm/debug_ll.h |   2 +
 include/mach/sc6531e/debug_ll.h |  17 ++
 6 files changed, 479 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b46d73f5084..ffd2ff8b531 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -88,6 +88,7 @@ config ARCH_SC6531E
        bool "SC6531E-based devices"
        depends on 32BIT
        select CPU_ARM926T
+       select HAS_DEBUG_LL
        select GPIOLIB
        help
          Support for feature phones based on the SC6531E chipset.
diff --git a/arch/arm/boards/ezzy-4/Makefile b/arch/arm/boards/ezzy-4/Makefile
index 458f5209008..c1253f3f64f 100644
--- a/arch/arm/boards/ezzy-4/Makefile
+++ b/arch/arm/boards/ezzy-4/Makefile
@@ -1,3 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 lwl-y += lowlevel.o
+
+lwl-y += usbio.o
+obj-y += usbio.o
diff --git a/arch/arm/boards/ezzy-4/usbio.c b/arch/arm/boards/ezzy-4/usbio.c
new file mode 100644
index 00000000000..954765d70fd
--- /dev/null
+++ b/arch/arm/boards/ezzy-4/usbio.c
@@ -0,0 +1,449 @@
+/*
+ * This file is part of fpdoom
+ * https://github.com/ilyakurdyukov/fpdoom/blob/main/fpdoom/usbio.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+void *memcpy(void *dst, const void *src, size_t count);
+size_t strlen(const char *src);
+
+void usb_debug_ll_init(void);
+int usb_PUTC_LL(char ch);
+
+#define ALIGN(n) __attribute__((aligned(n)))
+
+#define readl(a) (*(volatile uint32_t *)(a))
+#define writel(v,a)    (*(volatile uint32_t *)(a) = (v))
+
+#define MEM4(addr) *(volatile uint32_t*)(addr)
+
+#define READ32_BE(p) (uint32_t)( \
+       ((uint8_t*)(p))[0] << 24 | \
+       ((uint8_t*)(p))[1] << 16 | \
+       ((uint8_t*)(p))[2] << 8 | \
+       ((uint8_t*)(p))[3])
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+
+static inline uint32_t swap_be32(uint32_t v) {
+       uint32_t t = v >> 24 | v << 24, m = 0xff00;
+       return t | (v >> 8 & m) | (v & m) << 8;
+}
+#endif
+
+static unsigned fastchk16(unsigned crc, const void *src, int len)
+{
+       uint8_t *s = (uint8_t*)src;
+
+       while (len > 1) {
+               crc += s[1] << 8 | s[0]; s += 2;
+               len -= 2;
+       }
+
+       if (len)
+               crc += *s;
+
+       crc = (crc >> 16) + (crc & 0xffff);
+       crc += crc >> 16;
+
+       return crc & 0xffff;
+}
+
+enum {
+       HOST_CONNECT = 0x00,
+
+       CMD_MESSAGE = 0x80,
+       CMD_FOPEN = 0x81,
+       CMD_FREAD = 0x82,
+       CMD_FWRITE = 0x83,
+       CMD_FCLOSE = 0x84,
+       CMD_FSEEK = 0x85,
+       CMD_FTELL = 0x86,
+       CMD_GETARGS = 0x87,
+};
+
+#define CHECKSUM_INIT 0x5a5a
+#define USB_WAIT 1
+#define USB_NOWAIT 0
+
+#define USB_BASE_INIT
+#define USB_BASE 0x90000000
+
+#define USB_CR(o) MEM4(USB_BASE + o)
+
+#define USB_MAXREAD 64
+
+// not necessary, because USB is already
+// initialized by the bootloader
+#define INIT_USB 1
+
+#define USB_BUFSIZE 0x800
+
+#if (USB_BUFSIZE) & (USB_BUFSIZE - 1)
+#error
+#endif
+
+typedef struct {
+       uint32_t rpos, wpos;
+       uint8_t buf[USB_BUFSIZE];
+} usb_buf_t;
+
+usb_buf_t usb_buf;
+
+static const uint8_t dev_desc[] ALIGN(4) = {
+       0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40,
+       0x82, 0x17, 0x00, 0x4d, 0x02, 0x02, 0x00, 0x00,
+       0x00, 0x01
+};
+
+static const uint8_t config_desc[] ALIGN(4) = {
+       0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0, 0x32,
+       0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00,
+       0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
+       0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
+};
+
+enum {
+       USB_CTRL = 0,
+       INT_STS = 0x18,
+       INT_CLR = 0x1c,
+       TIMEOUT_LMT = 0x28,
+
+       TR_SIZE_IN_ENDP0 = 0x40,
+       REQ_SETUP_LOW = 0x5c,
+       REQ_SETUP_HIGH = 0x60,
+       ENDP0_CTRL = 0x64,
+       INT_CTRL_ENDP0 = 0x68,
+       INT_STS_ENDP0 = 0x6c,
+       INT_CLR_ENDP0 = 0x70,
+
+       ENDP1_CTRL = 0xc0,
+       TRANS_SIZE_ENDP1 = 0xc8,
+       INT_CTRL_ENDP1 = 0xcc,
+       INT_STS_ENDP1 = 0xd0,
+       INT_CLR_ENDP1 = 0xd4,
+
+       ENDP2_CTRL = 0x100,
+       RCV_DATA_ENDP2 = 0x104,
+       INT_CTRL_ENDP2 = 0x10c,
+       INT_STS_ENDP2 = 0x110,
+       INT_CLR_ENDP2 = 0x114,
+
+       ENDP3_CTRL = 0x140,
+       TRANS_SIZE_ENDP3 = 0x148,
+       INT_CTRL_ENDP3 = 0x14c,
+       INT_STS_ENDP3 = 0x150,
+       INT_CLR_ENDP3 = 0x154,
+};
+
+#define FIFO_entry_endp0_in (uint32_t*)(USB_BASE + 0x80000)
+#define FIFO_entry_endp1 (FIFO_entry_endp0_in + 1)
+#define FIFO_entry_endp3 (FIFO_entry_endp0_in + 2)
+
+#define FIFO_entry_endp_out (uint32_t*)(USB_BASE + 0x8000c)
+#define FIFO_entry_endp2 (FIFO_entry_endp_out + 1)
+
+/* max packet size */
+#define USB_MAXPSIZE(o, n) \
+       (USB_CR(o) = (USB_CR(o) & ~0x7ff000) | (n) << 12)
+/* transfer size */
+#define USB_TRSIZE(o, n) \
+       (USB_CR(o) = (USB_CR(o) & ~0x1ffff) | (n))
+
+#if INIT_USB
+static void usb_init_endp0(void) {
+       USB_BASE_INIT
+       USB_MAXPSIZE(ENDP0_CTRL, 8);
+       USB_CR(INT_CLR_ENDP0) |= 1 << 8;
+       USB_CR(INT_CTRL_ENDP0) |= 1 << 8;
+       USB_CR(ENDP0_CTRL) |= 1 << 28; // buffer ready
+}
+
+static void usb_init_endp2(void) {
+       USB_BASE_INIT
+       USB_MAXPSIZE(ENDP2_CTRL, 0x40);
+       USB_TRSIZE(RCV_DATA_ENDP2, 0x2000);
+       USB_CR(INT_CLR_ENDP2) = 0x3fff;
+       USB_CR(INT_CTRL_ENDP2) = 0;
+       USB_CR(INT_CLR_ENDP2) |= 1;
+       USB_CR(INT_CTRL_ENDP2) |= 1;
+       USB_CR(ENDP2_CTRL) |= 1 << 25; // endpoint enable
+       USB_CR(ENDP2_CTRL) |= 1 << 28; // buffer ready
+}
+
+static void usb_init_endp3(void) {
+       USB_BASE_INIT
+       USB_MAXPSIZE(ENDP3_CTRL, 0x40);
+       USB_TRSIZE(TRANS_SIZE_ENDP3, 0x40);
+       USB_CR(INT_CLR_ENDP3) = 0x3fff;
+       USB_CR(INT_CTRL_ENDP3) = 0;
+       USB_CR(INT_CLR_ENDP3) |= 1 << 9;
+       USB_CR(INT_CTRL_ENDP3) |= 1 << 9;
+       USB_CR(ENDP3_CTRL) |= 1 << 25; // endpoint enable
+}
+#endif
+
+// len = 0..0x7ff
+static void usb_send(uint32_t ep, const void *src, uint32_t len) {
+       uint32_t i, ctrl, tr_size; uint32_t *fifo;
+       const uint32_t *s = (const uint32_t*)src;
+       USB_BASE_INIT
+       do {
+               if (ep == 0) {
+                       ctrl = ENDP0_CTRL;
+                       tr_size = TR_SIZE_IN_ENDP0;
+                       fifo = FIFO_entry_endp0_in;
+               } else if (ep == 4) {
+                       ctrl = ENDP3_CTRL;
+                       tr_size = TRANS_SIZE_ENDP3;
+                       fifo = FIFO_entry_endp3;
+               } else break;
+
+               USB_MAXPSIZE(ctrl, len);
+               USB_TRSIZE(tr_size, len);
+
+               for (i = 0; i < len; i += 4, s++)
+                       *(volatile uint32_t*)fifo = READ32_BE(s);
+
+               USB_CR(ctrl) |= 1 << 27;
+
+               if (ep == 4) {
+                       // TRANSFER_END
+                       while ((USB_CR(INT_STS_ENDP3) & 1 << 9) == 0);
+                       USB_CR(INT_CLR_ENDP3) |= 1 << 9;
+               }
+       } while (0);
+}
+
+static void usb_recv(uint32_t ep, uint32_t *dst, uint32_t len) {
+       uint32_t i, ctrl; uint32_t *fifo;
+       USB_BASE_INIT
+       do {
+               fifo = FIFO_entry_endp_out;
+               if (ep == 1) {
+                       ctrl = ENDP0_CTRL;
+               } else if (ep == 3) {
+                       ctrl = ENDP2_CTRL;
+                       fifo += 1;      // FIFO_entry_endp2
+               } else break;
+
+               for (i = 0; i < len; i += 8) {
+                       *dst++ = swap_be32(*(volatile uint32_t*)fifo);
+                       *dst++ = swap_be32(*(volatile uint32_t*)fifo);
+               }
+
+               USB_CR(ctrl) |= 1 << 28;
+       } while (0);
+}
+
+#define USB_REC_DEVICE     0
+#define USB_REC_INTERFACE  1
+#define USB_REC_MASK       0x1f
+
+#define USB_REQ_STANDARD   (0 << 5)
+#define USB_REQ_CLASS      (1 << 5)
+#define USB_REQ_VENDOR     (2 << 5)
+#define USB_REQ_MASK       (3 << 5)
+
+#define USB_REQUEST_GET_DESCRIPTOR  6
+
+#define USB_DEVICE_DESCRIPTOR_TYPE  1
+#define USB_CONFIGURATION_DESCRIPTOR_TYPE  2
+
+static void usb_send_desc(int type, int len) {
+       const void *p; int n;
+       if (type == USB_DEVICE_DESCRIPTOR_TYPE) {
+               p = dev_desc; n = sizeof(dev_desc);
+       } else if (type == USB_CONFIGURATION_DESCRIPTOR_TYPE) {
+               p = config_desc; n = sizeof(config_desc);
+       } else return;
+
+       if (len > n) len = n;
+       usb_send(0, p, len);
+}
+
+static void usb_int_endp0(void) {
+       uint32_t a, b, len, req;
+       USB_BASE_INIT
+       if (USB_CR(INT_STS_ENDP0) & 1 << 8) { // SETUP_TRANS_END
+               a = USB_CR(REQ_SETUP_LOW);
+               len = USB_CR(REQ_SETUP_HIGH) >> 16; // wLength
+               req = (a >> 8) & 0xff;
+
+               b = a & (USB_REC_MASK | USB_REQ_MASK);
+               if (b == (USB_REC_DEVICE | USB_REQ_STANDARD)) {
+                       if (req == USB_REQUEST_GET_DESCRIPTOR)
+                               usb_send_desc(a >> 24, len);
+               }
+       }
+       USB_CR(INT_CLR_ENDP0) = 0x3fff;
+}
+
+static void usb_int_endp2(void) {
+       usb_buf_t *p; int i, len, wpos;
+       USB_BASE_INIT
+       if (USB_CR(INT_STS_ENDP2) & 1) { // TRANSACTION_END
+               uint8_t buf[USB_MAXREAD];
+               len = USB_CR(ENDP2_CTRL) & (USB_BUFSIZE - 1);
+               if (len > USB_MAXREAD) len = USB_MAXREAD;
+               usb_recv(3, (uint32_t*)buf, len);
+               p = &usb_buf;
+               wpos = p->wpos;
+               for (i = 0; i < len; i++) {
+                       p->buf[wpos++] = buf[i];
+                       wpos &= (USB_BUFSIZE - 1);
+               }
+               p->wpos = wpos;
+               USB_CR(ENDP2_CTRL) |= 1 << 28;
+       }
+       USB_CR(INT_CLR_ENDP2) = 0x3fff;
+}
+
+static void usb_int_endp3(void) {
+       USB_BASE_INIT
+       USB_CR(INT_CLR_ENDP3) = 0x3fff;
+}
+
+static void usb_check_int(void) {
+       USB_BASE_INIT
+       if ( readl(0x80001004) & (1 << 5) /* SC6531(DA/E) */ ) {
+               int mask = USB_CR(INT_STS);
+               if (mask & 0x3fff) {
+                       if (mask & 1 << 10) usb_int_endp2();
+                       if (mask & 1 << 11) usb_int_endp3();
+                       if (mask & 1 << 8) usb_int_endp0();
+               }
+               USB_CR(INT_CLR) = 0x7f;
+       }
+}
+
+static void usb_init(void) {
+       usb_buf_t *p = &usb_buf;
+       p->rpos = 0;
+       p->wpos = 0;
+
+#if INIT_USB
+       USB_CR(USB_CTRL) |= 1; // USB_ENABLE
+       usb_init_endp0();
+       usb_init_endp2();
+       usb_init_endp3();
+       // 12MHz / 15 = 800kHz
+       USB_CR(TIMEOUT_LMT) = 15;
+#endif
+}
+
+static int usb_read(void *dst, unsigned len, int wait) {
+       usb_buf_t *p = &usb_buf;
+       uint8_t *d = (uint8_t*)dst;
+       unsigned rpos, n, n2;
+
+       while (len) {
+               // usb_buf_free - 1 >= USB_MAXREAD
+               if (((p->rpos - p->wpos - 1) & (USB_BUFSIZE - 1)) >= 
USB_MAXREAD)
+                       usb_check_int();
+
+               rpos = p->rpos;
+               n = (p->wpos - rpos) & (USB_BUFSIZE - 1);
+               if (n) {
+                       if (n > len) n = len;
+                       len -= n;
+                       n2 = USB_BUFSIZE - rpos;
+                       if (n <= n2) {
+                               memcpy(d, p->buf + rpos, n);
+                       } else {
+                               memcpy(d, p->buf + rpos, n2);
+                               memcpy(d + n2, p->buf, n - n2);
+                       }
+                       d += n;
+                       p->rpos = (rpos + n) & (USB_BUFSIZE - 1);
+               } else if (!wait) break;
+       }
+       return d - (uint8_t*)dst;
+}
+
+static int usb_write(const void *src, unsigned len) {
+       const uint8_t *s = (const uint8_t*)src;
+       for (; len > USB_MAXREAD; len -= USB_MAXREAD) {
+               usb_send(4, s, USB_MAXREAD);
+               s += USB_MAXREAD;
+       }
+       if (len) {
+               if (len == USB_MAXREAD) {
+                       len >>= 1;
+                       usb_send(4, s, len);
+                       s += len;
+               }
+               usb_send(4, s, len);
+       }
+       return s - (uint8_t*)src;
+}
+
+static void _debug_msg(const char *msg)
+{
+       union { uint8_t u8[4]; uint16_t u16[2]; } buf;
+       int len;
+       unsigned tmp;
+
+       len = strlen(msg);
+       if (len > 255)
+               len = 255;
+
+       tmp = CMD_MESSAGE | len << 8;
+       buf.u16[0] = tmp;
+
+       tmp += CHECKSUM_INIT;
+       tmp = fastchk16(tmp, msg, len);
+       buf.u16[1] = tmp;
+
+       usb_write(buf.u16, 4);
+       usb_write(msg, len);
+}
+
+int usb_PUTC_LL(char ch)
+{
+       union { uint8_t u8[6]; uint16_t u16[3]; } buf;
+       unsigned tmp;
+
+       size_t size = 1;
+       void *src;
+
+       // stdout: handle = 1
+       int handle = 1;
+
+       src = &ch;
+
+       tmp = CMD_FWRITE | handle << 8;
+       buf.u16[0] = tmp;
+       buf.u16[1] = size;
+       tmp += CHECKSUM_INIT + size;
+       tmp = fastchk16(tmp, src, size);
+       buf.u16[2] = tmp;
+       usb_write(buf.u16, 6);
+       usb_write(src, size);
+       usb_read(buf.u16, 2, USB_WAIT);
+
+       return buf.u16[0];
+}
+
+void usb_debug_ll_init(void)
+{
+       static const uint8_t fdl_ack[8] = {
+               0x7e, 0, 0x80, 0, 0, 0xff, 0x7f, 0x7e };
+
+       usb_init();
+
+       usb_write(fdl_ack, sizeof(fdl_ack));
+
+       for (;;) {
+               char buf[4];
+
+               usb_read(buf, 1, USB_WAIT);
+
+               if (buf[0] == HOST_CONNECT)
+                       break;
+       }
+
+       _debug_msg("debug_ll\n");
+}
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index a481c4634d7..a92115eddd1 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -79,6 +79,13 @@ void __noreturn barebox_pbl_start(unsigned long membase, 
unsigned long memsize,
 
        setup_c();
 
+       if (IS_ENABLED(CONFIG_ARCH_SC6531E) && IS_ENABLED(CONFIG_DEBUG_LL)) {
+               usb_debug_ll_init();
+
+               puts_ll("Hello world\n");
+               puts_ll("\n");
+       }
+
        pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
 
        if (IS_ENABLED(CONFIG_MMU))
diff --git a/arch/arm/include/asm/debug_ll.h b/arch/arm/include/asm/debug_ll.h
index a1d5161ccf2..22628c5b4da 100644
--- a/arch/arm/include/asm/debug_ll.h
+++ b/arch/arm/include/asm/debug_ll.h
@@ -64,6 +64,8 @@
 #include <mach/clps711x/debug_ll.h>
 #elif defined CONFIG_ARCH_AT91
 #include <mach/at91/debug_ll.h>
+#elif defined CONFIG_ARCH_SC6531E
+#include <mach/sc6531e/debug_ll.h>
 #endif
 
 #endif
diff --git a/include/mach/sc6531e/debug_ll.h b/include/mach/sc6531e/debug_ll.h
new file mode 100644
index 00000000000..82c22fba647
--- /dev/null
+++ b/include/mach/sc6531e/debug_ll.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-FileCopyrightText: 2023 Antony Pavlov <[email protected]> */
+
+#ifndef __MACH_SC6531E_DEBUG_LL_H__
+#define __MACH_SC6531E_DEBUG_LL_H__
+
+#include <io.h>
+
+void usb_debug_ll_init(void);
+int usb_PUTC_LL(char ch);
+
+static inline void PUTC_LL(char ch)
+{
+       usb_PUTC_LL(ch);
+}
+
+#endif /* __MACH_SC6531E_DEBUG_LL_H__ */
-- 
2.39.0


Reply via email to