M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
.text
.globl __cpu_early_init
__cpu_early_init:
/* do an omap3 specific setup of the L2 */
mov r12, #1
.word 0xe1600070
bx lr

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdarg.h>
#include <reg.h>
#include <debug.h>
#include <printf.h>
#include <kernel/thread.h>
#include <platform/debug.h>
#include <arch/ops.h>
#include <dev/uart.h>
#include <target/debugconfig.h>
void _dputc(char c)
{
if (c == '\n')
uart_putc(DEBUG_UART, '\r');
uart_putc(DEBUG_UART, c);
}
int dgetc(char *c, bool wait)
{
int _c;
if ((_c = uart_getc(DEBUG_UART, false)) < 0)
return -1;
*c = _c;
return 0;
}
void debug_dump_regs(void)
{
PANIC_UNIMPLEMENTED;
}
void platform_halt(void)
{
dprintf(ALWAYS, "HALT: spinning forever...\n");
for(;;);
}
void debug_dump_memory_bytes(void *mem, int len)
{
PANIC_UNIMPLEMENTED;
}
void debug_dump_memory_halfwords(void *mem, int len)
{
PANIC_UNIMPLEMENTED;
}
void debug_dump_memory_words(void *mem, int len)
{
PANIC_UNIMPLEMENTED;
}
void debug_set_trace_level(int trace_type, int level)
{
PANIC_UNIMPLEMENTED;
}

View File

@@ -0,0 +1,315 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <err.h>
#include <reg.h>
#include <string.h>
#include <platform.h>
#include <platform/omap3.h>
#define LOCAL_TRACE 0
#define I2C_TIMEOUT 200
static const addr_t i2c_reg_base[] = {
I2C1_BASE,
I2C2_BASE,
I2C3_BASE,
};
#define I2C_REG_ADDR(bus, reg) (i2c_reg_base[bus] + (reg))
#define I2C_REG(bus, reg) (*REG16(I2C_REG_ADDR(bus, reg)))
#define I2C_RMW_REG(bus, reg, startbit, width, val) RMWREG16(I2C_REG_ADDR(bus, reg), startbit, width, val)
static void i2c_dump_bus(int bus)
{
hexdump((void *)i2c_reg_base[bus], 128);
}
static void i2c_reset_bus(int bus)
{
I2C_REG(bus, I2C_CON) &= ~(1<<15); // make sure the bus is disabled
/* reset the bus */
I2C_REG(bus, I2C_SYSC) = (1<<1);
I2C_REG(bus, I2C_CON) = (1<<15); // enable the bus
while ((I2C_REG(bus, I2C_SYSS) & 1) == 0)
;
/* disable the bus again and set up some internals */
I2C_REG(bus, I2C_CON) &= ~(1<<15); // make sure the bus is disabled
/* set up the clock */
I2C_REG(bus, I2C_PSC) = 23; // 96Mhz / 23 == 4Mhz
I2C_REG(bus, I2C_SCLL) = 13;
I2C_REG(bus, I2C_SCLH) = 15; // 4Mhz / combined divider of 40 (13+7 + 15+5) == 100khz
/* slave address */
I2C_REG(bus, I2C_OA0) = 1; // XXX made this up
/* fifo is set to 1 byte trigger */
I2C_REG(bus, I2C_BUF) = 0;
/* disable all interrupts */
I2C_REG(bus, I2C_IE) = 0;
/* enable the bus */
I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<9); // enable, master, transmitter mode
}
static void i2c_wait_for_bb(int bus)
{
I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending
while (I2C_REG(bus, I2C_STAT) & (1<<12)) {
I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending
}
I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending
}
int i2c_transmit(int bus, uint8_t address, const void *buf, size_t count)
{
int err;
LTRACEF("bus %d, address 0x%hhx, buf %p, count %zd\n", bus, address, buf, count);
i2c_wait_for_bb(bus);
I2C_REG(bus, I2C_SA) = address;
I2C_REG(bus, I2C_CNT) = count;
I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<9)|(1<<1)|(1<<0); // enable, master, transmit, STP, STT
time_t t = current_time();
const uint8_t *ptr = (const uint8_t *)buf;
for(;;) {
uint16_t stat = I2C_REG(bus, I2C_STAT);
if (stat & (1<<1)) {
// NACK
// printf("NACK\n");
err = -1;
goto out;
}
if (stat & (1<<0)) {
// AL (arbitration lost)
// printf("arbitration lost!\n");
err = -1;
goto out;
}
if (stat & (1<<2)) {
// ARDY
// printf("ARDY, completed\n");
break;
}
if (stat & (1<<4)) {
// RRDY
// printf("XRDY\n");
// transmit a byte
*REG8(I2C_REG_ADDR(bus, I2C_DATA)) = *ptr;
ptr++;
}
I2C_REG(bus, I2C_STAT) = stat;
if (current_time() - t > I2C_TIMEOUT) {
// printf("i2c timeout\n");
err = ERR_TIMED_OUT;
goto out;
}
}
err = 0;
out:
I2C_REG(bus, I2C_STAT) = 0xffff;
I2C_REG(bus, I2C_CNT) = 0;
return err;
}
int i2c_receive(int bus, uint8_t address, void *buf, size_t count)
{
int err;
LTRACEF("bus %d, address 0x%hhx, buf %p, count %zd\n", bus, address, buf, count);
i2c_wait_for_bb(bus);
I2C_REG(bus, I2C_SA) = address;
I2C_REG(bus, I2C_CNT) = count;
I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<1)|(1<<0); // enable, master, STP, STT
time_t t = current_time();
uint8_t *ptr = (uint8_t *)buf;
for(;;) {
uint16_t stat = I2C_REG(bus, I2C_STAT);
if (stat & (1<<1)) {
// NACK
// printf("NACK\n");
err = -1;
goto out;
}
if (stat & (1<<0)) {
// AL (arbitration lost)
// printf("arbitration lost!\n");
err = -1;
goto out;
}
if (stat & (1<<2)) {
// ARDY
// printf("ARDY, completed\n");
break;
}
if (stat & (1<<3)) {
// RRDY
// printf("RRDY\n");
// read a byte, since our fifo threshold is set to 1 byte
*ptr = *REG8(I2C_REG_ADDR(bus, I2C_DATA));
ptr++;
}
I2C_REG(bus, I2C_STAT) = stat;
if (current_time() - t > I2C_TIMEOUT) {
// printf("i2c timeout\n");
err = ERR_TIMED_OUT;
goto out;
}
}
err = 0;
out:
I2C_REG(bus, I2C_STAT) = 0xffff;
I2C_REG(bus, I2C_CNT) = 0;
return err;
}
int i2c_write_reg(int bus, uint8_t address, uint8_t reg, uint8_t val)
{
uint8_t buf[2];
buf[0] = reg;
buf[1] = val;
return i2c_transmit(bus, address, buf, 2);
}
int i2c_read_reg(int bus, uint8_t address, uint8_t reg, uint8_t *val)
{
int err = i2c_transmit(bus, address, &reg, 1);
if (err < 0)
return err;
return i2c_receive(bus, address, val, 1);
}
void i2c_init_early(void)
{
LTRACE_ENTRY;
/* enable clocks on i2c 0-2 */
RMWREG32(CM_FCLKEN1_CORE, 15, 3, 0x7),
RMWREG32(CM_ICLKEN1_CORE, 15, 3, 0x7),
i2c_reset_bus(0);
i2c_reset_bus(1);
i2c_reset_bus(2);
#if 0
// write something into a reg
char buf[2];
i2c_write_reg(0, 0x4b, 0x14, 0x99);
i2c_write_reg(0, 0x4b, 0x15, 0x98);
i2c_read_reg(0, 0x4b, 0x15, buf);
printf("0x%hhx\n", buf[0]);
i2c_read_reg(0, 0x4b, 0x14, buf);
printf("0x%hhx\n", buf[0]);
int i;
for (i=0; i < 255; i++) {
char buf[1];
buf[0] = i;
i2c_transmit(0, 0x4b, buf, 1);
i2c_receive(0, 0x4b, buf, sizeof(buf));
printf("0x%hhx\n", buf[0]);
}
#endif
LTRACE_EXIT;
}
void i2c_init(void)
{
}
#if WITH_LIB_CONSOLE
#include <lib/console.h>
static int cmd_i2c(int argc, const cmd_args *argv);
STATIC_COMMAND_START
{ "i2c", "i2c read/write commands", &cmd_i2c },
STATIC_COMMAND_END(i2c);
static int cmd_i2c(int argc, const cmd_args *argv)
{
int err;
if (argc < 5) {
printf("not enough arguments\n");
usage:
printf("%s read_reg <bus> <i2c address> <register>\n", argv[0].str);
printf("%s write_reg <bus> <i2c address> <register> <val>\n", argv[0].str);
return -1;
}
int bus = argv[2].u;
uint8_t i2c_address = argv[3].u;
if (!strcmp(argv[1].str, "read_reg")) {
uint8_t reg = argv[4].u;
uint8_t val;
err = i2c_read_reg(bus, i2c_address, reg, &val);
printf("i2c_read_reg err %d, val 0x%hhx\n", err, val);
} else if (!strcmp(argv[1].str, "write_reg")) {
uint8_t reg = argv[4].u;
uint8_t val = argv[5].u;
err = i2c_write_reg(bus, i2c_address, reg, val);
printf("i2c_write_reg err %d\n", err);
} else {
printf("unrecognized subcommand\n");
goto usage;
}
return 0;
}
#endif // WITH_APP_CONSOLE

View File

@@ -0,0 +1,257 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __PLATFORM_OMAP3_H
#define __PLATFORM_OMAP3_H
#define SDRAM_BASE 0x80000000
#define L4_BASE 0x48000000
#define L4_WKUP_BASE 0x48300000
#define L4_PER_BASE 0x49000000
#define L4_EMU_BASE 0x54000000
#define GFX_BASE 0x50000000
#define L3_BASE 0x68000000
#define SMS_BASE 0x6C000000
#define SDRC_BASE 0x6D000000
#define GPMC_BASE 0x6E000000
#define SCM_BASE 0x48002000
/* clocks */
#define CM_CLKSEL_PER (L4_BASE + 0x5040)
/* PRCM */
#define CM_FCLKEN_IVA2 (L4_BASE + 0x4000)
#define CM_CLKEN_PLL_IVA2 (L4_BASE + 0x4004)
#define CM_IDLEST_PLL_IVA2 (L4_BASE + 0x4024)
#define CM_CLKSEL1_PLL_IVA2 (L4_BASE + 0x4040)
#define CM_CLKSEL2_PLL_IVA2 (L4_BASE + 0x4044)
#define CM_CLKEN_PLL_MPU (L4_BASE + 0x4904)
#define CM_IDLEST_PLL_MPU (L4_BASE + 0x4924)
#define CM_CLKSEL1_PLL_MPU (L4_BASE + 0x4940)
#define CM_CLKSEL2_PLL_MPU (L4_BASE + 0x4944)
#define CM_FCLKEN1_CORE (L4_BASE + 0x4a00)
#define CM_ICLKEN1_CORE (L4_BASE + 0x4a10)
#define CM_ICLKEN2_CORE (L4_BASE + 0x4a14)
#define CM_CLKSEL_CORE (L4_BASE + 0x4a40)
#define CM_FCLKEN_GFX (L4_BASE + 0x4b00)
#define CM_ICLKEN_GFX (L4_BASE + 0x4b10)
#define CM_CLKSEL_GFX (L4_BASE + 0x4b40)
#define CM_FCLKEN_WKUP (L4_BASE + 0x4c00)
#define CM_ICLKEN_WKUP (L4_BASE + 0x4c10)
#define CM_CLKSEL_WKUP (L4_BASE + 0x4c40)
#define CM_IDLEST_WKUP (L4_BASE + 0x4c20)
#define CM_CLKEN_PLL (L4_BASE + 0x4d00)
#define CM_IDLEST_CKGEN (L4_BASE + 0x4d20)
#define CM_CLKSEL1_PLL (L4_BASE + 0x4d40)
#define CM_CLKSEL2_PLL (L4_BASE + 0x4d44)
#define CM_CLKSEL3_PLL (L4_BASE + 0x4d48)
#define CM_FCLKEN_DSS (L4_BASE + 0x4e00)
#define CM_ICLKEN_DSS (L4_BASE + 0x4e10)
#define CM_CLKSEL_DSS (L4_BASE + 0x4e40)
#define CM_FCLKEN_CAM (L4_BASE + 0x4f00)
#define CM_ICLKEN_CAM (L4_BASE + 0x4f10)
#define CM_CLKSEL_CAM (L4_BASE + 0x4F40)
#define CM_FCLKEN_PER (L4_BASE + 0x5000)
#define CM_ICLKEN_PER (L4_BASE + 0x5010)
#define CM_CLKSEL_PER (L4_BASE + 0x5040)
#define CM_CLKSEL1_EMU (L4_BASE + 0x5140)
#define PRM_CLKSEL (L4_BASE + 0x306d40)
#define PRM_RSTCTRL (L4_BASE + 0x307250)
#define PRM_CLKSRC_CTRL (L4_BASE + 0x307270)
/* General Purpose Timers */
#define OMAP34XX_GPT1 (L4_BASE + 0x318000)
#define OMAP34XX_GPT2 (L4_BASE + 0x1032000)
#define OMAP34XX_GPT3 (L4_BASE + 0x1034000)
#define OMAP34XX_GPT4 (L4_BASE + 0x1036000)
#define OMAP34XX_GPT5 (L4_BASE + 0x1038000)
#define OMAP34XX_GPT6 (L4_BASE + 0x103A000)
#define OMAP34XX_GPT7 (L4_BASE + 0x103C000)
#define OMAP34XX_GPT8 (L4_BASE + 0x103E000)
#define OMAP34XX_GPT9 (L4_BASE + 0x1040000)
#define OMAP34XX_GPT10 (L4_BASE + 0x86000)
#define OMAP34XX_GPT11 (L4_BASE + 0x88000)
#define OMAP34XX_GPT12 (L4_BASE + 0x304000)
#define TIDR 0x00
#define TIOCP_CFG 0x10
#define TISTAT 0x14
#define TISR 0x18
#define TIER 0x1C
#define TWER 0x20
#define TCLR 0x24
#define TCRR 0x28
#define TLDR 0x2C
#define TTGR 0x30
#define TWPS 0x34
#define TMAR 0x38
#define TCAR1 0x3C
#define TSICR 0x40
#define TCAR2 0x44
#define TPIR 0x48
#define TNIR 0x4C
#define TCVR 0x50
#define TOCR 0x54
#define TOWR 0x58
/* WatchDog Timers (1 secure, 3 GP) */
#define WD1_BASE (0x4830C000)
#define WD2_BASE (0x48314000)
#define WD3_BASE (0x49030000)
#define WIDR 0x00
#define WD_SYSCONFIG 0x10
#define WD_SYSSTATUS 0x14
#define WISR 0x18
#define WIER 0x1C
#define WCLR 0x24
#define WCRR 0x28
#define WLDR 0x2C
#define WTGR 0x30
#define WWPS 0x34
#define WSPR 0x48
#define W_PEND_WCLR (1<<0)
#define W_PEND_WCRR (1<<1)
#define W_PEND_WLDR (1<<2)
#define W_PEND_WTGR (1<<3)
#define W_PEND_WSPR (1<<4)
#define WD_UNLOCK1 0xAAAA
#define WD_UNLOCK2 0x5555
/* 32KTIMER */
#define TIMER32K_BASE (L4_BASE + 0x320000)
#define TIMER32K_REV (TIMER32K_BASE + 0x00)
#define TIMER32K_CR (TIMER32K_BASE + 0x10)
/* UART */
#define OMAP_UART1_BASE (L4_BASE + 0x6a000)
#define OMAP_UART2_BASE (L4_BASE + 0x6c000)
#define OMAP_UART3_BASE (L4_BASE + 0x01020000)
#define UART_RHR 0
#define UART_THR 0
#define UART_DLL 0
#define UART_IER 1
#define UART_DLH 1
#define UART_IIR 2
#define UART_FCR 2
#define UART_EFR 2
#define UART_LCR 3
#define UART_MCR 4
#define UART_LSR 5
#define UART_MSR 6
#define UART_TCR 6
#define UART_SPR 7
#define UART_TLR 7
#define UART_MDR1 8
#define UART_MDR2 9
#define UART_SFLSR 10
#define UART_RESUME 11
#define UART_TXFLL 10
#define UART_TXFLH 11
#define UART_SFREGL 12
#define UART_SFREGH 13
#define UART_RXFLL 12
#define UART_RXFLH 13
#define UART_BLR 14
#define UART_UASR 14
#define UART_ACREG 15
#define UART_SCR 16
#define UART_SSR 17
#define UART_EBLR 18
#define UART_MVR 19
#define UART_SYSC 20
/* MPU INTC */
#define INTC_BASE (L4_BASE + 0x200000)
#define INTC_REVISION (INTC_BASE + 0x000)
#define INTC_SYSCONFIG (INTC_BASE + 0x010)
#define INTC_SYSSTATUS (INTC_BASE + 0x014)
#define INTC_SIR_IRQ (INTC_BASE + 0x040)
#define INTC_SIR_FIQ (INTC_BASE + 0x044)
#define INTC_CONTROL (INTC_BASE + 0x048)
#define INTC_PROTECTION (INTC_BASE + 0x04C)
#define INTC_IDLE (INTC_BASE + 0x050)
#define INTC_IRQ_PRIORITY (INTC_BASE + 0x060)
#define INTC_FIQ_PRIORITY (INTC_BASE + 0x064)
#define INTC_THRESHOLD (INTC_BASE + 0x068)
#define INTC_ITR(n) (INTC_BASE + 0x080 + (n) * 0x20)
#define INTC_MIR(n) (INTC_BASE + 0x084 + (n) * 0x20)
#define INTC_MIR_CLEAR(n) (INTC_BASE + 0x088 + (n) * 0x20)
#define INTC_MIR_SET(n) (INTC_BASE + 0x08C + (n) * 0x20)
#define INTC_ISR_SET(n) (INTC_BASE + 0x090 + (n) * 0x20)
#define INTC_ISR_CLEAR(n) (INTC_BASE + 0x094 + (n) * 0x20)
#define INTC_PENDING_IRQ(n) (INTC_BASE + 0x098 + (n) * 0x20)
#define INTC_PENDING_FIQ(n) (INTC_BASE + 0x09C + (n) * 0x20)
#define INTC_ILR(n) (INTC_BASE + 0x100 + (n) * 4)
/* interrupts */
#define INT_VECTORS 96
#define GPT2_IRQ 38
/* HS USB */
#define USB_HS_BASE (L4_BASE + 0xab000)
/* USB OTG */
#define OTG_BASE (L4_BASE + 0xab400)
#define OTG_REVISION (OTG_BASE + 0x00)
#define OTG_SYSCONFIG (OTG_BASE + 0x04)
#define OTG_SYSSTATUS (OTG_BASE + 0x08)
#define OTG_INTERFSEL (OTG_BASE + 0x0C)
#define OTG_SIMENABLE (OTG_BASE + 0x10)
#define OTG_FORCESTDBY (OTG_BASE + 0x14)
/* I2C */
#define I2C1_BASE (L4_BASE + 0x70000)
#define I2C2_BASE (L4_BASE + 0x72000)
#define I2C3_BASE (L4_BASE + 0x60000)
#define I2C_REV (0x00)
#define I2C_IE (0x04)
#define I2C_STAT (0x08)
#define I2C_WE (0x0C)
#define I2C_SYSS (0x10)
#define I2C_BUF (0x14)
#define I2C_CNT (0x18)
#define I2C_DATA (0x1C)
#define I2C_SYSC (0x20)
#define I2C_CON (0x24)
#define I2C_OA0 (0x28)
#define I2C_SA (0x2C)
#define I2C_PSC (0x30)
#define I2C_SCLL (0x34)
#define I2C_SCLH (0x38)
#define I2C_SYSTEST (0x3C)
#define I2C_BUFSTAT (0x40)
#define I2C_OA1 (0x44)
#define I2C_OA2 (0x48)
#define I2C_OA3 (0x4C)
#define I2C_ACTOA (0x50)
#define I2C_SBLOCK (0x54)
#endif

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
#include <debug.h>
#include <err.h>
#include <reg.h>
#include <kernel/thread.h>
#include <platform/interrupts.h>
#include <arch/ops.h>
#include <arch/arm.h>
#include "platform_p.h"
#include <platform/omap3.h>
struct int_handler_struct {
int_handler handler;
void *arg;
};
static struct int_handler_struct int_handler_table[INT_VECTORS];
#define vectorToController(vector) ((vector) / 32)
void platform_init_interrupts(void)
{
unsigned int i;
// reset the controller
*REG32(INTC_SYSCONFIG) = 0x2; // start a reset
while ((*REG32(INTC_SYSSTATUS) & 0x1) == 0)
;
// mask all interrupts
*REG32(INTC_MIR(0)) = 0xffffffff;
*REG32(INTC_MIR(1)) = 0xffffffff;
*REG32(INTC_MIR(2)) = 0xffffffff;
// set up each of the interrupts
for (i = 0; i < INT_VECTORS; i++) {
// set each vector up as high priority IRQ
*REG32(INTC_ILR(i)) = 0;
//*ICReg(i / 32, INTCON_ILR_BASE + 4*(i%32)) = ((level_trigger[i/32] & (1<<(i%32))) ? (1<<1) : (0<<1)) | 0;
}
// disable the priority threshold
*REG32(INTC_THRESHOLD) = 0xff;
// clear any pending sw interrupts
*REG32(INTC_ISR_CLEAR(0)) = 0xffffffff;
*REG32(INTC_ISR_CLEAR(1)) = 0xffffffff;
*REG32(INTC_ISR_CLEAR(2)) = 0xffffffff;
// globally unmask interrupts
*REG32(INTC_CONTROL) = 3; // reset and enable the controller
}
status_t mask_interrupt(unsigned int vector)
{
if (vector >= INT_VECTORS)
return ERR_INVALID_ARGS;
// dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
enter_critical_section();
*REG32(INTC_MIR_SET(vectorToController(vector))) = 1 << (vector % 32);
exit_critical_section();
return NO_ERROR;
}
void platform_mask_irqs(void)
{
int i;
for (i=0; i<INT_VECTORS; i++)
mask_interrupt(i);
}
status_t unmask_interrupt(unsigned int vector)
{
if (vector >= INT_VECTORS)
return ERR_INVALID_ARGS;
// dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
enter_critical_section();
*REG32(INTC_MIR_CLEAR(vectorToController(vector))) = 1 << (vector % 32);
exit_critical_section();
return NO_ERROR;
}
enum handler_return platform_irq(struct arm_iframe *frame)
{
// get the current vector
unsigned int vector;
// read the currently active IRQ
vector = *REG32(INTC_SIR_IRQ) & 0x7f;
// TRACEF("spsr 0x%x, pc 0x%x, currthread %p, vector %d, handler %p\n", frame->spsr, frame->pc, current_thread, vector, int_handler_table[vector].handler);
#if THREAD_STATS
thread_stats.interrupts++;
#endif
// deliver the interrupt
enum handler_return ret;
ret = INT_NO_RESCHEDULE;
if (int_handler_table[vector].handler)
ret = int_handler_table[vector].handler(int_handler_table[vector].arg);
// ack the interrupt
*REG32(INTC_CONTROL) = 0x1;
return ret;
}
void platform_fiq(struct arm_iframe *frame)
{
PANIC_UNIMPLEMENTED;
}
void register_int_handler(unsigned int vector, int_handler handler, void *arg)
{
if (vector >= INT_VECTORS)
panic("register_int_handler: vector out of range %d\n", vector);
enter_critical_section();
int_handler_table[vector].arg = arg;
int_handler_table[vector].handler = handler;
exit_critical_section();
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <err.h>
#include <debug.h>
#include <arch/arm/mmu.h>
#include <platform.h>
#include "platform_p.h"
#include <platform/omap3.h>
#include <dev/i2c.h>
#include <dev/uart.h>
#include <dev/usbc.h>
void platform_init_mmu_mappings(void)
{
/* do some memory map initialization */
addr_t addr;
arm_mmu_map_section(SDRAM_BASE, 0, MMU_FLAG_CACHED|MMU_FLAG_BUFFERED);
for (addr = SDRAM_BASE; addr < SDRAM_BASE + SDRAM_SIZE; addr += (1024*1024)) {
arm_mmu_map_section(addr, addr, MMU_FLAG_CACHED|MMU_FLAG_BUFFERED|MMU_FLAG_READWRITE);
}
}
void platform_early_init(void)
{
/* initialize the interrupt controller */
platform_init_interrupts();
/* initialize the timer block */
platform_init_timer();
/* initialize the uart */
uart_init_early();
i2c_init_early();
}
void platform_init(void)
{
i2c_init();
uart_init();
usbc_init();
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __PLATFORM_P_H
#define __PLATFORM_P_H
void platform_init_interrupts(void);
void platform_init_timer(void);
#endif

View File

@@ -0,0 +1,37 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
ARCH := arm
ARM_CPU := cortex-a8
CPU := generic
DEVS += usb
# provides a few devices
DEFINES += \
WITH_DEV_USBC=1 \
WITH_DEV_UART=1
MODULES += \
dev/usb
INCLUDES += \
-I$(LOCAL_DIR)/include
OBJS += \
$(LOCAL_DIR)/cpu_early_init.Ao \
$(LOCAL_DIR)/debug.o \
$(LOCAL_DIR)/i2c.o \
$(LOCAL_DIR)/interrupts.o \
$(LOCAL_DIR)/platform.o \
$(LOCAL_DIR)/timer.o \
$(LOCAL_DIR)/uart.o \
$(LOCAL_DIR)/usbc.o
MEMBASE := 0x80000000
DEFINES += MEMBASE=$(MEMBASE) \
WITH_CPU_EARLY_INIT=1
LINKER_SCRIPT += \
$(BUILDDIR)/system-onesegment.ld

View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
#include <err.h>
#include <reg.h>
#include <debug.h>
#include <kernel/thread.h>
#include <platform.h>
#include <platform/interrupts.h>
#include <platform/timer.h>
#include <platform/omap3.h>
#include "platform_p.h"
static time_t tick_interval;
static platform_timer_callback t_callback;
static void *callback_arg;
/* timer 2 */
static const ulong timer_base = OMAP34XX_GPT2;
#define TIMER_TICK_RATE 32768
#define TIMER_REG(reg) *REG32(timer_base + (reg))
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, time_t interval)
{
enter_critical_section();
t_callback = callback;
callback_arg = arg;
tick_interval = interval;
uint32_t ticks_per_interval = (uint64_t)interval * TIMER_TICK_RATE / 1000; // interval is in ms
TIMER_REG(TCLR) = 0; // stop the timer
TIMER_REG(TLDR) = -ticks_per_interval;
TIMER_REG(TTGR) = 1;
TIMER_REG(TIER) = 0x2;
TIMER_REG(TCLR) = 0x3; // autoreload, start
unmask_interrupt(GPT2_IRQ);
exit_critical_section();
return NO_ERROR;
}
time_t current_time(void)
{
uint32_t delta_ticks;
uint32_t delta_ticks2;
retry:
delta_ticks = *REG32(TIMER32K_CR);
delta_ticks2 = *REG32(TIMER32K_CR);
if (delta_ticks2 != delta_ticks)
goto retry;
uint64_t longtime = delta_ticks * 1000ULL / 32768ULL;
return (time_t)longtime;
}
bigtime_t current_time_hires(void)
{
uint32_t delta_ticks;
uint32_t delta_ticks2;
retry:
delta_ticks = *REG32(TIMER32K_CR);
delta_ticks2 = *REG32(TIMER32K_CR);
if (delta_ticks2 != delta_ticks)
goto retry;
uint64_t longtime = delta_ticks * 1000000ULL / 32768ULL;
return (bigtime_t)longtime;
}
static enum handler_return os_timer_tick(void *arg)
{
TIMER_REG(TISR) = TIMER_REG(TISR);
return t_callback(callback_arg, current_time());
}
void platform_init_timer(void)
{
/* GPT2 */
RMWREG32(CM_CLKSEL_PER, 0, 1, 1);
RMWREG32(CM_ICLKEN_PER, 3, 1, 1);
RMWREG32(CM_FCLKEN_PER, 3, 1, 1);
// reset the GP timer
TIMER_REG(TIOCP_CFG) = 0x2;
while ((TIMER_REG(TISTAT) & 1) == 0)
;
// set GPT2-9 clock inputs over to 32k
*REG32(CM_CLKSEL_PER) = 0;
// disable ints
TIMER_REG(TIER) = 0;
TIMER_REG(TISR) = 0x7; // clear any pending bits
// XXX make sure 32K timer is running
register_int_handler(GPT2_IRQ, &os_timer_tick, NULL);
}
void platform_halt_timers(void)
{
TIMER_REG(TCLR) = 0;
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <reg.h>
#include <dev/uart.h>
#include <platform/omap3.h>
#include <target/debugconfig.h>
struct uart_stat {
addr_t base;
uint shift;
};
static struct uart_stat uart[3] = {
{ OMAP_UART1_BASE, 2 },
{ OMAP_UART2_BASE, 2 },
{ OMAP_UART3_BASE, 2 },
};
static inline void write_uart_reg(int port, uint reg, unsigned char data)
{
*(volatile unsigned char *)(uart[port].base + (reg << uart[port].shift)) = data;
}
static inline unsigned char read_uart_reg(int port, uint reg)
{
return *(volatile unsigned char *)(uart[port].base + (reg << uart[port].shift));
}
#define LCR_8N1 0x03
#define FCR_FIFO_EN 0x01 /* Fifo enable */
#define FCR_RXSR 0x02 /* Receiver soft reset */
#define FCR_TXSR 0x04 /* Transmitter soft reset */
#define MCR_DTR 0x01
#define MCR_RTS 0x02
#define MCR_DMA_EN 0x04
#define MCR_TX_DFR 0x08
#define LCR_WLS_MSK 0x03 /* character length select mask */
#define LCR_WLS_5 0x00 /* 5 bit character length */
#define LCR_WLS_6 0x01 /* 6 bit character length */
#define LCR_WLS_7 0x02 /* 7 bit character length */
#define LCR_WLS_8 0x03 /* 8 bit character length */
#define LCR_STB 0x04 /* Number of stop Bits, off = 1, on = 1.5 or 2) */
#define LCR_PEN 0x08 /* Parity eneble */
#define LCR_EPS 0x10 /* Even Parity Select */
#define LCR_STKP 0x20 /* Stick Parity */
#define LCR_SBRK 0x40 /* Set Break */
#define LCR_BKSE 0x80 /* Bank select enable */
#define LSR_DR 0x01 /* Data ready */
#define LSR_OE 0x02 /* Overrun */
#define LSR_PE 0x04 /* Parity error */
#define LSR_FE 0x08 /* Framing error */
#define LSR_BI 0x10 /* Break */
#define LSR_THRE 0x20 /* Xmit holding register empty */
#define LSR_TEMT 0x40 /* Xmitter empty */
#define LSR_ERR 0x80 /* Error */
#define LCRVAL LCR_8N1 /* 8 data, 1 stop, no parity */
#define MCRVAL (MCR_DTR | MCR_RTS) /* RTS/DTR */
#define FCRVAL (FCR_FIFO_EN | FCR_RXSR | FCR_TXSR) /* Clear & enable FIFOs */
#define V_NS16550_CLK (48000000) /* 48MHz (APLL96/2) */
void uart_init_port(int port, uint baud)
{
/* clear the tx & rx fifo and disable */
uint16_t baud_divisor = (V_NS16550_CLK / 16 / baud);
write_uart_reg(port, UART_IER, 0);
write_uart_reg(port, UART_LCR, LCR_BKSE | LCRVAL); // config mode A
write_uart_reg(port, UART_DLL, baud_divisor & 0xff);
write_uart_reg(port, UART_DLH, (baud_divisor >> 8) & 0xff);
write_uart_reg(port, UART_LCR, LCRVAL); // operational mode
write_uart_reg(port, UART_MCR, MCRVAL);
write_uart_reg(port, UART_FCR, FCRVAL);
write_uart_reg(port, UART_MDR1, 0); // UART 16x mode
// write_uart_reg(port, UART_LCR, 0xBF); // config mode B
// write_uart_reg(port, UART_EFR, (1<<7)|(1<<6)); // hw flow control
// write_uart_reg(port, UART_LCR, LCRVAL); // operational mode
}
void uart_init_early(void)
{
/* UART1 */
RMWREG32(CM_FCLKEN1_CORE, 13, 1, 1),
RMWREG32(CM_ICLKEN1_CORE, 13, 1, 1),
/* UART2 */
RMWREG32(CM_FCLKEN1_CORE, 14, 1, 1),
RMWREG32(CM_ICLKEN1_CORE, 14, 1, 1),
/* UART3 */
RMWREG32(CM_FCLKEN_PER, 11, 1, 1),
RMWREG32(CM_ICLKEN_PER, 11, 1, 1),
uart_init_port(DEBUG_UART, 115200);
}
void uart_init(void)
{
}
int uart_putc(int port, char c )
{
while (!(read_uart_reg(port, UART_LSR) & (1<<6))) // wait for the last char to get out
;
write_uart_reg(port, UART_THR, c);
return 0;
}
int uart_getc(int port, bool wait) /* returns -1 if no data available */
{
if (wait) {
while (!(read_uart_reg(port, UART_LSR) & (1<<0))) // wait for data to show up in the rx fifo
;
} else {
if (!(read_uart_reg(port, UART_LSR) & (1<<0)))
return -1;
}
return read_uart_reg(port, UART_RHR);
}
void uart_flush_tx(int port)
{
while (!(read_uart_reg(port, UART_LSR) & (1<<6))) // wait for the last char to get out
;
}
void uart_flush_rx(int port)
{
// empty the rx fifo
while (read_uart_reg(port, UART_LSR) & (1<<0)) {
volatile char c = read_uart_reg(port, UART_RHR);
(void)c;
}
}

View File

@@ -0,0 +1,882 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <string.h>
#include <stdlib.h>
#include <kernel/thread.h>
#include <dev/usbc.h>
#include <dev/twl4030.h>
#include <reg.h>
#include <platform/omap3.h>
#include <platform/interrupts.h>
#include <hw/usb.h>
#define LOCAL_TRACE 0
#define hsusb_reg8(reg) *REG8(USB_HS_BASE + (reg))
#define hsusb_reg16(reg) *REG16(USB_HS_BASE + (reg))
#define hsusb_reg32(reg) *REG32(USB_HS_BASE + (reg))
/* registers */
#define FADDR 0x0
#define POWER 0x1
#define INTRTX 0x2
#define INTRRX 0x4
#define INTRTXE 0x6
#define INTRRXE 0x8
#define INTRUSB 0xa
#define INTRUSBE 0xb
#define FRAME 0xc
#define INDEX 0xe
#define TESTMODE 0xf
// indexed endpoint regs
#define IDX_TXMAXP 0x10
#define IDX_TXCSR 0x12
#define IDX_TXCSRL 0x12
#define IDX_TXCSRH 0x13
#define IDX_RXMAXP 0x14
#define IDX_RXCSR 0x16
#define IDX_RXCSRL 0x16
#define IDX_RXCSRH 0x17
#define IDX_RXCOUNT 0x18
#define IDX_FIFOSIZE 0x1f
// if endpoint 0 is selected
#define IDX_CSR0 0x12
#define IDX_CONFIGDATA 0x1f
// endpoint FIFOs
#define FIFOBASE 0x20
#define DEVCTL 0x60
#define TXFIFOSZ 0x62
#define RXFIFOSZ 0x63
#define TXFIFOADD 0x64
#define RXFIFOADD 0x66
#define HWVERS 0x6c
#define EPINFO 0x78
#define RAMINFO 0x79
#define LINKINFO 0x7a
static void setup_dynamic_fifos(void);
enum usb_state {
USB_DEFAULT = 0,
USB_ADDRESS,
USB_CONFIGURED
};
struct usbc_ep {
bool active;
uint width;
uint blocksize;
/* current data buffer */
usbc_transfer *transfer;
/* callback when tx or rx happens on the endpoint */
int (*callback)(ep_t endpoint, usbc_callback_op_t op, usbc_transfer *transfer);
};
struct usbc_stat {
bool active;
enum usb_state state;
uint8_t active_config;
// callback for device events
usb_callback callback;
// ep0 pending tx
const void *ep0_tx_buf;
size_t ep0_tx_len;
uint ep0_tx_pos;
struct usbc_ep inep[16]; // IN endpoints (device to host)
struct usbc_ep outep[16]; // OUT endpoint (host to device)
};
static struct usbc_stat *usbc;
struct usbc_callback {
struct list_node node;
usb_callback callback;
};
static struct list_node usbc_callback_list;
static void call_all_callbacks(usbc_callback_op_t op, const union usb_callback_args *arg)
{
struct usbc_callback *cb;
list_for_every_entry(&usbc_callback_list, cb, struct usbc_callback, node) {
LTRACEF("calling %p, op %d, arg %p\n", cb->callback, op, arg);
cb->callback(op, arg);
}
}
static void print_usb_setup(const struct usb_setup *setup)
{
printf("usb_setup:\n");
printf("\ttype 0x%hhx\n", setup->request_type);
printf("\trequest 0x%hhx\n", setup->request);
printf("\tvalue 0x%hx\n", setup->value);
printf("\tindex 0x%hx\n", setup->index);
printf("\tlength 0x%hx\n", setup->length);
}
static void select_ep(uint ep)
{
DEBUG_ASSERT(ep < 16);
hsusb_reg8(INDEX) = ep;
}
static void dump_ep_regs(uint ep)
{
#if 0
select_ep(ep);
LTRACEF("%d txmaxp 0x%hx\n", ep, hsusb_reg16(IDX_TXMAXP));
LTRACEF("%d rxmaxp 0x%hx\n", ep, hsusb_reg16(IDX_RXMAXP));
LTRACEF("%d txfifosz 0x%hhx\n", ep, hsusb_reg8(TXFIFOSZ));
LTRACEF("%d rxfifosz 0x%hhx\n", ep, hsusb_reg8(RXFIFOSZ));
LTRACEF("%d txfifoadd 0x%hx\n", ep, hsusb_reg16(TXFIFOADD));
LTRACEF("%d rxfifoadd 0x%hx\n", ep, hsusb_reg16(RXFIFOADD));
#endif
}
#define MULOF4(val) (((uint32_t)(val) & 0x3) == 0)
static int read_ep_fifo(uint ep, void *_buf, size_t maxlen)
{
char *buf = (void *)_buf;
select_ep(ep);
uint8_t fifo_reg = FIFOBASE + ep * 4;
size_t rxcount = hsusb_reg16(IDX_RXCOUNT);
if (rxcount > maxlen)
rxcount = maxlen;
if (MULOF4(buf) && MULOF4(rxcount)) {
uint i;
uint32_t *buf32 = (uint32_t *)_buf;
for (i=0; i < rxcount / 4; i++) {
buf32[i] = hsusb_reg32(fifo_reg);
}
} else {
/* slow path */
uint i;
for (i=0; i < rxcount; i++) {
buf[i] = hsusb_reg8(fifo_reg);
}
}
return rxcount;
}
static int write_ep_fifo(uint ep, const void *_buf, size_t len)
{
char *buf = (void *)_buf;
select_ep(ep);
uint8_t fifo_reg = FIFOBASE + ep * 4;
if (MULOF4(buf) && MULOF4(len)) {
uint i;
uint32_t *buf32 = (uint32_t *)_buf;
for (i=0; i < len / 4; i++) {
hsusb_reg32(fifo_reg) = buf32[i];
}
} else {
/* slow path */
uint i;
for (i=0; i < len; i++) {
hsusb_reg8(fifo_reg) = buf[i];
}
}
return len;
}
#undef MULOF4
void usbc_ep0_send(const void *buf, size_t len, size_t maxlen)
{
LTRACEF("buf %p, len %zu, maxlen %zu\n", buf, len, maxlen);
// trim the transfer
len = MIN(len, maxlen);
size_t transfer_len = MIN(64, len);
// write the first 64 bytes
write_ep_fifo(0, buf, transfer_len);
// set txpktready
select_ep(0);
if (len > 64) {
// we have more data to send, don't mark data end
hsusb_reg16(IDX_CSR0) |= (1<<1); // TxPktRdy
// save our position so we can continue
usbc->ep0_tx_buf = buf;
usbc->ep0_tx_pos = 64;
usbc->ep0_tx_len = len;
} else {
hsusb_reg16(IDX_CSR0) |= (1<<3) | (1<<1); // DataEnd, TxPktRdy
usbc->ep0_tx_buf = NULL;
}
}
static void ep0_control_send_resume(void)
{
DEBUG_ASSERT(usbc->ep0_tx_buf != NULL);
DEBUG_ASSERT(usbc->ep0_tx_len > usbc->ep0_tx_pos);
LTRACEF("buf %p pos %d len %d\n", usbc->ep0_tx_buf, usbc->ep0_tx_pos, usbc->ep0_tx_len);
size_t transfer_len = MIN(64, usbc->ep0_tx_len - usbc->ep0_tx_pos);
write_ep_fifo(0, (const uint8_t *)usbc->ep0_tx_buf + usbc->ep0_tx_pos, transfer_len);
usbc->ep0_tx_pos += transfer_len;
if (usbc->ep0_tx_pos >= usbc->ep0_tx_len) {
// completes the transfer
hsusb_reg16(IDX_CSR0) |= (1<<3) | (1<<1); // DataEnd, TxPktRdy
usbc->ep0_tx_buf = NULL;
} else {
hsusb_reg16(IDX_CSR0) |= (1<<1); // TxPktRdy
}
}
void usbc_ep0_ack(void)
{
hsusb_reg16(IDX_CSR0) |= (1<<6)|(1<<3); // servicedrxpktrdy & dataend
}
void usbc_ep0_stall(void)
{
printf("USB STALL\n");
}
static void usb_shutdown_endpoints(void)
{
// iterate through all the endpoints, cancelling any pending io and shut down the endpoint
ep_t i;
for (i=1; i < 16; i++) {
if (usbc->inep[i].active && usbc->inep[i].transfer) {
// pool's closed
usbc_transfer *t = usbc->inep[i].transfer;
usbc->inep[i].transfer = NULL;
t->result = USB_TRANSFER_RESULT_CANCELLED;
usbc->inep[i].callback(i, CB_EP_TRANSFER_CANCELLED, t);
}
if (usbc->outep[i].active && usbc->outep[i].transfer) {
// pool's closed
usbc_transfer *t = usbc->outep[i].transfer;
usbc->outep[i].transfer = NULL;
t->result = USB_TRANSFER_RESULT_CANCELLED;
usbc->outep[i].callback(i, CB_EP_TRANSFER_CANCELLED, t);
}
}
// clear pending ep0 data
usbc->ep0_tx_buf = 0;
}
static void usb_enable_endpoints(void)
{
setup_dynamic_fifos();
}
static void usb_disconnect(void)
{
// we've been disconnected
usbc->state = USB_DEFAULT;
usbc->active_config = 0;
usb_shutdown_endpoints();
}
static void usb_reset(void)
{
// this wipes out our endpoint interrupt disables
hsusb_reg16(INTRTXE) = (1<<0);
hsusb_reg16(INTRRXE) = 0;
usb_shutdown_endpoints();
}
static int handle_ep_rx(int ep)
{
struct usbc_ep *e = &usbc->outep[ep];
DEBUG_ASSERT(e->active);
DEBUG_ASSERT(e->transfer); // can't rx to no transfer
usbc_transfer *t = e->transfer;
uint rxcount = hsusb_reg16(IDX_RXCOUNT);
uint readcount = MIN(rxcount, t->buflen - t->bufpos);
readcount = MIN(readcount, e->blocksize);
int len = read_ep_fifo(ep, (uint8_t *)t->buf + t->bufpos, readcount);
LTRACEF("read %d bytes from the fifo\n", len);
// no more packet ready
hsusb_reg16(IDX_RXCSRL) &= ~(1<<0); // clear rxpktrdy
t->bufpos += len;
if (rxcount < e->blocksize || t->bufpos >= t->buflen) {
// we're done with this transfer, clear it and disable the endpoint
e->transfer = NULL;
hsusb_reg16(INTRRXE) &= ~(1<<ep);
t->result = USB_TRANSFER_RESULT_OK;
DEBUG_ASSERT(e->callback);
e->callback(ep, CB_EP_RXCOMPLETE, t);
return 1;
}
return 0;
}
bool usbc_is_highspeed(void)
{
return (hsusb_reg8(POWER) & (1<<4)) ? true : false;
}
static enum handler_return hsusb_interrupt(void *arg)
{
uint16_t intrtx = hsusb_reg16(INTRTX);
uint16_t intrrx = hsusb_reg16(INTRRX);
uint8_t intrusb = hsusb_reg8(INTRUSB);
enum handler_return ret = INT_NO_RESCHEDULE;
LTRACEF("intrtx 0x%hx (0x%x), intrrx 0x%hx (0x%x), intrusb 0x%hhx, intrusbe 0x%hhx\n",
intrtx, hsusb_reg16(INTRTXE), intrrx, hsusb_reg16(INTRRXE), intrusb, hsusb_reg8(INTRUSBE));
dump_ep_regs(2);
// look for global usb interrupts
intrusb &= hsusb_reg8(INTRUSBE);
if (intrusb) {
if (intrusb & (1<<0)) {
// suspend
TRACEF("suspend\n");
call_all_callbacks(CB_SUSPEND, 0);
ret = INT_RESCHEDULE;
}
if (intrusb & (1<<1)) {
// resume
TRACEF("resume\n");
call_all_callbacks(CB_RESUME, 0);
ret = INT_RESCHEDULE;
}
if (intrusb & (1<<2)) {
// reset
TRACEF("reset\n");
TRACEF("high speed %d\n", hsusb_reg8(POWER) & (1<<4) ? 1 : 0);
call_all_callbacks(CB_RESET, 0);
usb_reset();
ret = INT_RESCHEDULE;
}
if (intrusb & (1<<3)) {
// SOF
TRACEF("sof\n");
}
if (intrusb & (1<<4)) {
// connect (host only)
TRACEF("connect\n");
}
if (intrusb & (1<<5)) {
// disconnect
TRACEF("disconnect\n");
call_all_callbacks(CB_DISCONNECT, 0);
usb_disconnect();
ret = INT_RESCHEDULE;
}
if (intrusb & (1<<6)) {
// session request (A device only)
TRACEF("session request\n");
}
if (intrusb & (1<<7)) {
// vbus error (A device only)
TRACEF("vbus error\n");
}
}
// look for endpoint 0 interrupt
if (intrtx & 1) {
select_ep(0);
uint16_t csr = hsusb_reg16(IDX_CSR0);
LTRACEF("ep0 csr 0x%hhx\n", csr);
// clear the stall bit
if (csr & (1<<2))
hsusb_reg16(IDX_CSR0) &= ~(1<<2);
// do we have any pending tx data?
if (usbc->ep0_tx_buf != NULL) {
if (csr & (1<<4)) { // setup end
// we got an abort on the data transfer
usbc->ep0_tx_buf = NULL;
} else {
// send more data
ep0_control_send_resume();
}
}
// clear the setup end bit
if (csr & (1<<4)) {
hsusb_reg16(IDX_CSR0) |= (1<<7); // servicedsetupend
}
if (csr & 0x1) {
// rxpktrdy
LTRACEF("ep0: rxpktrdy, count %d\n", hsusb_reg16(IDX_RXCOUNT));
struct usb_setup setup;
read_ep_fifo(0, (void *)&setup, sizeof(setup));
// print_usb_setup(&setup);
hsusb_reg16(IDX_CSR0) |= (1<<6); // servicedrxpktrdy
union usb_callback_args args;
args.setup = &setup;
call_all_callbacks(CB_SETUP_MSG, &args);
switch (setup.request) {
case SET_ADDRESS: {
LTRACEF("got SET_ADDRESS: value %d\n", setup.value);
dprintf(INFO, "usb: got assigned address %d\n", setup.value);
usbc_ep0_ack();
hsusb_reg8(FADDR) = setup.value;
if (setup.value == 0)
usbc->state = USB_DEFAULT;
else
usbc->state = USB_ADDRESS;
break;
}
case SET_CONFIGURATION:
LTRACEF("got SET_CONFIGURATION, config %d\n", setup.value);
if (setup.value == 0) {
if (usbc->state == USB_CONFIGURED)
usbc->state = USB_ADDRESS;
call_all_callbacks(CB_OFFLINE, 0);
} else {
usbc->state = USB_CONFIGURED;
call_all_callbacks(CB_ONLINE, 0);
}
usbc->active_config = setup.value;
ret = INT_RESCHEDULE;
// set up all of the endpoints
usb_enable_endpoints();
break;
}
}
}
// handle endpoint interrupts
// mask out ones we don't want to play with
intrtx &= hsusb_reg16(INTRTXE);
intrrx &= hsusb_reg16(INTRRXE);
int i;
for (i=1; i < 16; i++) {
if (intrtx & (1<<i)) {
select_ep(i);
LTRACEF("txcsr %i: 0x%hx\n", i, hsusb_reg16(IDX_TXCSR));
// data was sent, see if we have more to send
struct usbc_ep *e = &usbc->inep[i];
DEBUG_ASSERT(e->transfer); // interrupts shouldn't be enabled if there isn't a transfer queued
usbc_transfer *t = e->transfer;
if (t->bufpos < t->buflen) {
// cram more stuff in the buffer
uint queuelen = MIN(e->blocksize, t->buflen - t->bufpos);
LTRACEF("writing more tx data into fifo: len %u, remaining %zu\n", queuelen, t->buflen - t->bufpos);
write_ep_fifo(i, (uint8_t *)t->buf + t->bufpos, queuelen);
t->bufpos += queuelen;
// start the transfer
hsusb_reg16(IDX_TXCSR) |= (1<<0); // txpktrdy
} else {
// we're done, callback
e->transfer = NULL;
hsusb_reg16(INTRTXE) &= ~(1<<i);
t->result = USB_TRANSFER_RESULT_OK;
DEBUG_ASSERT(e->callback);
e->callback(i, CB_EP_TXCOMPLETE, t);
ret = INT_RESCHEDULE;
}
}
if (intrrx & (1<<i)) {
select_ep(i);
uint16_t csr = hsusb_reg16(IDX_RXCSR);
LTRACEF("rxcsr %i: 0x%hx\n", i, csr);
if (csr & 0x1) { // rxpktrdy
// see if the endpoint is ready
struct usbc_ep *e = &usbc->outep[i];
if (!e->active) {
// stall it
hsusb_reg16(IDX_RXCSR) |= (1<<6); // stall
hsusb_reg16(IDX_RXCSR) |= (1<<4); // flush fifo
panic("rx on inactive endpoint\n");
continue;
}
if (handle_ep_rx(i) > 0)
ret = INT_RESCHEDULE;
}
}
}
return ret;
}
static enum handler_return hsusb_dma_interrupt(void *arg)
{
LTRACE;
return INT_NO_RESCHEDULE;
}
void usbc_setup_endpoint(ep_t ep, ep_dir_t dir, bool active, ep_callback callback, uint width, uint blocksize)
{
DEBUG_ASSERT(ep != 0);
DEBUG_ASSERT(ep < 16);
DEBUG_ASSERT(dir == IN || dir == OUT);
struct usbc_ep *e;
if (dir == IN)
e = &usbc->inep[ep];
else
e = &usbc->outep[ep];
// for now we can only make active
e->active = active;
e->callback = callback;
e->width = width;
e->blocksize = blocksize;
}
int usbc_queue_rx(ep_t ep, usbc_transfer *transfer)
{
LTRACE;
struct usbc_ep *e = &usbc->outep[ep];
DEBUG_ASSERT(ep != 0);
DEBUG_ASSERT(ep < 16);
DEBUG_ASSERT(e->active);
DEBUG_ASSERT(transfer);
DEBUG_ASSERT(transfer->buf);
DEBUG_ASSERT(e->transfer == NULL);
// can only queue up multiples of the endpoint blocksize
DEBUG_ASSERT(transfer->buflen >= e->blocksize && (transfer->buflen % e->blocksize) == 0);
enter_critical_section();
if (usbc->state != USB_CONFIGURED) {
// can't transfer now
exit_critical_section();
return -1;
}
e->transfer = transfer;
// make sure the ep is set up right
// select_ep(ep);
// hsusb_reg8(IDX_RXCSRH) = 0;
dump_ep_regs(ep);
select_ep(ep);
if (hsusb_reg16(IDX_RXCSR) & (1<<0)) {
// packet already ready
LTRACEF("****packet already ready (%d)\n", hsusb_reg16(IDX_RXCOUNT));
int rc = handle_ep_rx(ep);
if (rc > 0) {
// the transfer was completed
goto done;
}
}
// unmask irqs for this endpoint
hsusb_reg16(INTRRXE) |= (1<<ep);
done:
exit_critical_section();
return 0;
}
int usbc_queue_tx(ep_t ep, usbc_transfer *transfer)
{
LTRACEF("ep %u, transfer %p (buf %p, len %zu)\n", ep, transfer, transfer->buf, transfer->buflen);
struct usbc_ep *e = &usbc->inep[ep];
DEBUG_ASSERT(ep != 0);
DEBUG_ASSERT(ep < 16);
DEBUG_ASSERT(e->active);
DEBUG_ASSERT(e->transfer == NULL);
enter_critical_section();
if (usbc->state != USB_CONFIGURED) {
// can't transfer now
exit_critical_section();
return -1;
}
e->transfer = transfer;
select_ep(ep);
// set this endpoint in tx mode
// hsusb_reg8(IDX_TXCSRH) = (1<<7)|(1<<5); // autoset, tx direction
dump_ep_regs(ep);
// unmask irqs for this endpoint
hsusb_reg16(INTRTXE) |= (1<<ep);
// if the fifo is empty, start the transfer
if ((hsusb_reg16(IDX_TXCSR) & (1<<1)) == 0) {
// dump the start of the transfer in the fifo
uint queuelen = MIN(e->blocksize, transfer->buflen);
write_ep_fifo(ep, transfer->buf, queuelen);
transfer->bufpos = queuelen;
// start the transfer
hsusb_reg16(IDX_TXCSR) |= (1<<0); // txpktrdy
}
exit_critical_section();
return 0;
}
int usbc_set_callback(usb_callback callback)
{
DEBUG_ASSERT(callback != NULL);
struct usbc_callback *cb = malloc(sizeof(struct usbc_callback));
enter_critical_section();
cb->callback = callback;
list_add_head(&usbc_callback_list, &cb->node);
exit_critical_section();
return 0;
}
int usbc_set_active(bool active)
{
LTRACEF("active %d\n", active);
if (active) {
DEBUG_ASSERT(!usbc->active);
hsusb_reg8(POWER) |= (1<<6); // soft conn
twl4030_set_usb_pullup(true);
usbc->active = true;
} else {
hsusb_reg8(POWER) &= ~(1<<6); // soft conn
twl4030_set_usb_pullup(false);
usbc->active = false;
}
return 0;
}
static void setup_dynamic_fifos(void)
{
// LTRACE;
#if LOCAL_TRACE
uint8_t raminfo = hsusb_reg8(RAMINFO);
size_t ramsize = (1 << ((raminfo & 0xf) + 2));
LTRACEF("%zd bytes of onboard ram\n", ramsize);
#endif
uint32_t offset = 128;
int highspeed = hsusb_reg8(POWER) & (1<<4);
int i;
for (i=1; i < 16; i++) {
select_ep(i);
if (usbc->inep[i].active) {
hsusb_reg8(TXFIFOSZ) = (1<<4)|(0x6); // 512 byte, double buffered
hsusb_reg8(RXFIFOSZ) = 0;
hsusb_reg16(TXFIFOADD) = offset / 8;
hsusb_reg16(RXFIFOADD) = 0;
if (highspeed) {
hsusb_reg16(IDX_TXMAXP) = usbc->inep[i].width;
} else {
hsusb_reg16(IDX_TXMAXP) = (((usbc->inep[i].blocksize / 64) - 1) << 11) | 64;
// hsusb_reg16(IDX_TXMAXP) = 64;
// usbc->inep[i].blocksize = 64;
}
hsusb_reg16(IDX_RXMAXP) = 0;
LTRACEF("%d: txmaxp 0x%hx\n", i, hsusb_reg16(IDX_TXMAXP));
hsusb_reg8(IDX_TXCSRH) = (1<<5)|(1<<3);
hsusb_reg8(IDX_TXCSRL) = (1<<3);
hsusb_reg8(IDX_TXCSRL) = (1<<3);
offset += 512*2;
} else {
hsusb_reg8(TXFIFOSZ) = 0;
hsusb_reg16(TXFIFOADD) = 0;
hsusb_reg16(IDX_TXMAXP) = 0;
}
if (usbc->outep[i].active) {
hsusb_reg8(TXFIFOSZ) = 0;
hsusb_reg8(RXFIFOSZ) = (0<<4)|(0x6); // 512 byte, single buffered
hsusb_reg16(TXFIFOADD) = 0;
hsusb_reg16(RXFIFOADD) = offset / 8;
hsusb_reg16(IDX_TXMAXP) = 0;
if (highspeed) {
hsusb_reg16(IDX_RXMAXP) = usbc->inep[i].width;
} else {
hsusb_reg16(IDX_RXMAXP) = (((usbc->outep[i].blocksize / 64) - 1) << 11) | 64;
// hsusb_reg16(IDX_RXMAXP) = 64;
// usbc->outep[i].blocksize = 64;
}
LTRACEF("%d: rxmaxp 0x%hx\n", i, hsusb_reg16(IDX_RXMAXP));
offset += 512;
hsusb_reg8(IDX_RXCSRH) = (1<<7);
hsusb_reg8(IDX_RXCSRL) = (1<<7);
// LTRACEF("rxcsr 0x%hx\n", hsusb_reg16(IDX_RXCSR));
} else {
hsusb_reg8(RXFIFOSZ) = 0;
hsusb_reg16(RXFIFOADD) = 0;
hsusb_reg16(IDX_RXMAXP) = 0;
}
// LTRACEF("%d txfifosz 0x%hhx\n", i, hsusb_reg8(TXFIFOSZ));
// LTRACEF("%d rxfifosz 0x%hhx\n", i, hsusb_reg8(RXFIFOSZ));
// LTRACEF("%d txfifoadd 0x%hx\n", i, hsusb_reg16(TXFIFOADD));
// LTRACEF("%d rxfifoadd 0x%hx\n", i, hsusb_reg16(RXFIFOADD));
}
}
static void otg_reset(void)
{
/* reset the chip */
*REG32(OTG_SYSCONFIG) |= (1<<1);
while ((*REG32(OTG_SYSSTATUS) & 1) == 0)
;
/* power up the controller */
*REG32(OTG_FORCESTDBY) = 0; // disable forced standby
*REG32(OTG_SYSCONFIG) &= ~(1<<1); // autoidle off
*REG32(OTG_SYSCONFIG) = (2<<12) | (2<<3) | (0<<0); // master in smart-standby, periph in smart-idle, autoidle off
*REG32(OTG_SYSCONFIG) |= 1; // autoidle on
*REG32(OTG_INTERFSEL) = 1; // 8 bit ULPI
}
static void hsusb_init(void)
{
LTRACE_ENTRY;
// select endpoint 0
dprintf(SPEW, "hwvers 0x%hx\n", hsusb_reg16(HWVERS));
dprintf(SPEW, "epinfo 0x%hhx\n", hsusb_reg8(EPINFO));
dprintf(SPEW, "raminfo 0x%hhx\n", hsusb_reg8(RAMINFO));
hsusb_reg8(INDEX) = 0;
dprintf(SPEW, "config 0x%hhx\n", hsusb_reg8(IDX_CONFIGDATA));
// assert that we have dynamic fifo sizing
DEBUG_ASSERT(hsusb_reg8(IDX_CONFIGDATA) & (1<<2));
// mask all the interrupts for the endpoints (except 0)
hsusb_reg16(INTRTXE) = (1<<0);
hsusb_reg16(INTRRXE) = 0;
twl4030_usb_reset();
twl4030_init_hs();
hsusb_reg8(DEVCTL) = 0; // peripheral mode
// hsusb_reg8(POWER) &= (1<<5); // disable high speed
hsusb_reg8(POWER) |= (1<<5); // enable high speed
hsusb_reg8(INTRUSBE) = (1<<5)|(1<<2)|(1<<1)|(1<<0); // disconnect, reset, resume, suspend
LTRACE_EXIT;
}
void usbc_init(void)
{
LTRACE_ENTRY;
// enable the clock
RMWREG32(CM_ICLKEN1_CORE, 4, 1, 1);
// allocate some ram for the usb struct
usbc = malloc(sizeof(struct usbc_stat));
memset(usbc, 0, sizeof(struct usbc_stat));
usbc->state = USB_DEFAULT;
// initialize the callback list
list_initialize(&usbc_callback_list);
// register the interrupt handlers
register_int_handler(92, hsusb_interrupt, NULL);
// register_int_handler(93, hsusb_dma_interrupt, NULL);
otg_reset();
hsusb_init();
unmask_interrupt(92);
// unmask_interrupt(93);
LTRACE_EXIT;
}