[RFC 3/4] sc6531e: add debug_ll support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Antony Pavlov <antonynpavlov@xxxxxxxxx>
---
 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 <antonynpavlov@xxxxxxxxx> */
+
+#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





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux