A27系列优化I2C/RTC处理,新增版本A270Y

This commit is contained in:
2025-06-07 10:24:51 +08:00
parent 413dd88f3b
commit 73e1c7dafa
372 changed files with 60642 additions and 60661 deletions

269
A27-STEPLDR/Src/Boot.s Normal file
View File

@ -0,0 +1,269 @@
MODULE ?cstartup
;; Forward declaration of sections.
SECTION IRQ_STACK:DATA:NOROOT(3)
SECTION FIQ_STACK:DATA:NOROOT(3)
SECTION SVC_STACK:DATA:NOROOT(3)
SECTION ABT_STACK:DATA:NOROOT(3)
SECTION UND_STACK:DATA:NOROOT(3)
SECTION CSTACK:DATA:NOROOT(3)
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#define __ASSEMBLY__
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
#define IRAM_BASE 0x300000
#define SYS_CPU_CTL 0xe4900208
#define AIC 0xFFFFF000
#define AIC_IVR 0x10
#define AIC_EOICR 0x38
#define ARM_MODE_ABT 0x17
#define ARM_MODE_FIQ 0x11
#define ARM_MODE_IRQ 0x12
#define ARM_MODE_SVC 0x13
#define ARM_MODE_SYS 0x1F
#define I_BIT 0x80
#define F_BIT 0x40
//------------------------------------------------------------------------------
// Startup routine
//------------------------------------------------------------------------------
/*
Exception vectors
*/
// SECTION .vectors:CODE:NOROOT(2)
SECTION .intvec:CODE:NOROOT(2)
PUBLIC __vector
PUBLIC __iar_program_start
ARM ; Always ARM mode after reset
__vector:
ldr pc, Reset
LDR PC, Undefined_Addr
LDR PC, SWI_Addr
LDR PC, Prefetch_Addr
LDR PC, Abort_Addr
NOP ; Reserved vector
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
IMPORT undef_handler
IMPORT swi_handler
IMPORT prefetch_handler
IMPORT data_abort_handler
IMPORT AIC_IrqHandler
IMPORT fiq_handler
Reset: dc32 __iar_program_start
Undefined_Addr: dc32 undef_handler ;Undefined_Handler
SWI_Addr: dc32 swi_handler ;SWI_Handler
Prefetch_Addr: dc32 prefetch_handler ;ExceptionPAB
Abort_Addr: dc32 data_abort_handler ;ExceptionDAB
Reserved_Addr: dc32 0 ;ExceptionREV
IRQ_Addr: dc32 irqHandler
FIQ_Addr: dc32 fiq_handler
MODE_MSK DEFINE 0x1F ; Bit mask for mode bits in CPSR
USR_MODE DEFINE 0x10 ; User mode
FIQ_MODE DEFINE 0x11 ; Fast Interrupt Request mode
IRQ_MODE DEFINE 0x12 ; Interrupt Request mode
SVC_MODE DEFINE 0x13 ; Supervisor mode
ABT_MODE DEFINE 0x17 ; Abort mode
UND_MODE DEFINE 0x1B ; Undefined Instruction mode
SYS_MODE DEFINE 0x1F ; System mode
CP_DIS_MASK DEFINE 0xFFFFEFFA
SECTION .text:CODE:NOROOT(2)
EXTERN ?main
REQUIRE __vector
__iar_program_start:
b reset_handler
// DCD 0x424b5241
// DCD 0
// DCD 0
reset_handler:
;==================================================================
; Reset registers
;==================================================================
MOV r2, #0
MOV r3, #0
MOV r4, #0
MOV r5, #0
MOV r6, #0
MOV r7, #0
MOV r8, #0
MOV r9, #0
MOV r10, #0
MOV r11, #0
MOV r12, #0
;==================================================================
; Disable caches, MMU and branch prediction in case they were left enabled from an earlier run
; This does not need to be done from a cold reset
;==================================================================
MRC p15, 0, r0, c1, c0, 0 ; Read CP15 System Control register
BIC r0, r0, #(0x1 << 12) ; Clear I bit 12 to disable I Cache
;ORR r0, r0, #(0x1 << 12) ; Set I bit 12 to enable I Cache
BIC r0, r0, #(0x1 << 2) ; Clear C bit 2 to disable D Cache
BIC r0, r0, #0x1 ; Clear M bit 0 to disable MMU
BIC r0, r0, #(0x1 << 11) ; Clear Z bit 11 to disable branch prediction
MCR p15, 0, r0, c1, c0, 0 ; Write value back to CP15 System Control register
;==================================================================
; Cache Invalidation code for Cortex-A7
; NOTE: Neither Caches, nor MMU, nor BTB need post-reset invalidation on Cortex-A7,
; but forcing a cache invalidation, makes the code more portable to other CPUs (e.g. Cortex-A9)
;==================================================================
; Invalidate L1 Instruction Cache
MRC p15, 1, r0, c0, c0, 1 ; Read Cache Level ID Register (CLIDR)
TST r0, #0x3 ; Harvard Cache?
MOV r0, #0 ; SBZ
MCRNE p15, 0, r0, c7, c5, 0 ; ICIALLU - Invalidate instruction cache and flush branch target cache
; Invalidate Data/Unified Caches
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
ANDS r3, r0, #0x07000000 ; Extract coherency level
MOV r3, r3, LSR #23 ; Total cache levels << 1
BEQ Finished ; If 0, no need to clean
MOV r10, #0 ; R10 holds current cache level << 1
Loop1 ADD r2, r10, r10, LSR #1 ; R2 holds cache "Set" position
MOV r1, r0, LSR r2 ; Bottom 3 bits are the Cache-type for this level
AND r1, r1, #7 ; Isolate those lower 3 bits
CMP r1, #2
BLT Skip ; No cache or only instruction cache at this level
MCR p15, 2, r10, c0, c0, 0 ; Write the Cache Size selection register
ISB ; ISB to sync the change to the CacheSizeID reg
MRC p15, 1, r1, c0, c0, 0 ; Reads current Cache Size ID register
AND r2, r1, #7 ; Extract the line length field
ADD r2, r2, #4 ; Add 4 for the line length offset (log2 16 bytes)
LDR r4, =0x3FF
ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ r5, r4 ; R5 is the bit position of the way size increment
LDR r7, =0x7FFF
ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned)
Loop2 MOV r9, r4 ; R9 working copy of the max way size (right aligned)
Loop3 ORR r11, r10, r9, LSL r5 ; Factor in the Way number and cache number into R11
ORR r11, r11, r7, LSL r2 ; Factor in the Set number
MCR p15, 0, r11, c7, c6, 2 ; Invalidate by Set/Way
SUBS r9, r9, #1 ; Decrement the Way number
BGE Loop3
SUBS r7, r7, #1 ; Decrement the Set number
BGE Loop2
Skip ADD r10, r10, #2 ; increment the cache number
CMP r3, r10
BGT Loop1
Finished
;==================================================================
; Invalidate TLB
;==================================================================
MOV r0, #0
MCR p15, 0, r0, c8, c7, 0
;==================================================================
; Branch Prediction Enable
;==================================================================
;MOV r1, #0
;MRC p15, 0, r1, c1, c0, 0 /* Read Control Register configuration data */
;ORR r1, r1, #(0x1 << 11) /* Global BP Enable bit */
;MCR p15, 0, r1, c1, c0, 0 /* Write Control Register configuration data */
; Initialize the stack pointers.
; The pattern below can be used for any of the exception stacks:
; FIQ, IRQ, SVC, ABT, UND, SYS.
; The USR mode uses the same stack as SYS.
; The stack segments must be defined in the linker command file,
; and be declared above.
mrs r0,cpsr ; Original PSR value
bic r0,r0,#MODE_MSK ; Clear the mode bits
orr r0,r0,#SVC_MODE ; Set Supervisor mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(SVC_STACK) ; End of SVC_STACK
bic r0,r0,#MODE_MSK ; Clear the mode bits
orr r0,r0,#ABT_MODE ; Set Abort mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(ABT_STACK) ; End of ABT_STACK
bic r0,r0,#MODE_MSK ; Clear the mode bits
orr r0,r0,#UND_MODE ; Set Undefined mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(UND_STACK) ; End of UND_STACK
bic r0,r0,#MODE_MSK ; Clear the mode bits
orr r0,r0,#FIQ_MODE ; Set FIR mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(FIQ_STACK) ; End of FIQ_STACK
bic r0,r0,#MODE_MSK ; Clear the mode bits
orr r0,r0,#IRQ_MODE ; Set IRQ mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(IRQ_STACK) ; End of IRQ_STACK
bic r0,r0,#MODE_MSK ; Clear the mode bits
orr r0,r0,#SYS_MODE ; Set System mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(CSTACK) ; End of CSTACK
/* Branch to main() */
LDR r0, =?main
BLX r0
/* Loop indefinitely when program is finished */
loop4:
B loop4
/*
Handles incoming interrupt requests by branching to the corresponding
handler, as defined in the AIC. Supports interrupt nesting.
*/
irqHandler:
NOP
NOP
;/* IRQ entry {{{ */ /* save r0 in r13_IRQ */
SUB lr,lr,#4 /* put return address in r0_SYS */
STMFD sp!,{lr} /* save r1 in r14_IRQ (lr) */
MRS lr,spsr /* put the SPSR in r1_SYS */
STMFD sp!,{r0,lr}
ldr r0, = AIC_IrqHandler
; ldr r0, [r0];
MSR cpsr_c,#(ARM_MODE_SYS | I_BIT) /* SYSTEM, no IRQ, but FIQ enabled! */ /* save SPSR and PC on SYS stack */
// mcr p15, 0, r0, c7, c10, 5
STMFD sp!, {r1-r3, r4, r12, lr} /* save all other regs on SYS stack */
AND r1, sp, #4
SUB sp, sp, r1
STMFD sp!, {r1, lr}
BLX r0
LDMIA sp!, {r1, lr}
ADD sp, sp, r1
LDMIA sp!, {r1-r3, r4, r12, lr}
MSR CPSR_c, #ARM_MODE_IRQ | I_BIT
LDMIA sp!, {r0, lr}
MSR SPSR_cxsf, lr
LDMIA sp!, {pc}^
END

View File

@ -0,0 +1,58 @@
;Pre-defined run mode constants
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK EQU 0x1f
NOINT EQU 0xc0
;Stacks defination for each run mode
_STACK_BASEADDRESS EQU 0xC0008000
UserStackLen EQU 0x10
SVCStackLen EQU 0x2000
UndefStackLen EQU 0x10
AbortStackLen EQU 0x10
IRQStackLen EQU 0x400
FIQStackLen EQU 0x10
UserStackStart EQU (_STACK_BASEADDRESS)
UndefStackStart EQU (UserStackStart - UserStackLen)
AbortStackStart EQU (UndefStackStart - UndefStackLen)
IRQStackStart EQU (AbortStackStart - AbortStackLen)
FIQStackStart EQU (IRQStackStart - IRQStackLen)
SVCStackStart EQU (FIQStackStart - FIQStackLen)
VICL_BASE EQU 0xE0C00000
VICH_BASE EQU 0xE0B00000
ENABLE_REG_OFFSET EQU 0x10
CLR_REG_OFFSET EQU 0x14
ADDRESS_REG_OFFSET EQU 0xF00
VICL_RAW_STATUS EQU 0xE0C00008 ;Interrupt raw status low 32 vector
VICH_RAW_STATUS EQU 0xE0B00008 ;Interrupt raw status high 32 vector
VICL_SEL_REG EQU 0xE0C0000C ;Interrupt select reg for low 32 vector
VICH_SEL_REG EQU 0xE0B0000C ;Interrupt select reg for high 32 vector
VICL_ENABLE EQU 0xE0C00010 ;Interrupt Enable control low 32 vector
VICH_ENABLE EQU 0xE0B00010 ;Interrupt Enable control high 32 vector
VICL_CLR EQU 0xE0C00014 ;Interrupt clear control low 32 vector
VICH_CLR EQU 0xE0B00014 ;Interrupt clear control high 32 vector
VICL_ADDR_BASE EQU 0xE0C00100
VICH_ADDR_BASE EQU 0xE0B00100
VICL_PROORITY_BASE EQU 0xE0C00200
VICH_PROORITY_BASE EQU 0xE0B00200
;ENABLE_VE EQU 0x01000000
VICL_ADDRESS EQU 0xE0C00F00
VICH_ADDRESS EQU 0xE0B00F00
WDT_CTL EQU 0xE4B00000
ITCM0_BaseAddress EQU 0xA0000000 ;ITCM0 base : 0xA0000000, Size : 8KB,
ITCM1_BaseAddress EQU 0xA0002000 ;ITCM1 base : 0xA0002000, Size : 8KB,
DTCM0_BaseAddress EQU 0xA0004000 ;DTCM0 base : 0xA0004000, Size : 8KB,
DTCM1_BaseAddress EQU 0xA0006000 ;DTCM1 base : 0xA0006000, Size : 8KB,

393
A27-STEPLDR/Src/Entry.c Normal file
View File

@ -0,0 +1,393 @@
/*
**********************************************************************
Copyright (c)2021 Arkmicro Technologies Inc. All Rights Reserved
Filename: Entry.c
Version : 1.00
Date : 2021.08.20
Author : Sim
***********************************************************************
*/
#include "typedef.h"
#include "amt630h.h"
#include "uart.h"
#include "timer.h"
#include "aic.h"
#include "mmu.h"
#include "lcd.h"
#include "spi.h"
#include "sysinfo.h"
#include "sysctl.h"
#include "board.h"
#include "fs/ff.h"
#include "fs/diskio.h"
#include "crc32.h"
#include "sdmmc.h"
#include <intrinsics.h>
extern void bootFromSPI(void);
extern void updateFromSD(int chipid);
extern void updateFromUSB(void);
int wdt_init(void);
void wdt_stop(void);
void wdt_start(void);
static SysInfo *pSysInfo = NULL;
void UpdateFromMedia(int drv)
{
FRESULT fret;
FIL fp = {0};
UINT32 size;
unsigned int checksum, calc_checksum;
int timeout = 0;
int update_ok = 0;
SysInfo *sysinfo = GetSysInfo();
#if DEVICE_TYPE_SELECT == EMMC_FLASH
char launchemmcfile[32];
#endif
char loaderfile[32];
char stepldrfile[32];
char appfile[32];
FILINFO fileinfo = {0};
int leftsize;
if (drv == SDMMC) {
strcpy(loaderfile, LOADER_FILE_NAME);
strcpy(stepldrfile, STEPLDR_FILE_NAME);
strcpy(appfile, APP_FILE_NAME);
} else if (drv == USB) {
#if DEVICE_TYPE_SELECT == EMMC_FLASH
strcpy(launchemmcfile, "1:/");
strcat(launchemmcfile, LAUNCHEMMC_FILE_NAME);
#endif
strcpy(loaderfile, "1:/");
strcat(loaderfile, LOADER_FILE_NAME);
strcpy(stepldrfile, "1:/");
strcat(stepldrfile, STEPLDR_FILE_NAME);
strcpy(appfile, "1:/");
strcat(appfile, APP_FILE_NAME);
} else {
SendUartString("Unknown disk drv\r\n");
return;
}
fret = f_mount(drv, &g_fs);
if(fret == FR_OK)
SendUartString("Mount file ok\r\n");
else
{
SendUartString("Mount file fail\r\n");
return;
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
SendUartString("burn emmc launcher start... \r\n");
readlaunchemmc:
fret = f_open(&fp, launchemmcfile, FA_OPEN_EXISTING | FA_READ);
if(fret != FR_OK) {
SendUartString("Open file fail, don't update.\r\n");
} else {
fret = f_read(&fp, (void *)IMAGE_ENTRY, LOADER_MAX_SIZE, &size);
f_close(&fp);
if(fret != FR_OK) {
if (timeout++ < 3) {
SendUartString("Read file fail, read again.\r\n");
goto readlaunchemmc;
}
} else {
checksum = *(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET);
*(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET) = 0;
calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, size, 0xffffffff);
*(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET) = checksum;
if (calc_checksum != checksum) {
if (timeout++ < 3) {
SendUartString("read step emmc checksum fail, read again.\n");
goto readlaunchemmc;
}
else {
SendUartString("read step emmc fail, don't update.\n");
}
} else {
if (FlashBurn((void*)IMAGE_ENTRY, LOADER_OFFSET, size, 0)) {
SendUartString("burn step emmc fail.\n");
goto end;
}
}
}
}
SendUartString("burn emmc launcher end. \r\n");
#endif
SendUartString("burn loader start... \r\n");
readloader:
fret = f_open(&fp, loaderfile, FA_OPEN_EXISTING | FA_READ);
if(fret != FR_OK) {
SendUartString("Open file fail, don't update.\r\n");
} else {
fret = f_read(&fp, (void *)IMAGE_ENTRY, LOADER_MAX_SIZE, &size);
f_close(&fp);
if(fret != FR_OK) {
if (timeout++ < 3) {
SendUartString("Read file fail, read again.\r\n");
goto readloader;
}
} else {
checksum = *(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET);
*(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET) = 0;
calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, size, 0xffffffff);
*(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET) = checksum;
if (calc_checksum != checksum) {
if (timeout++ < 3) {
SendUartString("read loader checksum fail, read again.\n");
goto readloader;
}
else {
SendUartString("read loader fail, don't update.\n");
}
} else {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
if (FlashBurn((void*)IMAGE_ENTRY, LOADER_OFFSET, size, 0)) {
SendUartString("burn loader fail.\n");
goto end;
}
#else
if (sysinfo->loader_offset == LOADER_OFFSET)
sysinfo->loader_offset = LOADERB_OFFSET;
else
sysinfo->loader_offset = LOADER_OFFSET;
sysinfo->loader_size = size;
if (EmmcBurn((void*)IMAGE_ENTRY, sysinfo->loader_offset, size, 0)) {
SendUartString("burn emmc loader fail.\n");
goto end;
}
#endif
}
}
}
SendUartString("burn loader end. \r\n");
timeout = 0;
SendUartString("burn stepldr start... \r\n");
readstepldr:
fret = f_open(&fp, stepldrfile, FA_OPEN_EXISTING | FA_READ);
if(fret != FR_OK) {
SendUartString("Open file fail, don't update.\r\n");
} else {
fret = f_read(&fp, (void *)IMAGE_ENTRY, STEPLDR_MAX_SIZE, &size);
f_close(&fp);
if(fret != FR_OK) {
if (timeout++ < 3) {
SendUartString("Read file fail, read again.\r\n");
goto readstepldr;
} else {
SendUartString("read stepldr fail, don't update.\n");
}
} else {
checksum = *(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET);
*(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET) = 0;
calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, size, 0xffffffff);
*(unsigned int*)(IMAGE_ENTRY + APPLDR_CHECKSUM_OFFSET) = checksum;
if (calc_checksum != checksum) {
if (timeout++ < 3) {
SendUartString("read stepldr checksum fail, read again.\n");
goto readstepldr;
}
else {
SendUartString("read stepldr fail, don't update.\n");
}
} else {
if (sysinfo->stepldr_offset == STEPLDRA_OFFSET)
sysinfo->stepldr_offset = STEPLDRB_OFFSET;
else
sysinfo->stepldr_offset = STEPLDRA_OFFSET;
sysinfo->stepldr_size = size;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
if (FlashBurn((void*)IMAGE_ENTRY, sysinfo->stepldr_offset, size, 0)) {
SendUartString("burn stepldr fail.\n");
goto end;
}
#else
if (EmmcBurn((void*)IMAGE_ENTRY, sysinfo->stepldr_offset, size, 0)) {
SendUartString("burn emmc stepldr fail.\n");
goto end;
}
#endif
}
}
}
SendUartString("burn stepldr end. \r\n");
timeout = 0;
SendUartString("burn app start... \r\n");
update_logo_init();
SendUartString("A274.6 PWM2 -250606.\r\n");
gpio_direction_output(6,1);
readapp:
fret = f_stat(appfile, &fileinfo);
if (fret != FR_OK) {
SendUartString("Get file info fail, don't update.\r\n");
goto end;
}
leftsize = fileinfo.fsize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (sysinfo->image_offset == IMAGE_OFFSET)
sysinfo->image_offset = IMAGEB_OFFSET;
else
sysinfo->image_offset = IMAGE_OFFSET;
if(leftsize)
{
unsigned int start = sysinfo->image_offset;
unsigned int blkcnt;
unsigned int blkstart;
if(start % 512)
blkstart = start / 512 + 1;
else
blkstart = start / 512;
if(fileinfo.fsize % 512)
blkcnt = fileinfo.fsize / 512 + 1;
else
blkcnt = fileinfo.fsize / 512;
mmc_berase(blkstart, blkcnt);
}
#endif
fret = f_open(&fp, appfile, FA_OPEN_EXISTING | FA_READ);
if(fret != FR_OK) {
SendUartString("Open file fail, don't update.\r\n");
} else {
UpFileHeader *header = (UpFileHeader *)IMAGE_ENTRY;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
UINT32 woff = IMAGE_OFFSET;
#else
UINT32 woff = sysinfo->image_offset;
#endif
UINT32 app_size;
while (leftsize > 0) {
fret = f_read(&fp, (void *)IMAGE_ENTRY, IMAGE_READ_SIZE, &size);
if(fret != FR_OK) {
SendUartString("Read file fail\r\n");
if (timeout++ < 3) {
SendUartString("Read file fail, read again.\r\n");
f_close(&fp);
goto readapp;
} else {
SendUartString("read update file fail, don't update.\n");
}
} else {
if (leftsize == fileinfo.fsize) {
calc_checksum = 0xffffffff;
checksum = header->checksum;
header->checksum = 0;
app_size = header->files[0].size;
}
calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, size, calc_checksum);
if (leftsize == fileinfo.fsize)
header->checksum = checksum;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
if(FlashBurn((void*)IMAGE_ENTRY, woff, size, 0)) {
SendUartString("burn app fail.\n");
f_close(&fp);
goto end;
}
#else
if (mmc_write((void*)IMAGE_ENTRY, woff, size, 0)) {
SendUartString("burn app fail.\n");
f_close(&fp);
goto end;
}
#endif
update_progress_set(100 - leftsize * 100 / fileinfo.fsize);
}
woff += size;
leftsize -= size;
}
f_close(&fp);
update_progress_set(100);
if (calc_checksum != checksum) {
SendUartString("app checksum fail, update again.\n");
} else {
sysinfo->app_checksum = header->checksum = checksum;
sysinfo->app_size = app_size;
update_ok = 1;
}
}
SendUartString("burn app end.\r\n");
if (update_ok) {
SendUartString("update ok, save sysinfo.\r\n");
sysinfo->update_status = UPDATE_STATUS_END;
SaveSysInfo(sysinfo);
}
end:
SendUartString("Update is finished.\r\n");
}
void main(void)
{
wdt_init();
timer_init();
AIC_Initialize();
InitUart(115200);
SendUartString("ARK AMT630HV100 STEPLDR V 1.0\r\n");
#ifdef MMU_ENABLE
MMU_Init();
#endif
SendUartString("HS VS >> GPIO .\r\n");
vSysctlConfigure(SYS_PAD_CTRL05, 20, 0x0f, 0x00);
gpio_direction_output(90,0);
gpio_direction_output(91,0);
if(SpiInit()) {
SendUartString("SpiInit failed.\n");
while(1);
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
Emmcinit(0);
#endif
if (ReadSysInfo()) {
SendUartString("read sysinfo fail, use default.\r\n");
SetDefaultSysInfo();
}
pSysInfo = GetSysInfo();
//pSysInfo->update_status = UPDATE_STATUS_START;
//pSysInfo->update_media_type = UPDATE_MEDIA_USB;
if (pSysInfo->update_status == UPDATE_STATUS_START) {
lcd_init();
wdt_stop();
switch (pSysInfo->update_media_type) {
case UPDATE_MEDIA_SD:
updateFromSD(0);
break;
#ifdef USB_SUPPORT
case UPDATE_MEDIA_USB:
__enable_irq();
extern int ark_usb_init(void);
if (!ark_usb_init())
UpdateFromMedia(USB);
break;
#endif
case UPDATE_MEDIA_UART:
__enable_irq();
updateFromUart(UART_MCU_PORT);
break;
}
wdt_start();
}
__disable_irq();
#if DEVICE_TYPE_SELECT != EMMC_FLASH
bootFromSPI();
#else
bootFromEmmc(0);
#endif
}

1160
A27-STEPLDR/Src/SpiBooter.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

103
A27-STEPLDR/Src/aic.c Normal file
View File

@ -0,0 +1,103 @@
/**
* \file
*
* Implementation of Ark Interrupt Controller (AIC) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "amt630h.h"
#include "aic.h"
#include "timer.h"
#include <stdint.h>
#include <string.h>
#define ICSET 0x00
#define ICPEND 0x04
#define ICMODE 0x08
#define ICMASK 0x0C
#define ICLEVEL 0x10
#define IRQISPR 0x3C
#define IRQISPC 0x40
#define IVEC_ADDR 0x78
typedef struct {
ISRFunction_t handler;
void *handler_param;
}IrqDesc_t;
static IrqDesc_t irq_descs[MAX_IRQ_NUM];
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void AIC_Initialize(void)
{
memset(irq_descs, 0, sizeof(irq_descs));
writel(0x8, REGS_AIC_BASE + ICSET);
udelay(10);
writel(0x5, REGS_AIC_BASE + ICSET);
writel(0x0, REGS_AIC_BASE + ICMODE);
writel(0xffffffff, REGS_AIC_BASE + ICMASK);
writel(0xffffffff, REGS_AIC_BASE + ICLEVEL);
writel(0xffffffff, REGS_AIC_BASE + IRQISPC);
}
/**
* \brief Enables interrupts coming from the given (unique) source (ID_xxx).
*
* \param source Interrupt source to enable.
*/
void AIC_EnableIT(uint32_t source)
{
writel(readl(REGS_AIC_BASE + ICMASK) & ~(1 << source), REGS_AIC_BASE + ICMASK);
}
/**
* \brief Disables interrupts coming from the given (unique) source (ID_xxx).
*
* \param source Interrupt source to disable.
*/
void AIC_DisableIT(uint32_t source)
{
writel(readl(REGS_AIC_BASE + ICMASK) | (1 << source), REGS_AIC_BASE + ICMASK);
}
int32_t request_irq(uint32_t irq_source, int32_t priority, ISRFunction_t func, void *param)
{
if (irq_source > MAX_IRQ_NUM - 1) {
return -1;
}
irq_descs[irq_source].handler = func;
irq_descs[irq_source].handler_param = param;
AIC_EnableIT(irq_source);
return 0;
}
int32_t free_irq(uint32_t irq_source)
{
if (irq_source > MAX_IRQ_NUM - 1) {
return -1;
}
irq_descs[irq_source].handler = NULL;
irq_descs[irq_source].handler_param = NULL;
AIC_DisableIT(irq_source);
return 0;
}
void AIC_IrqHandler(void)
{
int32_t source = readl(REGS_AIC_BASE + IVEC_ADDR) >> 2;
if (irq_descs[source].handler)
irq_descs[source].handler(irq_descs[source].handler_param);
writel(1 << source, REGS_AIC_BASE + IRQISPC);
}

45
A27-STEPLDR/Src/aic.h Normal file
View File

@ -0,0 +1,45 @@
/**
* \file
*
* \section Purpose
*
* Methods and definitions for configuring interrupts.
*
* \section Usage
* -# Enable or disable interrupt generation of a particular source with
* IRQ_EnableIT and IRQ_DisableIT.
* -# Start or stop the timer clock using TC_Start() and TC_Stop().
*/
#ifndef AIC_H
#define AIC_H
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include <stdint.h>
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*ISRFunction_t)( void *param );
extern void AIC_Initialize(void);
extern void AIC_EnableIT( uint32_t source);
extern void AIC_DisableIT(uint32_t source);
extern int32_t request_irq(uint32_t irq_source, int32_t priority, ISRFunction_t func, void *param);
extern int32_t free_irq(uint32_t irq_source);
extern void AIC_IrqHandler(void);
#ifdef __cplusplus
}
#endif
#endif //#ifndef AIC_H

485
A27-STEPLDR/Src/amt630h.h Normal file
View File

@ -0,0 +1,485 @@
/***********************************************************************
Copyright (c)2020 Arkmicro Technologies Inc. All Rights Reserved
Filename: amt630h.h
Version : 1.0
Date : 2020.04.08
Author : Sim. Huang
History :
************************************************************************/
#ifndef _AMT630H_H_
#define _AMT630H_H_
#include <stdint.h>
#include <string.h>
//change the Assemble logic valuable VECTOR_ENABLE //in file Boot.s
#define CLK_24MHZ 24000000
/*@}*/
/* ************************************************************************** */
/* BASE ADDRESS DEFINITIONS FOR AMT630H */
/* ************************************************************************** */
/** \addtogroup AMT630H_base Peripheral Base Address Definitions */
/*@{*/
#define REGS_SYSCTL_BASE (0x60000000U)
#define REGS_SPI0_BASE (0x60100000U)
#define REGS_SPI1_BASE (0x60200000U)
#define REGS_IIC0_BASE (0x60300000U)
#define REGS_IIC1_BASE (0x60400000U)
#define REGS_UART0_BASE (0x60500000U)
#define REGS_UART1_BASE (0x60600000U)
#define REGS_UART2_BASE (0x60700000U)
#define REGS_UART3_BASE (0x60800000U)
#define REGS_GPIO_BASE (0x60900000U)
#define REGS_TIMER_BASE (0x60a00000U)
#define REGS_PWM_BASE (0x60b00000U)
#define REGS_WDT_BASE (0x60c00000U)
#define REGS_I2S_BASE (0x60d00000U)
#define REGS_MIPI_BASE (0x60e00000U)
#define REGS_RTC_BASE (0x61000000U)
#define REGS_ADC_BASE (0x61100000U)
#define REGS_RCRT_BASE (0x61200000U)
#define REGS_AES_BASE (0x61300000U)
#define REGS_AIC_BASE (0x61400000U)
#define REGS_CAN0_BASE (0x61500000U)
#define REGS_CAN1_BASE (0x61600000U)
#define REGS_DMAC_BASE (0x70100000U)
#define REGS_GPU_BASE (0x70200000U)
#define REGS_USB_BASE (0x70300000U)
#define REGS_SDMMC0_BASE (0X70400000U)
#define REGS_ITU_BASE (0X70600000U)
#define REGS_LCD_BASE (0X71000000U)
#define REGS_PXP_BASE (0X71100000U)
#define REGS_ROTATE_BASE (0X71207000U)
#define REGS_JPG_BASE (0X71208000U)
#define REGS_DDRC_BASE (0X71300000U)
#define SYS_IO_DRIVER00 0xe0
#define SYS_IO_DRIVER01 0xe4
#define SYS_IO_DRIVER02 0xe8
#define SYS_IO_DRIVER03 0xec
#define SYS_IO_DRIVER04 0xf0
#define SYS_IO_DRIVER05 0xf4
#define SYS_IO_DRIVER06 0xf8
#define SYS_IO_DRIVER07 0xfc
/* register base address */
#define SDHC0_BASE 0x70400000
#define USB_BASE 0x70300000//0x700C0000
#define SSI1_BASE 0x60200000//0x48002000
#define SSI0_BASE 0x60100000
#define GPIO_BASE 0x60900000//0x40409000
#define SYS_BASE 0x60000000//0x40408000
#define TIMER_BASE 0x60a00000//0x40405000
#define WDT_BASE 0x60c00000//0x40404000
#define RTC_BASE 0x61000000//0x40406000
#define UART0_BASE 0x60500000//0x4040B000
//uart
#define UART_BASE UART0_BASE
#define rUART_DR *((volatile unsigned int *)(UART_BASE + 0x00))
#define rUART_RSR *((volatile unsigned int *)(UART_BASE + 0x04))
#define rUART_FR *((volatile unsigned int *)(UART_BASE + 0x18))
#define rUART_ILPR *((volatile unsigned int *)(UART_BASE + 0x20))
#define rUART_IBRD *((volatile unsigned int *)(UART_BASE + 0x24))
#define rUART_FBRD *((volatile unsigned int *)(UART_BASE + 0x28))
#define rUART_LCR_H *((volatile unsigned int *)(UART_BASE + 0x2C))
#define rUART_CR *((volatile unsigned int *)(UART_BASE + 0x30))
#define rUART_IFLS *((volatile unsigned int *)(UART_BASE + 0x34))
#define rUART_IMSC *((volatile unsigned int *)(UART_BASE + 0x38))
#define rUART_RIS *((volatile unsigned int *)(UART_BASE + 0x3C))
#define rUART_MIS *((volatile unsigned int *)(UART_BASE + 0x40))
#define rUART_ICR *((volatile unsigned int *)(UART_BASE + 0x44))
#define rUART_DMACR *((volatile unsigned int *)(UART_BASE + 0x48))
/***************************************************************
AHB slave interface registers definition
****************************************************************/
/* AHB system */
#define rSYS_BOOT_SAMPLE *((volatile unsigned int *)(SYS_BASE+0x0))
#define rSYS_BUS_CLK_SEL *((volatile unsigned int *)(SYS_BASE+0x40))
#define rSYS_PLLRFCK_CTL *((volatile unsigned int *)(SYS_BASE+0x44))
#define rSYS_SDMMC_CLK_CFG *((volatile unsigned int *)(SYS_BASE+0x48))
#define rSYS_VOU_CLK_CFG *((volatile unsigned int *)(SYS_BASE+0x4c))
#define rSYS_PER_CLK_EN *((volatile unsigned int *)(SYS_BASE+0x50))
#define rSYS_LCD_CLK_CFG *((volatile unsigned int *)(SYS_BASE+0x54))
#define rSYS_SD_CLK_CFG *((volatile unsigned int *)(SYS_BASE+0x58))
#define rSYS_SOFT_RST *((volatile unsigned int *)(SYS_BASE+0x5c))
#define rSYS_SOFT1_RST *((volatile unsigned int *)(SYS_BASE+0x60))
#define rSYS_SSP_CLK_CFG *((volatile unsigned int *)(SYS_BASE+0x64))
#define rSYS_TIMER_CLK_CFG *((volatile unsigned int *)(SYS_BASE+0x68))
#define rSYS_I2S_NCO_CFG *((volatile unsigned int *)(SYS_BASE+0x6c))
#define rSYS_DDRCTL_CFG *((volatile unsigned int *)(SYS_BASE+0x70))
#define rSYS_DDRCTL1_CFG *((volatile unsigned int *)(SYS_BASE+0x74))
#define rSYS_PERCTL_CFG *((volatile unsigned int *)(SYS_BASE+0x78))
#define rSYS_TIMER1_CLK_CFG *((volatile unsigned int *)(SYS_BASE+0x7c))
#define rSYS_ANA_CFG *((volatile unsigned int *)(SYS_BASE+0x80))
#define rSYS_ANA1_CFG *((volatile unsigned int *)(SYS_BASE+0x84))
#define rSYS_CPUPLL_CFG *((volatile unsigned int *)(SYS_BASE+0x88))
#define rSYS_SYSPLL_CFG *((volatile unsigned int *)(SYS_BASE+0x8c))
#define rSYS_ANA2_CFG *((volatile unsigned int *)(SYS_BASE+0x98))
#define rSYS_ANA3_CFG *((volatile unsigned int *)(SYS_BASE+0x9c))
#define rSYS_PAD_CTRL00 *((volatile unsigned int *)(SYS_BASE+0x30*4))
#define rSYS_PAD_CTRL01 *((volatile unsigned int *)(SYS_BASE+0x31*4))
#define rSYS_PAD_CTRL02 *((volatile unsigned int *)(SYS_BASE+0x32*4))
#define rSYS_PAD_CTRL03 *((volatile unsigned int *)(SYS_BASE+0x33*4))
#define rSYS_PAD_CTRL04 *((volatile unsigned int *)(SYS_BASE+0x34*4))
#define rSYS_PAD_CTRL05 *((volatile unsigned int *)(SYS_BASE+0xD4))
#define rSYS_PAD_CTRL06 *((volatile unsigned int *)(SYS_BASE+0x36*4))
#define rSYS_PAD_CTRL07 *((volatile unsigned int *)(SYS_BASE+0x37*4))
#define rSYS_IO_DRIVER00 *((volatile unsigned int *)(SYS_BASE+0x38*4))
#define rSYS_IO_DRIVER01 *((volatile unsigned int *)(SYS_BASE+0x39*4))
#define rSYS_IO_DRIVER02 *((volatile unsigned int *)(SYS_BASE+0x3A*4))
#define rSYS_IO_DRIVER03 *((volatile unsigned int *)(SYS_BASE+0x3B*4))
#define rSYS_IO_DRIVER04 *((volatile unsigned int *)(SYS_BASE+0x3C*4))
#define rSYS_IO_DRIVER05 *((volatile unsigned int *)(SYS_BASE+0x3D*4))
#define rSYS_IO_DRIVER06 *((volatile unsigned int *)(SYS_BASE+0x3E*4))
#define rSYS_IO_DRIVER07 *((volatile unsigned int *)(SYS_BASE+0x3F*4))
/* Timer */
#define rTIMER0_LOAD_COUNT (*(volatile unsigned int *)(TIMER_BASE + 0x00))
#define rTIMER0_CURRENT_VALUE (*(volatile unsigned int *)(TIMER_BASE + 0x04))
#define rTIMER0_CONTROL (*(volatile unsigned int *)(TIMER_BASE + 0x08))
#define rTIMER0_EOI (*(volatile unsigned int *)(TIMER_BASE + 0x0C))
#define rTIMER0_INT_STATUS (*(volatile unsigned int *)(TIMER_BASE + 0x10))
/* WDT */
#define rWDT_CR (*(volatile unsigned int *)(WDT_BASE + 0x00))
#define rWDT_PSR (*(volatile unsigned int *)(WDT_BASE + 0x04))
#define rWDT_LDR (*(volatile unsigned int *)(WDT_BASE + 0x08))
#define rWDT_VLR (*(volatile unsigned int *)(WDT_BASE + 0x0C))
#define rWDT_ISR (*(volatile unsigned int *)(WDT_BASE + 0x10))
#define rWDT_RCR (*(volatile unsigned int *)(WDT_BASE + 0x14))
#define rWDT_TMR (*(volatile unsigned int *)(WDT_BASE + 0x18))
#define rWDT_TCR (*(volatile unsigned int *)(WDT_BASE + 0x1C))
/* RTC */
#define rRTC_CTL (*(volatile unsigned int *)(RTC_BASE + 0x00)) /*control register*/
#define rRTC_ANAWEN (*(volatile unsigned int *)(RTC_BASE + 0x04)) /*analog block write enable register*/
#define rRTC_ANACTL (*(volatile unsigned int *)(RTC_BASE + 0x08)) /*analog block control register*/
#define rRTC_IM (*(volatile unsigned int *)(RTC_BASE + 0x0C)) /*interrupt mode register*/
#define rRTC_STA (*(volatile unsigned int *)(RTC_BASE + 0x10)) /*rtc status register*/
#define rRTC_ALMDAT (*(volatile unsigned int *)(RTC_BASE + 0x14)) /*alarm data register*/
#define rRTC_DONT (*(volatile unsigned int *)(RTC_BASE + 0x18)) /*delay on timer register*/
#define rRTC_RAM (*(volatile unsigned int *)(RTC_BASE + 0x1C)) /*ram bit register*/
#define rRTC_CNTL (*(volatile unsigned int *)(RTC_BASE + 0x20)) /*rtc counter register*/
#define rRTC_CNTH (*(volatile unsigned int *)(RTC_BASE + 0x24)) /*rtc sec counter register*/
/* UART0 */
#define rUART0_DR (*(volatile unsigned int *)(UART0_BASE + 0x00))
#define rUART0_RSR (*(volatile unsigned int *)(UART0_BASE + 0x04))
#define rUART0_FR (*(volatile unsigned int *)(UART0_BASE + 0x18))
#define rUART0_ILPR (*(volatile unsigned int *)(UART0_BASE + 0x20))
#define rUART0_IBRD (*(volatile unsigned int *)(UART0_BASE + 0x24))
#define rUART0_FBRD (*(volatile unsigned int *)(UART0_BASE + 0x28))
#define rUART0_LCR_H (*(volatile unsigned int *)(UART0_BASE + 0x2C))
#define rUART0_CR (*(volatile unsigned int *)(UART0_BASE + 0x30))
#define rUART0_IFLS (*(volatile unsigned int *)(UART0_BASE + 0x34))
#define rUART0_IMSC (*(volatile unsigned int *)(UART0_BASE + 0x38))
#define rUART0_RIS (*(volatile unsigned int *)(UART0_BASE + 0x3C))
#define rUART0_MIS (*(volatile unsigned int *)(UART0_BASE + 0x40))
#define rUART0_ICR (*(volatile unsigned int *)(UART0_BASE + 0x44))
#define rUART0_DMACR (*(volatile unsigned int *)(UART0_BASE + 0x48))
/* SSI */
#define rSPI_CONTROLREG (*(volatile unsigned int *)(SSI1_BASE + 0x08))
#define rSPI_CONFIGREG (*(volatile unsigned int *)(SSI1_BASE + 0x0C))
#define rSPI_INTREG (*(volatile unsigned int *)(SSI1_BASE + 0x10))
#define rSPI_DMAREG (*(volatile unsigned int *)(SSI1_BASE + 0x14))
#define rSPI_STATUSREG (*(volatile unsigned int *)(SSI1_BASE + 0x18))
#define rSPI_PERIODREG (*(volatile unsigned int *)(SSI1_BASE + 0x1C))
#define rSPI_TESTREG (*(volatile unsigned int *)(SSI1_BASE + 0x20))
#define rSPI_MSGREG (*(volatile unsigned int *)(SSI1_BASE + 0x40))
#define rSPI_RXDATA (*(volatile unsigned int *)(SSI1_BASE + 0x50))
#define rSPI_TXDATA (*(volatile unsigned int *)(SSI1_BASE + 0x460))
#define rSPI_TXFIFO (SSI_BASE + 0x460)
#define rSPI_RXFIFO (SSI_BASE + 0x50)
/* SSI0 */
#define rSPI_CTLR0 (*(volatile unsigned int *)(SSI0_BASE + 0x00))
#define rSPI_CTLR1 (*(volatile unsigned int *)(SSI0_BASE + 0x04))
#define rSPI_SSIENR (*(volatile unsigned int *)(SSI0_BASE + 0x08))
#define rSPI_MWCR (*(volatile unsigned int *)(SSI0_BASE + 0x0c))
#define rSPI_SER (*(volatile unsigned int *)(SSI0_BASE + 0x10))
#define rSPI_BAUDR (*(volatile unsigned int *)(SSI0_BASE + 0x14))
#define rSPI_TXFTLR (*(volatile unsigned int *)(SSI0_BASE + 0x18))
#define rSPI_RXFTLR (*(volatile unsigned int *)(SSI0_BASE + 0x1C))
#define rSPI_TXFLR (*(volatile unsigned int *)(SSI0_BASE + 0x20))
#define rSPI_RXFLR (*(volatile unsigned int *)(SSI0_BASE + 0x24))
#define rSPI_SR (*(volatile unsigned int *)(SSI0_BASE + 0x28))
#define rSPI_IMR (*(volatile unsigned int *)(SSI0_BASE + 0x2C))
#define rSPI_ISR (*(volatile unsigned int *)(SSI0_BASE + 0x30))
#define rSPI_RISR (*(volatile unsigned int *)(SSI0_BASE + 0x34))
#define rSPI_TXOICR (*(volatile unsigned int *)(SSI0_BASE + 0x38))
#define rSPI_RXOICR (*(volatile unsigned int *)(SSI0_BASE + 0x3C))
#define rSPI_RXUICR (*(volatile unsigned int *)(SSI0_BASE + 0x40))
#define rSPI_MSTICR (*(volatile unsigned int *)(SSI0_BASE + 0x44))
#define rSPI_ICR (*(volatile unsigned int *)(SSI0_BASE + 0x48))
#define rSPI_DMACR (*(volatile unsigned int *)(SSI0_BASE + 0x4C))
#define rSPI_DMATDLR (*(volatile unsigned int *)(SSI0_BASE + 0x50))
#define rSPI_DMARDLR (*(volatile unsigned int *)(SSI0_BASE + 0x54))
#define rSPI_IDR (*(volatile unsigned int *)(SSI0_BASE + 0x58))
#define rSPI_SSI_COMP_VERSION (*(volatile unsigned int *)(SSI0_BASE + 0x5C))
#define rSPI_DR (*(volatile unsigned int *)(SSI0_BASE + 0x60))
#define SPI_DR (SSI0_BASE + 0x60)
#define rSPI_RX_SAMPLE_DLY (*(volatile unsigned int *)(SSI0_BASE + 0xf0))
#define rSPI_SPI_CTRLR0 (*(volatile unsigned int *)(SSI0_BASE + 0xf4))
//#define rSPI_RSVD_1 (*(volatile unsigned int *)(SSI0_BASE + 0xf8))
//#define rSPI_RSVD_1 (*(volatile unsigned int *)(SSI0_BASE + 0xfC))
/* GPIO */
#define rGPIO_PA_MOD (*(volatile unsigned int *)(GPIO_BASE + 0x00))
#define rGPIO_PA_RDATA (*(volatile unsigned int *)(GPIO_BASE + 0x04))
#define rGPIO_PA_INTEN (*(volatile unsigned int *)(GPIO_BASE + 0x08))
#define rGPIO_PA_LEVEL (*(volatile unsigned int *)(GPIO_BASE + 0x0C))
#define rGPIO_PA_PEND (*(volatile unsigned int *)(GPIO_BASE + 0x10))
#define rGPIO_PB_MOD (*(volatile unsigned int *)(GPIO_BASE + 0x20))
#define rGPIO_PB_RDATA (*(volatile unsigned int *)(GPIO_BASE + 0x24))
#define rGPIO_PB_INTEN (*(volatile unsigned int *)(GPIO_BASE + 0x28))
#define rGPIO_PB_LEVEL (*(volatile unsigned int *)(GPIO_BASE + 0x2C))
#define rGPIO_PB_PEND (*(volatile unsigned int *)(GPIO_BASE + 0x30))
#define rGPIO_PC_MOD (*(volatile unsigned int *)(GPIO_BASE + 0x40))
#define rGPIO_PC_RDATA (*(volatile unsigned int *)(GPIO_BASE + 0x44))
#define rGPIO_PC_INTEN (*(volatile unsigned int *)(GPIO_BASE + 0x48))
#define rGPIO_PC_LEVEL (*(volatile unsigned int *)(GPIO_BASE + 0x4C))
#define rGPIO_PC_PEND (*(volatile unsigned int *)(GPIO_BASE + 0x50))
#define rGPIO_PD_MOD (*(volatile unsigned int *)(GPIO_BASE + 0x60))
#define rGPIO_PD_RDATA (*(volatile unsigned int *)(GPIO_BASE + 0x64))
#define rGPIO_PD_INTEN (*(volatile unsigned int *)(GPIO_BASE + 0x68))
#define rGPIO_PD_LEVEL (*(volatile unsigned int *)(GPIO_BASE + 0x6C))
#define rGPIO_PD_PEND (*(volatile unsigned int *)(GPIO_BASE + 0x70))
//DDR Reg
#define DDR_BASE 0x71300000
#define MEM_STA_REG *(volatile unsigned int *)(DDR_BASE + 0x00)
#define MEM_CMD_REG *(volatile unsigned int *)(DDR_BASE + 0x04)
#define DIR_CMD_REG *(volatile unsigned int *)(DDR_BASE + 0x08)
#define MEM_CFG_REG *(volatile unsigned int *)(DDR_BASE + 0x0C)
#define REF_PRD_REG *(volatile unsigned int *)(DDR_BASE + 0x10)
#define TCAS_REG *(volatile unsigned int *)(DDR_BASE + 0x14)
#define TDQSS_REG *(volatile unsigned int *)(DDR_BASE + 0x18)
#define TMRD_REG *(volatile unsigned int *)(DDR_BASE + 0x1C)
#define TRAS_REG *(volatile unsigned int *)(DDR_BASE + 0x20)
#define TRC_REG *(volatile unsigned int *)(DDR_BASE + 0x24)
#define TRCD_REG *(volatile unsigned int *)(DDR_BASE + 0x28)
#define TRFC_REG *(volatile unsigned int *)(DDR_BASE + 0x2C)
#define TRP_REG *(volatile unsigned int *)(DDR_BASE + 0x30)
#define TRRD_REG *(volatile unsigned int *)(DDR_BASE + 0x34)
#define TWR_REG *(volatile unsigned int *)(DDR_BASE + 0x38)
#define TWTR_REG *(volatile unsigned int *)(DDR_BASE + 0x3C)
#define TXP_REG *(volatile unsigned int *)(DDR_BASE + 0x40)
#define TXSR_REG *(volatile unsigned int *)(DDR_BASE + 0x44)
#define TESR_REG *(volatile unsigned int *)(DDR_BASE + 0x48)
#define MEM_CFG2_REG *(volatile unsigned int *)(DDR_BASE + 0x4C)
#define CHIP_CFG_REG *(volatile unsigned int *)(DDR_BASE + 0x200)
#define FEA_CTL_REG *(volatile unsigned int *)(DDR_BASE + 0x30C)
typedef enum IRQn
{
LCD_IRQn = 0, /**< 0 AMT630H LCD Interrupt ID */
JPG_IRQn = 1, /**< 1 AMT630H Jpeg Decoder Interrupt (JPG) */
GPU_IRQn = 2, /**< 2 AMT630H GPU Interrupt (GPU) */
USB_IRQn = 3, /**< 3 AMT630H USB Controller Interrupt (USB) */
PXP_IRQn = 4, /**< 4 AMT630H PXP Interrupt (PXP) */
DMA_IRQn = 5, /**< 5 AMT630H DMA Controller Interrupt (DMAC) */
SDMMC0_IRQn = 6, /**< 6 AMT630H SDMMC 0 Controller Interrupt (SDMMC0) */
SPI0_IRQn = 7, /**< 7 AMT630H SPI 0 Controller Interrupt (SPI0) */
SPI1_IRQn = 8, /**< 8 AMT630H SPI 1 Controller Interrupt (SPI1) */
I2C0_IRQn = 9, /**< 9 AMT630H I2C0 Controller Interrupt (I2C0) */
I2C1_IRQn = 10, /**< 10 AMT630H I2C1 Controller Interrupt (I2C1) */
UART0_IRQn = 11, /**< 11 AMT630H UART 0 Controller Interrupt (UART0) */
UART1_IRQn = 12, /**< 12 AMT630H UART 1 Controller Interrupt (UART1) */
UART2_IRQn = 13, /**< 13 AMT630H UART 2 Controller Interrupt (UART2) */
UART3_IRQn = 14, /**< 14 AMT630H UART 3 Controller Interrupt (UART3) */
GPIOA_IRQn = 15, /**< 15 AMT630H GPIO0~31 Controller Interrupt (GPIOA) */
GPIOB_IRQn = 16, /**< 16 AMT630H GPIO32~63 Controller Interrupt (GPIOB) */
GPIOC_IRQn = 17, /**< 17 AMT630H GPIO64~95 Controller Interrupt (GPIOC) */
GPIOD_IRQn = 18, /**< 18 AMT630H GPIO96~127 Controller Interrupt (GPIOD) */
TIMER0_IRQn = 19, /**< 19 AMT630H Timer 0 Interrupt (TIMER0) */
TIMER1_IRQn = 20, /**< 20 AMT630H Timer 1 Interrupt (TIMER1) */
TIMER2_IRQn = 21, /**< 21 AMT630H Timer 2 Interrupt (TIMER2) */
TIMER3_IRQn = 22, /**< 22 AMT630H Timer 3 Interrupt (TIMER3) */
ITU_IRQn = 23, /**< 23 AMT630H ITU Controller Interrupt (ITU) */
WDT_IRQn = 24, /**< 24 AMT630H Watchdog timer Interrupt (WDT) */
RTC_I2S_IRQn = 25, /**< 25 AMT630H I2S Interrupt (I2S) */
RTC_ALM_IRQn = 26, /**< 26 AMT630H RTC Controller Alarm Interrupt (RTCA) */
RTC_PRD_IRQn = 27, /**< 27 AMT630H RTC Controller Period Interrupt (RTCP) */
ADC_IRQn = 28, /**< 28 AMT630H ADC controller Interrupt (ADC) */
RCRT_IRQn = 29, /**< 29 */
CAN0_IRQn = 30, /**< 30 AMT630H CAN0 Controller Interrupt (CAN0) */
CAN1_IRQn = 31, /**< 31 AMT630H CAN1 Controller Interrupt (CAN1) */
MAX_IRQ_NUM = 32 /**< Number of peripheral IDs */
} IRQn_Type;
#define MMU_ENABLE
#define SPI_NOR_FLASH 0
#define SPI_NAND_FLASH 1
#define EMMC_FLASH 2
#define DEVICE_TYPE_SELECT SPI_NOR_FLASH
#define OTA_UPDATE_SUPPORT
#if DEVICE_TYPE_SELECT == SPI_NAND_FLASH
#define LOADER_OFFSET 0x0
#define LOADER_MAX_SIZE 0x4000
#define STEPLDRA_OFFSET 0x20000
#define STEPLDRB_OFFSET 0x40000
#define STEPLDR_MAX_SIZE 0x14000
#define SYSINFOA_OFFSET 0x60000
#define SYSINFOB_OFFSET 0x80000
#define SYSINFO_MAX_SIZE 0x1000
#define IMAGE_OFFSET 0xa0000
#ifdef OTA_UPDATE_SUPPORT
#define IMAGEB_OFFSET 0xc00000
#else
#define IMAGEB_OFFSET IMAGE_OFFSET
#endif
#define IMAGE_READ_SIZE 0x20000
#define LOADER_FILE_NAME "spildr.bin"
#define STEPLDR_FILE_NAME "stepldr.bin"
#define APP_FILE_NAME "update.bin"
#elif DEVICE_TYPE_SELECT == SPI_NOR_FLASH
#define LOADER_OFFSET 0x0
#define LOADER_MAX_SIZE 0x4000
#define STEPLDRA_OFFSET 0x4000
#define STEPLDRB_OFFSET 0x20000
#define STEPLDR_MAX_SIZE 0x14000
#define SYSINFOA_OFFSET 0x3c000
#define SYSINFOB_OFFSET 0x3e000
#define SYSINFO_MAX_SIZE 0x1000
#define IMAGE_OFFSET 0x40000
#define IMAGE_MAX_SIZE 0xb00000
#ifdef OTA_UPDATE_SUPPORT
#define IMAGEB_OFFSET 0xc00000
#else
#define IMAGEB_OFFSET IMAGE_OFFSET
#endif
#define IMAGE_READ_SIZE 0x10000
#define OTA_OFFSET 0x1800000
#define LOADER_FILE_NAME "spildr.bin"
#define STEPLDR_FILE_NAME "stepldr.bin"
#define APP_FILE_NAME "update.bin"
#elif DEVICE_TYPE_SELECT == EMMC_FLASH
/**********************************************************************************************
emmc<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
(0-------0x200000-------0x400000------0x500000---0xA00000-----0x40000000-----0x80000000-----end
|------------|--------------|--------------|---------|-------------|----------- --|-----------|
| | | | | | | |
| EMMCLDR | stepldr | SYSINFO | log | app1 | app2 | ota |
|____________|______________|______________|_________|_____________|______________|___________|
**********************************************************************************************/
#define LOADER_OFFSET 0x0
#define LOADERB_OFFSET 0x100000
#define LOADER_MAX_SIZE 0x4000
#define STEPLDRA_OFFSET 0x200000
#define STEPLDRB_OFFSET 0x300000
#define STEPLDR_MAX_SIZE 0x14000
#define SYSINFOA_OFFSET 0x400000
#define SYSINFOB_OFFSET 0x500000
#define SYSINFO_MAX_SIZE 0x1000
#define IMAGE_OFFSET 0xa00000
#define IMAGEB_OFFSET 0x40000000
#define IMAGE_MAX_SIZE 0xf00000
#define IMAGE_READ_SIZE 0x80000
#define OTA_OFFSET 0x80000000
#define LOADER_FILE_NAME "emmcldr.bin"
#define LAUNCHEMMC_FILE_NAME "lnchemmc.bin"
#define STEPLDR_FILE_NAME "stepldr.bin"
#define APP_FILE_NAME "update.bin"
#endif
#define IMAGE_ENTRY 0x20000000
typedef struct {
unsigned int magic;
unsigned int offset;
unsigned int size;
} UpFileInfo;
typedef struct {
unsigned int magic;
unsigned int filenum;
unsigned int size;
unsigned int checksum;
unsigned int reserved1;
unsigned int reserved2;
UpFileInfo files[];
} UpFileHeader;
#define ENOENT 2 /* No such file or directory */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define ENOMEM 12 /* Out of memory */
#define ENODEV 19 /* No such device */
#define EINVAL 22 /* Invalid argument */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define EPROTO 71 /* Protocol error */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ROUND(a,b) (((a) + (b) - 1) & ~((b) - 1))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
//typedef unsigned long uintptr_t;
#define PAD_COUNT(s, pad) (((s) - 1) / (pad) + 1)
#define PAD_SIZE(s, pad) (PAD_COUNT(s, pad) * pad)
#define ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, pad) \
char __##name[ROUND(PAD_SIZE((size) * sizeof(type), pad), align) \
+ (align - 1)]; \
\
type *name = (type *)ALIGN((uintptr_t)__##name, align)
#define ALLOC_ALIGN_BUFFER(type, name, size, align) \
ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, 1)
#define ALLOC_CACHE_ALIGN_BUFFER_PAD(type, name, size, pad) \
ALLOC_ALIGN_BUFFER_PAD(type, name, size, ARCH_DMA_MINALIGN, pad)
#define ALLOC_CACHE_ALIGN_BUFFER(type, name, size) \
ALLOC_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
#define reg32_read(addr) *((volatile uint32_t *)(addr))
#define reg32_write(addr,val) *((volatile uint32_t *)(addr)) = (val)
#define readl(a) reg32_read(a)
#define writel(v, a) reg32_write(a, v)
#endif // _AMT630H_H_

164
A27-STEPLDR/Src/board.h Normal file
View File

@ -0,0 +1,164 @@
#ifndef _BOARD_H
#define _BOARD_H
/********** display configuration **********/
#define LCD_INTERFACE_TTL 0
#define LCD_INTERFACE_LVDS 1
#define LCD_INTERFACE_CPU 2
#define LCD_INTERFACE_MIPI 3
#define LCD_WIRING_MODE_RGB 0
#define LCD_WIRING_MODE_RBG 1
#define LCD_WIRING_MODE_GRB 2
#define LCD_WIRING_MODE_GBR 3
#define LCD_WIRING_MODE_BRG 4
#define LCD_WIRING_MODE_BGR 5
#define LCD_WIRING_BIT_ORDER_MSB 0
#define LCD_WIRING_BIT_ORDER_LSB 1
#define LVDS_PANEL_FORMAT_TI 0
#define LVDS_PANEL_FORMAT_NS 1
#define LVDS_PANEL_DATA_8BIT 0
#define LVDS_PANEL_DATA_6BIT 1
#define CPU_PANEL_18BIT_MODE 0
#define CPU_PANEL_16BIT_MODE 1
#define CPU_PANEL_9BIT_MODE 2
#define CPU_PANEL_8BIT_MODE 3
#define LCD_ROTATE_ANGLE_0 0
#define LCD_ROTATE_ANGLE_90 1
#define LCD_ROTATE_ANGLE_180 2
#define LCD_ROTATE_ANGLE_270 3
#ifdef DOUBLE_POINTER_HALO
#define LCD_WIDTH 1280
#define LCD_HEIGHT 480
#define LCD_BPP 16
#define LCD_INTERFACE_TYPE LCD_INTERFACE_LVDS
#else
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define LCD_BPP 32
#define LCD_INTERFACE_TYPE LCD_INTERFACE_TTL
#endif
#define LCD_H_FLIP 0//水平镜像
#define LCD_V_FLIP 0//垂直镜像
#define LCD_ROTATE_ANGLE LCD_ROTATE_ANGLE_0
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_TTL
#define LCD_WIRING_MODE LCD_WIRING_MODE_RGB
#define LCD_WIRING_BIT_ORDER LCD_WIRING_BIT_ORDER_LSB
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_LVDS
#define LCD_WIRING_MODE LCD_WIRING_MODE_BGR
#define LCD_WIRING_BIT_ORDER LCD_WIRING_BIT_ORDER_MSB
#define LVDS_SCREEN_RST_GPIO 74
#define LVDS_PANEL_FORMAT LVDS_PANEL_FORMAT_TI
#define LVDS_PANEL_DATA LVDS_PANEL_DATA_8BIT
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_CPU
#define CPU_PANEL_DATA CPU_PANEL_8BIT_MODE
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_MIPI
#define LCD_WIRING_MODE LCD_WIRING_MODE_RGB
#define LCD_WIRING_BIT_ORDER LCD_WIRING_BIT_ORDER_MSB
#endif
#define FB_SIZE (LCD_WIDTH * LCD_HEIGHT * LCD_BPP / 8)
#define VIDEO_DISPLAY_WIDTH LCD_WIDTH
#define VIDEO_DISPLAY_HEIGHT LCD_HEIGHT
#define VIDEO_DISPLAY_BUF_NUM 2
#if (LCD_WIDTH == 1024 && LCD_HEIGHT == 600)
#define LCD_TIMING_VBP 1
#define LCD_TIMING_VFP 1
#define LCD_TIMING_VSW 30
#define LCD_TIMING_HBP 100
#define LCD_TIMING_HFP 100
#define LCD_TIMING_HSW 370
#define LCD_CLK_FREQ 50000000
#elif (LCD_WIDTH == 800 && LCD_HEIGHT == 480)
#define LCD_TIMING_VBP 1
#define LCD_TIMING_VFP 1
#define LCD_TIMING_VSW 30
#define LCD_TIMING_HBP 50
#define LCD_TIMING_HFP 50
#define LCD_TIMING_HSW 180
#define LCD_CLK_FREQ 35000000
#elif (LCD_WIDTH == 480 && LCD_HEIGHT == 800)
#define LCD_TIMING_VBP 1
#define LCD_TIMING_VFP 1
#define LCD_TIMING_VSW 30
#define LCD_TIMING_HBP 50
#define LCD_TIMING_HFP 50
#define LCD_TIMING_HSW 180
#define LCD_CLK_FREQ 35000000
#elif (LCD_WIDTH == 1280 && LCD_HEIGHT == 720)
#define LCD_TIMING_VBP 5
#define LCD_TIMING_VFP 65
#define LCD_TIMING_VSW 2
#define LCD_TIMING_HBP 16
#define LCD_TIMING_HFP 42
#define LCD_TIMING_HSW 2
#define LCD_CLK_FREQ 60000000
#elif (LCD_WIDTH == 1280 && LCD_HEIGHT == 480)
#define LCD_TIMING_VBP 5
#define LCD_TIMING_VFP 8
#define LCD_TIMING_VSW 3
#define LCD_TIMING_HBP 16
#define LCD_TIMING_HFP 26
#define LCD_TIMING_HSW 12
#define LCD_CLK_FREQ 40000000
#elif (LCD_WIDTH == 480 && LCD_HEIGHT == 1280)
#define LCD_TIMING_VBP 6// 14
#define LCD_TIMING_VFP 6// 16
#define LCD_TIMING_VSW 16// 2
#define LCD_TIMING_HBP 16
#define LCD_TIMING_HFP 36
#define LCD_TIMING_HSW 26
#define LCD_CLK_FREQ 50000000
#elif (LCD_WIDTH == 480 && LCD_HEIGHT == 960)
#define LCD_TIMING_VBP 20
#define LCD_TIMING_VFP 20
#define LCD_TIMING_VSW 10
#define LCD_TIMING_HBP 30
#define LCD_TIMING_HFP 40
#define LCD_TIMING_HSW 10
#define LCD_CLK_FREQ 33330000
#else
#error "no lcd timing configuraion."
#endif
/*******************************************/
/*********** uart configuration ************/
#define UART_MCU_PORT 3
/*******************************************/
/************ usb configuration ************/
#define USB_SUPPORT
#define CONFIG_USB_DWC2_HOST 1
#define CONFIG_USB_NEW_DWC2_HOST 1
/*******************************************/
/************ spi configuration ************/
#define SPI0_QSPI_MODE
/*******************************************/
/************ i2c configuration ************/
//#define I2C_SUPPORT
#ifdef I2C_SUPPORT
#define ANALOG_I2C_SUPPORT //Analog i2c support
#ifdef ANALOG_I2C_SUPPORT
#define I2C_GPIO0_SDA_PIN 49//51
#define I2C_GPIO0_SCL_PIN 48//50
#endif
#endif
/*******************************************/
#endif

365
A27-STEPLDR/Src/cp15.c Normal file
View File

@ -0,0 +1,365 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Reg Reads Writes
//----------------------------------------------------------------------------
// 0 ID code Unpredictable
// 0 cache type Unpredictable
// 0 TCM status Unpredictable
// 1 Control Control
// 2 Translation table base Translation table base
// 3 Domain access control Domain access control
// 4 (Reserved)
// 5 Data fault status Data fault status
// 5 Instruction fault status Instruction fault status
// 6 Fault address Fault address
// 7 cache operations cache operations
// 8 Unpredictable TLB operations
// 9 cache lockdown cache lockdown
// 9 TCM region TCM region
// 10 TLB lockdown TLB lockdown
// 11 (Reserved)
// 12 (Reserved)
// 13 FCSE PID FCSE PID
// 13 Context ID Context ID
// 14 (Reserved)
// 15 Test configuration Test configuration
//-----------------------------------------------------------------------------
/** \page cp15_f CP15 Functions.
*
* \section CP15 function Usage
*
* Methods to manage the Coprocessor 15. Coprocessor 15, or System Control
* Coprocessor CP15, is used to configure and control all the items in the
* list below:
* <ul>
* <li> ARM core
* <li> caches (Icache, Dcache and write buffer)
* <li> TCM
* <li> MMU
* <li> Other system options
* </ul>
* \section Usage
*
* -# Enable or disable D cache with Enable_D_cache and Disable_D_cache
* -# Enable or disable I cache with Enable_I_cache and Disable_I_cache
*
* Related files:\n
* \ref cp15.h\n
* \ref cp15.c.\n
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "cp15.h"
#include "uart.h"
#if defined(__ICCARM__)
#include <intrinsics.h>
#endif
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Check Instruction cache
* \return 0 if I_cache disable, 1 if I_cache enable
*/
unsigned int CP15_IsIcacheEnabled(void)
{
unsigned int control;
control = CP15_ReadControl();
return ((control & (1 << CP15_I_BIT)) != 0);
}
/**
* \brief Enable Instruction cache
*/
void CP15_EnableIcache(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if cache is disabled
if ((control & (1 << CP15_I_BIT)) == 0) {
control |= (1 << CP15_I_BIT);
CP15_WriteControl(control);
//SendUartString("I cache enabled.\n\r");
}
else {
//SendUartString("I cache is already enabled.\n\r");
}
}
/**
* \brief Disable Instruction cache
*/
void CP15_DisableIcache(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if cache is enabled
if ((control & (1 << CP15_I_BIT)) != 0) {
control &= ~(1ul << CP15_I_BIT);
CP15_WriteControl(control);
//SendUartString("I cache disabled.\n\r");
}
else {
//SendUartString("I cache is already disabled.\n\r");
}
}
/**
* \brief Check MMU
* \return 0 if MMU disable, 1 if MMU enable
*/
unsigned int CP15_IsMMUEnabled(void)
{
unsigned int control;
control = CP15_ReadControl();
return ((control & (1 << CP15_M_BIT)) != 0);
}
/**
* \brief Enable MMU
*/
void CP15_EnableMMU(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if MMU is disabled
if ((control & (1 << CP15_M_BIT)) == 0) {
control |= (1 << CP15_M_BIT);
CP15_WriteControl(control);
//SendUartString("MMU enabled.\n\r");
}
else {
//SendUartString("MMU is already enabled.\n\r");
}
}
/**
* \brief Disable MMU
*/
void CP15_DisableMMU(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if MMU is enabled
if ((control & (1 << CP15_M_BIT)) != 0) {
control &= ~(1ul << CP15_M_BIT);
control &= ~(1ul << CP15_C_BIT);
CP15_WriteControl(control);
//SendUartString("MMU disabled.\n\r");
}
else {
//SendUartString("MMU is already disabled.\n\r");
}
}
/**
* \brief Check D_cache
* \return 0 if D_cache disable, 1 if D_cache enable (with MMU of course)
*/
unsigned int CP15_IsDcacheEnabled(void)
{
unsigned int control;
control = CP15_ReadControl();
return ((control & ((1 << CP15_C_BIT)||(1 << CP15_M_BIT))) != 0);
}
/**
* \brief Enable Data cache
*/
void CP15_EnableDcache(void)
{
unsigned int control;
control = CP15_ReadControl();
if( !CP15_IsMMUEnabled() ) {
//SendUartString("Do nothing: MMU not enabled\r\n");
}
else {
// Check if cache is disabled
if ((control & (1 << CP15_C_BIT)) == 0) {
control |= (1 << CP15_C_BIT);
CP15_WriteControl(control);
//SendUartString("D cache enabled.\r\n");
}
else {
//SendUartString("D cache is already enabled.\r\n");
}
}
}
/**
* \brief Disable Data cache
*/
void CP15_DisableDcache(void)
{
unsigned int control;
control = CP15_ReadControl();
// Check if cache is enabled
if ((control & (1 << CP15_C_BIT)) != 0) {
control &= ~(1ul << CP15_C_BIT);
CP15_WriteControl(control);
//SendUartString("D cache disabled.\n\r");
}
else {
//SendUartString("D cache is already disabled.\n\r");
}
}
/**
* \brief Invalidate TLB
*/
void CP15_InvalidateTLB(void)
{
asm("MCR p15, 0, %0, c8, c3, 0" : : "r"(1));
asm("DSB");
}
/**
* \brief Clean Data cache
*/
void CP15_CacheClean(uint8_t CacheType)
{
//assert(!CacheType);
CP15_SelectDCache();
CP15_CleanDCacheBySetWay();
asm("DSB");
}
/**
* \brief Invalidate D/Icache
*/
void CP15_CacheInvalidate(uint8_t CacheType)
{
if(CacheType)
{
CP15_SelectICache();
CP15_InvalidateIcacheInnerSharable();
asm("DSB");
asm("ISB");
}
else
{
CP15_SelectDCache();
CP15_InvalidateDcacheBySetWay();
asm("DSB");
asm("ISB");
}
}
/**
* \brief Flush(Clean and invalidate) Data cache
*/
void CP15_CacheFlush(uint8_t CacheType)
{
//assert(!CacheType);
CP15_SelectDCache();
CP15_CleanInvalidateDCacheBySetWay();
asm("DSB");
}
/**
* \brief Invalidate Data cache by address
*/
void CP15_InvalidateDCacheByVA(uint32_t S_Add, uint32_t E_Add)
{
CP15_SelectDCache();
CP15_InvalidateDcacheByMva(S_Add, E_Add);
}
/**
* \brief Clean Data cache by address
*/
void CP15_CleanDCacheByVA(uint32_t S_Add, uint32_t E_Add)
{
CP15_SelectDCache();
CP15_CleanDCacheByMva(S_Add, E_Add);
}
/**
* \brief Flush Data cache by address
*/
void CP15_FlushDCacheByVA(uint32_t S_Add, uint32_t E_Add)
{
CP15_SelectDCache();
CP15_CleanInvalidateDcacheByMva(S_Add, E_Add);
}

166
A27-STEPLDR/Src/cp15.h Normal file
View File

@ -0,0 +1,166 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
#ifndef _CP15_H
#define _CP15_H
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definition
*----------------------------------------------------------------------------*/
#define CP15_L4_BIT 15 // Determines if the T bit is set when load instructions
// change the PC:
// 0 = loads to PC set the T bit
// 1 = loads to PC do not set T bit
#define CP15_RR_BIT 14 // RR bit Replacement strategy for Icache and Dcache:
// 0 = Random replacement
// 1 = Round-robin replacement.
#define CP15_V_BIT 13 // V bit Location of exception vectors:
// 0 = Normal exception vectors selected address range = 0x0000 0000 to 0x0000 001C
// 1 = High exception vect selected, address range = 0xFFFF 0000 to 0xFFFF 001C
#define CP15_I_BIT 12 // I bit Icache enable/disable:
// 0 = Icache disabled
// 1 = Icache enabled
#define CP15_R_BIT 9 // R bit ROM protection
#define CP15_S_BIT 8 // S bit System protection
#define CP15_B_BIT 7 // B bit Endianness:
// 0 = Little-endian operation
// 1 = Big-endian operation.
#define CP15_C_BIT 2 // C bit Dcache enable/disable:
// 0 = cache disabled
// 1 = cache enabled
#define CP15_A_BIT 1 // A bit Alignment fault enable/disable:
// 0 = Data address alignment fault checking disabled
// 1 = Data address alignment fault checking enabled
#define CP15_M_BIT 0 // M bit MMU enable/disable: 0 = disabled 1 = enabled.
// 0 = disabled
// 1 = enabled
/** No access Any access generates a domain fault. */
#define CP15_DOMAIN_NO_ACCESS 0x00
/** Client Accesses are checked against the access permission bits in the section or page descriptor. */
#define CP15_DOMAIN_CLIENT_ACCESS 0x01
/** Manager Accesses are not checked against the access permission bits so a permission fault cannot be generated. */
#define CP15_DOMAIN_MANAGER_ACCESS 0x03
#define CP15_ICache 1
#define CP15_DCache 0
#define CP15_PMCNTENSET_ENABLE 31
#define CP15_PMCR_DIVIDER 3
#define CP15_PMCR_RESET 2
#define CP15_PMCR_ENABLE 0
/*------------------------------------------------------------------------------ */
/* Exported functions */
/*------------------------------------------------------------------------------ */
extern unsigned int CP15_ReadID(void);
extern unsigned int CP15_ReadControl(void);
extern void CP15_ExclusiveCache(void);
extern void CP15_NonExclusiveCache(void);
extern void CP15_ISB(void);
extern void CP15_DSB(void);
extern void CP15_DMB(void);
extern void CP15_SelectDCache(void);
extern void CP15_SelectICache(void);
extern void CP15_WriteControl(unsigned int value);
extern void CP15_WriteTTB(unsigned int value);
extern void CP15_WriteDomainAccessControl(unsigned int value);
extern void CP15_InvalidateIcacheInnerSharable(void);
extern void CP15_InvalidateBTBinnerSharable(void);
extern void CP15_InvalidateIcache(void);
extern void CP15_InvalidateIcacheByMva(void);
extern void CP15_InvalidateBTB(void);
extern void CP15_InvalidateBTBbyMva(uint32_t VA_Addr);
extern void CP15_InvalidateDcacheBySetWay(void);
extern void CP15_CleanDCacheBySetWay(void);
extern void CP15_CleanInvalidateDCacheBySetWay(void);
extern void CP15_InvalidateDcacheByMva(uint32_t startAddr, uint32_t endAddr );
extern void CP15_CleanDCacheByMva(uint32_t startAddr, uint32_t endAddr );
extern void CP15_CleanInvalidateDcacheByMva(uint32_t startAddr, uint32_t endAddr );
extern void CP15_CleanDCacheUMva(void);
extern void CP15_InvalidateTranslationTable(void);
extern void CP15_coherent_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_invalidate_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_clean_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_flush_dcache_for_dma (uint32_t startAddr, uint32_t endAddr );
extern void CP15_flush_kern_dcache_for_dma (uint32_t startAddr, uint32_t size );
/*------------------------------------------------------------------------------ */
/* Exported functions from CP15.c */
/*------------------------------------------------------------------------------ */
/** MMU (Status/Enable/Disable) */
extern unsigned int CP15_IsMMUEnabled(void);
extern void CP15_EnableMMU(void);
extern void CP15_DisableMMU(void);
/** I cache (Status/Enable/Disable) */
extern unsigned int CP15_IsIcacheEnabled(void);
extern void CP15_EnableIcache(void);
extern void CP15_DisableIcache(void);
/** D cache (Status/Enable/Disable) */
extern unsigned int CP15_IsDcacheEnabled(void);
extern void CP15_EnableDcache(void);
extern void CP15_DisableDcache(void);
extern void CP15_InvalidateTLB(void);
extern void CP15_CacheClean(uint8_t CacheType);
extern void CP15_CacheInvalidate(uint8_t CacheType);
extern void CP15_CacheFlush(uint8_t CacheType);
extern void CP15_InvalidateDCacheByVA(uint32_t S_Add, uint32_t E_Add);
extern void CP15_CleanDCacheByVA(uint32_t S_Add, uint32_t E_Add);
extern void CP15_FlushDCacheByVA(uint32_t S_Add, uint32_t E_Add);
#endif // #ifndef _CP15_H

View File

@ -0,0 +1,728 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES// LOSS OF USE, DATA,
* OR PROFITS// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/** \file */
/**
* \addtogroup cp15_cache Cache Operations
*
* \section Usage
*
* They are performed as MCR instructions and only operate on a level 1 cache associated with
* ATM v7 processor.
* The supported operations are:
* <ul>
* <li> Any of these operations can be applied to
* -# any data cache
* -# any unified cache.
* <li> Invalidate by MVA
* Performs an invalidate of a data or unified cache line based on the address it contains.
* <li> Invalidate by set/way
* Performs an invalidate of a data or unified cache line based on its location in the cache hierarchy.
* <li> Clean by MVA
* Performs a clean of a data or unified cache line based on the address it contains.
* <li> Clean by set/way
* Performs a clean of a data or unified cache line based on its location in the cache hierarchy.
* <li> Clean and Invalidate by MVA
* Performs a clean and invalidate of a data or unified cache line based on the address it contains.
* <li> Clean and Invalidate by set/way
* Performs a clean and invalidate of a data or unified cache line based on its location in the cache hierarchy.
* </ul>
*
* Related files:\n
* \ref cp15.h\n
* \ref cp15_arm_iar.s \n
*/
MODULE ?cp15
//// Forward declaration of sections.
SECTION IRQ_STACK:DATA:NOROOT(2)
SECTION CSTACK:DATA:NOROOT(3)
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#define __ASSEMBLY__
/*----------------------------------------------------------------------------
* Functions to access CP15 coprocessor register
*----------------------------------------------------------------------------*/
PUBLIC CP15_ReadID
PUBLIC CP15_ExclusiveCache
PUBLIC CP15_NonExclusiveCache
PUBLIC CP15_ISB
PUBLIC CP15_DSB
PUBLIC CP15_DMB
PUBLIC CP15_SelectICache
PUBLIC CP15_SelectDCache
PUBLIC CP15_ReadControl
PUBLIC CP15_WriteControl
PUBLIC CP15_WriteDomainAccessControl
PUBLIC CP15_WriteTTB
PUBLIC CP15_InvalidateIcacheInnerSharable
PUBLIC CP15_InvalidateBTBinnerSharable
PUBLIC CP15_InvalidateIcache
PUBLIC CP15_InvalidateIcacheByMva
PUBLIC CP15_InvalidateBTB
PUBLIC CP15_InvalidateBTBbyMva
PUBLIC CP15_InvalidateDcacheBySetWay
PUBLIC CP15_CleanDCacheBySetWay
PUBLIC CP15_CleanInvalidateDCacheBySetWay
PUBLIC CP15_InvalidateDcacheByMva
PUBLIC CP15_CleanDCacheByMva
PUBLIC CP15_CleanDCacheUMva
PUBLIC CP15_CleanInvalidateDcacheByMva
PUBLIC CP15_InvalidateTranslationTable
PUBLIC CP15_coherent_dcache_for_dma
PUBLIC CP15_invalidate_dcache_for_dma
PUBLIC CP15_clean_dcache_for_dma
PUBLIC CP15_flush_dcache_for_dma
PUBLIC CP15_flush_kern_dcache_for_dma
/**
* \brief Register c0 accesses the ID Register, Cache Type Register, and TCM Status Registers.
* Reading from this register returns the device ID, the cache type, or the TCM status
* depending on the value of Opcode_2 used.
*/
SECTION .CP15_ReadID:DATA:NOROOT(2)
PUBLIC CP15_ReadID
CP15_ReadID:
mov r0, #0
mrc p15, 0, r0, c0, c0, 0
bx lr
/**
* \brief Register c7 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_ISB:DATA:NOROOT(2)
PUBLIC CP15_ISB
CP15_ISB:
mov r0, #0
mcr p15, 0, r0, c7, c5, 4
nop
bx lr
/**
* \brief Register c7 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_DSB:DATA:NOROOT(2)
PUBLIC CP15_DSB
CP15_DSB:
mov r0, #0
mcr p15, 0, r0, c7, c10, 4
nop
bx lr
/**
* \brief Register c7 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_DMB:DATA:NOROOT(2)
PUBLIC CP15_DMB
CP15_DMB:
mov r0, #0
mcr p15, 0, r0, c7, c10, 5
nop
bx lr
/**
* \brief Register c1 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_ExclusiveCache:DATA:NOROOT(2)
PUBLIC CP15_ExclusiveCache
CP15_ExclusiveCache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 ; Read ACTLR
orr r0, r0, #0x00000080
mcr p15, 0, r0, c1, c0, 1 ; Write ACTLR
nop
bx lr
/**
* \brief Register c1 accesses the ACTLR Register, to indicate cpu that L2 is in exclusive mode
*/
SECTION .CP15_NonExclusiveCache:DATA:NOROOT(2)
PUBLIC CP15_NonExclusiveCache
CP15_NonExclusiveCache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 ; Read ACTLR
bic r0, r0, #0x00000080
mcr p15, 0, r0, c1, c0, 1 ; Write ACTLR
nop
bx lr
/**
* \brief Register c1 accesses the CSSELR Register, to select ICache
*/
SECTION .CP15_SelectICache:DATA:NOROOT(2)
PUBLIC CP15_SelectICache
CP15_SelectICache:
mrc p15, 2, r0, c0, c0, 0 ; Read CSSELR
orr r0, r0, #0x1 ; Change 0th bit to ICache
mcr p15, 2, r0, c0, c0, 0 ; Write CSSELR
nop
bx lr
/**
* \brief Register c1 accesses the CSSELR Register, to select DCache
*/
SECTION .CP15_SelectDCache:DATA:NOROOT(2)
PUBLIC CP15_SelectDCache
CP15_SelectDCache:
mrc p15, 2, r0, c0, c0, 0 ; Read CSSELR
and r0, r0, #0xFFFFFFFE ; Change 0th bit to ICache
mcr p15, 2, r0, c0, c0, 0 ; Write CSSELR
nop
bx lr
/**
* \brief Register c1 is the Control Register for the ARM926EJ-S processor.
* This register specifies the configuration used to enable and disable the
* caches and MMU. It is recommended that you access this register using a
* read-modify-write sequence
*/
SECTION .CP15_ReadControl:CODE:NOROOT(2)
PUBLIC CP15_ReadControl
CP15_ReadControl:
mov r0, #0
mrc p15, 0, r0, c1, c0, 0
bx lr
SECTION .CP15_WriteControl:CODE:NOROOT(2)
PUBLIC CP15_WriteControl
CP15_WriteControl:
mcr p15, 0, r0, c1, c0, 0
dsb
isb
bx lr
SECTION .CP15_WriteDomainAccessControl:CODE:NOROOT(2)
PUBLIC CP15_WriteDomainAccessControl
CP15_WriteDomainAccessControl:
mcr p15, 0, r0, c3, c0, 0
dsb
isb
bx lr
/**
* \brief ARMv7A architecture supports two translation tables
* Configure translation table base (TTB) control register cp15,c2
* to a value of all zeros, indicates we are using TTB register 0.
* write the address of our page table base to TTB register 0.
*/
SECTION .CP15_WriteTTB:CODE:NOROOT(2)
PUBLIC CP15_WriteTTB
CP15_WriteTTB:
mcr p15, 0, r0, c2, c0, 0
dsb
isb
bx lr
/**
* \brief Invalidate I cache predictor array inner Sharable
*/
SECTION .CP15_InvalidateIcacheInnerSharable:CODE:NOROOT(2)
PUBLIC CP15_InvalidateIcacheInnerSharable
CP15_InvalidateIcacheInnerSharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 0
bx lr
/**
* \brief Invalidate entire branch predictor array inner Sharable
*/
SECTION .CP15_InvalidateBTBinnerSharable:CODE:NOROOT(2)
PUBLIC CP15_InvalidateBTBinnerSharable
CP15_InvalidateBTBinnerSharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 6
bx lr
/**
* \brief Invalidate all instruction caches to PoU, also flushes branch target cache
*/
SECTION .CP15_InvalidateIcache:CODE:NOROOT(2)
PUBLIC CP15_InvalidateIcache
CP15_InvalidateIcache:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
isb
bx lr
/**
* \brief Invalidate instruction caches by VA to PoU
*/
SECTION .CP15_InvalidateIcacheByMva:CODE:NOROOT(2)
PUBLIC CP15_InvalidateIcacheByMva
CP15_InvalidateIcacheByMva:
mov r0, #0
mcr p15, 0, r0, c7, c5, 1
bx lr
/**
* \brief Invalidate entire branch predictor array
*/
SECTION .CP15_InvalidateBTB:CODE:NOROOT(2)
PUBLIC CP15_InvalidateBTB
CP15_InvalidateBTB:
mov r0, #0
mcr p15, 0, r0, c7, c5, 6
dsb
isb
bx lr
/**
* \brief Invalidate branch predictor array entry by MVA
*/
SECTION .CP15_InvalidateBTBbyMva:CODE:NOROOT(2)
PUBLIC CP15_InvalidateBTBbyMva
CP15_InvalidateBTBbyMva:
mcr p15, 0, r0, c7, c5, 7
bx lr
/***********************************************************
*
* ===Data Cache related maintenance functions===
*
**************************************************************/
// ===Data Cache maintenance by SetWay ===
/**
* \brief Invalidate entire data cache by set/way
*/
SECTION .CP15_InvalidateDcacheBySetWay:CODE:NOROOT(2)
PUBLIC CP15_InvalidateDcacheBySetWay
CP15_InvalidateDcacheBySetWay:
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
ANDS r3, r0, #0x07000000 ; Extract coherency level
MOV r3, r3, LSR #23 ; Total cache levels << 1
BEQ inv_finish ; If 0, no need to clean
MOV r10, #0 ; R10 holds current cache level << 1
inv_cache_level_loop
ADD r2, r10, r10, LSR #1 ; R2 holds cache "Set" position
MOV r1, r0, LSR r2 ; Bottom 3 bits are the Cache-type for this level
AND r1, r1, #7 ; Isolate those lower 3 bits
CMP r1, #2
BLT inv_skip ; No cache or only instruction cache at this level
MCR p15, 2, r10, c0, c0, 0 ; Write the Cache Size selection register
ISB ; ISB to sync the change to the CacheSizeID reg
MRC p15, 1, r1, c0, c0, 0 ; Reads current Cache Size ID register
AND r2, r1, #7 ; Extract the line length field
ADD r2, r2, #4 ; Add 4 for the line length offset (log2 16 bytes)
LDR r4, =0x3FF
ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ r5, r4 ; R5 is the bit position of the way size increment
LDR r7, =0x7FFF
ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned)
inv_set_loop
MOV r9, r4 ; R9 working copy of the max way size (right aligned)
inv_way_loop
ORR r11, r10, r9, LSL r5 ; Factor in the Way number and cache number into R11
ORR r11, r11, r7, LSL r2 ; Factor in the Set number
MCR p15, 0, r11, c7, c6, 2 ; Invalidate by Set/Way
SUBS r9, r9, #1 ; Decrement the Way number
BGE inv_way_loop
SUBS r7, r7, #1 ; Decrement the Set number
BGE inv_set_loop
inv_skip
ADD r10, r10, #2 ; increment the cache number
CMP r3, r10
BGT inv_cache_level_loop
inv_finish
NOP
BX lr
/**
* \brief Clean entire data cache by set/way
*/
SECTION .CP15_CleanDCacheBySetWay:CODE:NOROOT(2)
PUBLIC CP15_CleanDCacheBySetWay
CP15_CleanDCacheBySetWay:
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
ANDS r3, r0, #0x07000000 ; Extract coherency level
MOV r3, r3, LSR #23 ; Total cache levels << 1
BEQ clean_finish ; If 0, no need to clean
MOV r10, #0 ; R10 holds current cache level << 1
clean_cache_level_loop
ADD r2, r10, r10, LSR #1 ; R2 holds cache "Set" position
MOV r1, r0, LSR r2 ; Bottom 3 bits are the Cache-type for this level
AND r1, r1, #7 ; Isolate those lower 3 bits
CMP r1, #2
BLT clean_skip ; No cache or only instruction cache at this level
MCR p15, 2, r10, c0, c0, 0 ; Write the Cache Size selection register
ISB ; ISB to sync the change to the CacheSizeID reg
MRC p15, 1, r1, c0, c0, 0 ; Reads current Cache Size ID register
AND r2, r1, #7 ; Extract the line length field
ADD r2, r2, #4 ; Add 4 for the line length offset (log2 16 bytes)
LDR r4, =0x3FF
ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ r5, r4 ; R5 is the bit position of the way size increment
LDR r7, =0x7FFF
ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned)
clean_set_loop
MOV r9, r4 ; R9 working copy of the max way size (right aligned)
clean_way_loop
ORR r11, r10, r9, LSL r5 ; Factor in the Way number and cache number into R11
ORR r11, r11, r7, LSL r2 ; Factor in the Set number
MCR p15, 0, r11, c7, c10, 2 ; Clean by Set/Way
SUBS r9, r9, #1 ; Decrement the Way number
BGE clean_way_loop
SUBS r7, r7, #1 ; Decrement the Set number
BGE clean_set_loop
clean_skip
ADD r10, r10, #2 ; increment the cache number
CMP r3, r10
BGT clean_cache_level_loop
clean_finish
NOP
BX lr
/**
* \brief Clean and Invalidate entire data cache by set/way
*/
SECTION .CP15_CleanInvalidateDCacheBySetWay:CODE:NOROOT(2)
PUBLIC CP15_CleanInvalidateDCacheBySetWay
CP15_CleanInvalidateDCacheBySetWay:
MRC p15, 1, r0, c0, c0, 1 ; Read CLIDR
ANDS r3, r0, #0x07000000 ; Extract coherency level
MOV r3, r3, LSR #23 ; Total cache levels << 1
BEQ clinv_finish ; If 0, no need to clean
MOV r10, #0 ; R10 holds current cache level << 1
clinv_cache_level_loop
ADD r2, r10, r10, LSR #1 ; R2 holds cache "Set" position
MOV r1, r0, LSR r2 ; Bottom 3 bits are the Cache-type for this level
AND r1, r1, #7 ; Isolate those lower 3 bits
CMP r1, #2
BLT clean_skip ; No cache or only instruction cache at this level
MCR p15, 2, r10, c0, c0, 0 ; Write the Cache Size selection register
ISB ; ISB to sync the change to the CacheSizeID reg
MRC p15, 1, r1, c0, c0, 0 ; Reads current Cache Size ID register
AND r2, r1, #7 ; Extract the line length field
ADD r2, r2, #4 ; Add 4 for the line length offset (log2 16 bytes)
LDR r4, =0x3FF
ANDS r4, r4, r1, LSR #3 ; R4 is the max number on the way size (right aligned)
CLZ r5, r4 ; R5 is the bit position of the way size increment
LDR r7, =0x7FFF
ANDS r7, r7, r1, LSR #13 ; R7 is the max number of the index size (right aligned)
clinv_set_loop
MOV r9, r4 ; R9 working copy of the max way size (right aligned)
clinv_way_loop
ORR r11, r10, r9, LSL r5 ; Factor in the Way number and cache number into R11
ORR r11, r11, r7, LSL r2 ; Factor in the Set number
MCR p15, 0, r11, c7, c14, 2 ; Clean and Invalidate by Set/Way
SUBS r9, r9, #1 ; Decrement the Way number
BGE clean_way_loop
SUBS r7, r7, #1 ; Decrement the Set number
BGE clean_set_loop
clinv_skip
ADD r10, r10, #2 ; increment the cache number
CMP r3, r10
BGT clean_cache_level_loop
clinv_finish
NOP
BX lr
// ===Data Cache maintenance by VA ===
/**
* \brief Invalidate data cache by VA to Poc
*/
SECTION .CP15_InvalidateDcacheByMva:CODE:NOROOT(2)
PUBLIC CP15_InvalidateDcacheByMva
CP15_InvalidateDcacheByMva:
mov r2, #0x20 ;Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
inv_loop
mcr p15, 0, r0, c7, c6, 1
add r3, r3, r2
cmp r3, r1
bls inv_loop
bx lr
/**
* \brief Clean data cache by MVA
*/
SECTION .CP15_CleanDCacheByMva:CODE:NOROOT(2)
PUBLIC CP15_CleanDCacheByMva
CP15_CleanDCacheByMva:
mov r2, #0x20 ;Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clean_loop
mcr p15, 0, r0, c7, c10, 1
add r3, r3, r2
cmp r3, r1
bls clean_loop
bx lr
/**
* \brief Clean unified cache by MVA
*/
SECTION .CP15_CleanDCacheUMva:CODE:NOROOT(2)
PUBLIC CP15_CleanDCacheUMva
CP15_CleanDCacheUMva:
mov r0, #0
mcr p15, 0, r0, c7, c11, 1
bx lr
/**
* \brief Clean and invalidate data cache by VA to PoC
*/
SECTION .CP15_CleanInvalidateDcacheByMva:CODE:NOROOT(2)
PUBLIC CP15_CleanInvalidateDcacheByMva
CP15_CleanInvalidateDcacheByMva:
mov r2, #0x20 ;Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clinv_loop
mcr p15, 0, r0, c7, c14, 1
add r3, r3, r2
cmp r3, r1
bls clinv_loop
bx lr
/**
* \brief Invalidate translation table
*/
SECTION .CP15_InvalidateTranslationTable:CODE:NOROOT(2)
PUBLIC CP15_InvalidateTranslationTable
CP15_InvalidateTranslationTable:
mov r0, #0
mcr p15, 0, r0, c8, c3, 0
dsb
isb
mcr p15, 0, r0, c8, c7, 0
dsb
isb
bx lr
/**
* \brief flush translation table
*/
SECTION .CP15_FlushTranslationTable:CODE:NOROOT(2)
PUBLIC CP15_FlushTranslationTable
CP15_FlushTranslationTable:
mov r0, #0
mcr p15, 0, r0, c8, c3, 0
dsb
isb
bx lr
/**
* \brief Ensure that the I and D caches are coherent within specified
* region. This is typically used when code has been written to
* a memory region, and will be executed.
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_coherent_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_coherent_dcache_for_dma
CP15_coherent_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r12, r0, r3
loop1:
mcr p15, 0, r12, c7, c11, 1 // clean D line to the point of unification
add r12, r12, r2
cmp r12, r1
blo loop1
dsb
// .macro icache_line_size, reg, tmp
mrc p15, 0, r3, c0, c0, 1 // read ctr
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r12, r0, r3
loop2:
mcr p15, 0, r12, c7, c5, 1 // invalidate I line
add r12, r12, r2
cmp r12, r1
blo loop2
mov r0, #0
mcr p15, 0, r0, c7, c1, 6 //invalidate BTB Inner Shareable
mcr p15, 0, r0, c7, c5, 6 // invalidate BTB
dsb
isb
bx lr
/**
* \brief Invalidate the data cache within the specified region; we will
* be performing a DMA operation in this region and we want to
* purge old data in the cache.
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_invalidate_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_invalidate_dcache_for_dma
CP15_invalidate_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
tst r0, r3
bic r0, r0, r3
mcrne p15, 0, r0, c7, c14, 1 // clean & invalidate D / U line
tst r1, r3
bic r1, r1, r3
mcrne p15, 0, r1, c7, c14, 1 // clean & invalidate D / U line
loop3:
mcr p15, 0, r0, c7, c6, 1 // invalidate D / U line
add r0, r0, r2
cmp r0, r1
blo loop3
dsb
bx lr
/**
* \brief Clean the data cache within the specified region
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_clean_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_clean_dcache_for_dma
CP15_clean_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r0, r0, r3
loop4:
mcr p15, 0, r0, c7, c10, 1 // clean D / U line
add r0, r0, r2
cmp r0, r1
blo loop4
dsb
bx lr
/**
* \brief Flush the data cache within the specified region
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_flush_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_flush_dcache_for_dma
CP15_flush_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
sub r3, r2, #1
bic r0, r0, r3
loop5:
mcr p15, 0, r0, c7, c14, 1 // clean & invalidate D / U line
add r0, r0, r2
cmp r0, r1
blo loop5
dsb
bx lr
/**
* \brief CP15_flush_kern_dcache_for_dma
* Ensure that the data held in the page kaddr is written back to the page in question.
* \param start virtual start address of region
* \param end virtual end address of region
*/
SECTION .CP15_flush_kern_dcache_for_dma:CODE:NOROOT(2)
PUBLIC CP15_flush_kern_dcache_for_dma
CP15_flush_kern_dcache_for_dma:
// dcache_line_size r2, r3
mrc p15, 0, r3, c0, c0, 1 // read ctr
lsr r3, r3, #16
and r3, r3, #0xf // cache line size encoding
mov r2, #4 // bytes per word
mov r2, r2, lsl r3 // actual cache line size
add r1, r0, r1
sub r3, r2, #1
bic r0, r0, r3
mcr p15, 0, r0, c7, c14, 1 // clean & invalidate D line / unified line
add r0, r0, r2
cmp r0, r1
blo 1b
dsb
bx lr
END

51
A27-STEPLDR/Src/crc32.c Normal file
View File

@ -0,0 +1,51 @@
#include <stdio.h>
#include <stdlib.h>
#define CRC32_POLY 0x04C11DB7L
unsigned int get_sum_poly(unsigned char top_byte)
{
/// sum all the polys at various offsets
unsigned int sum_poly = top_byte << 24;
int i;
for (i = 0; i < 8; ++i) {
/// check the top bit
if( ( sum_poly >> 31 ) != 0 )
/// TODO : understand why '<<' first
sum_poly = ( sum_poly << 1 ) ^ CRC32_POLY;
else
sum_poly <<= 1;
}
return sum_poly;
}
void create_table(unsigned int *table)
{
for( int i = 0; i < 256; ++ i )
{
table[i] = get_sum_poly( (unsigned char) i );
}
}
static const unsigned int *crc32_table = NULL;
unsigned int
xcrc32(const unsigned char *buf, int len, unsigned int init)
{
unsigned int crc = init;
static unsigned int table[256];
if (!crc32_table) {
create_table(table);
crc32_table = &table[0];
}
while (len--)
{
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
buf++;
}
return crc;
}

7
A27-STEPLDR/Src/crc32.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _CRC32_H
#define _CRC32_H
unsigned int
xcrc32(const unsigned char *buf, int len, unsigned int init);
#endif

View File

@ -0,0 +1,38 @@
#include "uart.h"
void undef_handler()
{
SendUartString("\r\nUndef EXC");
while(1);
}
void prefetch_handler()
{
SendUartString("\r\nPrefetch EXC");
while(1);
}
void data_abort_handler()
{
SendUartString("\r\nData abort EXC");
while(1);
}
void irq_handler()
{
SendUartString("\r\nIRQ EXC");
while(1);
}
void fiq_handler()
{
SendUartString("\r\nFIQ EXC");
while(1);
}
void swi_handler()
{
SendUartString("\r\nSWI EXC");
while(1);
}

238
A27-STEPLDR/Src/fs/diskio.c Normal file
View File

@ -0,0 +1,238 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
//#include <windows.h>
//#include "sdfmd.h"
//#include <ethdbg.h>
//#include <halether.h>
//extern DWORD SDInitialize(void);
//extern DWORD WriteSector(PBYTE pData, DWORD dwStartSector, DWORD dwNumber);
//extern DWORD ReadSector(PBYTE pData, DWORD dwStartSector, DWORD dwNumber);
//extern void Delay(UINT32 count);
/*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive. */
/* Note that Tiny-FatFs supports only single drive and always */
/* accesses drive number 0. */
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat;
int result;
switch (drv) {
/*case ATA :
result = ATA_disk_initialize();
// translate the reslut code here
return stat;*/
case SDMMC :
result = MMC_disk_initialize();
// translate the reslut code here
if(result < 0)
stat = STA_NOINIT;
else
stat = 0;
return stat;
case USB :
result = USB_disk_initialize();
// translate the reslut code here
if(result < 0)
stat = STA_NOINIT;
else
stat = 0;
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0..) */
)
{
//drv = drv;
return 0;
#if 0
DSTATUS stat;
int result;
switch (drv) {
case ATA :
result = ATA_disk_status();
// translate the reslut code here
return stat;
case SDMMC :
result = MMC_disk_status();
// translate the reslut code here
return stat;
#if 0
case USB :
result = USB_disk_status();
// translate the reslut code here
return stat;
#endif
}
return STA_NOINIT;
#endif
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to read (1..255) */
)
{
DRESULT res;
int result;
switch (drv) {
/*case ATA :
result = ATA_disk_read(buff, sector, count);
// translate the reslut code here
return res;*/
case SDMMC :
result = MMC_disk_read(buff, sector, count);
// translate the reslut code here
if(result == 0)
res = RES_ERROR;
else
res = RES_OK;
return res;
case USB :
result = USB_disk_read(buff, sector, count);
// translate the reslut code here
if(result == 0)
res = RES_ERROR;
else
res = RES_OK;
return res;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..255) */
)
{
DRESULT res;
int result;
switch (drv) {
case ATA :
result = ATA_disk_write(buff, sector, count);
// translate the reslut code here
return res;
case SDMMC :
result = MMC_disk_write(buff, sector, count);
// translate the reslut code here
return res;
#if 0
case USB :
result = USB_disk_write(buff, sector, count);
// translate the reslut code here
return res;
#endif
}
return RES_PARERR;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
int result;
switch (drv) {
/*case ATA :
// pre-process here
result = ATA_disk_ioctl(ctrl, buff);
// post-process here
return res;*/
case SDMMC :
// pre-process here
result = MMC_disk_ioctl(ctrl, buff);
// post-process here
if(result < 0)
res = RES_PARERR;
else
res = RES_OK;
return res;
case USB :
// pre-process here
result = USB_disk_ioctl(ctrl, buff);
if(result < 0)
res = RES_PARERR;
else
res = RES_OK;
return res;
}
return RES_PARERR;
}

View File

@ -0,0 +1,86 @@
/*-----------------------------------------------------------------------
/ Low level disk interface modlue include file R0.06 (C)ChaN, 2007
/-----------------------------------------------------------------------*/
#ifndef _DISKIO
#define _DISKIO
#define _READONLY 1 /* 1: Read-only mode */
#define _USE_IOCTL 1
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE);
DSTATUS disk_status (BYTE);
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
#if _READONLY == 0
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
#endif
DRESULT disk_ioctl (BYTE, BYTE, void*);
void disk_timerproc (void);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl() */
/* Generic command */
#define CTRL_SYNC 0 /* Mandatory for read/write configuration */
#define GET_SECTOR_COUNT 1 /* Mandatory for only f_mkfs() */
#define GET_SECTOR_SIZE 2
#define GET_BLOCK_SIZE 3 /* Mandatory for only f_mkfs() */
#define CTRL_POWER 4
#define CTRL_LOCK 5
#define CTRL_EJECT 6
/* MMC/SDC command */
#define MMC_GET_TYPE 10
#define MMC_GET_CSD 11
#define MMC_GET_CID 12
#define MMC_GET_OCR 13
#define MMC_GET_SDSTAT 14
/* ATA/CF command */
#define ATA_GET_REV 20
#define ATA_GET_MODEL 21
#define ATA_GET_SN 22
#define SDMMC 0
#define USB 1
#define ATA 2
int MMC_disk_initialize(void);
int MMC_disk_read(void *buff, DWORD sector, BYTE count);
int MMC_disk_ioctl(BYTE ctrl, void *buff);
int USB_disk_initialize(void);
int USB_disk_read(void *buff, DWORD sector, BYTE count);
int USB_disk_ioctl(BYTE ctrl, void *buff);
#endif

2057
A27-STEPLDR/Src/fs/ff.c Normal file

File diff suppressed because it is too large Load Diff

343
A27-STEPLDR/Src/fs/ff.h Normal file
View File

@ -0,0 +1,343 @@
/*--------------------------------------------------------------------------/
/ FatFs - FAT file system module include file R0.06 (C)ChaN, 2008
/---------------------------------------------------------------------------/
/ FatFs module is an experimenal project to implement FAT file system to
/ cheap microcontrollers. This is a free software and is opened for education,
/ research and development under license policy of following trems.
/
/ Copyright (C) 2008, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is no warranty.
/ * You can use, modify and/or redistribute it for personal, non-profit or
/ commercial use without any restriction under your responsibility.
/ * Redistributions of source code must retain the above copyright notice.
/
/---------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS
#define _MCU_ENDIAN 2
/* The _MCU_ENDIAN defines which access method is used to the FAT structure.
/ 1: Enable word access.
/ 2: Disable word access and use byte-by-byte access instead.
/ When the architectural byte order of the MCU is big-endian and/or address
/ miss-aligned access results incorrect behavior, the _MCU_ENDIAN must be set to 2.
/ If it is not the case, it can also be set to 1 for good code efficiency. */
#define _FS_READONLY 1
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/ f_truncate and useless f_getfree. */
#define _FS_MINIMIZE 0
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/ 0: Full function.
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename are removed.
/ 2: f_opendir and f_readdir are removed in addition to level 1.
/ 3: f_lseek is removed in addition to level 2. */
#define _USE_STRFUNC 0
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define _USE_MKFS 0
/* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is
/ enabled. */
#define _DRIVES 2
/* Number of logical drives to be used. This affects the size of internal table. */
#define _MULTI_PARTITION 0
/* When _MULTI_PARTITION is set to 0, each logical drive is bound to same
/ physical drive number and can mount only 1st primaly partition. When it is
/ set to 1, each logical drive can mount a partition listed in Drives[]. */
#define _USE_FSINFO 1
/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */
#define _USE_SJIS 0
/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
/ only US-ASCII(7bit) code can be accepted as file/directory name. */
#define _USE_NTFLAG 1
/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
/ Note that the files are always accessed in case insensitive. */
#include "integer.h"
/* Definitions corresponds to multiple sector size (not tested) */
#define S_MAX_SIZ 512U /* Do not change */
#if S_MAX_SIZ > 512U
#define SS(fs) ((fs)->s_size)
#else
#define SS(fs) 512U
#endif
/* File system object structure */
typedef struct _FATFS {
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries */
DWORD winsect; /* Current sector appearing in the win[] */
DWORD sects_fat; /* Sectors per fat */
DWORD max_clust; /* Maximum cluster# + 1 */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (cluster# for FAT32) */
DWORD database; /* Data start sector */
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
#if _USE_FSINFO
DWORD fsi_sector; /* fsinfo sector */
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
BYTE pad2;
#endif
#else
BYTE pad3;
BYTE pad2;
#endif
BYTE fs_type; /* FAT sub type */
BYTE csize; /* Number of sectors per cluster */
#if S_MAX_SIZ > 512U
WORD s_size; /* Sector size */
#endif
BYTE n_fats; /* Number of FAT copies */
BYTE drive; /* Physical drive number */
BYTE winflag; /* win[] dirty flag (1:must be written back) */
BYTE pad1;
BYTE win[S_MAX_SIZ]; /* Disk access window for Directory/FAT */
} FATFS;
/* Directory object structure */
typedef struct _DIR {
WORD id; /* Owner file system mount ID */
WORD index; /* Current index */
FATFS* fs; /* Pointer to the owner file system object */
DWORD sclust; /* Start cluster */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
} DIR;
/* File object structure */
typedef struct _FIL {
WORD id; /* Owner file system mount ID */
BYTE flag; /* File status flags */
BYTE csect; /* Sector address in the cluster */
FATFS* fs; /* Pointer to the owner file system object */
DWORD fptr; /* File R/W pointer */
DWORD fsize; /* File size */
DWORD org_clust; /* File start cluster */
DWORD curr_clust; /* Current cluster */
DWORD curr_sect; /* Current sector */
#if _FS_READONLY == 0
DWORD dir_sect; /* Sector containing the directory entry */
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
#endif
BYTE buffer[S_MAX_SIZ]; /* File R/W buffer */
} FIL;
/* File status structure */
typedef struct _FILINFO {
DWORD fsize; /* Size */
WORD fdate; /* Date */
WORD ftime; /* Time */
BYTE fattrib; /* Attribute */
char fname[8+1+3+1]; /* Name (8.3 format) */
} FILINFO;
/* Definitions corresponds to multi partition */
#if _MULTI_PARTITION != 0 /* Multiple partition cfg */
typedef struct _PARTITION {
BYTE pd; /* Physical drive # (0-255) */
BYTE pt; /* Partition # (0-3) */
} PARTITION;
extern
const PARTITION Drives[]; /* Logical drive# to physical location conversion table */
#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */
#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */
#else /* Single partition cfg */
#define LD2PD(drv) (drv) /* Physical drive# is equal to logical drive# */
#define LD2PT(drv) 0 /* Always mounts the 1st partition */
#endif
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* 0 */
FR_NOT_READY, /* 1 */
FR_NO_FILE, /* 2 */
FR_NO_PATH, /* 3 */
FR_INVALID_NAME, /* 4 */
FR_INVALID_DRIVE, /* 5 */
FR_DENIED, /* 6 */
FR_EXIST, /* 7 */
FR_RW_ERROR, /* 8 */
FR_WRITE_PROTECTED, /* 9 */
FR_NOT_ENABLED, /* 10 */
FR_NO_FILESYSTEM, /* 11 */
FR_INVALID_OBJECT, /* 12 */
FR_MKFS_ABORTED /* 13 */
} FRESULT;
/*-----------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const char*, BYTE); /* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
FRESULT f_close (FIL*); /* Close an open file object */
FRESULT f_opendir (DIR*, const char*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (const char*, FILINFO*); /* Get file status */
FRESULT f_getfree (const char*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
FRESULT f_truncate (FIL*); /* Truncate file */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (const char*); /* Delete an existing file or directory */
FRESULT f_mkdir (const char*); /* Create a new directory */
FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file/dir attriburte */
FRESULT f_utime (const char*, const FILINFO*); /* Change file/dir timestamp */
FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */
FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */
#if _USE_STRFUNC
#define feof(fp) ((fp)->fptr == (fp)->fsize)
#define EOF -1
int fputc (int, FIL*); /* Put a character to the file */
int fputs (const char*, FIL*); /* Put a string to the file */
int fprintf (FIL*, const char*, ...); /* Put a formatted string to the file */
char* fgets (char*, int, FIL*); /* Get a string from the file */
#endif
/* User defined function to give a current time to fatfs module */
DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
/* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#if _FS_READONLY == 0
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
#define FA__ERROR 0x80
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
/* Offset of FAT structure members */
#define BS_jmpBoot 0
#define BS_OEMName 3
#define BPB_BytsPerSec 11
#define BPB_SecPerClus 13
#define BPB_RsvdSecCnt 14
#define BPB_NumFATs 16
#define BPB_RootEntCnt 17
#define BPB_TotSec16 19
#define BPB_Media 21
#define BPB_FATSz16 22
#define BPB_SecPerTrk 24
#define BPB_NumHeads 26
#define BPB_HiddSec 28
#define BPB_TotSec32 32
#define BS_55AA 510
#define BS_DrvNum 36
#define BS_BootSig 38
#define BS_VolID 39
#define BS_VolLab 43
#define BS_FilSysType 54
#define BPB_FATSz32 36
#define BPB_ExtFlags 40
#define BPB_FSVer 42
#define BPB_RootClus 44
#define BPB_FSInfo 48
#define BPB_BkBootSec 50
#define BS_DrvNum32 64
#define BS_BootSig32 66
#define BS_VolID32 67
#define BS_VolLab32 71
#define BS_FilSysType32 82
#define FSI_LeadSig 0
#define FSI_StrucSig 484
#define FSI_Free_Count 488
#define FSI_Nxt_Free 492
#define MBR_Table 446
#define DIR_Name 0
#define DIR_Attr 11
#define DIR_NTres 12
#define DIR_CrtTime 14
#define DIR_CrtDate 16
#define DIR_FstClusHI 20
#define DIR_WrtTime 22
#define DIR_WrtDate 24
#define DIR_FstClusLO 26
#define DIR_FileSize 28
/* Multi-byte word access macros */
#if _MCU_ENDIAN==1 /* Use word access */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#elif _MCU_ENDIAN==2 /* Use byte-by-byte access */
#define LD_WORD(ptr) (WORD)(((WORD)*(volatile BYTE*)((ptr)+1)<<8)|(WORD)*(volatile BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*(volatile BYTE*)((ptr)+3)<<24)|((DWORD)*(volatile BYTE*)((ptr)+2)<<16)|((WORD)*(volatile BYTE*)((ptr)+1)<<8)|*(volatile BYTE*)(ptr))
#define ST_WORD(ptr,val) *(volatile BYTE*)(ptr)=(BYTE)(val); *(volatile BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(volatile BYTE*)(ptr)=(BYTE)(val); *(volatile BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(volatile BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(volatile BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
#else
#error Do not forget to set _MCU_ENDIAN properly!
#endif
extern FATFS g_fs;
#endif /* _FATFS */

View File

@ -0,0 +1,33 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _INTEGER
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef signed char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
/* Boolean type */
#undef FALSE
#undef TRUE
typedef enum { FALSE = 0, TRUE } BOOL;
#define _INTEGER
#endif

View File

@ -0,0 +1,10 @@
#ifndef SD_IF_H__
#define SD_IF_H__
int MMC_disk_initialize();
int MMC_disk_read(void *buff, DWORD sector, BYTE count);
int MMC_disk_ioctl(BYTE ctrl, void *buff);
#endif

96
A27-STEPLDR/Src/gpio.c Normal file
View File

@ -0,0 +1,96 @@
#include "amt630h.h"
#include "pinctrl.h"
#define GPIO_SWPORTA_DR 0x00
#define GPIO_SWPORTA_DDR 0x04
#define GPIO_SWPORTA_CTL 0x08
#define GPIO_SWPORTA_INTEN 0x30
#define GPIO_SWPORTA_INTMASK 0x34
#define GPIO_SWPORTA_INTTYPE_LEVEL 0x38
#define GPIO_SWPORTA_INT_POLARITY 0x3c
#define GPIO_SWPORTA_INTSTATUS 0x40
#define GPIO_SWPORTA_RAW_INTSTATUS 0x44
#define GPIO_SWPORTA_DEBOUNCE 0x48
#define GPIO_SWPORTA_EOI 0x4c
#define GPIO_SWPORTA_EXT_PORTA 0x50
#define GPIO_SWPORTA_EXT_PORTB 0x54
#define GPIO_SWPORTA_EXT_PORTC 0x58
#define GPIO_SWPORTA_EXT_PORTD 0x5c
#define GPIO_SWPORTA_LS_SYNC 0x60
#define GPIO_SWPORTA_ID_CODE 0x64
#define GPIO_SWPORTA_INT_BOTHEDGE 0x68
#define GPIO_SWPORTA_VER_ID_CODE 0x6C
#define GPIO_SWPORTA_CONFIG_REG2 0x70
#define GPIO_SWPORTA_CONFIG_REG1 0x74
#define GPIO_NUM 128
static uint32_t gpio_get_regbase(int gpio)
{
int gpiox = (gpio >> 5) & 0x3;
return REGS_GPIO_BASE + 0x80 * gpiox;
}
static int GPIO_OFFSET(unsigned gpio)
{
if (gpio == 96)
return 2;
else if (gpio == 97)
return 0;
else if (gpio == 98)
return 3;
else if (gpio == 99)
return 1;
else
return gpio & 0x1F;
}
static void *GPIO_MODREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DDR);
}
static void *GPIO_WDATAREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DR);
}
static void *GPIO_RDATAREG(unsigned gpio)
{
return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_EXT_PORTA);
}
void gpio_request(unsigned gpio)
{
pinctrl_gpio_request(gpio);
}
void gpio_direction_output(unsigned gpio, int value)
{
gpio_request(gpio);
writel(readl(GPIO_MODREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio));
if (value)
writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
else
writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
}
void gpio_direction_input(unsigned gpio)
{
gpio_request(gpio);
writel(readl(GPIO_MODREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio));
}
void gpio_set_value(unsigned gpio, int value)
{
if (value)
writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
else
writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio));
}
int gpio_get_value(unsigned gpio)
{
return !!(readl(GPIO_RDATAREG(gpio)) & (1 << GPIO_OFFSET(gpio)));
}

23
A27-STEPLDR/Src/gpio.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _GPIO_H
#define _GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
void gpio_request(unsigned gpio);
void gpio_direction_output(unsigned gpio, int value);
void gpio_direction_input(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
#ifdef __cplusplus
}
#endif
#endif

650
A27-STEPLDR/Src/i2c-gpio.c Normal file
View File

@ -0,0 +1,650 @@
#include <string.h>
#include "cp15.h"
#include "board.h"
#include "amt630h.h"
#include "errno.h"
#include "timer.h"
#include "os_adapt.h"
#include "gpio.h"
#include "trace.h"
#include "i2c.h"
#include "i2c-gpio.h"
#ifdef ANALOG_I2C_SUPPORT
struct i2c_gpio_private_data {
struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata;
};
/* Toggle SDA by changing the direction of the pin */
static void i2c_gpio_setsda_dir(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
if (state)
gpio_direction_input(pdata->sda_pin);
else
gpio_direction_output(pdata->sda_pin, 0);
}
/*
* Toggle SDA by changing the output value of the pin. This is only
* valid for pins configured as open drain (i.e. setting the value
* high effectively turns off the output driver.)
*/
static void i2c_gpio_setsda_val(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_output(pdata->sda_pin, state);
gpio_set_value(pdata->sda_pin, state);
}
/* Toggle SCL by changing the direction of the pin. */
static void i2c_gpio_setscl_dir(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
if (state)
gpio_direction_input(pdata->scl_pin);
else
gpio_direction_output(pdata->scl_pin, 0);
}
/*
* Toggle SCL by changing the output value of the pin. This is used
* for pins that are configured as open drain and for output-only
* pins. The latter case will break the i2c protocol, but it will
* often work in practice.
*/
static void i2c_gpio_setscl_val(void *data, int state)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_output(pdata->scl_pin, state);
gpio_set_value(pdata->scl_pin, state);
}
static int i2c_gpio_getsda(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_input(pdata->sda_pin);
return gpio_get_value(pdata->sda_pin);
}
static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
gpio_direction_input(pdata->scl_pin);
return gpio_get_value(pdata->scl_pin);
}
/* --- setting states on the bus with the right timing: --------------- */
#define setsda(adap, val) adap->setsda(adap->data, val)
#define setscl(adap, val) adap->setscl(adap->data, val)
#define getsda(adap) adap->getsda(adap->data)
#define getscl(adap) adap->getscl(adap->data)
static __INLINE void sdalo(struct i2c_algo_bit_data *adap)
{
setsda(adap, 0);
udelay((adap->udelay + 1) / 2);
}
static __INLINE void sdahi(struct i2c_algo_bit_data *adap)
{
setsda(adap, 1);
udelay((adap->udelay + 1) / 2);
}
static __INLINE void scllo(struct i2c_algo_bit_data *adap)
{
setscl(adap, 0);
udelay(adap->udelay / 2);
}
/*
* Raise scl line, and do checking for delays. This is necessary for slower
* devices.
*/
static int sclhi(struct i2c_algo_bit_data *adap)
{
unsigned long start = 0;
setscl(adap, 1);
/* Not all adapters have scl sense line... */
if (!adap->getscl)
goto done;
#if 0
start = xTaskGetTickCount();
while (!getscl(adap)) {
/* This hw knows how to read the clock line, so we wait
* until it actually gets high. This is safer as some
* chips may hold it low ("clock stretching") while they
* are processing data internally.
*/
if (xTaskGetTickCount() > start + adap->timeout) {
/* Test one last time, as we may have been preempted
* between last check and timeout test.
*/
if (getscl(adap))
break;
return -ETIMEDOUT;
}
taskYIELD();
}
#else
while (!getscl(adap)) {
udelay(1);
if (++start > adap->timeout) {
/* Test one last time, as we may have been preempted
* between last check and timeout test.
*/
if (getscl(adap))
break;
return -ETIMEDOUT;
}
}
#endif
done:
udelay(adap->udelay);
return 0;
}
/* --- other auxiliary functions -------------------------------------- */
static void i2c_start(struct i2c_algo_bit_data *adap)
{
/* assert: scl, sda are high */
setsda(adap, 0);
udelay(adap->udelay);
scllo(adap);
}
static void i2c_repstart(struct i2c_algo_bit_data *adap)
{
/* assert: scl is low */
sdahi(adap);
sclhi(adap);
setsda(adap, 0);
udelay(adap->udelay);
scllo(adap);
}
static void i2c_stop(struct i2c_algo_bit_data *adap)
{
/* assert: scl is low */
sdalo(adap);
sclhi(adap);
setsda(adap, 1);
udelay(adap->udelay);
}
/* send a byte without start cond., look for arbitration,
check ackn. from slave */
/* returns:
* 1 if the device acknowledged
* 0 if the device did not ack
* -ETIMEDOUT if an error occurred (while raising the scl line)
*/
static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
{
int i;
int sb;
int ack;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: scl is low */
for (i = 7; i >= 0; i--) {
sb = (c >> i) & 1;
setsda(adap, sb);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timed out */
TRACE_DEBUG("i2c_outb: 0x%02x, timeout at bit #%d\n", (int)c, i);
return -ETIMEDOUT;
}
/* FIXME do arbitration here:
* if (sb && !getsda(adap)) -> ouch! Get out of here.
*
* Report a unique code, so higher level code can retry
* the whole (combined) message and *NOT* issue STOP.
*/
scllo(adap);
}
sdahi(adap); //---
//sdalo(adap); //+++
if (sclhi(adap) < 0) { /* timeout */
TRACE_DEBUG("i2c_outb: 0x%02x, timeout at ack\n", (int)c);
return -ETIMEDOUT;
}
/* read ack: SDA should be pulled down by slave, or it may
* NAK (usually to report problems with the data we wrote).
*/
ack = !getsda(adap); /* ack: sda is pulled low -> success */
TRACE_DEBUG("i2c_outb: 0x%02x %s\n", (int)c, ack ? "A" : "NA");
scllo(adap);
//sdalo(adap); //+++
return ack;
/* assert: scl is low (sda undef) */
}
static int i2c_inb(struct i2c_adapter *i2c_adap)
{
/* read byte via i2c port, without start/stop sequence */
/* acknowledge is sent in i2c_read. */
int i;
unsigned char indata = 0;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: scl is low */
sdahi(adap); //---
for (i = 0; i < 8; i++) {
if (sclhi(adap) < 0) { /* timeout */
TRACE_DEBUG("i2c_inb: timeout at bit #%d\n", 7 - i);
return -ETIMEDOUT;
}
indata *= 2;
if (getsda(adap))
indata |= 0x01;
setscl(adap, 0);
udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
}
/* assert: scl is low */
return indata;
}
/* try_address tries to contact a chip for a number of
* times before it gives up.
* return values:
* 1 chip answered
* 0 chip did not answer
* -x transmission error
*/
static int try_address(struct i2c_adapter *i2c_adap,
unsigned char addr, int retries)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
int i, ret = 0;
for (i = 0; i <= retries; i++) {
ret = i2c_outb(i2c_adap, addr);
if (ret == 1 || i == retries)
break;
TRACE_DEBUG("emitting stop condition\n");
i2c_stop(adap);
udelay(adap->udelay);
// taskYIELD();
TRACE_DEBUG("emitting start condition\n");
i2c_start(adap);
}
if (i && ret)
TRACE_DEBUG("Used %d tries to %s client at "
"0x%02x: %s\n", i + 1,
addr & 1 ? "read from" : "write to", addr >> 1,
ret == 1 ? "success" : "failed, timeout?");
return ret;
}
static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
const unsigned char *temp = msg->buf;
int count = msg->len;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
int retval;
int wrcount = 0;
while (count > 0) {
retval = i2c_outb(i2c_adap, *temp);
/* OK/ACK; or ignored NAK */
if ((retval > 0) || (nak_ok && (retval == 0))) {
count--;
temp++;
wrcount++;
/* A slave NAKing the master means the slave didn't like
* something about the data it saw. For example, maybe
* the SMBus PEC was wrong.
*/
} else if (retval == 0) {
TRACE_ERROR("sendbytes: NAK bailout.\n");
return -EIO;
/* Timeout; or (someday) lost arbitration
*
* FIXME Lost ARB implies retrying the transaction from
* the first message, after the "winning" master issues
* its STOP. As a rule, upper layer code has no reason
* to know or care about this ... it is *NOT* an error.
*/
} else {
TRACE_ERROR("sendbytes: error %d\n", retval);
return retval;
}
}
return wrcount;
}
static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
/* assert: sda is high */
if (is_ack) /* send ack */
setsda(adap, 0);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timeout */
TRACE_ERROR("readbytes: ack/nak timeout\n");
return -ETIMEDOUT;
}
scllo(adap);
return 0;
}
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
int inval;
int rdcount = 0; /* counts bytes read */
unsigned char *temp = msg->buf;
int count = msg->len;
const unsigned flags = msg->flags;
while (count > 0) {
inval = i2c_inb(i2c_adap);
if (inval >= 0) {
*temp = inval;
rdcount++;
} else { /* read timed out */
break;
}
temp++;
count--;
/* Some SMBus transactions require that we receive the
transaction length as the first read byte. */
if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
if (!(flags & I2C_M_NO_RD_ACK))
acknak(i2c_adap, 0);
TRACE_ERROR("readbytes: invalid block length (%d)\n", inval);
return -EPROTO;
}
/* The original count value accounts for the extra
bytes, that is, either 1 for a regular transaction,
or 2 for a PEC transaction. */
count += inval;
msg->len += inval;
}
TRACE_DEBUG( "readbytes: 0x%02x %s\n",
inval,
(flags & I2C_M_NO_RD_ACK)
? "(no ack/nak)"
: (count ? "A" : "NA"));
if (!(flags & I2C_M_NO_RD_ACK)) {
inval = acknak(i2c_adap, count);
if (inval < 0)
return inval;
}
}
return rdcount;
}
/* doAddress initiates the transfer by generating the start condition (in
* try_address) and transmits the address in the necessary format to handle
* reads, writes as well as 10bit-addresses.
* returns:
* 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
* -x an error occurred (like: -ENXIO if the device did not answer, or
* -ETIMEDOUT, for example if the lines are stuck...)
*/
static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
unsigned short flags = msg->flags;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
unsigned char addr;
int ret, retries;
retries = nak_ok ? 0 : i2c_adap->retries;
if (flags & I2C_M_TEN) {
/* a ten bit address */
addr = 0xf0 | ((msg->addr >> 7) & 0x06);
TRACE_DEBUG("addr0: %d\n", addr);
/* try extended address code...*/
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok) {
TRACE_ERROR("died at extended address code\n");
return -ENXIO;
}
/* the remaining 8 bit address */
ret = i2c_outb(i2c_adap, msg->addr & 0xff);
if ((ret != 1) && !nak_ok) {
/* the chip did not ack / xmission error occurred */
TRACE_ERROR("died at 2nd address code\n");
return -ENXIO;
}
if (flags & I2C_M_RD) {
TRACE_DEBUG("emitting repeated start condition\n");
i2c_repstart(adap);
/* okay, now switch into reading mode */
addr |= 0x01;
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok) {
TRACE_ERROR("died at repeated address code\n");
return -EIO;
}
}
} else { /* normal 7bit address */
addr = msg->addr << 1;
if (flags & I2C_M_RD)
addr |= 1;
if (flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok)
return -ENXIO;
}
return 0;
}
static int bit_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
struct i2c_msg *pmsg;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
int i, ret;
unsigned short nak_ok;
TRACE_DEBUG("emitting start condition\n");
i2c_start(adap);
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
if (!(pmsg->flags & I2C_M_NOSTART)) {
if (i) {
if (msgs[i - 1].flags & I2C_M_STOP) {
TRACE_DEBUG("emitting enforced stop/start condition\n");
i2c_stop(adap);
i2c_start(adap);
} else {
TRACE_DEBUG("emitting repeated start condition\n");
i2c_repstart(adap);
}
}
ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) {
TRACE_DEBUG("NAK from device addr 0x%02x msg #%d\n", msgs[i].addr, i);
goto bailout;
}
}
if (pmsg->flags & I2C_M_RD) {
/* read bytes into buffer*/
ret = readbytes(i2c_adap, pmsg);
if (ret >= 1)
TRACE_DEBUG("read %d byte%s\n", ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
goto bailout;
}
} else {
/* write bytes from buffer */
ret = sendbytes(i2c_adap, pmsg);
if (ret >= 1)
TRACE_DEBUG("wrote %d byte%s\n", ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
goto bailout;
}
}
}
ret = i;
bailout:
TRACE_DEBUG("emitting stop condition\n");
i2c_stop(adap);
return ret;
}
struct i2c_gpio_platform_data i2c_gpio[] = {
{
.devid = 0,
.sda_pin = I2C_GPIO0_SDA_PIN,
.scl_pin = I2C_GPIO0_SCL_PIN,
.udelay = 5, /* clk freq 500/udelay kHz */
.timeout = configTICK_RATE_HZ / 10, /* 100ms */
.sda_is_open_drain = 0,
.scl_is_open_drain = 0,
.scl_is_output_only = 1,
}
};
const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
};
int i2c_bit_add_bus(struct i2c_adapter *adap)
{
int ret;
/* register new adapter to i2c module... */
adap->algo = &i2c_bit_algo;
adap->retries = 3;
ret = i2c_add_adapter(adap);
if (ret < 0)
return ret;
return 0;
}
static int i2c_gpio_add_device(struct i2c_gpio_platform_data *pdevdata)
{
struct i2c_gpio_private_data *priv;
struct i2c_gpio_platform_data *pdata;
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
int ret;
priv = pvPortMalloc(sizeof(*priv));
if (!priv) {
TRACE_ERROR("[%s] pvPortMalloc failed, devid:%d\n", __func__, pdevdata->devid);
return -ENOMEM;
}
memset(priv, 0, sizeof(*priv));
adap = &priv->adap;
bit_data = &priv->bit_data;
pdata = &priv->pdata;
memcpy(pdata, pdevdata, sizeof(*pdata));
gpio_request(pdata->sda_pin);
gpio_request(pdata->scl_pin);
if (pdata->sda_is_open_drain) {
gpio_direction_output(pdata->sda_pin, 1);
bit_data->setsda = i2c_gpio_setsda_val;
} else {
gpio_direction_input(pdata->sda_pin);
bit_data->setsda = i2c_gpio_setsda_dir;
}
if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
gpio_direction_output(pdata->scl_pin, 1);
bit_data->setscl = i2c_gpio_setscl_val;
} else {
gpio_direction_input(pdata->scl_pin);
bit_data->setscl = i2c_gpio_setscl_dir;
}
if (!pdata->scl_is_output_only)
bit_data->getscl = i2c_gpio_getscl;
bit_data->getsda = i2c_gpio_getsda;
if (pdata->udelay)
bit_data->udelay = pdata->udelay;
else if (pdata->scl_is_output_only)
bit_data->udelay = 50; /* 10 kHz */
else
bit_data->udelay = 5; /* 100 kHz */
if (pdata->timeout)
bit_data->timeout = pdata->timeout;
else
bit_data->timeout = configTICK_RATE_HZ / 10; /* 100 ms */
bit_data->data = pdata;
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdata->devid);
adap->algo_data = bit_data;
ret = i2c_bit_add_bus(adap);
if (ret) {
TRACE_ERROR("[%s] i2c_bit_add_bus failed, devid:%d\n", __func__, pdata->devid);
return ret;
}
TRACE_INFO("using pins %u (SDA) and %u (SCL%s)\n",
pdata->sda_pin, pdata->scl_pin,
pdata->scl_is_output_only
? ", no clock stretching" : "");
return 0;
}
void i2c_gpio_init(void)
{
int i;
for(i=0; i<sizeof(i2c_gpio)/sizeof(i2c_gpio[0]); i++) {
i2c_gpio_add_device(&i2c_gpio[i]);
}
}
#endif

View File

@ -0,0 +1,40 @@
#ifndef _I2C_GPIO_H
#define _I2C_GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
struct i2c_gpio_platform_data {
int devid;
unsigned int sda_pin;
unsigned int scl_pin;
int udelay;
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
};
struct i2c_algo_bit_data {
void *data; /* private data for lowlevel routines */
void (*setsda) (void *data, int state);
void (*setscl) (void *data, int state);
int (*getsda) (void *data);
int (*getscl) (void *data);
/* local settings */
int udelay; /* half clock cycle time in us,
minimum 2 us for fast-mode I2C,
minimum 5 us for standard-mode I2C and SMBus,
maximum 50 us for SMBus */
int timeout; /* in jiffies */
};
void i2c_gpio_init(void);
#ifdef __cplusplus
}
#endif
#endif

72
A27-STEPLDR/Src/i2c.c Normal file
View File

@ -0,0 +1,72 @@
#include <string.h>
#include "FreeRTOS.h"
#include "amt630h.h"
#include "board.h"
#include "timer.h"
#include "i2c.h"
#include "i2c-gpio.h"
#ifdef I2C_SUPPORT
#define MAX_I2C_DEVICE_NUM 4
static struct i2c_adapter *i2c_devs[MAX_I2C_DEVICE_NUM] = {NULL};
static int i2c_devices_count = 0;
int i2c_add_adapter(struct i2c_adapter *adap)
{
if (i2c_devices_count >= MAX_I2C_DEVICE_NUM)
return -1;
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
adap->timeout = configTICK_RATE_HZ;
i2c_devs[i2c_devices_count++] = adap;
return 0;
}
struct i2c_adapter *i2c_open(const char *i2cdev)
{
struct i2c_adapter *adap;
int i;
for (i = 0; i < i2c_devices_count; i++) {
adap = i2c_devs[i];
if (!strcmp(adap->name, i2cdev)) {
adap->open_count++;
return adap;
}
}
return NULL;
}
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
configASSERT(adap && msgs);
/* Retry automatically on arbitration loss */
orig_jiffies = get_timer(0);
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (get_timer(orig_jiffies) > adap->timeout)
break;
}
return ret;
}
void i2c_init(void)
{
#ifdef ANALOG_I2C_SUPPORT
i2c_gpio_init();
#endif
}
#endif

177
A27-STEPLDR/Src/i2c.h Normal file
View File

@ -0,0 +1,177 @@
#ifndef _I2C_H
#define _I2C_H
#ifdef __cplusplus
extern "C" {
#endif
struct i2c_adapter;
/**
* struct i2c_msg - an I2C transaction segment beginning with START
* @addr: Slave address, either seven or ten bits. When this is a ten
* bit address, I2C_M_TEN must be set in @flags and the adapter
* must support I2C_FUNC_10BIT_ADDR.
* @flags: I2C_M_RD is handled by all adapters. No other flags may be
* provided unless the adapter exported the relevant I2C_FUNC_*
* flags through i2c_check_functionality().
* @len: Number of data bytes in @buf being read from or written to the
* I2C slave address. For read transactions where I2C_M_RECV_LEN
* is set, the caller guarantees that this buffer can hold up to
* 32 bytes in addition to the initial length byte sent by the
* slave (plus, if used, the SMBus PEC); and this value will be
* incremented by the number of block data bytes received.
* @buf: The buffer into which data is read, or from which it's written.
*
* An i2c_msg is the low level representation of one segment of an I2C
* transaction. It is visible to drivers in the @i2c_transfer() procedure,
* to userspace from i2c-dev, and to I2C adapter drivers through the
* @i2c_adapter.@master_xfer() method.
*
* Except when I2C "protocol mangling" is used, all I2C adapters implement
* the standard rules for I2C transactions. Each transaction begins with a
* START. That is followed by the slave address, and a bit encoding read
* versus write. Then follow all the data bytes, possibly including a byte
* with SMBus PEC. The transfer terminates with a NAK, or when all those
* bytes have been transferred and ACKed. If this is the last message in a
* group, it is followed by a STOP. Otherwise it is followed by the next
* @i2c_msg transaction segment, beginning with a (repeated) START.
*
* Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
* passing certain @flags may have changed those standard protocol behaviors.
* Those flags are only for use with broken/nonconforming slaves, and with
* adapters which are known to support the specific mangling options they
* need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
*/
struct i2c_msg {
uint16_t addr; /* slave address */
uint16_t flags;
#define I2C_M_RD 0x0001 /* read data, from slave to master */
/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
uint16_t len; /* msg length */
uint8_t *buf; /* pointer to msg data */
};
/* To determine what functionality is present */
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_IGNORE_NAK etc. */
#define I2C_FUNC_SMBUS_PEC 0x00000008
#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */
#define I2C_FUNC_SLAVE 0x00000020
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000
#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE)
#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
I2C_FUNC_SMBUS_WRITE_WORD_DATA)
#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_PROC_CALL | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK | \
I2C_FUNC_SMBUS_PEC)
/*
* Data for SMBus Messages
*/
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
union i2c_smbus_data {
uint8_t byte;
uint16_t word;
uint8_t block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
/* and one more for user-space compatibility */
};
/* i2c_smbus_xfer read or write markers */
#define I2C_SMBUS_READ 1
#define I2C_SMBUS_WRITE 0
/* SMBus transaction types (size parameter in the above functions)
Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
#define I2C_SMBUS_QUICK 0
#define I2C_SMBUS_BYTE 1
#define I2C_SMBUS_BYTE_DATA 2
#define I2C_SMBUS_WORD_DATA 3
#define I2C_SMBUS_PROC_CALL 4
#define I2C_SMBUS_BLOCK_DATA 5
#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
#define I2C_SMBUS_I2C_BLOCK_DATA 8
/*flags for the client struct: */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
/* Must equal I2C_M_TEN below */
#define I2C_CLIENT_SLAVE 0x20 /* we are the slave */
#define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */
#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */
/* Must match I2C_M_STOP|IGNORE_NAK */
struct i2c_algorithm {
/* master_xfer should return the number of messages successfully
processed, or a negative value on error */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
int (*reg_slave)(struct i2c_adapter *adap);
int (*unreg_slave)(struct i2c_adapter *adap);
};
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
* with the access algorithms necessary to access it.
*/
struct i2c_adapter {
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;
void *dw_dev;
int retries;
int timeout; /* in jiffies */
int open_count;
unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
char name[16];
};
void i2c_init(void);
int i2c_add_adapter(struct i2c_adapter *adap);
struct i2c_adapter *i2c_open(const char *i2cdev);
void i2c_close(struct i2c_adapter *adap);
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
#ifdef __cplusplus
}
#endif
#endif

696
A27-STEPLDR/Src/lcd.c Normal file
View File

@ -0,0 +1,696 @@
#include "amt630h.h"
#include "board.h"
#include "lcd.h"
#include "gpio.h"
#include "sysctl.h"
#include "timer.h"
/* LCD timing */
#define LCD_PARAM0 0x000
#define LCD_PARAM1 0x004
#define LCD_PARAM2 0x008
#define LCD_PARAM3 0x00C
#define LCD_PARAM4 0x010
#define LCD_PARAM5 0x014
#define LCD_PARAM6 0x018
#define LCD_PARAM7 0x01C
#define LCD_PARAM8 0x020
#define LCD_PARAM9 0x024
#define LCD_PARAM10 0x028
#define LCD_PARAM11 0x02C
#define LCD_PARAM12 0x030
#define LCD_PARAM13 0x034
#define LCD_PARAM14 0x038
#define LCD_PARAM15 0x03C
#define LCD_PARAM16 0x040
#define LCD_PARAM17 0x044
#define LCD_PARAM18 0x048
#define LCD_PARAM19 0x04C
#define LCD_PARAM20 0x050
#define LCD_PARAM21 0x054
#define LCD_PARAM22 0x058
/* OSD */
#define LCD_OSD0_PARAM0 0x05C
#define LCD_OSD0_PARAM1 0x060
#define LCD_OSD0_PARAM2 0x064
#define LCD_OSD0_PARAM3 0x068
#define LCD_OSD0_PARAM4 0x06C
#define LCD_OSD0_PARAM5 0x070
#define LCD_OSD1_PARAM0 0x074
#define LCD_OSD1_PARAM1 0x078
#define LCD_OSD1_PARAM2 0x07C
#define LCD_OSD1_PARAM3 0x080
#define LCD_OSD1_PARAM4 0x084
#define LCD_OSD1_PARAM5 0x088
#define LCD_OSD01_PARAM 0x08C
#define LCD_OSD_COEF_SYNC 0x090
#define LCD_OSD0_PARAM2_RD 0x280
#define LCD_OSD0_PARAM3_RD 0x284
#define LCD_OSD0_PARAM4_RD 0x288
#define LCD_OSD1_PARAM2_RD 0x28C
#define LCD_OSD1_PARAM3_RD 0x290
#define LCD_OSD1_PARAM4_RD 0x294
/* Dithering */
#define LCD_DITHERING_CFG0 0x0BC
#define LCD_DITHERING_CFG1 0x0C0
#define LCD_DITHERING_CFG2 0x0C4
#define LCD_INTR_CLR 0x0C8
#define LCD_STATUS_REG 0x0CC
#define LCD_R_BIT_ORDER 0x130
#define LCD_G_BIT_ORDER 0x134
#define LCD_B_BIT_ORDER 0x138
#define LCD_GAMMA_REG 0x13c
/* CPU screen & SRGB screen */
#define LCD_SRGB_CFG 0x200
#define LCD_CPU_SCR_SOFT_REG 0x0E0
#define LCD_CPU_SCR_CTRL_REG 0x0E4
#define LCD_ADR_CLR_DATA_REG0 0x0E8
#define LCD_ADR_CLR_DATA_REG1 0x0EC
#define LCD_ADR_CLR_DATA_REG2 0x0F0
#define LCD_ADR_CLR_DATA_REG3 0x0F4
#define LCD_ADR_CLR_DATA_REG4 0x0F8
#define LCD_ADR_CLR_DATA_REG5 0x0FC
#define LCD_ADR_CLR_DATA_REG6 0x100
#define LCD_ADR_CLR_DATA_REG7 0x104
#define LCD_ADR_CLR_DATA_REG8 0x108
#define LCD_ADR_CLR_DATA_REG9 0x10C
#define LCD_ADR_CLR_DATA_REGA 0x110
#define LCD_ADR_CLR_DATA_REGB 0x114
#define LCD_ADR_CLR_DATA_REGC 0x118
#define LCD_ADR_CLR_DATA_REGD 0x11C
#define LCD_ADR_CLR_DATA_REGE 0x120
#define LCD_ADR_CLR_DATA_REGF 0x124
#define LCD_CPU_SCREEN_STATUS 0x128
#define LCD_OSD_CCM_REG0 0x208
#define LCD_OSD_CCM_REG1 0x20C
#define LCD_OSD_CCM_REG2 0x210
#define LCD_OSD_CCM_REG3 0x214
#define LCD_OSD_CCM_REG4 0x218
#define LCD_OSD_CCM_REG5 0x21C
#define LCD_CCM_EN_REG0 0x238
#define LCD_CCM_EN_REG1 0x23C
#define LCD_CCM_EN_REG2 0x240
#define LCD_CCM_EN_REG3 0x244
#define LCD_CCM_EN_REG4 0x248
#define LCD_CCM_EN_REG5 0x24C
#define LCD_CCM_EN_REG 0x250
#define LCD_ITU_EAV_CODE_CFG 0x254
#define LCD_ITU_SAV_CODE_CFG 0x258
#define LCD_HLOCK_CFG_RG 0x25C
static uint32_t fb_addr = 0;
struct ark_lcd_timing
{
uint32_t vs_start;
uint32_t hs_start;
uint32_t hd; //width
uint32_t vd; //height
uint32_t vbp;
uint32_t vfp;
uint32_t vsw;
uint32_t hbp;
uint32_t hfp;
uint32_t hsw;
};
static void ark_lcd_writel(uint32_t reg, uint32_t mask, uint8_t offset, uint32_t val)
{
uint32_t tmp = readl(REGS_LCD_BASE+reg);
tmp &= (~(mask << offset));
tmp |= (val << offset);
writel(tmp, REGS_LCD_BASE+reg);
}
int ark_lcd_set_osd_sync(LCD_OSD_LAYER osd)
{
if(osd >= LCD_OSD_NUMS) {
return -1;
}
if(osd == LCD_OSD0)
writel(readl(REGS_LCD_BASE+LCD_OSD_COEF_SYNC)|(1<<0), REGS_LCD_BASE+LCD_OSD_COEF_SYNC);
else if(osd == LCD_OSD1)
writel(readl(REGS_LCD_BASE+LCD_OSD_COEF_SYNC)|(1<<1), REGS_LCD_BASE+LCD_OSD_COEF_SYNC);
else if(osd == LCD_OSD_NUMS)
writel(readl(REGS_LCD_BASE+LCD_OSD_COEF_SYNC)|(3<<0), REGS_LCD_BASE+LCD_OSD_COEF_SYNC);
return 0;
}
static int ark_lcd_set_osd_stride(LCD_OSD_LAYER osd, uint32_t width)
{
uint32_t reg = LCD_OSD0_PARAM5 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
if(width > 0xFFF) {
return -1;
}
ark_lcd_writel(reg, 0xFFF, 0, width);
return 0;
}
int ark_lcd_get_osd_size(LCD_OSD_LAYER osd, uint32_t *width, uint32_t *height)
{
uint32_t reg = LCD_OSD0_PARAM0 + osd*0x18;
uint32_t val;
if(osd>= LCD_OSD_NUMS) {
return -1;
}
val = readl(REGS_LCD_BASE+reg);
*width = (val >> 6) & 0xFFF;
*height = (val >> 18) & 0xFFF;
return 0;
}
int ark_lcd_set_osd_size(LCD_OSD_LAYER osd, uint32_t width, uint32_t height)
{
uint32_t reg = LCD_OSD0_PARAM0 + osd*0x18;
if(osd>= LCD_OSD_NUMS) {
return -1;
}
width &= 0xFFF;
height &= 0xFFF;
ark_lcd_writel(reg, 0xFFFFFF, 6, (height<<12)|width);
ark_lcd_set_osd_stride(osd, width);
return 0;
}
int ark_lcd_set_osd_format(LCD_OSD_LAYER osd, LCD_OSD_FORMAT format)
{
uint32_t reg = LCD_OSD0_PARAM0 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
if(format >= LCD_OSD_FORAMT_NUMS) {
return -1;
}
ark_lcd_writel(reg, 0x7, 3, format);
return 0;
}
int ark_lcd_osd_enable(LCD_OSD_LAYER osd, uint8_t enable)
{
uint32_t reg = LCD_OSD0_PARAM0 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
ark_lcd_writel(reg, 0x1, 1, (enable?1:0));
return 0;
}
int ark_lcd_osd_coeff_enable(LCD_OSD_LAYER osd, uint8_t enable)
{
uint32_t reg = LCD_OSD0_PARAM0 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
ark_lcd_writel(reg, 0x1, 0, (enable?1:0));
return 0;
}
int ark_lcd_osd_set_coeff(LCD_OSD_LAYER osd, uint32_t value)
{
uint32_t reg = LCD_OSD0_PARAM1 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
ark_lcd_writel(reg, 0xFF, 24, value);
return 0;
}
int ark_lcd_set_osd_possition(LCD_OSD_LAYER osd, uint32_t h, uint32_t v)
{
uint32_t reg = LCD_OSD0_PARAM1 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
if((v > 0xFFF) || (h > 0xFFF)) {
return -1;
}
ark_lcd_writel(reg, 0xFFFFFF, 0, ((v<<12)|h));
return 0;
}
int ark_lcd_get_osd_yaddr(LCD_OSD_LAYER osd, uint32_t *yaddr)
{
uint32_t reg = LCD_OSD0_PARAM2 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
*yaddr = readl(REGS_LCD_BASE+reg);
return 0;
}
int ark_lcd_set_osd_yaddr(LCD_OSD_LAYER osd, uint32_t yaddr)
{
uint32_t reg = LCD_OSD0_PARAM2 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
writel(yaddr, REGS_LCD_BASE+reg);
return 0;
}
int ark_lcd_set_osd_uaddr(LCD_OSD_LAYER osd, uint32_t uaddr)
{
uint32_t reg = LCD_OSD0_PARAM3 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
writel(uaddr, REGS_LCD_BASE+reg);
return 0;
}
int ark_lcd_set_osd_vaddr(LCD_OSD_LAYER osd, uint32_t vaddr)
{
uint32_t reg = LCD_OSD0_PARAM4 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
writel(vaddr, REGS_LCD_BASE+reg);
return 0;
}
int ark_lcd_set_osd_mult_coef(LCD_OSD_LAYER osd, uint32_t value)
{
uint32_t reg = LCD_OSD0_PARAM5 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
if(value > 0x7F) {
return -1;
}
ark_lcd_writel(reg, 0x7F, 24, value);
return 0;
}
int ark_lcd_set_osd_h_offset(LCD_OSD_LAYER osd, uint32_t offset)
{
uint32_t reg = LCD_OSD0_PARAM5 + osd*0x18;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
if(offset > 0xFFF) {
return -1;
}
ark_lcd_writel(reg, 0xFFF, 12, offset);
return 0;
}
int ark_lcd_set_osd_yuv420_mode(LCD_OSD_LAYER osd, LCD_OSD_YUV420_MODE mode)
{
uint32_t reg = LCD_OSD01_PARAM;
if(osd >= LCD_OSD_NUMS) {
return -1;
}
if(mode > LCD_OSD_Y_UV420) {
return -1;
}
if (osd == LCD_OSD0)
ark_lcd_writel(reg, 0x1, 12, mode);
else
ark_lcd_writel(reg, 0x1, 14, mode);
return 0;
}
int ark_lcd_enable(uint8_t enable)
{
ark_lcd_writel(LCD_PARAM0, 0x01, 0, (enable?1:0));
return 0;
}
static int ark_lcd_timing_init(struct ark_lcd_timing *timing)
{
uint32_t VS_START, HS_START, HD, VD;
uint32_t VBP, VFP, VSW, TV;
uint32_t HBP, HFP, HSW, TH;
uint32_t lcd_param0, lcd_param1, lcd_param2, lcd_param3 ;
uint32_t lcd_param4, lcd_param5, lcd_param6, lcd_param7 ;
uint32_t lcd_param8, lcd_param9, lcd_param10, lcd_param11 ;
uint32_t lcd_param12, lcd_param13, lcd_param14, lcd_param15 ;
uint32_t lcd_param16, lcd_param17;
uint8_t stop_lcd = 0 ;
VS_START = timing->vs_start;
HS_START = timing->hs_start;
HD = timing->hd;
VD = timing->vd;
VBP = timing->vbp;
VFP = timing->vfp;
VSW = timing->vsw;
TV =(VS_START+VSW+VBP+VD+VFP);
HBP = timing->hbp;
HFP = timing->hfp;
HSW = timing->hsw;
TH = (HS_START+HSW+HBP+HD+HFP);
#define lcd_enable 0 // 1
#define screen_width HD
#define rgb_pad_mode LCD_WIRING_MODE
#define direct_enable 0
#define mem_lcd_enable 0
#define range_coeff_y 0
#define range_coeff_uv 0
#define lcd_done_intr_enable 1
#define dac_for_video 0
#define dac_for_cvbs 0
#define lcd_interlace_flag 0
#define screen_type 1 //pRGB_i 0 pRGB_p 1 sRGB_p 2 ITU656 3
#define VSW1_enable 0
#define LcdVComp 0
#define itu_pal_ntsc 0
#define hsync_ivs 1
#define vsync_ivs 1
#define lcd_ac_ivs 0
#define test_on_flag 0
#define back_color (0x00<<16)|(0x00<<8)|(0x00)
#define DEN_h_rise (HFP+HSW+HBP)
#define DEN_h_fall (HFP+HSW+HBP+HD)//(20+800*1)
#define DEN0_v_rise (VFP+VSW+VBP)
#define DEN0_v_fall (VFP+VSW+VBP+VD)
#define DEN1_v_rise (VFP+VSW+VBP)
#define DEN1_v_fall (VFP+VSW+VBP+VD)
// ֡Ƶ = LCDʱ<44><CAB1>/(CPL * LPS)
// ÿ<><C3BF>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>ڸ<EFBFBD><DAB8><EFBFBD>
#define CPL (TH) // clock cycles per line max 4096 ; from register timing2 16
#define LPS (TV) // Lines per screen value ; from register timing1 0
#define HSW_rise (HFP)
#define HSW_fall (HFP+HSW)
#define VSW0_v_rise (VFP) // Vertical sync width value ; from register timing1 10
#define VSW0_v_fall (VFP+VSW) // Vertical sync width value ; from register timing1 10
#define VSW0_h_rise (HFP)
#define VSW0_h_fall (HFP+HSW)
#define VSW1_v_rise (VFP) // Vertical sync width value ; from register timing1 10
#define VSW1_v_fall (VFP+VSW) // Vertical sync width value ; from register timing1 10
#define VSW1_h_rise (HFP)
#define VSW1_h_fall (HFP+HSW)
writel(0, REGS_LCD_BASE+LCD_PARAM0);
lcd_param0 =
lcd_enable |
(screen_width<<1) |
(rgb_pad_mode<<13) |
(direct_enable<<16) |
(mem_lcd_enable<<17)|
(range_coeff_y<<18) |
(range_coeff_uv<<22)|
(lcd_done_intr_enable<<26)|
(dac_for_video<<27) |
(dac_for_cvbs<<28) |
(1<<30) |
(stop_lcd<<31);
lcd_param1 =
(lcd_interlace_flag<<0) |
(screen_type<<1) |
(VSW1_enable<<13) |
(LcdVComp<<14) |
(itu_pal_ntsc<<15) |
(hsync_ivs<<17) |
(vsync_ivs<<18) |
(lcd_ac_ivs<<19) |
(1<<21) |
(1<<23) |
(test_on_flag<<31);
lcd_param2 =
(back_color<<0) |
(1<<24) |
(1<<25);
lcd_param3 =
(DEN_h_rise<<0) |
(DEN_h_fall<<12) ;
lcd_param4 =
(DEN0_v_rise<<0) |
(DEN0_v_fall<<12) ;
lcd_param5 =
(DEN1_v_rise<<0) |
(DEN1_v_fall<<12 ) ;
lcd_param6 =
(CPL<<0) | // clock cycles per line max 4096 ; from register timing2 16
(LPS<<12) ; // Lines per screen value ; from register timing1 0
lcd_param7 =
(HSW_rise<<0)|
(HSW_fall<<12) ;
lcd_param8 =
(VSW0_v_rise<<0)| // Vertical sync width value ; from register timing1 10
(VSW0_v_fall<<12) ; // Vertical sync width value ; from register timing1 10
lcd_param9 =
(VSW0_h_rise <<0 )|
(VSW0_h_fall <<12 ) ;
lcd_param10 =
(VSW1_v_rise<<0)|
(VSW1_v_fall<<12) ;
lcd_param11 =
(VSW1_h_rise<<0)|
(VSW1_h_fall<<12) ;
lcd_param12 = 66 | (129<<9) | (25<<18);
lcd_param13 = 38 | (74<<9) | (112<<18);
lcd_param14 = 112 | (94<<9) | (18<<18);
lcd_param15 = 256 | (0<<9) | (351<<18);
lcd_param16 = 256 | (86<<9) | (179<<18);
lcd_param17 = 256 | (443<<10) | (0<<19);
writel(lcd_param1, REGS_LCD_BASE+LCD_PARAM1);
writel(lcd_param2, REGS_LCD_BASE+LCD_PARAM2);
writel(lcd_param3, REGS_LCD_BASE+LCD_PARAM3);
writel(lcd_param4, REGS_LCD_BASE+LCD_PARAM4);
writel(lcd_param5, REGS_LCD_BASE+LCD_PARAM5);
writel(lcd_param6, REGS_LCD_BASE+LCD_PARAM6);
writel(lcd_param7, REGS_LCD_BASE+LCD_PARAM7);
writel(lcd_param8, REGS_LCD_BASE+LCD_PARAM8);
writel(lcd_param9, REGS_LCD_BASE+LCD_PARAM9);
writel(lcd_param10, REGS_LCD_BASE+LCD_PARAM10);
writel(lcd_param11, REGS_LCD_BASE+LCD_PARAM11);
writel(lcd_param12, REGS_LCD_BASE+LCD_PARAM12);
writel(lcd_param13, REGS_LCD_BASE+LCD_PARAM13);
writel(lcd_param14, REGS_LCD_BASE+LCD_PARAM14);
writel(lcd_param15, REGS_LCD_BASE+LCD_PARAM15);
writel(lcd_param16, REGS_LCD_BASE+LCD_PARAM16);
writel(lcd_param17, REGS_LCD_BASE+LCD_PARAM17);
writel(lcd_param0, REGS_LCD_BASE+LCD_PARAM0);
#if LCD_WIRING_BIT_ORDER == LCD_WIRING_BIT_ORDER_LSB
writel((0<<21|1<<18|2<<15|3<<12|4<<9|5<<6|6<<3|7<<0), REGS_LCD_BASE+LCD_R_BIT_ORDER);
writel((0<<21|1<<18|2<<15|3<<12|4<<9|5<<6|6<<3|7<<0), REGS_LCD_BASE+LCD_G_BIT_ORDER);
writel((0<<21|1<<18|2<<15|3<<12|4<<9|5<<6|6<<3|7<<0), REGS_LCD_BASE+LCD_B_BIT_ORDER);
#elif LCD_WIRING_BIT_ORDER == LCD_WIRING_BIT_ORDER_MSB
writel((7<<21|6<<18|5<<15|4<<12|3<<9|2<<6|1<<3|0<<0), REGS_LCD_BASE+LCD_R_BIT_ORDER);
writel((7<<21|6<<18|5<<15|4<<12|3<<9|2<<6|1<<3|0<<0), REGS_LCD_BASE+LCD_G_BIT_ORDER);
writel((7<<21|6<<18|5<<15|4<<12|3<<9|2<<6|1<<3|0<<0), REGS_LCD_BASE+LCD_B_BIT_ORDER);
#endif
return 0;
}
static int ark_lcd_hw_init()
{
uint32_t HD, VD;
HD = LCD_WIDTH;
VD = LCD_HEIGHT;
#if LCD_H_FLIP
uint8_t osd_0_hflip = 1;
uint8_t osd_1_hflip = 1;
uint8_t osd_0_uvfirst = 1;
#else
uint8_t osd_0_hflip = 0;
uint8_t osd_1_hflip = 0;
uint8_t osd_0_uvfirst = 0;
#endif
#if LCD_V_FLIP
uint8_t osd_0_vflip = 1;
uint8_t osd_1_vflip = 1;
#else
uint8_t osd_0_vflip = 0;
uint8_t osd_1_vflip = 0;
#endif
uint8_t osd_0_yuv420mode = 1;
//uint8_t osd_0_yuv422mode = 0;
uint32_t osd_01_param =
//osd_0_yuv422mode<<20|
osd_0_hflip<<16|
osd_0_vflip<<17|
osd_1_hflip<<18|
osd_1_vflip<<19|
osd_0_yuv420mode<<12|
osd_0_uvfirst<<13;
writel(osd_01_param, REGS_LCD_BASE+LCD_OSD01_PARAM);
//osd0 init
ark_lcd_set_osd_size(LCD_OSD0, HD, VD);
ark_lcd_set_osd_format(LCD_OSD0, LCD_OSD_FORAMT_YUV420);
ark_lcd_set_osd_possition(LCD_OSD0, 0, 0);
ark_lcd_set_osd_yaddr(LCD_OSD0, fb_addr);
ark_lcd_set_osd_uaddr(LCD_OSD0, fb_addr + HD * VD);
ark_lcd_set_osd_vaddr(LCD_OSD0, fb_addr + HD * VD);
ark_lcd_set_osd_h_offset(LCD_OSD0, 0);
ark_lcd_set_osd_mult_coef(LCD_OSD0, 64);
ark_lcd_osd_enable(LCD_OSD0, 0);
ark_lcd_set_osd_sync(LCD_OSD0);
//osd1 init
ark_lcd_set_osd_size(LCD_OSD1, HD, VD);
#if LCD_BPP == 32
ark_lcd_set_osd_format(LCD_OSD1, LCD_OSD_FORAMT_ARGB888);
ark_lcd_osd_coeff_enable(LCD_OSD1, 0);
#elif LCD_BPP == 16
ark_lcd_set_osd_format(LCD_OSD1, LCD_OSD_FORAMT_RGB565);
ark_lcd_osd_coeff_enable(LCD_OSD1, 1);
ark_lcd_osd_set_coeff(LCD_OSD1, 255);
#endif
ark_lcd_set_osd_possition(LCD_OSD1, 0, 0);
ark_lcd_set_osd_h_offset(LCD_OSD1, 0);
ark_lcd_set_osd_mult_coef(LCD_OSD1, 64);
ark_lcd_set_osd_yaddr(LCD_OSD1, fb_addr);
ark_lcd_osd_enable(LCD_OSD1, 0);
ark_lcd_set_osd_sync(LCD_OSD1);
ark_lcd_enable(1);
return 0;
}
#define LCD_SRC_FREQ 396000000//498000000
static int ark_lcd_clk_init(uint32_t freq)
{
int div;
if (freq > 16000000) {
vSysctlConfigure(SYS_VOU_CLK_CFG, 0, 3, 0);
div = DIV_ROUND_UP(LCD_SRC_FREQ, freq);
} else if (freq >= 14000000) { //14-16MH配置为16MHZ
vSysctlConfigure(SYS_VOU_CLK_CFG, 0, 3, 0);
div = DIV_ROUND_UP(LCD_SRC_FREQ, 16000000);
} else {
vSysctlConfigure(SYS_VOU_CLK_CFG, 0, 3, 2);
div = DIV_ROUND_UP(24000000, freq);
}
vSysctlConfigure(SYS_VOU_CLK_CFG, 3, 0x1f, div - 1);
return 0;
}
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_LVDS
static void lvds_screen_reset(void)
{
gpio_direction_output(LVDS_SCREEN_RST_GPIO, 0);
udelay(100);
gpio_direction_output(LVDS_SCREEN_RST_GPIO, 1);
mdelay(20);
}
#endif
int lcd_init(void)
{
struct ark_lcd_timing timing;
int ret = 0;
/* lcd pad select */
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_TTL
vSysctlConfigure(SYS_PAD_CTRL04, 0, 0xffffffff, 0x55555555);
vSysctlConfigure(SYS_PAD_CTRL05, 0, 0xffffff, 0x555555);
#elif LCD_INTERFACE_TYPE == LCD_INTERFACE_LVDS
vSysctlConfigure(SYS_PAD_CTRL04, 0, 0xfffff, 0xaaaaa);
#endif
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_MIPI
mipi_init();
#endif
/* lcd timing init */
timing.vs_start = 0;
timing.hs_start = 0;
timing.hd = LCD_WIDTH;
timing.vd = LCD_HEIGHT;
timing.vbp = LCD_TIMING_VBP;
timing.vfp = LCD_TIMING_VFP;
timing.vsw = LCD_TIMING_VSW;
timing.hbp = LCD_TIMING_HBP;
timing.hfp = LCD_TIMING_HFP;
timing.hsw = LCD_TIMING_HSW;
ark_lcd_clk_init(LCD_CLK_FREQ);
ark_lcd_timing_init(&timing);
ark_lcd_hw_init();
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_LVDS
mdelay(2);
uint32_t lvds_cfg = 0xe0ec;
#if LVDS_PANEL_FORMAT == LVDS_PANEL_FORMAT_TI
lvds_cfg |= (1 << 16);
#endif
#if LVDS_PANEL_DATA == LVDS_PANEL_DATA_8BIT
lvds_cfg &= ~(1 << 15);
lvds_cfg |= (1 << 4) | 1;
#endif
writel(lvds_cfg, REGS_SYSCTL_BASE + SYS_ANA3_CFG);
lvds_screen_reset();
#endif
return ret;
}

65
A27-STEPLDR/Src/lcd.h Normal file
View File

@ -0,0 +1,65 @@
/*
* ark_lcd.h
*
*/
#ifndef _LCD_H
#define _LCD_H
typedef enum {
LCD_OSD0 = 0,
LCD_OSD1,
LCD_OSD_NUMS,
}LCD_OSD_LAYER;
typedef enum {
LCD_OSD_FORAMT_YUV420 = 0,
LCD_OSD_FORAMT_ARGB888,
LCD_OSD_FORAMT_RGB565,
LCD_OSD_FORAMT_RGB454,
LCD_OSD_FORAMT_NUMS,
}LCD_OSD_FORMAT;
typedef enum {
LCD_OSD_Y_U_V420 = 0,
LCD_OSD_Y_UV420,
}LCD_OSD_YUV420_MODE;
#define LCD_UI_LAYER LCD_OSD1
/* osd layer set func */
/************************************************************/
int ark_lcd_set_osd_size(LCD_OSD_LAYER osd, uint32_t width, uint32_t height);
int ark_lcd_set_osd_format(LCD_OSD_LAYER osd, LCD_OSD_FORMAT format);
int ark_lcd_set_osd_yaddr(LCD_OSD_LAYER osd, uint32_t yaddr);
int ark_lcd_set_osd_uaddr(LCD_OSD_LAYER osd, uint32_t yaddr);
int ark_lcd_set_osd_vaddr(LCD_OSD_LAYER osd, uint32_t yaddr);
int ark_lcd_osd_enable(LCD_OSD_LAYER osd, uint8_t enable);
/* Interface with default argument value, may be you need them. If you not sure, ingore them */
int ark_lcd_set_osd_possition(LCD_OSD_LAYER osd, uint32_t h, uint32_t v);
int ark_lcd_set_osd_h_offset(LCD_OSD_LAYER osd, uint32_t offset);
int ark_lcd_osd_coeff_enable(LCD_OSD_LAYER osd, uint8_t enable);
int ark_lcd_osd_set_coeff(LCD_OSD_LAYER osd, uint32_t value);
int ark_lcd_set_osd_mult_coef(LCD_OSD_LAYER osd, uint32_t value);
int ark_lcd_set_osd_yuv420_mode(LCD_OSD_LAYER osd, LCD_OSD_YUV420_MODE mode);
/* after calling the osd layer set func, you should call */
/* this function to flush the parameters for atom option */
int ark_lcd_set_osd_sync(LCD_OSD_LAYER osd);
/************************************************************/
int ark_lcd_get_osd_size(LCD_OSD_LAYER osd, uint32_t *width, uint32_t *height);
int ark_lcd_get_osd_format(LCD_OSD_LAYER osd, LCD_OSD_FORMAT *format);
int ark_lcd_get_osd_yaddr(LCD_OSD_LAYER osd, uint32_t *yaddr);
uint32_t ark_lcd_get_virt_addr(void);
int ark_lcd_enable(uint8_t enable);
int ark_lcd_wait_for_vsync(void);
int lcd_init(void);
void lcd_uninit(void);
#endif

346
A27-STEPLDR/Src/mipi.c Normal file
View File

@ -0,0 +1,346 @@
#include "amt630h.h"
#include "board.h"
#include "sysctl.h"
#include "timer.h"
#include "uart.h"
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_MIPI
/* Global macro defination */
#define MIPI_WTIRE_DATA 0x70
#define MIPI_WTIRE_COMMAND 0x6c
#define ARK_MIPI_WRITEL(reg, val) writel(val, REGS_MIPI_BASE + reg); udelay(200)
#define ARK_MIPI_READL(reg) readl(REGS_MIPI_BASE + reg)
/* Mipi panel parameters */
#define LPDT_LPK 0x39 //1cmd + >=2data
#define LPDT_SPK 0x15 //1cmd + 1data.
#define NORM_LPK 0x05 //1cmd
#define MIPI_WIDTH LCD_WIDTH
#define MIPI_HEIGHT LCD_HEIGHT
#define MIPI_VBP LCD_TIMING_VBP
#define MIPI_VFP LCD_TIMING_VFP
#define MIPI_VSW LCD_TIMING_VSW
#define MIPI_HBP LCD_TIMING_HBP
#define MIPI_HFP LCD_TIMING_HFP
#define MIPI_HSW LCD_TIMING_HSW
#define MIPI_SPEED 460000000
#define MIPI_LANE 4 //1-4LANE
#define DISPLAY_MODE 0 //0: nornal mode; 1: test colour bar mode.
#define MIPI_NP_POLARITY_INVERSE 0 //0: clk and data NP polarity normal; 1:clk and data NP polarity inverse.
//#define MIPI_RESET_GPIO 73
/* End of mipi panel parameters */
#define MIPI_SEND_DATA(arg...) do { \
uint8_t buf[] = {arg}; \
mipi_write_data(buf, sizeof(buf)); \
mdelay(2); \
} while (0)
static void mipi_set_speed(uint32_t speed)
{
speed = speed / 1000000;
if ((speed >= 200) && (speed <= 219))
{
ARK_MIPI_WRITEL(0xb8, 0x06);
}
else if((speed >= 220) && (speed <= 239))
{
ARK_MIPI_WRITEL(0xb8, 0x26);
}
else if((speed >= 240) && (speed <= 249))
{
ARK_MIPI_WRITEL(0xb8, 0x46);
}
else if((speed >= 250) && (speed <= 269))
{
ARK_MIPI_WRITEL(0xb8, 0x08);
}
else if((speed >= 270) && (speed <= 299))
{
ARK_MIPI_WRITEL(0xb8, 0x28);
}
else if((speed >= 300) && (speed <= 329))
{
ARK_MIPI_WRITEL(0xb8, 0x0a);
}
else if((speed >= 330) && (speed <= 359))
{
ARK_MIPI_WRITEL(0xb8, 0x2a);
}
else if((speed >= 260) && (speed <= 399))
{
ARK_MIPI_WRITEL(0xb8, 0x4a);
}
else if((speed >= 400) && (speed <= 449))
{
ARK_MIPI_WRITEL(0xb8, 0x0c);
}
else if((speed >= 450) && (speed <= 499))
{
ARK_MIPI_WRITEL(0xb8, 0x2c);
}
else if((speed >= 500) && (speed <= 549))
{
ARK_MIPI_WRITEL(0xb8, 0x0e);
}
else if((speed >= 550) && (speed <= 599))
{
ARK_MIPI_WRITEL(0xb8, 0x2e);
}
else if((speed >= 600) && (speed <= 649))
{
ARK_MIPI_WRITEL(0xb8, 0x10);
}
else if((speed >= 650) && (speed <= 699))
{
ARK_MIPI_WRITEL(0xb8, 0x30);
}
else if((speed >= 700) && (speed <= 749))
{
ARK_MIPI_WRITEL(0xb8, 0x12);
}
else if((speed >= 750) && (speed <= 799))
{
ARK_MIPI_WRITEL(0xb8, 0x32);
}
else if((speed >= 800) && (speed <= 849))
{
ARK_MIPI_WRITEL(0xb8, 0x52);
}
else if((speed >= 850) && (speed <= 899))
{
ARK_MIPI_WRITEL(0xb8, 0x72);
}
else if((speed >= 900) && (speed <= 949))
{
ARK_MIPI_WRITEL(0xb8, 0x14);
}
else if((speed >= 950) && (speed <= 1000))
{
ARK_MIPI_WRITEL(0xb8, 0x34);
}
else
{
ARK_MIPI_WRITEL(0xb8, 0x2c);
}
}
static int mipi_write_data(const uint8_t *buffer, int length)
{
uint32_t value = 0;
int mult = length / 4;
int left = length % 4;
int i = 0;
if (!buffer || (length <= 0))
{
if (!buffer)
SendUartString("mipi_write_data buffer NULL\n");
if (length <= 0)
SendUartString("mipi_write_data data length invalid\n");
return -1;
}
if (length == 1) //only 1cmd.
{
ARK_MIPI_WRITEL(MIPI_WTIRE_COMMAND, (buffer[0]<<8) | NORM_LPK);
}
else if (length == 2) //1cmd + 1data.
{
ARK_MIPI_WRITEL(MIPI_WTIRE_DATA, (buffer[1]<<8)|buffer[0]);
ARK_MIPI_WRITEL(MIPI_WTIRE_COMMAND, (length<<8) | LPDT_SPK);
}
else //1cmd + >=2data.
{
for (i=0; i<mult; i++) {
value = (buffer[4*i+3]<<24) | (buffer[4*i+2]<<16) | (buffer[4*i+1]<<8) | buffer[4*i+0];
ARK_MIPI_WRITEL(MIPI_WTIRE_DATA, value);
}
if (left) {
for (value=0,i=0; i<left; i++) {
value |= (buffer[4*mult+i] << 8*i);
}
ARK_MIPI_WRITEL(MIPI_WTIRE_DATA, value);
}
ARK_MIPI_WRITEL(MIPI_WTIRE_COMMAND, LPDT_LPK | (length<<8));
}
return 0;
}
static int mipi_panel_init(void)
{
//SendUartString("mipi_panel_init start\r\n");
#ifdef MIPI_RESET_GPIO
gpio_direction_output(MIPI_RESET_GPIO, 1);
mdelay(10);
gpio_direction_output(MIPI_RESET_GPIO, 0);
mdelay(220);
gpio_direction_output(MIPI_RESET_GPIO, 1);
mdelay(120);
#endif
MIPI_SEND_DATA(0xB9,0xFF,0x83,0x94);
MIPI_SEND_DATA(0xB1,0x48,0x12,0x72,0x09,0x32,0x24,0x71,0x51,0x2F,0x43);
MIPI_SEND_DATA(0xBA,0x63,0x03,0x68,0x6B,0xB2,0xC0);
MIPI_SEND_DATA(0xB2,0x40,0xA0,0x64,0x0E,0x0A,0x2F);
MIPI_SEND_DATA( 0xB4,0x1C,0x78,0x1C,0x78,0x1C,0x78,0x01,0x0C,0x86,0x55,0x00,0x3F,0x1C,0x78,0x1C,
0x78,0x1C,0x78,0x01,0x0C,0x86);
MIPI_SEND_DATA( 0xD3,0x00,0x00,0x00,0x00,0x64,0x07,0x08,0x08,0x32,0x10,0x07,0x00,0x07,0x32,0x15,
0x15,0x05,0x15,0x00,0x32,0x10,0x08,0x00,0x35,0x33,0x09,0x09,0x37,0x0D,0x07,0x37,
0x0E,0x08);
MIPI_SEND_DATA( 0xD5,0x18,0x18,0x24,0x24,0x1A,0x1A,0x1B,0x1B,0x04,0x05,0x06,0x07,0x00,0x01,0x02,
0x03,0x18,0x18,0x19,0x19,0x20,0x21,0x22,0x23,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18);
MIPI_SEND_DATA( 0xD6,0x19,0x19,0x24,0x24,0x1A,0x1A,0x1B,0x1B,0x03,0x02,0x01,0x00,0x07,0x06,0x05,
0x04,0x18,0x18,0x18,0x18,0x23,0x22,0x21,0x20,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18);
MIPI_SEND_DATA(0xB6,0x48,0x48);
MIPI_SEND_DATA( 0xE0,0x00,0x1E,0x28,0x2F,0x30,0x33,0x37,0x34,0x6B,0x7A,0x88,0x84,0x8B,0x9B,0x9E,
0x9F,0xAA,0xAA,0xA4,0xB1,0xC0,0x5F,0x5D,0x61,0x65,0x68,0x70,0x7E,0x7F,0x00,0x1E,
0x28,0x2F,0x30,0x33,0x37,0x34,0x6B,0x7A,0x88,0x84,0x8B,0x9B,0x9E,0x9F,0xAA,0xAA,
0xA4,0xB1,0xC0,0x5F,0x5D,0x61,0x65,0x68,0x70,0x7E,0x7F);
MIPI_SEND_DATA(0xCC,0x03);
MIPI_SEND_DATA(0xC0,0x1F,0x31);
MIPI_SEND_DATA(0xD4,0x02);
MIPI_SEND_DATA(0xBD,0x01);
MIPI_SEND_DATA(0xB1,0x00);
MIPI_SEND_DATA(0xBD,0x00);
MIPI_SEND_DATA(0xC6,0xED);
MIPI_SEND_DATA(0x11);
mdelay(200);
MIPI_SEND_DATA(0x29);
mdelay(120);
//MIPI_SEND_DATA(0x35,0x00);
//SendUartString("mipi_panel_init finish\r\n");
return 0;
}
#if MIPI_NP_POLARITY_INVERSE
/* mipi clk and 4channel data NP polarity inverse. */
static void mipi_np_polarity_inv(void)
{
ARK_MIPI_WRITEL(0xb8, 0x35);
ARK_MIPI_WRITEL(0xb8, 0x10035);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x1);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x45);
ARK_MIPI_WRITEL(0xb8, 0x10045);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x1);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x55);
ARK_MIPI_WRITEL(0xb8, 0x10055);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x1);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x85);
ARK_MIPI_WRITEL(0xb8, 0x10085);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x1);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x95);
ARK_MIPI_WRITEL(0xb8, 0x10095);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
ARK_MIPI_WRITEL(0xb8, 0x1);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
}
#endif
void mipi_init(void)
{
unsigned int val;
val = readl(REGS_SYSCTL_BASE + SYS_ANA1_CFG);
val |= (0x3 <<30)|(0x7 <<22);
writel(val, REGS_SYSCTL_BASE + SYS_ANA1_CFG);
val = readl(REGS_SYSCTL_BASE + SYS_PERCTL_CFG);
val |= (0x1<<8);
writel(val, REGS_SYSCTL_BASE + SYS_PERCTL_CFG);
ARK_MIPI_WRITEL(0x04, 0x0);
ARK_MIPI_WRITEL(0xa0, 0x0);
ARK_MIPI_WRITEL(0x08, 0x17);
ARK_MIPI_WRITEL(0x2c, 0x1c);
ARK_MIPI_WRITEL(0x9c, 0x09000c);
ARK_MIPI_WRITEL(0x94, 0x0);
ARK_MIPI_WRITEL(0x98, 0x180014);
ARK_MIPI_WRITEL(0xa4, 0x2800+(MIPI_LANE-1));
ARK_MIPI_WRITEL(0x38, 0xbf02);
ARK_MIPI_WRITEL(0x0c, 0x0);
ARK_MIPI_WRITEL(0x68, 0x000b4700);
ARK_MIPI_WRITEL(0x10, 0x5);
ARK_MIPI_WRITEL(0x14, 0x00);
ARK_MIPI_WRITEL(0x3c, MIPI_WIDTH);
ARK_MIPI_WRITEL(0x48, MIPI_HSW);
ARK_MIPI_WRITEL(0x4c, MIPI_HBP);
ARK_MIPI_WRITEL(0x50, MIPI_WIDTH+MIPI_HSW+MIPI_HBP+MIPI_HFP);
ARK_MIPI_WRITEL(0x54, MIPI_VSW);
ARK_MIPI_WRITEL(0x58, MIPI_VBP);
ARK_MIPI_WRITEL(0x5c, MIPI_VFP);
ARK_MIPI_WRITEL(0x60, MIPI_HEIGHT);
ARK_MIPI_WRITEL(0x34, 0x1);
ARK_MIPI_WRITEL(0x18, 0xa000a);
ARK_MIPI_WRITEL(0xc4, 0xffffffff);
ARK_MIPI_WRITEL(0xc8, 0xffffffff);
ARK_MIPI_WRITEL(0x04, 0x1);
ARK_MIPI_WRITEL(0xa0, 0xf);
#if MIPI_NP_POLARITY_INVERSE
mipi_np_polarity_inv();
#endif
ARK_MIPI_WRITEL(0xb8, 0x44);
ARK_MIPI_WRITEL(0xb8, 0x10044);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
//ARK_MIPI_WRITEL(0xb8, 0x0C); //MIPI CLK
mipi_set_speed(MIPI_SPEED);
ARK_MIPI_WRITEL(0xb4, 0x2);
ARK_MIPI_WRITEL(0xb4, 0x0);
while(!(ARK_MIPI_READL(0xb0) & 0x5));
ARK_MIPI_WRITEL(0x94, 0x1);
ARK_MIPI_WRITEL(0x100, 0x1000000);
mdelay(200);
/* mipi panel init */
mipi_panel_init();
#if DISPLAY_MODE
ARK_MIPI_WRITEL(0x38, 0x1bf02); //test mode test mode colour bar
#else
ARK_MIPI_WRITEL(0x38, 0xbf02); //normal mode
#endif
ARK_MIPI_WRITEL(0x34, 0x0);
}
#endif

97
A27-STEPLDR/Src/mmu.c Normal file
View File

@ -0,0 +1,97 @@
#include "mmu.h"
#pragma data_alignment=16384
__no_init unsigned int mmu_tlb_table[4096];
#define _MMUTT_STARTADDRESS ((unsigned int)mmu_tlb_table)
//#define _MMUTT_STARTADDRESS ((unsigned int)0x30c000)
/**
* \brief Initializes MMU.
* \param pTB Address of the translation table.
*/
void MMU_Initialize(unsigned int *pTB)
{
unsigned int index;
unsigned int addr;
/* Reset table entries */
for (index = 0; index < 4096; index++)
pTB[index] = 0;
/* interrupt vector address (after remap) 0x0000_0000 */
pTB[0x000] = (0x20f << 20)| // Physical Address
// ( 1 << 12)| // TEX[0]
( 3 << 10)| // Access in supervisor mode (AP)
( 0xF << 5)| // Domain 0xF
( 1 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => YES
( 0 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
/* SRAM address (after remap) 0x0030_0000 */
pTB[0x003] = (0x003 << 20)| // Physical Address
// ( 1 << 12)| // TEX[0]
( 3 << 10)| // Access in supervisor mode (AP)
( 0xF << 5)| // Domain 0xF
( 1 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => YES
( 0 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
/* DDRAM address (after remap) 0x2000_0000 */
for(addr = 0x200; addr < 0x240; addr++)
pTB[addr] = (addr << 20)| // Physical Address
( 1 << 18)| // 16MB Supersection
( 3 << 10)| // Access in supervisor mode (AP)
( 1 << 12)| // TEX[0]
( 0 << 5)| // Domain 0x0, Supersection only support domain 0
( 0 << 4)| // (XN)
( 1 << 3)| // C bit : cachable => YES
( 1 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
/* DDRAM non-cache address (after remap) 0x3000_0000 */
for(addr = 0x300; addr < 0x340; addr++)
pTB[addr] = ((addr - 0x100) << 20)| // Physical Address
( 1 << 18)| // 16MB Supersection
( 3 << 10)| // Access in supervisor mode (AP)
( 1 << 12)| // TEX[0]
( 0 << 5)| // Domain 0x0, Supersection only support domain 0
( 0 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => YES
( 0 << 2)| // B bit : write-back => YES
( 2 << 0); // Set as 1 Mbyte section
// periph address 0x60000000 ~ 0x80000000
for(addr = 0x600; addr < 0x800; addr++)
pTB[addr] = (addr << 20)| // Physical Address
( 3 << 10)| // Access in supervisor mode (AP)
( 0xF << 5)| // Domain 0xF
( 1 << 4)| // (XN)
( 0 << 3)| // C bit : cachable => NO
( 0 << 2)| // B bit : write-back => NO
( 2 << 0); // Set as 1 Mbyte section
CP15_WriteTTB((unsigned int)pTB);
/* Program the domain access register */
CP15_WriteDomainAccessControl(0xC0000003); // only domain 0 & 15: access are not checked
}
void MMU_Init(void)
{
if(CP15_IsIcacheEnabled())
CP15_DisableIcache();
if(CP15_IsDcacheEnabled())
CP15_DisableDcache();
if(CP15_IsMMUEnabled())
CP15_DisableMMU();
MMU_Initialize((unsigned int*)_MMUTT_STARTADDRESS);
CP15_EnableMMU();
CP15_EnableIcache();
CP15_EnableDcache();
}

21
A27-STEPLDR/Src/mmu.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef _MMU_
#define _MMU_
#include "cp15.h"
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern void MMU_Init(void);
extern void dma_flush_range(unsigned int ulStart, unsigned int ulEnd);
extern void dma_inv_range (unsigned int ulStart, unsigned int ulEnd);
extern void dma_clean_range(unsigned int ulStart, unsigned int ulEnd);
extern unsigned int vaddr_to_page_addr (unsigned int addr);
extern unsigned int page_addr_to_vaddr (unsigned int addr);
#endif /* #ifndef _MMU_ */

View File

@ -0,0 +1,11 @@
#include "os_adapt.h"
void *malloc(size_t size)
{
return pvPortMalloc(size);
}
void free(void *ptr)
{
vPortFree(ptr);
}

378
A27-STEPLDR/Src/os_adapt.h Normal file
View File

@ -0,0 +1,378 @@
#ifndef _OS_ADAPT_H
#define _OS_ADAPT_H
#include <string.h>
#include "FreeRTOS.h"
#include "list.h"
#include "typedef.h"
#ifdef __cplusplus
extern "C" {
#endif
#define __INLINE inline
#define PAGE_SIZE 4096
#define ARCH_DMA_MINALIGN 32
#define USEC_PER_MSEC 1000
#define MSEC_PER_SEC 1000
#define BUG() PrintVariableValueHex("bug on", __LINE__);
#define BUG_ON(condition) if (condition) BUG()
#define WARN_ON(condition) if (condition) BUG()
#define barrier()
#define wmb()
#define EXPORT_SYMBOL(x)
#define dev_dbg(dev, ...) TRACE_DEBUG(__VA_ARGS__)
#define dev_vdbg dev_dbg
#define dev_info(dev, ...) TRACE_INFO(__VA_ARGS__)
#define dev_warn(dev, ...) TRACE_WARNING(__VA_ARGS__)
#define dev_err(dev, ...) TRACE_ERROR(__VA_ARGS__)
#define __iomem volatile
#define unlikely(x) (x)
#define likely(x) (x)
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define DIV_ROUND_UP_ULL(ll, d) (((unsigned long long)(ll) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#define BITS_PER_LONG 32
#define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define min(x,y) ((x)<(y)?(x):(y))
/*
* Create a contiguous bitmask starting at bit position @l and ending at
* position @h. */
#define GENMASK(h, l) \
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
#define VOID void
#define BOOL int
#define TRUE 1
#define FALSE 0
#define FAR
#define NEAR
typedef unsigned long long u64;
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
//typedef s32 ssize_t;
typedef u32 __le32;
typedef UINT32 AARCHPTR;
typedef u32 dma_addr_t;
typedef u32 phys_addr_t;
typedef phys_addr_t resource_size_t;
typedef unsigned gfp_t;
#define le16_to_cpu(x) (x)
#define le32_to_cpu(x) (x)
#define cpu_to_le32(x) (x)
#define ___constant_swab32(x) ((u32)( \
(((u32)(x) & (u32)0x000000ffUL) << 24) | \
(((u32)(x) & (u32)0x0000ff00UL) << 8) | \
(((u32)(x) & (u32)0x00ff0000UL) >> 8) | \
(((u32)(x) & (u32)0xff000000UL) >> 24)))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
typedef struct {
int counter;
} atomic_t;
typedef struct refcount_struct {
atomic_t refs;
} refcount_t;
#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), }
struct kref {
refcount_t refcount;
};
#define KREF_INIT(n) { .refcount = REFCOUNT_INIT(n), }
#define small_const_nbits(nbits) \
(nbits && (nbits) <= BITS_PER_LONG)
#define reg8_read(addr) *((volatile uint8_t *)(addr))
#define reg16_read(addr) *((volatile uint16_t *)(addr))
#define reg32_read(addr) *((volatile uint32_t *)(addr))
#define reg8_write(addr,val) *((volatile uint8_t *)(addr)) = (val)
#define reg16_write(addr,val) *((volatile uint16_t *)(addr)) = (val)
#define reg32_write(addr,val) *((volatile uint32_t *)(addr)) = (val)
#define mem8_read(addr) *((volatile uint8_t *)(addr))
#define mem16_read(addr) *((volatile uint16_t *)(addr))
#define mem32_read(addr) *((volatile uint32_t *)(addr))
#define mem8_write(addr,val) *((volatile uint8_t *)(addr)) = (val)
#define mem16_write(addr,val) *((volatile uint16_t *)(addr)) = (val)
#define mem32_write(addr,val) *((volatile uint32_t *)(addr)) = (val)
#define readb(a) reg8_read(a)
#define readw(a) reg16_read(a)
#define readl(a) reg32_read(a)
#define writeb(v, a) reg8_write(a, v)
#define writew(v, a) reg16_write(a, v)
#define writel(v, a) reg32_write(a, v)
static __INLINE void memset_s(void *dest, size_t destMax, int c, size_t count)
{
memset(dest, c, destMax);
}
static __INLINE void bitmap_zero(unsigned long *dst, unsigned int nbits)
{
if (small_const_nbits(nbits))
*dst = 0UL;
else {
unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
memset(dst, 0, len);
}
}
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static __INLINE int fls(u32 x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
r -= 1;
}
return r;
}
/*
* __fls() returns the bit position of the last bit set, where the
* LSB is 0 and MSB is 31. Zero input is undefined.
*/
static __INLINE unsigned long __fls(unsigned long x)
{
return fls(x) - 1;
}
/*
* ffs() returns zero if the input was zero, otherwise returns the bit
* position of the first set bit, where the LSB is 1 and MSB is 32.
*/
static __INLINE int ffs(int x)
{
return fls(x & -x);
}
/*
* __ffs() returns the bit position of the first bit set, where the
* LSB is 0 and MSB is 31. Zero input is undefined.
*/
static __INLINE unsigned long __ffs(unsigned long x)
{
return ffs(x) - 1;
}
#define MAX_ERRNO 4095
#define IS_ERR_VALUE(x) (x) >= (unsigned long)-MAX_ERRNO
static __INLINE void *ERR_PTR(long error)
{
return (void *) error;
}
static __INLINE long PTR_ERR(const void *ptr)
{
return (long) ptr;
}
static __INLINE long IS_ERR(const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
static __INLINE int IS_ERR_OR_NULL(const void *ptr)
{
return !ptr || IS_ERR_VALUE((unsigned long)ptr);
}
static __INLINE void set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
static __INLINE void clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p &= ~mask;
}
/**
* test_bit - Determine whether a bit is set
* @nr: bit number to test
* @addr: Address to start counting from
*/
static __INLINE int test_bit(int nr, const volatile unsigned long *addr)
{
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
/**
* test_and_set_bit - Set a bit and return its old value
* @nr: Bit to set
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
* It may be reordered on other architectures than x86.
* It also implies a memory barrier.
*/
static __INLINE int test_and_set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old;
old = *p;
*p = old | mask;
return (old & mask) != 0;
}
static __INLINE int test_and_clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old;
old = *p;
*p = old & ~mask;
return (old & mask) != 0;
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static __INLINE void list_splice_init(List_t *list, List_t *head)
{
ListItem_t *pxIndex = head->pxIndex;
ListItem_t *first = list->pxIndex->pxNext;
ListItem_t *last = list->pxIndex->pxPrevious;
if (!listLIST_IS_EMPTY(list)) {
first->pxPrevious = pxIndex->pxPrevious;
last->pxNext = pxIndex;
pxIndex->pxPrevious->pxNext = first;
pxIndex->pxPrevious = last;
head->uxNumberOfItems += list->uxNumberOfItems;
vListInitialise(list);
}
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static __INLINE void list_move(ListItem_t *item, List_t *list, ListItem_t *pos)
{
void *pvOwner = item->pvOwner;
uxListRemove(item);
item->pvOwner = pvOwner;
item->pxNext = pos->pxNext;
item->pxNext->pxPrevious = item;
item->pxPrevious = pos;
pos->pxNext = item;
/* Remember which list the item is in. This allows fast removal of the
item later. */
item->pxContainer = list;
list->uxNumberOfItems++;
}
#define list_for_each_entry(pxListItem, pvOwner, list) \
for (pxListItem = listGET_HEAD_ENTRY(list), \
pvOwner = listGET_LIST_ITEM_OWNER(pxListItem); \
pxListItem != listGET_END_MARKER(list); \
pxListItem = listGET_NEXT(pxListItem), \
pvOwner = listGET_LIST_ITEM_OWNER(pxListItem))
#define list_entry(pxListItem) listGET_LIST_ITEM_OWNER(pxListItem)
#define list_first_entry(pxList) listGET_LIST_ITEM_OWNER(listGET_HEAD_ENTRY(pxList))
#define SG_MITER_ATOMIC (1 << 0) /* use kmap_atomic */
#define SG_MITER_TO_SG (1 << 1) /* flush back to phys on unmap */
#define SG_MITER_FROM_SG (1 << 2) /* nop */
void *malloc(size_t size);
extern void free(void *ptr);
struct device {
const char *init_name;
};
#ifdef __cplusplus
}
#endif
#endif

147
A27-STEPLDR/Src/pinctrl.c Normal file
View File

@ -0,0 +1,147 @@
#include "amt630h.h"
#include "pinctrl.h"
#include "sysctl.h"
#define PINCTL_REG_BASE REGS_SYSCTL_BASE
/* typedef struct {
} xPinFunction_t; */
typedef struct {
int reg;
int offset;
int mask;
} xPinmap_t;
static xPinmap_t amt630h_pin_map[] = {
{0xc0, 0, 0x3},
{0xc0, 2, 0x3},
{0xc0, 4, 0x3},
{0xc0, 6, 0x3},
{0xc0, 8, 0x3},
{0xc0, 10, 0x3},
{0xc0, 12, 0x3},
{0xc0, 14, 0x3},
{0xc0, 16, 0x3},
{0xc0, 18, 0x3},
{0xc0, 20, 0x3},
{0xc0, 22, 0x3},
{0xc0, 24, 0x3},
{0xc0, 26, 0x3},
{0xc0, 28, 0x3},
{0xc0, 30, 0x3},
{0xc4, 0, 0x3},
{0xc4, 2, 0x3},
{0xc4, 4, 0x3},
{0xc4, 6, 0x3},
{0xc4, 8, 0x3},
{0xc4, 10, 0x3},
{0xc4, 12, 0x3},
{0xc4, 14, 0x3},
{0xc4, 16, 0x3},
{0xc4, 18, 0x3},
{0xc4, 20, 0x3},
{0xc4, 22, 0x3},
{0xc4, 24, 0x3},
{0xc4, 26, 0x3},
{0xc4, 28, 0x3},
{0xc4, 30, 0x3},
{0xc8, 0, 0x3},
{0xc8, 2, 0x3},
{0xc8, 4, 0x3},
{0xc8, 6, 0x3},
{0xc8, 8, 0x3},
{0xc8, 10, 0x3},
{0xc8, 12, 0x3},
{0xc8, 14, 0x3},
{0xc8, 16, 0x3},
{0xc8, 18, 0x3},
{0xc8, 20, 0x3},
{0xc8, 22, 0x3},
{0xc8, 24, 0x3},
{0xc8, 26, 0x3},
{0xc8, 28, 0x3},
{0xc8, 30, 0x3},
{0xcc, 0, 0x3},
{0xcc, 2, 0x3},
{0xcc, 4, 0x3},
{0xcc, 6, 0x3},
{0xcc, 8, 0x3},
{0xcc, 10, 0x3},
{0xcc, 12, 0x3},
{0xcc, 14, 0x3},
{0xcc, 16, 0x3},
{0xcc, 18, 0x3},
{0xcc, 20, 0x3},
{0xcc, 22, 0x3},
{0xcc, 24, 0x3},
{0xcc, 26, 0x3},
{0xcc, 28, 0x3},
{0xcc, 30, 0x3},
{0xd0, 0, 0x3},
{0xd0, 2, 0x3},
{0xd0, 4, 0x3},
{0xd0, 6, 0x3},
{0xd0, 8, 0x3},
{0xd0, 10, 0x3},
{0xd0, 12, 0x3},
{0xd0, 14, 0x3},
{0xd0, 16, 0x3},
{0xd0, 18, 0x3},
{0xd0, 20, 0x3},
{0xd0, 22, 0x3},
{0xd0, 24, 0x3},
{0xd0, 26, 0x3},
{0xd0, 28, 0x3},
{0xd0, 30, 0x3},
{0xd4, 0, 0x3},
{0xd4, 2, 0x3},
{0xd4, 4, 0x3},
{0xd4, 6, 0x3},
{0xd4, 8, 0x3},
{0xd4, 10, 0x3},
{0xd4, 12, 0x3},
{0xd4, 14, 0x3},
{0xd4, 16, 0x3},
{0xd4, 18, 0x3},
{0xd4, 20, 0x3},
{0xd4, 22, 0x3},
{0xd4, 24, 0x3},
{0xd4, 26, 0x3},
{0xd4, 28, 0x3},
{0xd4, 30, 0x3},
{0xd8, 4, 0x3},
{0xd8, 0, 0x3},
{0xd8, 6, 0x3},
{0xd8, 2, 0x3},
{0xd8, 8, 0x3},
{0xd8, 10, 0x3},
/* pad not mux with gpio */
};
static void pinctrl_set_pin(int npin, int val, int drive)
{
xPinmap_t *pctrl;
uint32_t reg;
pctrl = &amt630h_pin_map[npin];
reg = readl(PINCTL_REG_BASE + pctrl->reg);
reg &= ~(pctrl->mask << pctrl->offset);
reg |= val << pctrl->offset;
writel(reg, PINCTL_REG_BASE + pctrl->reg);
if (drive != PAD_DRIVE_DEFAULT) {
uint32_t drv_reg = SYS_IO_DRIVER00 + npin / 16 * 4;
uint32_t offset = (npin % 16) * 2;
uint32_t drv_val = drive - 1;
vSysctlConfigure(drv_reg, offset, 3, drv_val);
}
}
void pinctrl_gpio_request(int gpio)
{
pinctrl_set_pin(gpio, 0, PAD_DRIVE_DEFAULT);
}

65
A27-STEPLDR/Src/pinctrl.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef _PINCTRL_H
#define _PINCTRL_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PGRP_I2C0,
PGRP_I2C1,
PGRP_LCD_TTL_CH0,
PGRP_LCD_TTL_CH1,
PGRP_LCD_LVDS,
PGRP_LCD_SRGB,
PGRP_LCD_ITU601,
PGRP_UART0,
PGRP_UART1,
PGRP_UART2,
PGRP_UART3,
PGRP_SPI0,
PGRP_SPI1,
PGRP_PWM0,
PGRP_PWM1,
PGRP_PWM2,
PGRP_PWM3,
PGRP_PWM0_IN,
PGRP_PWM1_IN,
PGRP_PWM2_IN,
PGRP_PWM3_IN,
PGRP_SDMMC0,
PGRP_ITU_CH0,
PGRP_ITU_CH0_INV,
PGRP_ITU_CH1,
PGRP_ITU_CH1_INV,
PGRP_CAN0_CH0,
PGRP_CAN0_CH1,
PGRP_CAN0_CH2,
PGRP_CAN1_CH0,
PGRP_CAN1_CH1,
PGRP_CAN1_CH2,
PGRP_I2S0_PLAY,
PGRP_I2S0_RECORD,
PGRP_I2S1_PLAY,
PGRP_I2S1_RECORD,
PGRP_RCRT,
}ePingroupID;
typedef enum {
PAD_DRIVE_DEFAULT,
PAD_DRIVE_2MA,
PAD_DRIVE_4MA,
PAD_DRIVE_8MA,
PAD_DRIVE_12MA,
}ePadDrive;
void vPinctrlSetup(void);
void pinctrl_gpio_request(int gpio);
void pinctrl_set_group(int groupid);
#ifdef __cplusplus
}
#endif
#endif

207
A27-STEPLDR/Src/pxp.c Normal file
View File

@ -0,0 +1,207 @@
#include "FreeRTOS.h"
#include "board.h"
#include "amt630h.h"
#include "pxp.h"
#include "timer.h"
#include "aic.h"
#include "uart.h"
#define PXP_CTRL 0x000
#define PXP_CTRL_SET 0x004
#define PXP_CTRL_CLR 0x008
#define PXP_CTRL_TOG 0x00C
#define PXP_STAT 0x010
#define PXP_STAT_SET 0x014
#define PXP_STAT_CLR 0x018
#define PXP_STAT_TOG 0x01c
#define PXP_OUTBUF 0x020
#define PXP_OUTBUF2 0x030
#define PXP_OUTSIZE 0x040
#define PXP_S0BUF 0x050
#define PXP_S0UBUF 0x060
#define PXP_S0VBUF 0x070
#define PXP_S0PARAM 0x080
#define PXP_S0BACKGROUND 0x090
#define PXP_S0CLIP 0x0A0
#define PXP_S0SCALE 0x0B0
#define PXP_S0OFFSET 0x0C0
#define PXP_CSCCOEFF0 0x0D0
#define PXP_CSCCOEFF1 0x0E0
#define PXP_CSCCOEFF2 0x0F0
#define PXP_NEXT 0x100
#define PXP_PAGETABLE 0x170
#define PXP_S0CKEYL 0x180
#define PXP_S0CKEYH 0x190
#define PXP_OLCKEYL 0x1A0
#define PXP_OLCKEYH 0x1B0
#define PXP_OL0BUF 0x200
#define PXP_OL0SIZE 0x210
#define PXP_OL0PARAM 0x220
#define PXP_OL1BUF 0x240
#define PXP_OL1SIZE 0x250
#define PXP_OL1PARAM 0x260
#define PXP_OL2BUF 0x280
#define PXP_OL2SIZE 0x290
#define PXP_OL2PARAM 0x2A0
#define PXP_OL3BUF 0x2C0
#define PXP_OL3SIZE 0x2D0
#define PXP_OL3PARAM 0x2E0
#define PXP_OL4BUF 0x300
#define PXP_OL4SIZE 0x310
#define PXP_OL4PARAM 0x320
#define PXP_OL5BUF 0x340
#define PXP_OL5SIZE 0x350
#define PXP_OL5PARAM 0x360
#define PXP_OL6BUF 0x380
#define PXP_OL6SIZE 0x390
#define PXP_OL6PARAM 0x3A0
#define PXP_OL7BUF 0x3C0
#define PXP_OL7SIZE 0x3D0
#define PXP_OL7PARAM 0x3E0
// offss for "NEXT" pointers
#define PXP_NEXTCTRL 0x000
#define PXP_NEXTRGBBUF 0x004
#define PXP_NEXTRGBBUF2 0x008
#define PXP_NEXTRGBSIZE 0x00C
#define PXP_NEXTS0BUF 0x010
#define PXP_NEXTS0UBUF 0x014
#define PXP_NEXTS0VBUF 0x018
#define PXP_NEXTS0PARAM 0x01C
#define PXP_NEXTS0BACKGROUND 0x020
#define PXP_NEXTS0CLIP 0x024
#define PXP_NEXTS0SCALE 0x028
#define PXP_NEXTS0OFFSET 0x02C
#define PXP_NEXTS0CKEYL 0x030
#define PXP_NEXTS0CKEYH 0x034
#define PXP_NEXTOLCKEYL 0x038
#define PXP_NEXTOLCKEYH 0x03C
#define PXP_NEXTOL0BUF 0x040
#define PXP_NEXTOL0SIZE 0x044
#define PXP_NEXTOL0PARAM 0x048
#define PXP_NEXTOL1BUF 0x050
#define PXP_NEXTOL1SIZE 0x054
#define PXP_NEXTOL1PARAM 0x058
#define PXP_NEXTOL2BUF 0x060
#define PXP_NEXTOL2SIZE 0x064
#define PXP_NEXTOL2PARAM 0x068
#define PXP_NEXTOL3BUF 0x070
#define PXP_NEXTOL3SIZE 0x074
#define PXP_NEXTOL3PARAM 0x078
#define PXP_NEXTOL4BUF 0x080
#define PXP_NEXTOL4SIZE 0x084
#define PXP_NEXTOL4PARAM 0x088
#define PXP_NEXTOL5BUF 0x090
#define PXP_NEXTOL5SIZE 0x094
#define PXP_NEXTOL5PARAM 0x098
#define PXP_NEXTOL6BUF 0x0A0
#define PXP_NEXTOL6SIZE 0x0A4
#define PXP_NEXTOL6PARAM 0x0A8
#define PXP_NEXTOL7BUF 0x0B0
#define PXP_NEXTOL7SIZE 0x0B4
#define PXP_NEXTOL7PARAM 0x0B8
static uint32_t pxpbase = REGS_PXP_BASE;
void waitforpxp_done(unsigned int count)
{
uint32_t status = 0;
while(count--)
{
status = readl(pxpbase + PXP_STAT);
// printf("+++++++++++status 0x%x++++++++++++++\n",status);
if(status & 1)
break;
}
if(count == 0)
SendUartString("pxp timeout.\n");
}
/* this function can not used in isr */
int pxp_scaler_rotate(uint32_t s0buf, uint32_t s0ubuf, uint32_t s0vbuf,
int s0format, uint32_t s0width, uint32_t s0height,
uint32_t outbuf, uint32_t outbuf2, int outformat,
uint32_t outwidth, uint32_t outheight, int outangle)
{
uint32_t ctrl;
int ret = 0;
configASSERT(outangle >= PXP_ROTATE_0 && outangle <= PXP_ROTATE_270);
if (outangle == PXP_ROTATE_90 || outangle == PXP_ROTATE_270) {
uint32_t tmp = outheight;
outheight = outwidth;
outwidth = tmp;
}
writel(1UL << 31, pxpbase + PXP_CTRL);
udelay(10);
writel(0, pxpbase + PXP_CTRL);
writel(outbuf, pxpbase + PXP_OUTBUF);
writel(outbuf2, pxpbase + PXP_OUTBUF2);
writel((0xffUL << 24) | (outwidth << 12) | outheight, pxpbase + PXP_OUTSIZE);
writel(s0buf, pxpbase + PXP_S0BUF);
writel(s0ubuf, pxpbase + PXP_S0UBUF);
writel(s0vbuf, pxpbase + PXP_S0VBUF);
writel((((s0width >> 3) & 0xff) << 8) | ((s0height >> 3) & 0xff), pxpbase + PXP_S0PARAM);
writel(0, pxpbase + PXP_S0BACKGROUND);
writel((((outwidth >> 3) & 0xff) << 8) | ((outheight >> 3) & 0xff), pxpbase + PXP_S0CLIP);
writel(((s0height * 0x1000 / (outheight + 2)) << 16) | (s0width * 0x1000 / (outwidth + 2)),
pxpbase + PXP_S0SCALE);
//YCbCr->RGB Coefficient Values bit31 ycbcr_mode
writel((1 << 31) | 0x1f0 | (0x180 << 9) | (0x12a << 18), pxpbase + PXP_CSCCOEFF0);
writel(0x204 | (0x198 <<16), pxpbase + PXP_CSCCOEFF1);
writel(0x79c | (0x730 <<16), pxpbase + PXP_CSCCOEFF2);
ctrl = (1 << 19) | (1 << 18) | ((s0format & 0xf) << 12) | (outangle << 8) |
#ifdef PXP_OUTPUT_MIRROR
(1<< 10) |
#endif
((outformat & 0xf) << 4) | 3;
writel(ctrl, pxpbase + PXP_CTRL);
waitforpxp_done(10000000);
return ret;
}
int pxp_rotate(uint32_t s0buf, uint32_t s0ubuf, uint32_t s0vbuf,
int s0format, uint32_t s0width, uint32_t s0height,
uint32_t outbuf, uint32_t outbuf2, int outformat,
int outangle)
{
uint32_t ctrl;
int ret = 0;
configASSERT(outangle >= PXP_ROTATE_0 && outangle <= PXP_ROTATE_270);
writel(1UL << 31, pxpbase + PXP_CTRL);
udelay(10);
writel(0, pxpbase + PXP_CTRL);
writel(outbuf, pxpbase + PXP_OUTBUF);
writel(outbuf2, pxpbase + PXP_OUTBUF2);
writel((0xffUL << 24) | (s0width << 12) | s0height, pxpbase + PXP_OUTSIZE);
writel(s0buf, pxpbase + PXP_S0BUF);
writel(s0ubuf, pxpbase + PXP_S0UBUF);
writel(s0vbuf, pxpbase + PXP_S0VBUF);
writel((((s0width >> 3) & 0xff) << 8) | ((s0height >> 3) & 0xff), pxpbase + PXP_S0PARAM);
writel(0, pxpbase + PXP_S0BACKGROUND);
//YCbCr->RGB Coefficient Values bit31 ycbcr_mode
writel((1 << 31) | 0x1f0 | (0x180 << 9) | (0x12a << 18), pxpbase + PXP_CSCCOEFF0);
writel(0x204 | (0x198 <<16), pxpbase + PXP_CSCCOEFF1);
writel(0x79c | (0x730 <<16), pxpbase + PXP_CSCCOEFF2);
ctrl = ((s0format & 0xf) << 12) | (outangle << 8) |
#ifdef PXP_OUTPUT_MIRROR
(1<< 10) |
#endif
((outformat & 0xf) << 4) | 3;
writel(ctrl, pxpbase + PXP_CTRL);
waitforpxp_done(10000);
return ret;
}

51
A27-STEPLDR/Src/pxp.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef _PXP_H
#define _PXP_H
typedef enum {
PXP_SRC_FMT_RGB888 = 0x1, /* 32-bit pixels (unpacked 24-bit format) */
PXP_SRC_FMT_RGB565 = 0x4, /* 16-bit pixels */
PXP_SRC_FMT_RGB555 = 0x5, /* 16-bit pixels */
PXP_SRC_FMT_YUV422 = 0x8, /* 16-bit pixels */
PXP_SRC_FMT_YUV420 = 0x9, /* 16-bit pixels */
PXP_SRC_FMT_UYVY1P422 = 0xa, /* 16-bit pixels (1-plane U0,Y0,V0,Y1 interleaved bytes) */
PXP_SRC_FMT_VYUY1P422 = 0xb, /* 16-bit pixels (1-plane V0,Y0,U0,Y1 interleaved bytes) */
PXP_SRC_FMT_YUV2P422 = 0xc, /* 16-bit pixels (2-plane UV interleaved bytes) */
PXP_SRC_FMT_YUV2P420 = 0xd, /* 16-bit pixels */
PXP_SRC_FMT_YVU2P422 = 0xe, /* 16-bit pixels (2-plane VU interleaved bytes) */
PXP_SRC_FMT_YVU2P420 = 0xf, /* 16-bit pixels */
} PXP_SRC_FMT;
typedef enum {
PXP_OUT_FMT_ARGB8888 = 0x0, /* 32-bit pixels */
PXP_OUT_FMT_RGB888 = 0x1, /* 32-bit pixels (unpacked 24-bit pixel in 32 bit DWORD.) */
PXP_OUT_FMT_RGB888P = 0x2, /* 24-bit pixels (packed 24-bit format) */
PXP_OUT_FMT_ARGB1555 = 0x3, /* 16-bit pixels */
PXP_OUT_FMT_RGB565 = 0x4, /* 16-bit pixels */
PXP_OUT_FMT_RGB555 = 0x5, /* 16-bit pixels */
PXP_OUT_FMT_YUV444 = 0x7, /* 32-bit pixels (1-plane XYUV unpacked) */
PXP_OUT_FMT_UYVY1P422 = 0xa, /* 16-bit pixels (1-plane U0,Y0,V0,Y1 interleaved bytes) */
PXP_OUT_FMT_VYUY1P422 = 0xb, /* 16-bit pixels (1-plane V0,Y0,U0,Y1 interleaved bytes) */
PXP_OUT_FMT_YUV2P422 = 0xc, /* 16-bit pixels (2-plane UV interleaved bytes) */
PXP_OUT_FMT_YUV2P420 = 0xd, /* 16-bit pixels (2-plane VU) */
PXP_OUT_FMT_YVU2P422 = 0xe, /* 16-bit pixels (2-plane VU interleaved bytes) */
PXP_OUT_FMT_YVU2P420 = 0xf, /* 16-bit pixels (2-plane VU) */
} PXP_OUT_FMT;
/* clockwise rotate */
typedef enum {
PXP_ROTATE_0 = 0,
PXP_ROTATE_90 = 1,
PXP_ROTATE_180 = 2,
PXP_ROTATE_270 = 3,
} PXP_ROTATE;
int pxp_scaler_rotate(uint32_t s0buf, uint32_t s0ubuf, uint32_t s0vbuf,
int s0format, uint32_t s0width, uint32_t s0height,
uint32_t outbuf, uint32_t outbuf2, int outformat,
uint32_t outwidth, uint32_t outheight, int outangle);
int pxp_rotate(uint32_t s0buf, uint32_t s0ubuf, uint32_t s0vbuf,
int s0format, uint32_t s0width, uint32_t s0height,
uint32_t outbuf, uint32_t outbuf2, int outformat,
int outangle);
#endif

1752
A27-STEPLDR/Src/sdmmc.c Normal file

File diff suppressed because it is too large Load Diff

303
A27-STEPLDR/Src/sdmmc.h Normal file
View File

@ -0,0 +1,303 @@
/*
**********************************************************************
Copyright (c)2007 Arkmicro Technologies Inc. All Rights Reserved
Filename: sdmmc.h
Version : 1.1
Date : 2008.01.08
Author : wx(Modify by Salem)
Abstract: ark1610 soc sd driver
History :
***********************************************************************
*/
#ifndef SDMMC_H
#define SDMMC_H
#define SD_DEBUG 0
typedef unsigned long ulong;
typedef ulong lbaint_t;
#define SDMMC_RW_SUCCES 0
#define SDMMC_RW_TIMEOUT -1
#define SDMMC_RW_DMAREAD_FAIL -2
#define SDMMC_RW_DMAWRITE_FAIL -3
#define SDMMC_RW_CMDTIMEROUT -4
#define PWREN_ON 0x00000000 //turn on all card power
#define PWREN_OFF 0xFFFFFFFF //turn off all card power
#define CLK_CLKEN 0x0000ffff //
#define CLK_CLKDIS 0x00000000 // disable clk
#define CLK_DIV_INITIAL 0x00000010 //initial choose frequency
#define CLK_DIV_NORMAL 0x00000000 //data transfers clk frequency
#define CLK_SRC 0x00000000 //
#define CMD_CHANG_CLK 0x80202000 //chang clk
#define CMD_INITIAL_CLK 0x80008000 //initial clk before work
#define CMD0_GO_IDLE 0x80000000 //go idle
#define CMD1_MATCH_VCC 0x80000041 //turn on for match vcc
#define CMD2_CID 0x800001c2 //initial card get CID
#define CMD3_RCA 0x80000143 //comfire RCA to card
#define CMD6_SWTICH 0x80000346 //switch function
#define CMD7_SELECT_CARD 0x80000147 //select card
#define CMD8_SPEC 0x80000048 //confire specfic
#define CMD9_CSD 0x800001c9 //get CSD
#define CMD10_CID 0x800001ca //get CID at transfers
#define CMD12_STOP_STEARM 0x8000004c //stop block transfers
#define CMD13_STATUS_CARD 0x8000014D //get card status
#define CMD15_INACTIVE 0x8000000F //make card to inactive
#define CMD16_SET_BLOCKLEN 0x80000150 //set card block length
#define CMD17_READ_SINGLE 0x80000351 //single block read
#define CMD18_READ_MUL 0x80001352 //multipe block read
#define CMD23_PRE_ERASE 0x80000157 //pre erase for write
#define CMD24_WRITE_SINGLE 0x80000758 //single block write
#define CMD25_WRITE_MUL 0x80000759 //multipe block write
#define CMD27_PROG_CSD 0x8000065b //programme csd
#define CMD28_SET_PROTECT 0x8000015c //set protect
#define CMD29_CLR_PROTECT 0x8000015d //clearn protect
#define CMD30_SEND_WRITE 0x8000025e //get the status about protect
#define CMD32_ERASESD_START 0x80000160 //set start erase SD card address
#define CMD33_ERASESD_END 0x80000161 //set end erase SD card address
#define CMD38_ERASE 0x80000166 //confirm erase
#define CMD41_MATCH_VCC 0x80000169 //FOR SD
#define CMD55_APP 0x80000177 //APP CMD
#define ACMD6_WID 0x80000146 //set bus width
#define ACMD13_GET_STATUS 0x8000024d //get status 512 bit
#define ACMD42_DISCON_DATA3 0x8000016a //make data3 disconnect
#define ACMD51_GET_CSR 0x80000273 //get card csr
//=======================MMC set bus==========================
#define CMD6_SWITH 0x80000446 //set bus width
//================================================
#define MMC_ERASE_ARG 0x00000000
#define MMC_CMD_GO_IDLE_STATE 0
#define MMC_CMD_SEND_OP_COND 1
#define MMC_CMD_ALL_SEND_CID 2
#define MMC_CMD_SET_RELATIVE_ADDR 3
#define MMC_CMD_SET_DSR 4
#define MMC_CMD_SWITCH 6
#define MMC_CMD_SELECT_CARD 7
#define MMC_CMD_SEND_EXT_CSD 8
#define MMC_CMD_SEND_CSD 9
#define MMC_CMD_SEND_CID 10
#define MMC_CMD_STOP_TRANSMISSION 12
#define MMC_CMD_SEND_STATUS 13
#define MMC_CMD_SET_BLOCKLEN 16
#define MMC_CMD_READ_SINGLE_BLOCK 17
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
#define MMC_CMD_SEND_TUNING_BLOCK 19
#define MMC_CMD_SEND_TUNING_BLOCK_HS200 21
#define MMC_CMD_SET_BLOCK_COUNT 23
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
#define MMC_CMD_ERASE_GROUP_START 35
#define MMC_CMD_ERASE_GROUP_END 36
#define MMC_CMD_ERASE 38
#define MMC_CMD_APP_CMD 55
#define MMC_CMD_SPI_READ_OCR 58
#define MMC_CMD_SPI_CRC_ON_OFF 59
#define MMC_CMD_RES_MAN 62
#define MMC_CMD62_ARG1 0xefac62ec
#define MMC_CMD62_ARG2 0xcbaea7
#define SD_CMD_SEND_RELATIVE_ADDR 3
#define SD_CMD_SWITCH_FUNC 6
#define SD_CMD_SEND_IF_COND 8
#define SD_CMD_SWITCH_UHS18V 11
#define SD_CMD_APP_SET_BUS_WIDTH 6
#define SD_CMD_APP_SD_STATUS 13
#define SD_CMD_ERASE_WR_BLK_START 32
#define SD_CMD_ERASE_WR_BLK_END 33
#define SD_CMD_APP_SEND_OP_COND 41
#define SD_CMD_APP_SEND_SCR 51
#define MMC_RSP_PRESENT (1 << 0)
#define MMC_RSP_136 (1 << 1) /* 136 bit response */
#define MMC_RSP_CRC (1 << 2) /* expect valid crc */
#define MMC_RSP_BUSY (1 << 3) /* card may send busy */
#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */
#define MMC_RSP_NONE (0)
#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R1b (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE| \
MMC_RSP_BUSY)
#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
#define MMC_RSP_R4 (MMC_RSP_PRESENT)
#define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define OCR_BUSY 0x80000000
#define OCR_HCS 0x40000000
#define OCR_S18R 0x1000000
#define OCR_VOLTAGE_MASK 0x007FFF80
#define OCR_ACCESS_MODE 0x60000000
#define MMC_STATUS_MASK (~0x0206BF7F)
#define MMC_STATUS_SWITCH_ERROR (1 << 7)
#define MMC_STATUS_RDY_FOR_DATA (1 << 8)
#define MMC_STATUS_CURR_STATE (0xf << 9)
#define MMC_STATUS_ERROR (1 << 19)
#define MMC_STATE_PRG (7 << 9)
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in EXT_CSD byte
addressed by index which are
1 in value field */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in EXT_CSD byte
addressed by index, which are
1 in value field */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target byte to value */
#define SD_SWITCH_CHECK 0
#define SD_SWITCH_SWITCH 1
/*
* EXT_CSD fields
*/
#define EXT_CSD_ENH_START_ADDR 136 /* R/W */
#define EXT_CSD_ENH_SIZE_MULT 140 /* R/W */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_SETTING 155 /* R/W */
#define EXT_CSD_PARTITIONS_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_MAX_ENH_SIZE_MULT 157 /* R */
#define EXT_CSD_PARTITIONING_SUPPORT 160 /* RO */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
#define EXT_CSD_BKOPS_EN 163 /* R/W & R/W/E */
#define EXT_CSD_WR_REL_PARAM 166 /* R */
#define EXT_CSD_WR_REL_SET 167 /* R/W */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_BOOT_BUS_WIDTH 177
#define EXT_CSD_PART_CONF 179 /* R/W */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_CMD_SET_NORMAL (1 << 0)
#define EXT_CSD_CMD_SET_SECURE (1 << 1)
#define EXT_CSD_CMD_SET_CPSECURE (1 << 2)
#define EXT_CSD_CARD_TYPE_26 (1 << 0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_52 (1 << 1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1 << 2)
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1 << 3)
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_HS200_1_8V BIT(4) /* Card can run at 200MHz */
/* SDR mode @1.8V I/O */
#define EXT_CSD_CARD_TYPE_HS200_1_2V BIT(5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_DDR_FLAG BIT(2) /* Flag for DDR mode */
#define EXT_CSD_TIMING_LEGACY 0 /* no high speed */
#define EXT_CSD_TIMING_HS 1 /* HS */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_BOOT_ACK_ENABLE (1 << 6)
#define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3)
#define EXT_CSD_PARTITION_ACCESS_ENABLE (1 << 0)
#define EXT_CSD_PARTITION_ACCESS_DISABLE (0 << 0)
#define EXT_CSD_BOOT_ACK(x) (x << 6)
#define EXT_CSD_BOOT_PART_NUM(x) (x << 3)
#define EXT_CSD_PARTITION_ACCESS(x) (x << 0)
#define EXT_CSD_EXTRACT_BOOT_ACK(x) (((x) >> 6) & 0x1)
#define EXT_CSD_EXTRACT_BOOT_PART(x) (((x) >> 3) & 0x7)
#define EXT_CSD_EXTRACT_PARTITION_ACCESS(x) ((x) & 0x7)
#define EXT_CSD_BOOT_BUS_WIDTH_MODE(x) (x << 3)
#define EXT_CSD_BOOT_BUS_WIDTH_RESET(x) (x << 2)
#define EXT_CSD_BOOT_BUS_WIDTH_WIDTH(x) (x)
#define EXT_CSD_PARTITION_SETTING_COMPLETED (1 << 0)
#define EXT_CSD_ENH_USR (1 << 0) /* user data area is enhanced */
#define EXT_CSD_ENH_GP(x) (1 << ((x)+1)) /* GP part (x+1) is enhanced */
#define EXT_CSD_HS_CTRL_REL (1 << 0) /* host controlled WR_REL_SET */
#define EXT_CSD_WR_DATA_REL_USR (1 << 0) /* user data area WR_REL */
#define EXT_CSD_WR_DATA_REL_GP(x) (1 << ((x)+1)) /* GP part (x+1) WR_REL */
#define MMC_DATA_READ 1
#define MMC_DATA_WRITE 2
/* Maximum block size for MMC */
#define MMC_MAX_BLOCK_LEN 512
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
struct mmc_cmd {
USHORT cmdidx;
UINT resp_type;
UINT cmdarg;
UINT response[4];
};
struct mmc_data {
union {
char *dest;
const char *src; /* src buffers don't get written to */
};
UINT flags;
UINT blocks;
UINT blocksize;
};
int EmmcBurn(void *buf, unsigned int offset, unsigned int size, int show_progress);
ulong mmc_berase( lbaint_t start, lbaint_t blkcnt);
unsigned int mmc_write(void *buf, unsigned int offset, unsigned int size, int show_progress);
void Emmcinit(int chipid);
void bootFromEmmc(int chipid);
unsigned int EmmcGetUpfileOffset(int type);
#endif

82
A27-STEPLDR/Src/spi.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef __SPI_H__
#define __SPI_H__
#include "update.h"
#define MAX_WAIT_LOOP_COUNT 100000
#define SPI_WRITE_ENABLE 0x06
#define SPI_WRITE_DISABLE 0x04
#define SPI_READ_STATUS 0x05
#define SPI_READ_STATUS2 0x35
#define SPI_READ_STATUS3 0x15
#define SPI_WRITE_STATUS 0x01
#define SPI_WRITE_STATUS2 0x31
#define SPI_READ_DATA 0x03
#define SPI_4BYTEADDR_READ_DATA 0x13
#define SPI_FAST_READ 0x0B
#define SPI_PAGE_PROGRAM 0x02
#define SPI_4BYTEADD_PAGE_PROGRAM 0x12
#define SPI_SECTOR_ERASE 0x20
#define SPI_4BYTEADD_SECTOR_ERASE 0x21
#define SPI_SECTOR_ERASE_1 0xD7
#define SPI_BLOCK_ERASE 0xD8
#define SPI_4BYTEADD_BLOCK_ERASE 0xDC
#define SPI_BLOCK_ERASE_1 0x52
#define SPI_CHIP_ERASE 0xC7
#define SPI_CHIP_ERASE_1 0x60
#define SPI_POWER_DOWN 0xB9
#define SPI_READ_JEDEC_ID 0x9F
#define SPI_READ_ID_1 0xAB
#define SPI_MF_DEVICE_ID 0x90
#define SPI_MF_DEVICE_ID_1 0x15
#define SPI_READ_ELECTRON_SIGN 0xAB
#define SPI_MF_WINBOND 0xEF
#define SPI_MF_EON 0x1C
#define SPI_MF_AMIC 0x37
#define SPI_MF_ATMEL 0x1F
#define SPI_MF_SST 0xBF
#define SPI_MF_MXIC 0xC2
#define SPI_ENABLE_4BYTE_MODE 0xB7
#define SPI_DISABLE_4BYTE_MODE 0xE9
#define SPI_QUAD_IO_READ_DATA 0xEB
#define SPI_BUSY (1<<0)
#define SPIFLASH_WRITEENABLE (1<<1)
#define SPI_QE (1 << 1)
#define SPI_SSI_QE (1 << 6)
#define SPI_MIC_QE (1 << 6)
#define SPI_WRITE_DMA
#define SPI_READ_DMA
#define WORDSPERPAGE 64
#define BYTESPERPAGE 256
#define PAGESPERSECTORS 16
#define SECTORSPERBLOCK 16
#define BLOCKSPERFLASH 64
#define BYTESPERBLOCK (BYTESPERPAGE*PAGESPERSECTORS*SECTORSPERBLOCK)
#define BYTESPERSECTOR (BYTESPERPAGE*PAGESPERSECTORS)
#define PAGES_PER_BLOCK 64
#define BYTES_PER_PAGE 2048
void SpiSelectPad(void);
int SpiInit(void);
void SpiBurnLoad(void);
void SpiReadId(void);
int FlashBurn(void *buf, unsigned int offset, unsigned int size, int show_progress);
unsigned int SpiGetUpfileOffset(int type);
#endif

376
A27-STEPLDR/Src/st7701s.c Normal file
View File

@ -0,0 +1,376 @@
/*
* ST7701S LCD Display.
*
* LCD Type: AMT TFT
* Display Format: 320(RGB)*960
* Input Data: RGB 16bits(RGB565)
*/
#include "board.h"
#include "gpio.h"
#include "timer.h"
//3 lines mode spi.
#define ST7701S_GPIO_SPI_CS 23
#define ST7701S_GPIO_SPI_SCL 24
#define ST7701S_GPIO_SPI_SDA 25
#define ST7701S_GPIO_SPI_RST 26
#define ST7701S_DELAY udelay(5)
static void SPI_SendData(unsigned char value)
{
int i;
for(i=0; i<8; i++)
{
if(value & 0x80)
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 1); //SDA=1
else
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
value<<= 1;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
ST7701S_DELAY;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
ST7701S_DELAY;
}
}
static void SPI_WriteComm(unsigned char value)
{
gpio_direction_output(ST7701S_GPIO_SPI_CS, 0); //CS=0
//D/CX = 0
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
ST7701S_DELAY;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
ST7701S_DELAY;
//Command data.
SPI_SendData(value);
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
ST7701S_DELAY;
}
static void SPI_WriteData(unsigned char value)
{
gpio_direction_output(ST7701S_GPIO_SPI_CS, 0); //CS=0
//D/CX = 1
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 1); //SDA=1
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
ST7701S_DELAY;
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
ST7701S_DELAY;
//Parameter data.
SPI_SendData(value);
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
ST7701S_DELAY;
}
static void st7701s_reg_init(void)
{
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x13);
SPI_WriteComm (0xEF);
SPI_WriteData (0x08);
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x10);
SPI_WriteComm (0xC0);
SPI_WriteData (0x77);
SPI_WriteData (0x00);
SPI_WriteComm (0xC1); //proch control.
SPI_WriteData (0x09); //vbp
SPI_WriteData (0x08); //vfp
SPI_WriteComm (0xC2); //inv
#if 0
SPI_WriteData (0x01);
#else
SPI_WriteData (0x07);
#endif
SPI_WriteData (0x02);
//default:0x00, DE mode.
SPI_WriteComm (0xC3); //RGB control.
SPI_WriteData (0x02); //82 HVmode 02 DEmode
#if 0 //default:0x00
SPI_WriteComm (0xC7); //add. Source direction control.
SPI_WriteData (0x04); //0x00:Source form 0 to 479, 0x04:from 479 to 0.
#endif
SPI_WriteComm (0xCC);
SPI_WriteData (0x10);
SPI_WriteComm (0xB0);
SPI_WriteData (0x40);
SPI_WriteData (0x14);
SPI_WriteData (0x59);
SPI_WriteData (0x10);
SPI_WriteData (0x12);
SPI_WriteData (0x08);
SPI_WriteData (0x03);
SPI_WriteData (0x09);
SPI_WriteData (0x05);
SPI_WriteData (0x1E);
SPI_WriteData (0x05);
SPI_WriteData (0x14);
SPI_WriteData (0x10);
SPI_WriteData (0x68);
SPI_WriteData (0x33);
SPI_WriteData (0x15);
SPI_WriteComm (0xB1);
SPI_WriteData (0x40);
SPI_WriteData (0x08);
SPI_WriteData (0x53);
SPI_WriteData (0x09);
SPI_WriteData (0x11);
SPI_WriteData (0x09);
SPI_WriteData (0x02);
SPI_WriteData (0x07);
SPI_WriteData (0x09);
SPI_WriteData (0x1A);
SPI_WriteData (0x04);
SPI_WriteData (0x12);
SPI_WriteData (0x12);
SPI_WriteData (0x64);
SPI_WriteData (0x29);
SPI_WriteData (0x29);
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x11);
SPI_WriteComm (0xB0);
SPI_WriteData (0x6D); //6D
SPI_WriteComm (0xB1); //vcom
SPI_WriteData (0x1D);
SPI_WriteComm (0xB2);
SPI_WriteData (0x87);
SPI_WriteComm (0xB3);
SPI_WriteData (0x80);
SPI_WriteComm (0xB5);
SPI_WriteData (0x49);
SPI_WriteComm (0xB7);
SPI_WriteData (0x85);
SPI_WriteComm (0xB8);
SPI_WriteData (0x20);
SPI_WriteComm (0xC1);
SPI_WriteData (0x78);
SPI_WriteComm (0xC2);
SPI_WriteData (0x78);
SPI_WriteComm (0xD0);
SPI_WriteData (0x88);
SPI_WriteComm (0xE0);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x02);
SPI_WriteComm (0xE1);
SPI_WriteData (0x02);
SPI_WriteData (0x8C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x03);
SPI_WriteData (0x8C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteComm (0xE2);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteData (0xC9);
SPI_WriteData (0x3C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0xCA);
SPI_WriteData (0x3C);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteComm (0xE3);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteComm (0xE4);
SPI_WriteData (0x44);
SPI_WriteData (0x44);
SPI_WriteComm (0xE5);
SPI_WriteData (0x05);
SPI_WriteData (0xCD);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x01);
SPI_WriteData (0xC9);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x07);
SPI_WriteData (0xCF);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x03);
SPI_WriteData (0xCB);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteComm (0xE6);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x33);
SPI_WriteData (0x33);
SPI_WriteComm (0xE7);
SPI_WriteData (0x44);
SPI_WriteData (0x44);
SPI_WriteComm (0xE8);
SPI_WriteData (0x06);
SPI_WriteData (0xCE);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x02);
SPI_WriteData (0xCA);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x08);
SPI_WriteData (0xD0);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteData (0x04);
SPI_WriteData (0xCC);
SPI_WriteData (0x82);
SPI_WriteData (0x82);
SPI_WriteComm (0xEB);
SPI_WriteData (0x08);
SPI_WriteData (0x01);
SPI_WriteData (0xE4);
SPI_WriteData (0xE4);
SPI_WriteData (0x88);
SPI_WriteData (0x00);
SPI_WriteData (0x40);
SPI_WriteComm (0xEC);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteComm (0xED);
SPI_WriteData (0xFF);
SPI_WriteData (0xF0);
SPI_WriteData (0x07);
SPI_WriteData (0x65);
SPI_WriteData (0x4F);
SPI_WriteData (0xFC);
SPI_WriteData (0xC2);
SPI_WriteData (0x2F);
SPI_WriteData (0xF2);
SPI_WriteData (0x2C);
SPI_WriteData (0xCF);
SPI_WriteData (0xF4);
SPI_WriteData (0x56);
SPI_WriteData (0x70);
SPI_WriteData (0x0F);
SPI_WriteData (0xFF);
SPI_WriteComm (0xEF);
SPI_WriteData (0x10);
SPI_WriteData (0x0D);
SPI_WriteData (0x04);
SPI_WriteData (0x08);
SPI_WriteData (0x3F);
SPI_WriteData (0x1F);
SPI_WriteComm (0xFF);
SPI_WriteData (0x77);
SPI_WriteData (0x01);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
SPI_WriteData (0x00);
mdelay(114); //Sleep out cmd cannot be send after hw-reset for 120ms.
SPI_WriteComm (0x11); //sleep out.
SPI_WriteComm (0x35);
SPI_WriteData (0x00);
#if 0
SPI_WriteComm (0x36); //
SPI_WriteData (0x10); //bit4(0:normal scan, 1:inverse scan); bit3(0:RGB, 1:BGR), default:0x00
#endif
SPI_WriteComm (0x3A); //RGB Interface pixel format.
SPI_WriteData (0x77); //bit[4-6](101:16-bit/pixel; 110:18-bit/pixel;111:24-bit/pixel), default:0x70
//SPI_WriteComm (0x11);
//Delay(120);
SPI_WriteComm (0x29); //display on.
}
static void st7701s_hw_reset(void)
{
gpio_direction_output(ST7701S_GPIO_SPI_RST, 1);
mdelay(10);
gpio_direction_output(ST7701S_GPIO_SPI_RST, 0);
mdelay(1); //>=9us
gpio_direction_output(ST7701S_GPIO_SPI_RST, 1);
mdelay(6); //>=5ms
}
int st7701s_init(void)
{
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
st7701s_hw_reset();
st7701s_reg_init();
return 0;
}

10
A27-STEPLDR/Src/sysctl.c Normal file
View File

@ -0,0 +1,10 @@
#include "amt630h.h"
void vSysctlConfigure(uint32_t regoffset, uint32_t bitoffset, uint32_t mask, uint32_t val)
{
uint32_t tmp = readl(REGS_SYSCTL_BASE + regoffset);
tmp &= ~(mask << bitoffset);
tmp |= val << bitoffset;
writel(tmp, REGS_SYSCTL_BASE + regoffset);
}

59
A27-STEPLDR/Src/sysctl.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef _SYSCTL_H
#define _SYSCTL_H
#ifdef __cplusplus
extern "C" {
#endif
#define SYS_BOOT_SAMPLE 0x0
#define SYS_BUS_CLK_CFG 0x40
#define SYS_PER_CLK_CFG 0x44
#define SYS_SDMMC_CLK_CFG 0x48
#define SYS_VOU_CLK_CFG 0x4c
#define SYS_BUS_CLK_EN 0x50
#define SYS_BUS1_CLK_EN 0x54
#define SYS_PER_CLK_EN 0x58
#define SYS_SOFT_RST 0x5c
#define SYS_SOFT1_RST 0x60
#define SYS_SSP_CLK_CFG 0x64
#define SYS_TIMER_CLK_CFG 0x68
#define SYS_I2S_NCO_CFG 0x6c
#define SYS_DDRCTL_CFG 0x70
#define SYS_PERCTL_CFG 0x78
#define SYS_TIMER1_CLK_CFG 0x7c
#define SYS_ANA_CFG 0x80
#define SYS_ANA1_CFG 0x84
#define SYS_CPUPLL_CFG 0x88
#define SYS_SYSPLL_CFG 0x8c
#define SYS_ANA2_CFG 0x98
#define SYS_ANA3_CFG 0x9c
#define SYS_ANA4_CFG 0xa0
#define SYS_PAD_CTRL00 0xc0
#define SYS_PAD_CTRL01 0xc4
#define SYS_PAD_CTRL02 0xc8
#define SYS_PAD_CTRL03 0xcc
#define SYS_PAD_CTRL04 0xd0
#define SYS_PAD_CTRL05 0xd4
#define SYS_PAD_CTRL06 0xd8
#define SYS_PAD_CTRL07 0xdc
#define SYS_IO_DRIVER00 0xe0
#define SYS_IO_DRIVER01 0xe4
#define SYS_IO_DRIVER02 0xe8
#define SYS_IO_DRIVER03 0xec
#define SYS_IO_DRIVER04 0xf0
#define SYS_IO_DRIVER05 0xf4
#define SYS_IO_DRIVER06 0xf8
#define SYS_IO_DRIVER07 0xfc
extern void vSysctlConfigure(uint32_t regoffset, uint32_t bitoffset, uint32_t mask, uint32_t val);
#ifdef __cplusplus
}
#endif
#endif

52
A27-STEPLDR/Src/sysinfo.c Normal file
View File

@ -0,0 +1,52 @@
#include "amt630h.h"
#include "sysinfo.h"
#include "crc32.h"
extern int SpiReadSysInfo(SysInfo *info);
extern void SpiWriteSysInfo(SysInfo *info);
extern int EmmcReadSysInfo(SysInfo *info);
extern void EmmcWriteSysInfo(SysInfo *info);
static SysInfo sysinfo = {0};
SysInfo *GetSysInfo(void)
{
return &sysinfo;
}
void SetDefaultSysInfo(void)
{
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sysinfo.update_media_type = UPDATE_MEDIA_SD;
#else
sysinfo.update_media_type = UPDATE_MEDIA_USB;
sysinfo.loader_offset = LOADERB_OFFSET;
sysinfo.loader_size = LOADER_MAX_SIZE;
sysinfo.image_offset = IMAGEB_OFFSET;
#endif
sysinfo.image_offset = IMAGE_OFFSET;
sysinfo.update_status = UPDATE_STATUS_START;
sysinfo.stepldr_offset = STEPLDRB_OFFSET;
sysinfo.stepldr_size = STEPLDR_MAX_SIZE;
}
int ReadSysInfo(void)
{
#if DEVICE_TYPE_SELECT != EMMC_FLASH
return SpiReadSysInfo(&sysinfo);
#else
return EmmcReadSysInfo(&sysinfo);
#endif
}
void SaveSysInfo(SysInfo *info)
{
if (!info)
info = &sysinfo;
info->checksum = xcrc32((unsigned char*)info, sizeof(SysInfo) - 4, 0xffffffff);
#if DEVICE_TYPE_SELECT != EMMC_FLASH
SpiWriteSysInfo(info);
#else
EmmcWriteSysInfo(info);
#endif
}

32
A27-STEPLDR/Src/sysinfo.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef _SYSINFO_H_
#define _SYSINFO_H_
#define UPDATE_MEDIA_SD 0
#define UPDATE_MEDIA_USB 1
#define UPDATE_MEDIA_UART 2
#define UPDATE_STATUS_START 0
#define UPDATE_STATUS_END 1
typedef struct {
unsigned int app_checksum;
unsigned int stepldr_offset;
unsigned int stepldr_size;
unsigned int update_media_type;
unsigned int update_status;
unsigned int app_size;
unsigned int image_offset;
unsigned int loader_offset;
unsigned int loader_size;
unsigned int reserved[10];
unsigned int upgrade_flag;
unsigned int upgrade_appsize;
unsigned int checksum;
} SysInfo;
SysInfo *GetSysInfo(void);
void SetDefaultSysInfo(void);
int ReadSysInfo(void);
void SaveSysInfo(SysInfo *info);
#endif

78
A27-STEPLDR/Src/timer.c Normal file
View File

@ -0,0 +1,78 @@
#include "amt630h.h"
#include "timer.h"
#define APBTMR_CONTROL_ENABLE (1 << 0)
/* 1: periodic, 0:free running. */
#define APBTMR_CONTROL_MODE_PERIODIC (1 << 1)
#define APBTMR_CONTROL_INT_DISABLE (1 << 2)
#define TIMER_CLK CLK_24MHZ
#define TIMER_PERIOD 1000000
#define TIMER_LOAD_VAL 0xffffffff
static unsigned long timestamp;
static unsigned long lastdec;
void timer_init(void)
{
rTIMER0_CONTROL = 0;
rTIMER0_LOAD_COUNT = TIMER_LOAD_VAL;
/* No timer interrupt */
rTIMER0_CONTROL = APBTMR_CONTROL_INT_DISABLE |
APBTMR_CONTROL_MODE_PERIODIC | APBTMR_CONTROL_ENABLE;
}
void udelay(unsigned long usec)
{
long tmo = usec * (TIMER_CLK / TIMER_PERIOD);
unsigned long last = rTIMER0_CURRENT_VALUE;
unsigned long now;
while (tmo > 0) {
now = rTIMER0_CURRENT_VALUE;
if (last >= now)
tmo -= last - now;
else
tmo -= last + (TIMER_LOAD_VAL - now);
last = now;
}
}
void mdelay(unsigned long msec)
{
udelay(1000*msec);
}
#if 0
void reset_timer_masked (void)
{
/* reset time */
lastdec = rTIMER0_CURRENT_VALUE; /* capure current decrementer value time */
timestamp = 0; /* start "advancing" time stamp from 0 */
}
#endif
ULONG get_timer_masked (void)
{
unsigned long now = rTIMER0_CURRENT_VALUE; /* current tick value */
if (lastdec >= now) { /* normal mode (non roll) */
/* normal mode */
timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */
} else { /* we have overflow of the count down timer */
/* nts = ts + ld + (TLV - now)
* ts=old stamp, ld=time that passed before passing through -1
* (TLV-now) amount of time after passing though -1
* nts = new "advancing time stamp"...it could also roll and cause problems.
*/
timestamp += lastdec + (TIMER_LOAD_VAL - now);
}
lastdec = now;
return timestamp / DIV_ROUND_UP(TIMER_CLK, TIMER_PERIOD) / 1000;
}
ULONG get_timer(ULONG base)
{
return get_timer_masked () - base;
}

12
A27-STEPLDR/Src/timer.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __TIMER_H__
#define __TIMER_H__
#include "typedef.h"
extern void timer_init(void);
//extern void reset_timer_masked (void);
extern void udelay(unsigned long usec);
extern void mdelay(unsigned long msec);
extern ULONG get_timer(ULONG base);
#endif

204
A27-STEPLDR/Src/trace.h Normal file
View File

@ -0,0 +1,204 @@
/**
* \file
*
* \par Purpose
*
* Standard output methods for reporting debug information, warnings and
* errors, which can be easily be turned on/off.
*
* \par Usage
* -# Initialize the DBGU using TRACE_CONFIGURE() if you intend to eventually
* disable ALL traces; otherwise use DBGU_Configure().
* -# Uses the TRACE_DEBUG(), TRACE_INFO(), TRACE_WARNING(), TRACE_ERROR()
* TRACE_FATAL() macros to output traces throughout the program.
* -# Each type of trace has a level : Debug 5, Info 4, Warning 3, Error 2
* and Fatal 1. Disable a group of traces by changing the value of
* TRACE_LEVEL during compilation; traces with a level bigger than TRACE_LEVEL
* are not generated. To generate no trace, use the reserved value 0.
* -# Trace disabling can be static or dynamic. If dynamic disabling is selected
* the trace level can be modified in runtime. If static disabling is selected
* the disabled traces are not compiled.
*
* \par traceLevels Trace level description
* -# TRACE_DEBUG (5): Traces whose only purpose is for debugging the program,
* and which do not produce meaningful information otherwise.
* -# TRACE_INFO (4): Informational trace about the program execution. Should
* enable the user to see the execution flow.
* -# TRACE_WARNING (3): Indicates that a minor error has happened. In most case
* it can be discarded safely; it may even be expected.
* -# TRACE_ERROR (2): Indicates an error which may not stop the program execution,
* but which indicates there is a problem with the code.
* -# TRACE_FATAL (1): Indicates a major error which prevents the program from going
* any further.
*/
#ifndef _TRACE_
#define _TRACE_
/*
* Headers
*/
//#include "pio.h"
#include <stdio.h>
#include "uart.h"
/*
* Global Definitions
*/
/** Softpack Version */
#define SOFTPACK_VERSION "1.1"
#define TRACE_LEVEL_DEBUG 5
#define TRACE_LEVEL_INFO 4
#define TRACE_LEVEL_WARNING 3
#define TRACE_LEVEL_ERROR 2
#define TRACE_LEVEL_FATAL 1
#define TRACE_LEVEL_NO_TRACE 0
#define TRACE_LEVEL TRACE_LEVEL_NO_TRACE
/* By default, all traces are output except the debug one. */
#if !defined(TRACE_LEVEL)
#define TRACE_LEVEL TRACE_LEVEL_INFO
#endif
/* By default, trace level is static (not dynamic) */
#if !defined(DYN_TRACES)
#define DYN_TRACES 0
#endif
#if defined(NOTRACE)
#error "Error: NOTRACE has to be not defined !"
#endif
#undef NOTRACE
#if (DYN_TRACES==0)
#if (TRACE_LEVEL == TRACE_LEVEL_NO_TRACE)
#define NOTRACE
#endif
#endif
/* ------------------------------------------------------------------------------
* Global Macros
* ------------------------------------------------------------------------------
*/
extern void TRACE_CONFIGURE( uint32_t dwBaudRate, uint32_t dwMCk ) ;
/**
* Initializes the DBGU for ISP project
*
* \param mode DBGU mode.
* \param baudrate DBGU baudrate.
* \param mck Master clock frequency.
*/
#ifndef DYNTRACE
#define DYNTRACE 0
#endif
#if (TRACE_LEVEL==0) && (DYNTRACE==0)
#define TRACE_CONFIGURE_ISP(mode, baudrate, mck) {}
#else
#define TRACE_CONFIGURE_ISP(mode, baudrate, mck) { \
const Pin pinsDBGU[] = {PINS_DBGU}; \
PIO_Configure(pinsDBGU, PIO_LISTSIZE(pinsDBGU)); \
DBGU_Configure( baudrate, mck ) ; \
}
#endif
/**
* Outputs a formatted string using 'printf' if the log level is high
* enough. Can be disabled by defining TRACE_LEVEL=0 during compilation.
* \param ... Additional parameters depending on formatted string.
*/
#if defined(NOTRACE)
/* Empty macro */
#define TRACE_DEBUG(...) { }
#define TRACE_INFO(...) { }
#define TRACE_WARNING(...) { }
#define TRACE_ERROR(...) { }
#define TRACE_FATAL(...) { while(1); }
#define TRACE_DEBUG_WP(...) { }
#define TRACE_INFO_WP(...) { }
#define TRACE_WARNING_WP(...) { }
#define TRACE_ERROR_WP(...) { }
#define TRACE_FATAL_WP(...) { while(1); }
#elif (DYN_TRACES == 1)
/* Trace output depends on dwTraceLevel value */
#define TRACE_DEBUG(...) { if (dwTraceLevel >= TRACE_LEVEL_DEBUG) { printf("-D- " __VA_ARGS__); } }
#define TRACE_INFO(...) { if (dwTraceLevel >= TRACE_LEVEL_INFO) { printf("-I- " __VA_ARGS__); } }
#define TRACE_WARNING(...) { if (dwTraceLevel >= TRACE_LEVEL_WARNING) { printf("-W- " __VA_ARGS__); } }
#define TRACE_ERROR(...) { if (dwTraceLevel >= TRACE_LEVEL_ERROR) { printf("-E- " __VA_ARGS__); } }
#define TRACE_FATAL(...) { if (dwTraceLevel >= TRACE_LEVEL_FATAL) { printf("-F- " __VA_ARGS__); while(1); } }
#define TRACE_DEBUG_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_DEBUG) { printf(__VA_ARGS__); } }
#define TRACE_INFO_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_INFO) { printf(__VA_ARGS__); } }
#define TRACE_WARNING_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_WARNING) { printf(__VA_ARGS__); } }
#define TRACE_ERROR_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_ERROR) { printf(__VA_ARGS__); } }
#define TRACE_FATAL_WP(...) { if (dwTraceLevel >= TRACE_LEVEL_FATAL) { printf(__VA_ARGS__); while(1); } }
#else
/* Trace compilation depends on TRACE_LEVEL value */
#if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
#define TRACE_DEBUG(...) { printf("-D- " __VA_ARGS__); }
#define TRACE_DEBUG_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_DEBUG(...) { }
#define TRACE_DEBUG_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
#define TRACE_INFO(...) { printf("-I- " __VA_ARGS__); }
#define TRACE_INFO_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_INFO(...) { }
#define TRACE_INFO_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_WARNING)
#define TRACE_WARNING(...) { printf("-W- " __VA_ARGS__); }
#define TRACE_WARNING_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_WARNING(...) { }
#define TRACE_WARNING_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_ERROR)
#define TRACE_ERROR(...) { printf("-E- " __VA_ARGS__); }
#define TRACE_ERROR_WP(...) { printf(__VA_ARGS__); }
#else
#define TRACE_ERROR(...) { }
#define TRACE_ERROR_WP(...) { }
#endif
#if (TRACE_LEVEL >= TRACE_LEVEL_FATAL)
#define TRACE_FATAL(...) { printf("-F- " __VA_ARGS__); while(1); }
#define TRACE_FATAL_WP(...) { printf(__VA_ARGS__); while(1); }
#else
#define TRACE_FATAL(...) { while(1); }
#define TRACE_FATAL_WP(...) { while(1); }
#endif
#endif
/**
* Exported variables
*/
/** Depending on DYN_TRACES, dwTraceLevel is a modifable runtime variable or a define */
#if !defined(NOTRACE) && (DYN_TRACES == 1)
extern uint32_t dwTraceLevel ;
#endif
#endif //#ifndef TRACE_H

126
A27-STEPLDR/Src/typedef.h Normal file
View File

@ -0,0 +1,126 @@
#ifndef TYPEDEF_HEAD_H__
#define TYPEDEF_HEAD_H__
#ifndef _INTEGER
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef signed char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
#define _INTEGER
#endif
typedef char INT8;
typedef unsigned char UINT8;
typedef short INT16;
typedef unsigned short UINT16;
typedef unsigned short HWORD;
typedef signed int INT32;
typedef unsigned int UINT32;
typedef unsigned long COLORREF;
typedef unsigned long long UINT64;
typedef void VOID;
typedef void * P_VOID;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
//typedef unsigned char uint8_t;
//typedef unsigned short uint16_t;
//typedef unsigned int uint32_t;
#define true 1
#define false 0
#if 0
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Invalid system call number */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#endif
#define EAGAIN 11 /* Try again */
#define ETIMEDOUT 110 /* Connection timed out */
typedef struct {
char Present; //1 - card is in the socket
char Changed; //1 - card changed(card is in socket)
unsigned int SecNum; // the whole setctor number
} FS_CARD;
#endif

761
A27-STEPLDR/Src/uart.c Normal file
View File

@ -0,0 +1,761 @@
#include <string.h>
#include "amt630h.h"
#include "typedef.h"
#include "uart.h"
#include "aic.h"
#include "update.h"
#include "spi.h"
#include "crc32.h"
#include "sysinfo.h"
#include "board.h"
#include "sysctl.h"
#include "sdmmc.h"
#define UART_CLK CLK_24MHZ
#define UART_ISR_PASS_LIMIT 1
static unsigned int ulUartBase[UART_NUM] = {REGS_UART0_BASE, REGS_UART1_BASE, REGS_UART2_BASE, REGS_UART3_BASE};
void InitUart(unsigned int baud)
{
unsigned int Baud_Rate_Divisor;
unsigned int val;
//select pad
val = rSYS_PAD_CTRL02;
val &= ~(0xF<<12);
val |=(0x1<<14)|(0x1<<12);
rSYS_PAD_CTRL02 = val;
Baud_Rate_Divisor = ((CLK_24MHZ<<3) + baud)/(baud<<1);
rUART_IBRD = Baud_Rate_Divisor >> 6;
rUART_FBRD = Baud_Rate_Divisor & 0x3f;
rUART_LCR_H = 0x70;//data len:8 bit,parity checking disable
rUART_IFLS = 0x19;
rUART_CR = 0x301;
}
static char HexToChar(unsigned char value)
{
value &= 0x0f;
if ( value < 10 )
return(0x30 + value);
else
return(0x60 + value - 9);
}
static void ShortToStr(unsigned short value, char *str)
{
str[0] = HexToChar(value >> 12);
str[1] = HexToChar((value >> 8) & 0x0f);
str[2] = HexToChar((value >> 4) & 0x0f);
str[3] = HexToChar(value & 0x0f);
str[4] = 0;
}
void IntToStr(unsigned int value, char *str)
{
ShortToStr(value >> 16, str);
ShortToStr(value & 0xffff, str + 4);
str[8] = 0;
}
void SendUartString(char * buf)
{
int i = 0;
while ( buf[i] != 0)
{
while ( !(rUART_FR & 0x20) )
{
rUART_DR = buf[i++];
if ( buf[i] == 0 )
return;
}
while ( (rUART_FR & 0x20));
}
}
void SendUartChar(char ch)
{
while ( (rUART_FR & 0x20) );
rUART_DR = ch;
}
void PrintVariableValueHex(char * variable, unsigned int value)
{
char buf[10];
SendUartString(variable);
SendUartString(": 0x");
IntToStr(value, buf);
SendUartString(buf);
SendUartString("\r\n");
}
void SendUartWord(unsigned int data)
{
char buf[10];
SendUartString("0x");
IntToStr(data, buf);
SendUartString(buf);
SendUartString("\r\n");
}
void uart_puts(const UINT8*buf)
{
INT32 i = 0;
while ( buf[i] != 0)
{
while( !(rUART_FR & 0x20) )
{
if ( buf[i] == '\n' )
{
rUART_DR = '\r';
while( (rUART_FR & 0x20) );
}
rUART_DR = buf[i++];
if ( buf[i] == 0 )
return;
}
while( (rUART_FR & 0x20) );
}
}
/* retarget printf function */
int putchar(int ch)
{
while (readl(REGS_UART0_BASE + UART_FR) & UART_FR_TXFF);
writel(ch, REGS_UART0_BASE + UART_DR);
return ch;
}
typedef enum {
UART_FRAME_START,
UART_FRAME_FILEINFO,
UART_FRAME_FILEXFER,
UART_FRAME_FINISH,
} eUartFrameType;
#define UUP_STATE_IDLE 0
#define UUP_STATE_START 1
#define UUP_STATE_END 2
#define UUP_ACK_OK 1
#define UUP_ACK_FAIL 0
#define UUP_MAX_FILE_SIZE 0x1000000
#define UUP_BUF_SIZE (BYTESPERPAGE * PAGESPERSECTORS)
#define UUP_PACKET_SIZE 128
#define UUP_MAX_FRAME_LEN (UUP_PACKET_SIZE + 16)
#define UUP_RX_FRAME_NUM 16
#define UUP_MAX_LOADER_SIZE STEPLDR_MAX_SIZE//0x10000
typedef struct {
int type;
unsigned char *buf;
unsigned int len;
int ack;
} UartFrame;
#pragma data_alignment=16
static unsigned char uup_rx_buf[UUP_RX_FRAME_NUM][UUP_MAX_FRAME_LEN];
static unsigned char *uup_rx_ptr;
static int uup_rx_rev_len = 0;
static int uup_rx_head = 0;
static int uup_rx_tail = 0;
static int uup_rx_state = 0;
static int uup_rx_data_len = 0;
static int uup_status = UUP_STATE_IDLE;
static int uup_file_type = 0;
static unsigned int uup_file_offset;
static int uup_file_size = 0;
static int uup_packet_num = 0;
static int uup_rev_packet = 0;
static int uup_rev_len = 0;
#pragma data_alignment=16
static unsigned char uup_buf[UUP_MAX_LOADER_SIZE];
static unsigned int uup_buf_len = 0;
static void uart_select_pad(int id)
{
switch (id) {
case UART_ID0:
vSysctlConfigure(SYS_PAD_CTRL02, 12, 0xf, 0x5);
break;
case UART_ID1:
vSysctlConfigure(SYS_PAD_CTRL02, 16, 0xf, 0x5);
break;
case UART_ID2:
vSysctlConfigure(SYS_PAD_CTRL02, 20, 0xf, 0x5);
break;
case UART_ID3:
vSysctlConfigure(SYS_PAD_CTRL02, 24, 0xf, 0x5);
break;
}
}
void uart_init(int id, unsigned int baud, unsigned int flags)
{
unsigned int lcr_h, quot, cr;
unsigned int regbase;
int count = 0;
//uart_select_pad(id);
regbase = ulUartBase[id];
if (id == UART_ID0 || id == UART_ID2) {
if (baud > UART_CLK / 16)
quot = (UART_CLK * 8 + baud / 2) / baud;
else
quot = (UART_CLK * 4 + baud / 2) / baud;
switch (flags & CSIZE) {
case CS5:
lcr_h = UART_LCRH_WLEN_5;
break;
case CS6:
lcr_h = UART_LCRH_WLEN_6;
break;
case CS7:
lcr_h = UART_LCRH_WLEN_7;
break;
default: // CS8
lcr_h = UART_LCRH_WLEN_8;
break;
}
if (flags & CSTOPB)
lcr_h |= UART_LCRH_STP2;
if (flags & PARENB) {
lcr_h |= UART_LCRH_PEN;
if (!(flags & PARODD))
lcr_h |= UART_LCRH_EPS;
if (flags & CMSPAR)
lcr_h |= UART_LCRH_SPS;
}
lcr_h |= UART_LCRH_FEN;
/* Provoke TX FIFO interrupt into asserting */
cr = UART_CR_UARTEN | UART_CR_TXE | UART_CR_LBE;
reconfig:
writel(cr, regbase + UART_CR);
writel(0, regbase + UART_FBRD);
writel(1, regbase + UART_IBRD);
writel(0, regbase + UART_LCRH);
writel(0, regbase + UART_DR);
while (readl(regbase + UART_FR) & UART_FR_BUSY);
if (count++ < 10 && !(readl(regbase + UART_RIS) & UART_TXIS)) {
SendUartString("ERROR! Uart status wrong.\n");
goto reconfig;
}
/* first, disable everything */
writel(0, regbase + UART_CR);
cr = UART_CR_RXE | UART_CR_TXE;
if (flags & CRTSCTS)
cr |= UART_CR_CTSEN | UART_CR_RTSEN;
/* Set baud rate */
writel(quot & 0x3f, regbase + UART_FBRD);
writel(quot >> 6, regbase + UART_IBRD);
writel(UART_RTIM | UART_RXIM, regbase + UART_IMSC);
writel(UART_IFLS_RX4_8 | UART_IFLS_TX4_8, regbase + UART_IFLS);
writel(lcr_h, regbase + UART_LCRH);
writel(cr | UART_CR_UARTEN, regbase + UART_CR);
} else {
//set modem
writel(0, regbase + UART485_MCR);
// baud = clk/(16*U_DLL)
//set baud rate
writel(readl(regbase + UART485_LCR) | (1 << 7), regbase + UART485_LCR);
writel(UART_CLK / (16 * baud), regbase + UART485_DLL);
writel(0, regbase + UART485_DLH);
//Set fractional baud rate
//Fractional baud divisor = ((uart_clk%(16*baud))/(16*baud)) * 16 = (uart_clk%(16*baud)) * 16 / (16*baud);
writel((UART_CLK % (16*baud)) * 16 / (16*baud), regbase + UART485_DLF);
writel(readl(regbase + UART485_LCR) & ~(1 << 7), regbase + UART485_LCR);
cr = readl(regbase + UART485_LCR);
//校验
cr &= ~(7 << 3);
if (flags & PARENB) {
cr |= (1 << 3);
if (!(flags & PARODD))
cr |= (1 << 4);
if (flags & CMSPAR)
cr |= (1 << 5);
}
//停止位
if (flags & CSTOPB)
cr |= (1 << 2);
else
cr &= ~(1 << 2);
//数据位
cr &= ~(3 << 0);
switch (flags & CSIZE) {
case CS5:
break;
case CS6:
cr |= 1;
break;
case CS7:
cr |= 2;
break;
default: // CS8
cr |= 3;
break;
}
writel(cr, regbase + UART485_LCR);
//set fifo
writel((2 << 6) | (3 << 4) | 7, regbase + UART485_FCR);
//enable rx and err interrupt
writel((1 << 4) | 1, regbase + UART485_IER);
//设置通信模式全双工还是半双工
//485mode disable
writel(0, regbase + UART485_TCR);
}
uart_select_pad(id);
}
static int uart_rx_chars(int id)
{
unsigned int regbase = ulUartBase[id];
unsigned int status;
unsigned int ch, max_count = 256;
int fifotaken = 0;
while (max_count--) {
if (id == UART_ID0 || id == UART_ID2) {
status = readl(regbase + UART_FR);
if (status & UART_FR_RXFE)
break;
/* Take chars from the FIFO and update status */
ch = readl(regbase + UART_DR);
} else {
status = readl(regbase + UART485_LSR);
if (!(status & UART485_LSR_DR))
break;
/* Take chars from the FIFO and update status */
ch = readl(regbase + UART485_RBR);
}
fifotaken++;
switch (uup_rx_state) {
case 0:
if (ch == 0x55) {
uup_rx_state++;
uup_rx_rev_len = 0;
uup_rx_ptr = &uup_rx_buf[uup_rx_head][0];
}
break;
case 1:
if (ch == 0x81)
uup_rx_state++;
else
uup_rx_state = 0;
*uup_rx_ptr++ = ch;
break;
case 2:
if (ch == 0xc6)
uup_rx_state++;
else
uup_rx_state = 0;
*uup_rx_ptr++ = ch;
break;
case 3:
uup_rx_data_len = ch;
if (uup_rx_data_len <= 0 || uup_rx_data_len > UUP_PACKET_SIZE + 2) {
SendUartString("Invalid uart frame len.\n");
uup_rx_state = 0;
} else {
uup_rx_state++;
*uup_rx_ptr++ = ch;
}
break;
case 4:
*uup_rx_ptr++ = ch;
if (++uup_rx_rev_len == uup_rx_data_len)
uup_rx_state++;
break;
case 5:
*uup_rx_ptr++ = ch;
uup_rx_head = (uup_rx_head + 1) % UUP_RX_FRAME_NUM;
uup_rx_state = 0;
break;
}
/* discard when rx buf is full */
}
return fifotaken;
}
void uart_tx_chars(int id, unsigned char *buf, int len)
{
unsigned int regbase = ulUartBase[id];
int i;
for (i = 0; i < len; i++) {
if (id == UART_ID0 || id == UART_ID2) {
while (readl(regbase + UART_FR) & UART_FR_TXFF);
writel(buf[i], regbase + UART_DR);
} else {
while (!(readl(regbase + UART485_LSR) & UART485_LSR_TEMT));
writel(buf[i], regbase + UART485_THR);
}
}
}
void uart_update_int_handler(void *param)
{
int id = (int)param;
unsigned int regbase = ulUartBase[id];
unsigned int status;
unsigned int imsc;
uint32_t pass_counter = UART_ISR_PASS_LIMIT;
imsc = readl(regbase + UART_IMSC);
status = readl(regbase + UART_RIS) & imsc;
if (status) {
do {
writel(status & ~(/*UART_TXIS | */UART_RTIS | UART_RXIS),
regbase + UART_ICR);
if (status & (UART_RTIS | UART_RXIS)) {
uart_rx_chars(id);
}
/* if (status & UART_TXIS)
xUartTxChars(uap, pdTRUE); */
if (pass_counter-- == 0)
break;
status = readl(regbase + UART_RIS) & imsc;
} while (status != 0);
}
}
void uart485_update_int_handler(void *param)
{
int id = (int)param;
unsigned int regbase = ulUartBase[id];
uint32_t iir;
iir = readl(regbase + UART485_IIR);
switch (iir & UART485_IIR_IID_MASK) {
case UART485_IIR_IID_REV_DATA_AVAIL:
case UART485_IIR_IID_REV_LINE_STATUS:
case UART485_IIR_IID_CHAR_TIMEOUT:
uart_rx_chars(id);
}
}
static void uart_send_ack(int type, int ret)
{
unsigned char buf[7] = {0x55, 0x80, 0xc5, 0x02, 0x00, 0x00, 0x00};
int i;
buf[4] = type;
buf[5] = ret;
for (i = 1; i < 6; i++)
buf[6] ^= buf[i];
uart_tx_chars(UART_MCU_PORT, buf, 7);
}
static int uart_rev_frame(UartFrame *frame)
{
unsigned char *buf;
int len;
unsigned char checksum = 0;
int i;
if (uup_rx_tail == uup_rx_head) {
return 0;
}
buf = &uup_rx_buf[uup_rx_tail][0];
uup_rx_tail = (uup_rx_tail + 1) % UUP_RX_FRAME_NUM;
len = buf[2];
for (i = 0; i < len + 3; i++)
checksum ^= buf[i];
if (checksum == buf[len + 3]) {
frame->buf = &buf[4];
frame->len = len - 1;
frame->type = buf[3];
} else {
SendUartString("rev frame checksum err.\n");
/* for (int i = 0; i < len + 4; i++) {
if (i && i % 16 == 0)
printf("\n");
printf("%.2x, ", buf[i]);
}
printf("\n0x%x, 0x%x.\n", checksum, buf[len + 3]); */
uart_send_ack(buf[3], UUP_ACK_FAIL);
return 0;
}
return 1;
}
void updateFromUart(int id)
{
UartFrame rx_frame;
unsigned char *buf;
unsigned int checksum = 0, calc_checksum = 0xffffffff;
unsigned int framelen;
unsigned int packetnum;
SysInfo *sysinfo = GetSysInfo();
uart_init(id, 115200, 0);
if (id == UART_ID0 || id == UART_ID2)
request_irq(UART0_IRQn + id, 0, uart_update_int_handler, (void*)id);
else
request_irq(UART0_IRQn + id, 0, uart485_update_int_handler, (void*)id);
do {
if (!uart_rev_frame(&rx_frame))
continue;
switch (rx_frame.type) {
case UART_FRAME_START:
uart_send_ack(rx_frame.type, UUP_ACK_OK);
uup_status = UUP_STATE_START;
update_logo_init();
break;
case UART_FRAME_FILEINFO:
if (uup_status != UUP_STATE_START)
break;
buf = rx_frame.buf;
uup_file_type = buf[0];
if (uup_file_type > UPFILE_TYPE_STEPLDR) {
PrintVariableValueHex("Rev wrong file type", uup_file_type);
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
#if DEVICE_TYPE_SELECT != EMMC_FLASH
uup_file_offset = SpiGetUpfileOffset(uup_file_type);
#else
uup_file_offset = EmmcGetUpfileOffset(uup_file_type);
#endif
if (uup_file_offset == 0xffffffff) {
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
uup_packet_num = (buf[1] << 16) | (buf[2] << 8) | buf[3];
uup_file_size = UUP_PACKET_SIZE * uup_packet_num;
if (uup_file_size > UUP_MAX_FILE_SIZE - uup_file_offset) {
SendUartString("Rev wrong file size.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
uart_send_ack(rx_frame.type, UUP_ACK_OK);
break;
case UART_FRAME_FILEXFER:
if (uup_status != UUP_STATE_START)
break;
buf = rx_frame.buf;
packetnum = buf[0];
PrintVariableValueHex("uup_rev_packet", uup_rev_packet);
if ((uup_rev_packet & 0xff) != packetnum) {
SendUartString("Wrong packet number.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
if (uup_rev_packet == 0) {
if (uup_file_type == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)&buf[1];
if (header->magic != MKTAG('U', 'P', 'D', 'F')) {
SendUartString("Wrong whole file magic.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
checksum = header->checksum;
sysinfo->app_size = header->files[0].size;
PrintVariableValueHex("sysinfo->appsize ", sysinfo->app_size);
} else if (uup_file_type == UPFILE_TYPE_RESOURCE) {
RomHeader *header = (RomHeader *)&buf[1];
if (header->magic != MKTAG('R', 'O', 'M', 'A')) {
SendUartString("Wrong resource file magic.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
checksum = header->checksum;
} else if (uup_file_type == UPFILE_TYPE_ANIMATION) {
BANIHEADER *header = (BANIHEADER *)&buf[1];
if (header->magic != MKTAG('B', 'A', 'N', 'I')) {
SendUartString("Wrong animation file magic.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
checksum = header->checksum;
} else if (uup_file_type == UPFILE_TYPE_APP) {
unsigned int magic = buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24);
if (magic != UPFILE_APP_MAGIC) {
SendUartString("Wrong app file magic.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
unsigned char *tmp = buf + 1 + APPLDR_CHECKSUM_OFFSET;
checksum = tmp[0] | (tmp[1] <<8) | (tmp[2] << 16) | (tmp[3] << 24);
}
}
framelen = rx_frame.len - 1;
/* only last frame size is less than UUP_PACKET_SIZE */
if (framelen > UUP_PACKET_SIZE ||
(framelen < UUP_PACKET_SIZE && uup_rev_packet != uup_packet_num - 1)) {
SendUartString("Wrong packet len.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
memcpy(uup_buf + uup_buf_len, buf + 1, framelen);
uup_buf_len += framelen;
if (uup_buf_len > UUP_MAX_LOADER_SIZE) {
SendUartString("loader file is too large.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
uup_rev_packet++;
//loader程序如果升级错误会导致系统起不来并且不能再继续升级因此需要
//等数据校验成功后再烧录(loader程序通常并不需要升级)
if (uup_file_type < UPFILE_TYPE_FIRSTLDR && uup_buf_len == UUP_BUF_SIZE) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
if(!FlashBurn(uup_buf, uup_file_offset, UUP_BUF_SIZE, 0))
#else
if(!EmmcBurn(uup_buf, uup_file_offset, UUP_BUF_SIZE, 0))
#endif
{
uart_send_ack(rx_frame.type, UUP_ACK_OK);
} else {
SendUartString("Burn failed.\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
break;
}
//文件起始部分需要先将头信息里的checksum清0来计算checksum
if (uup_rev_packet == UUP_BUF_SIZE / UUP_PACKET_SIZE) {
if (uup_file_type == UPFILE_TYPE_WHOLE) {
UpFileHeader *pheader = (UpFileHeader *)uup_buf;
pheader->checksum = 0;
} else if (uup_file_type == UPFILE_TYPE_RESOURCE) {
RomHeader *pheader = (RomHeader *)uup_buf;
pheader->checksum = 0;
} else if (uup_file_type == UPFILE_TYPE_ANIMATION) {
BANIHEADER *pheader = (BANIHEADER *)uup_buf;
pheader->checksum = 0;
} else if (uup_file_type == UPFILE_TYPE_APP) {
unsigned int *tmp = (unsigned int *)(uup_buf + APPLDR_CHECKSUM_OFFSET);
*tmp = 0;
}
}
calc_checksum = xcrc32(uup_buf, UUP_BUF_SIZE, calc_checksum);
uup_buf_len = 0;
uup_file_offset += UUP_BUF_SIZE;
uup_rev_len += UUP_BUF_SIZE;
update_progress_set(uup_rev_len * 100 / uup_file_size);
} else {
uart_send_ack(rx_frame.type, UUP_ACK_OK);
}
break;
case UART_FRAME_FINISH:
buf = rx_frame.buf;
if (!buf[0]) {
SendUartString("update end with error!\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
uup_status = UUP_STATE_END;
break;
}
if (uup_file_type < UPFILE_TYPE_FIRSTLDR) {
if (uup_buf_len) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
if(FlashBurn(uup_buf, uup_file_offset, uup_buf_len, 0))
#else
if(EmmcBurn(uup_buf, uup_file_offset, uup_buf_len, 0))
#endif
{
SendUartString("update fail with burn failed.!\n");
calc_checksum = 0xFFFFFFFF;
} else {
//如果升级文件小于UUP_BUF_SIZE此时收到的是文件起始部分
if (uup_rev_packet < UUP_BUF_SIZE / UUP_PACKET_SIZE) {
if (uup_file_type == UPFILE_TYPE_WHOLE) {
UpFileHeader *pheader = (UpFileHeader *)uup_buf;
pheader->checksum = 0;
} else if (uup_file_type == UPFILE_TYPE_RESOURCE) {
RomHeader *pheader = (RomHeader *)uup_buf;
pheader->checksum = 0;
} else if (uup_file_type == UPFILE_TYPE_ANIMATION) {
BANIHEADER *pheader = (BANIHEADER *)uup_buf;
pheader->checksum = 0;
} else if (uup_file_type == UPFILE_TYPE_APP) {
unsigned int *checksum = (unsigned int *)(uup_buf + APPLDR_CHECKSUM_OFFSET);
*checksum = 0;
}
}
calc_checksum = xcrc32(uup_buf, uup_buf_len, calc_checksum);
}
}
if (calc_checksum == checksum) {
SendUartString("update finish!\n");
update_progress_set(100);
if (uup_file_type == UPFILE_TYPE_APP)
sysinfo->app_size = uup_file_size;
sysinfo->update_status = UPDATE_STATUS_END;
SaveSysInfo(sysinfo);
uart_send_ack(rx_frame.type, UUP_ACK_OK);
} else {
SendUartString("update checksum fail!\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
}
} else {
unsigned int *tmp = (unsigned int *)(uup_buf + APPLDR_CHECKSUM_OFFSET);
checksum = *tmp;
*tmp = 0;
calc_checksum = xcrc32(uup_buf, uup_buf_len, calc_checksum);
if (calc_checksum == checksum) {
#if DEVICE_TYPE_SELECT != EMMC_FLASH
if (!FlashBurn(uup_buf, uup_file_offset, uup_buf_len, 1))
#else
if (!EmmcBurn(uup_buf, uup_file_offset, uup_buf_len, 1))
#endif
{
if (uup_file_type == UPFILE_TYPE_STEPLDR)
sysinfo->stepldr_size = uup_buf_len;
sysinfo->update_status = UPDATE_STATUS_END;
SaveSysInfo(sysinfo);
uart_send_ack(rx_frame.type, UUP_ACK_OK);
} else {
SendUartString("burn loader fail!\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
}
} else {
SendUartString("update checksum fail!\n");
uart_send_ack(rx_frame.type, UUP_ACK_FAIL);
}
}
uup_status = UUP_STATE_END;
break;
}
} while (uup_status != UUP_STATE_END);
}

205
A27-STEPLDR/Src/uart.h Normal file
View File

@ -0,0 +1,205 @@
#ifndef UART_PRINT_H__
#define UART_PRINT_H__
/* UART Register Offsets. */
#define UART_DR 0x00 /* Data read or written from the interface. */
#define UART_RSR 0x04 /* Receive status register (Read). */
#define UART_FR 0x18 /* Flag register (Read only). */
#define UART_ILPR 0x20 /* IrDA low power counter register. */
#define UART_IBRD 0x24 /* Integer baud rate divisor register. */
#define UART_FBRD 0x28 /* Fractional baud rate divisor register. */
#define UART_LCRH 0x2c /* Line control register. */
#define UART_CR 0x30 /* Control register. */
#define UART_IFLS 0x34 /* Interrupt fifo level select. */
#define UART_IMSC 0x38 /* Interrupt mask. */
#define UART_RIS 0x3c /* Raw interrupt status. */
#define UART_MIS 0x40 /* Masked interrupt status. */
#define UART_ICR 0x44 /* Interrupt clear register. */
#define UART_DMACR 0x48 /* DMA control register. */
#define UART_DR_OE (1 << 11)
#define UART_DR_BE (1 << 10)
#define UART_DR_PE (1 << 9)
#define UART_DR_FE (1 << 8)
#define UART_RSR_OE 0x08
#define UART_RSR_BE 0x04
#define UART_RSR_PE 0x02
#define UART_RSR_FE 0x01
#define UART_FR_RI 0x100
#define UART_FR_TXFE 0x080
#define UART_FR_RXFF 0x040
#define UART_FR_TXFF 0x020
#define UART_FR_RXFE 0x010
#define UART_FR_BUSY 0x008
#define UART_FR_DCD 0x004
#define UART_FR_DSR 0x002
#define UART_FR_CTS 0x001
#define UART_FR_TMSK (UART_FR_TXFF + UART_FR_BUSY)
#define UART_CR_CTSEN 0x8000 /* CTS hardware flow control */
#define UART_CR_RTSEN 0x4000 /* RTS hardware flow control */
#define UART_CR_OUT2 0x2000 /* OUT2 */
#define UART_CR_OUT1 0x1000 /* OUT1 */
#define UART_CR_RTS 0x0800 /* RTS */
#define UART_CR_DTR 0x0400 /* DTR */
#define UART_CR_RXE 0x0200 /* receive enable */
#define UART_CR_TXE 0x0100 /* transmit enable */
#define UART_CR_LBE 0x0080 /* loopback enable */
#define UART_CR_RTIE 0x0040
#define UART_CR_TIE 0x0020
#define UART_CR_RIE 0x0010
#define UART_CR_MSIE 0x0008
#define UART_CR_IIRLP 0x0004 /* SIR low power mode */
#define UART_CR_SIREN 0x0002 /* SIR enable */
#define UART_CR_UARTEN 0x0001 /* UART enable */
#define UART_LCRH_SPS 0x80
#define UART_LCRH_WLEN_8 0x60
#define UART_LCRH_WLEN_7 0x40
#define UART_LCRH_WLEN_6 0x20
#define UART_LCRH_WLEN_5 0x00
#define UART_LCRH_FEN 0x10
#define UART_LCRH_STP2 0x08
#define UART_LCRH_EPS 0x04
#define UART_LCRH_PEN 0x02
#define UART_LCRH_BRK 0x01
#define UART_IFLS_RX1_8 (0 << 3)
#define UART_IFLS_RX2_8 (1 << 3)
#define UART_IFLS_RX4_8 (2 << 3)
#define UART_IFLS_RX6_8 (3 << 3)
#define UART_IFLS_RX7_8 (4 << 3)
#define UART_IFLS_TX1_8 (0 << 0)
#define UART_IFLS_TX2_8 (1 << 0)
#define UART_IFLS_TX4_8 (2 << 0)
#define UART_IFLS_TX6_8 (3 << 0)
#define UART_IFLS_TX7_8 (4 << 0)
#define UART_OEIM (1 << 10) /* overrun error interrupt mask */
#define UART_BEIM (1 << 9) /* break error interrupt mask */
#define UART_PEIM (1 << 8) /* parity error interrupt mask */
#define UART_FEIM (1 << 7) /* framing error interrupt mask */
#define UART_RTIM (1 << 6) /* receive timeout interrupt mask */
#define UART_TXIM (1 << 5) /* transmit interrupt mask */
#define UART_RXIM (1 << 4) /* receive interrupt mask */
#define UART_DSRMIM (1 << 3) /* DSR interrupt mask */
#define UART_DCDMIM (1 << 2) /* DCD interrupt mask */
#define UART_CTSMIM (1 << 1) /* CTS interrupt mask */
#define UART_RIMIM (1 << 0) /* RI interrupt mask */
#define UART_OEIS (1 << 10) /* overrun error interrupt status */
#define UART_BEIS (1 << 9) /* break error interrupt status */
#define UART_PEIS (1 << 8) /* parity error interrupt status */
#define UART_FEIS (1 << 7) /* framing error interrupt status */
#define UART_RTIS (1 << 6) /* receive timeout interrupt status */
#define UART_TXIS (1 << 5) /* transmit interrupt status */
#define UART_RXIS (1 << 4) /* receive interrupt status */
#define UART_DSRMIS (1 << 3) /* DSR interrupt status */
#define UART_DCDMIS (1 << 2) /* DCD interrupt status */
#define UART_CTSMIS (1 << 1) /* CTS interrupt status */
#define UART_RIMIS (1 << 0) /* RI interrupt status */
#define UART485_RBR_THR_DLL 0x000
#define UART485_DLH_IER 0x004
#define UART485_IIR_FCR 0x008
#define UART485_RBR 0x000
#define UART485_THR 0x000
#define UART485_DLL 0x000
#define UART485_DLH 0x004
#define UART485_IER 0x004
#define UART485_IIR 0x008
#define UART485_FCR 0x008
#define UART485_LCR 0x00C
#define UART485_MCR 0x010
#define UART485_LSR 0x014
#define UART485_MSR 0x018
#define UART485_SCR 0x01C
#define UART485_LPDLL 0x020
#define UART485_LPDLH 0x024
#define UART485_RESERVED 0x028
#define UART485_SRBR 0x030
#define UART485_STHR 0x06C
#define UART485_FAR 0x070
#define UART485_TFR 0x074
#define UART485_RFW 0x078
#define UART485_USR 0x07C
#define UART485_TFL 0x080
#define UART485_RFL 0x084
#define UART485_SRR 0x088
#define UART485_SRTS 0x08C
#define UART485_SBCR 0x090
#define UART485_SDMAM 0x094
#define UART485_SFE 0x098
#define UART485_SRT 0x09C
#define UART485_STET 0x0A0
#define UART485_HTX 0x0A4
#define UART485_DMASA 0x0A8
#define UART485_TCR 0x0AC
#define UART485_DE_EN 0x0B0
#define UART485_RE_EN 0x0B4
#define UART485_DET 0x0B8
#define UART485_TAT 0x0BC
#define UART485_DLF 0x0C0
#define UART485_RAR 0x0C4
#define UART485_TAR 0x0C8
#define UART485_LCR_EXT 0x0CC
#define UART485_CPR 0x0F4
#define UART485_UCV 0x0F8
#define UART485_CTR 0x0FC
#define UART485_LSR_RFE (1 << 7)
#define UART485_LSR_TEMT (1 << 6)
#define UART485_LSR_THRE (1 << 5)
#define UART485_LSR_BI (1 << 4)
#define UART485_LSR_FE (1 << 3)
#define UART485_LSR_PE (1 << 2)
#define UART485_LSR_OE (1 << 1)
#define UART485_LSR_DR (1 << 0)
#define UART485_IIR_IID_MASK (0xf << 0)
#define UART485_IIR_IID_MODEM_STATUS 0x0
#define UART485_IIR_IID_NO_INT_PENDING 0x1
#define UART485_IIR_IID_THR_EMPTY 0x2
#define UART485_IIR_IID_REV_DATA_AVAIL 0x4
#define UART485_IIR_IID_REV_LINE_STATUS 0x6
#define UART485_IIR_IID_BUSY_DETECT 0x7
#define UART485_IIR_IID_CHAR_TIMEOUT 0xc
#define CSIZE 0x0003
#define CS8 0x0000
#define CS6 0x0001
#define CS7 0x0002
#define CS5 0x0003
#define CSTOPB 0x0004
#define PARENB 0x0010
#define PARODD 0x0020
#define CMSPAR 0x0100 /* mark or space (stick) parity */
#define CRTSCTS 0x0200 /* flow control */
typedef enum {
UART_ID0 = 0,
UART_ID1,
UART_ID2,
UART_ID3,
UART_NUM,
} eUartID;
void InitUart(unsigned int baud);
void SendUartString(char * buf);
void SendUartChar(char ch);
void PrintVariableValueHex(char * variable, unsigned int value);
void SendUartWord(unsigned int data);
void IntToStr(unsigned int value, char *str);
void uart_init(int id, unsigned int baud, unsigned int flags);
void updateFromUart(int id);
#endif

227
A27-STEPLDR/Src/update.c Normal file
View File

@ -0,0 +1,227 @@
#include "amt630h.h"
#include "board.h"
#include "lcd.h"
#include "update.h"
#include "cp15.h"
#include "pxp.h"
#if LCD_INTERFACE_TYPE == LCD_INTERFACE_MIPI
#define UPDATING_WIDTH 200
#define UPDATING_HEIGHT 20
#define PROGRESS_WIDTH 200
#define PROGRESS_HEIGHT 36
#else
#define UPDATING_WIDTH 200
#define UPDATING_HEIGHT 20
#define PROGRESS_WIDTH 200
#define PROGRESS_HEIGHT 32
#endif
#define UPDATE_LOGO_WIDTH PROGRESS_WIDTH
#define UPDATE_LOGO_HEIGHT (UPDATING_HEIGHT + PROGRESS_HEIGHT)
#define UPDATELOGO_DISPLAY_ADDR 0x20ff0000
#define PXP_DISPLAY_ADDR 0x21000000
#if LCD_BPP == 32
typedef unsigned int Upcolor;
#define UPDATE_TEXT_COLOR 0xffffffff; //white
#define UPDATE_RECT_COLOR 0xffffffff //white
#define UPDATE_BAR_COLOR 0xff00ff00; //green
#elif LCD_BPP == 16
typedef unsigned short Upcolor;
#define UPDATE_TEXT_COLOR 0xffff; //white
#define UPDATE_RECT_COLOR 0xffff; //white
#define UPDATE_BAR_COLOR 0x07e0; //green
#endif
// #define UPDATE_LAN_CHINESE
#ifndef UPDATE_LAN_CHINESE
#define UPDATE_LAN_ENGLISH
#endif
#ifdef UPDATE_LAN_CHINESE
//chinese
#define UPDATING_POINT_COUNT 397
static unsigned short updating[UPDATING_POINT_COUNT] =
{
810, 821, 828, 840, 866, 878, 883, 894, 900, 1008, 1009, 1010, 1021, 1024, 1025, 1026,
1027, 1028, 1040, 1060, 1066, 1076, 1077, 1078, 1079, 1080, 1083, 1086, 1093, 1094, 1096, 1097,
1098, 1099, 1100, 1206, 1207, 1210, 1220, 1223, 1224, 1225, 1227, 1228, 1240, 1260, 1261, 1263,
1264, 1265, 1266, 1267, 1268, 1269, 1275, 1276, 1277, 1280, 1281, 1283, 1285, 1293, 1299, 1404,
1405, 1406, 1407, 1410, 1420, 1422, 1425, 1427, 1436, 1440, 1441, 1442, 1443, 1444, 1445, 1461,
1466, 1467, 1468, 1477, 1481, 1483, 1484, 1492, 1494, 1498, 1499, 1500, 1501, 1502, 1603, 1606,
1610, 1619, 1621, 1622, 1624, 1627, 1628, 1629, 1636, 1637, 1638, 1639, 1640, 1641, 1644, 1645,
1664, 1665, 1666, 1667, 1669, 1677, 1678, 1679, 1680, 1683, 1684, 1685, 1686, 1692, 1694, 1695,
1696, 1697, 1698, 1702, 1806, 1810, 1812, 1813, 1814, 1818, 1819, 1820, 1821, 1824, 1825, 1826,
1827, 1828, 1829, 1836, 1840, 1844, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868,
1869, 1870, 1874, 1875, 1876, 1877, 1880, 1881, 1882, 1883, 1884, 1885, 1891, 1892, 1894, 1896,
1897, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2020, 2024, 2025, 2028,
2036, 2040, 2044, 2058, 2059, 2060, 2063, 2068, 2076, 2077, 2078, 2080, 2085, 2090, 2092, 2094,
2096, 2097, 2098, 2099, 2100, 2101, 2206, 2210, 2219, 2220, 2221, 2222, 2223, 2224, 2226, 2227,
2228, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244, 2245, 2260, 2264, 2265, 2266, 2267,
2268, 2276, 2277, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2292, 2294, 2295, 2296, 2298, 2406,
2410, 2419, 2420, 2423, 2426, 2427, 2436, 2440, 2460, 2464, 2465, 2466, 2467, 2468, 2475, 2477,
2480, 2485, 2492, 2494, 2498, 2499, 2500, 2501, 2502, 2606, 2610, 2621, 2622, 2623, 2626, 2627,
2640, 2660, 2662, 2663, 2664, 2668, 2674, 2675, 2677, 2680, 2681, 2682, 2683, 2684, 2685, 2692,
2694, 2695, 2696, 2697, 2698, 2805, 2810, 2820, 2821, 2822, 2825, 2826, 2827, 2840, 2851, 2852,
2860, 2861, 2862, 2864, 2865, 2866, 2867, 2868, 2874, 2877, 2880, 2885, 2892, 2897, 2899, 3004,
3005, 3010, 3018, 3019, 3021, 3022, 3024, 3025, 3028, 3040, 3051, 3052, 3060, 3061, 3064, 3068,
3077, 3080, 3083, 3085, 3092, 3096, 3100, 3106, 3107, 3114, 3115, 3122, 3123, 3203, 3204, 3210,
3221, 3223, 3224, 3228, 3229, 3230, 3240, 3252, 3264, 3266, 3267, 3268, 3277, 3280, 3284, 3285,
3292, 3295, 3296, 3300, 3301, 3403, 3422, 3423, 3451, 3464, 3494, 3495, 3502,
};
#else
//english
#define UPDATING_POINT_COUNT 237
static unsigned short updating[UPDATING_POINT_COUNT] =
{
1021, 1022, 1023, 1044, 1045, 1222, 1223, 1235, 1236, 1422, 1423, 1435, 1436, 1601, 1602, 1603,
1605, 1606, 1607, 1609, 1610, 1611, 1612, 1613, 1614, 1619, 1620, 1621, 1622, 1623, 1627, 1628,
1629, 1630, 1633, 1634, 1635, 1636, 1637, 1638, 1642, 1643, 1644, 1645, 1649, 1650, 1652, 1653,
1654, 1659, 1660, 1661, 1662, 1663, 1802, 1803, 1806, 1807, 1810, 1811, 1814, 1815, 1818, 1819,
1822, 1823, 1826, 1827, 1830, 1831, 1835, 1836, 1844, 1845, 1850, 1851, 1852, 1854, 1855, 1858,
1859, 1861, 1862, 2002, 2003, 2006, 2007, 2010, 2011, 2014, 2015, 2018, 2019, 2022, 2023, 2028,
2029, 2030, 2031, 2035, 2036, 2044, 2045, 2050, 2054, 2055, 2058, 2059, 2061, 2062, 2202, 2203,
2206, 2207, 2210, 2211, 2214, 2215, 2218, 2219, 2222, 2223, 2227, 2228, 2230, 2231, 2235, 2236,
2244, 2245, 2250, 2254, 2255, 2259, 2260, 2261, 2402, 2403, 2406, 2407, 2410, 2411, 2414, 2415,
2418, 2419, 2422, 2423, 2426, 2427, 2430, 2431, 2435, 2436, 2444, 2445, 2450, 2454, 2455, 2458,
2459, 2466, 2467, 2468, 2474, 2475, 2476, 2482, 2483, 2484, 2603, 2604, 2605, 2606, 2607, 2608,
2610, 2611, 2612, 2613, 2614, 2619, 2620, 2621, 2622, 2623, 2624, 2627, 2628, 2629, 2630, 2631,
2632, 2636, 2637, 2638, 2642, 2643, 2644, 2645, 2646, 2647, 2649, 2650, 2651, 2652, 2654, 2655,
2656, 2658, 2659, 2660, 2661, 2662, 2666, 2667, 2668, 2674, 2675, 2676, 2682, 2683, 2684, 2810,
2811, 2858, 2859, 2862, 2863, 3009, 3010, 3011, 3012, 3059, 3060, 3061, 3062,
};
#endif
static int update_start = 0;
static int update_percent = -1;
static void updating_init(void)
{
int i;
Upcolor *p = (Upcolor *)(UPDATELOGO_DISPLAY_ADDR);
Upcolor color = UPDATE_TEXT_COLOR;
int pos = 0;
for(i = 0; i < UPDATING_WIDTH * UPDATING_HEIGHT; i++) {
if(updating[pos] == i) {
*p = color;
pos++;
}
p++;
}
}
void update_progress_init(void)
{
int i, j;
Upcolor *p = (Upcolor *)(UPDATELOGO_DISPLAY_ADDR +
UPDATING_HEIGHT * PROGRESS_WIDTH * LCD_BPP / 8);
int height = UPDATE_LOGO_HEIGHT;
Upcolor color = UPDATE_RECT_COLOR;
for(j = UPDATING_HEIGHT; j < height; j++) {
for(i = 0; i < PROGRESS_WIDTH; i++) {
if(j < (UPDATING_HEIGHT + 2) || j > (height -3) || \
i < 2 || i > (PROGRESS_WIDTH -3)) {
*p = color;
}
p++;
}
}
}
void update_progress_set(int percent)
{
int i, j, end;
unsigned int memstart = UPDATELOGO_DISPLAY_ADDR +
UPDATING_WIDTH * UPDATING_HEIGHT * LCD_BPP / 8;
Upcolor *p = (Upcolor *)memstart;
int height = UPDATE_LOGO_HEIGHT;
Upcolor color = UPDATE_BAR_COLOR;
if(percent < 0 || percent > 100) {
return;
}
if (!update_start || percent == update_percent)
return;
update_percent = percent;
end = percent * (PROGRESS_WIDTH - 3) / 100;
for(j = UPDATING_HEIGHT; j < height; j++) {
for(i = 0; i < PROGRESS_WIDTH; i++) {
if(j > (UPDATING_HEIGHT + 2) && j < (height -3) \
&& i > 2 && i < end) {
*p = color;
}
p++;
}
}
CP15_clean_dcache_for_dma((unsigned int)memstart,
(unsigned int)memstart + PROGRESS_WIDTH *PROGRESS_HEIGHT * LCD_BPP / 8);
#if LCD_ROTATE_ANGLE != LCD_ROTATE_ANGLE_0
pxp_scaler_rotate(UPDATELOGO_DISPLAY_ADDR, 0, 0,
PXP_SRC_FMT_RGB565, UPDATE_LOGO_WIDTH, UPDATE_LOGO_HEIGHT,
PXP_DISPLAY_ADDR, 0, PXP_OUT_FMT_RGB565, UPDATE_LOGO_HEIGHT, UPDATE_LOGO_WIDTH, LCD_ROTATE_ANGLE);
#endif
}
void update_logo_init(void)
{
int x, y;
unsigned int width = UPDATE_LOGO_WIDTH;
unsigned int height = UPDATE_LOGO_HEIGHT;
#if LCD_ROTATE_ANGLE != LCD_ROTATE_ANGLE_0
unsigned int display_addr = PXP_DISPLAY_ADDR;
unsigned int out_width;
unsigned int out_height;
#endif
if (update_start)
return;
memset((void *)UPDATELOGO_DISPLAY_ADDR, 0 , width *height * LCD_BPP / 8);
updating_init();
update_progress_init();
CP15_clean_dcache_for_dma(UPDATELOGO_DISPLAY_ADDR,
UPDATELOGO_DISPLAY_ADDR + width *height * LCD_BPP / 8);
#if LCD_ROTATE_ANGLE != LCD_ROTATE_ANGLE_0
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_180
out_width = width;
out_height = height;
#else
out_width = height;
out_height = width;
#endif
ark_lcd_set_osd_size(LCD_OSD1, out_width, out_height);
pxp_scaler_rotate(UPDATELOGO_DISPLAY_ADDR, 0, 0, PXP_SRC_FMT_RGB565, width, height,
display_addr, 0, PXP_OUT_FMT_RGB565, out_width, out_height, LCD_ROTATE_ANGLE);
ark_lcd_set_osd_yaddr(LCD_OSD1, display_addr);
y = (LCD_HEIGHT - out_height) / 2;
x = (LCD_WIDTH - out_width) / 2;
#else
ark_lcd_set_osd_yaddr(LCD_OSD1, UPDATELOGO_DISPLAY_ADDR);
ark_lcd_set_osd_size(LCD_OSD1, width, height);
x = (LCD_WIDTH - width) / 2;
y = (LCD_HEIGHT - height) / 2;
#endif
ark_lcd_set_osd_possition(LCD_OSD1, x, y);
ark_lcd_osd_enable(LCD_OSD1, 1);
ark_lcd_set_osd_sync(LCD_OSD1);
update_start = 1;
}

52
A27-STEPLDR/Src/update.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef _UPDATE_H_
#define _UPDATE_H_
#define UPFILE_APP_MAGIC 0xe59ff030
#define APPLDR_CHECKSUM_OFFSET 20
#define ROMFILE_NAME_MAX_LEN 64
typedef struct {
char name[ROMFILE_NAME_MAX_LEN];
unsigned int offset;
unsigned int size;
} RomFileInfo;
typedef struct {
unsigned int magic;
unsigned int filenum;
unsigned int romsize;
unsigned int checksum;
RomFileInfo files[];
} RomHeader;
typedef struct {
unsigned int magic;
int hasBootlogo;
int bootlogoDisplayTime;
int aniCount;
int aniWidth;
int aniHeight;
int aniFps;
int aniDelayHideTime;
unsigned int aniSize;
unsigned int checksum;
unsigned int reserved[2];
}BANIHEADER;
typedef enum {
UPFILE_TYPE_WHOLE,
UPFILE_TYPE_RESOURCE,
UPFILE_TYPE_ANIMATION,
UPFILE_TYPE_APP,
UPFILE_TYPE_FIRSTLDR,
UPFILE_TYPE_STEPLDR,
UPFILE_TYPE_LNCHEMMC,
} eUpfileType;
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
void update_logo_init(void);
void update_progress_set(int percent);
#endif

View File

@ -0,0 +1,619 @@
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
#include "ark_dwc2.h"
#include "usbroothubdes.h"
#include "sysctl.h"
struct dwc2_host_data {
struct dwc2_hsotg *host;
struct usb_hcd hcd;
enum usb_device_speed host_speed;
int root_hub_devnum;
//struct usb_host_endpoint hep;
struct urb urb_in[16];
struct urb urb_out[16];
struct usb_host_endpoint hep_in[16];
struct usb_host_endpoint hep_out[16];
struct hc_driver *dw2_hc_driver;
List_t free_urb_list;
spinlock_t lock;
};
int dwc2_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int dwc2_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
extern int dwc2_driver_init(struct dwc2_hsotg **dev, struct usb_hcd *hcd);
extern int dwc2_driver_uninit(struct dwc2_hsotg *hsotg);
extern struct hc_driver* dwc2_get_driver();
static int dwc_otg_submit_rh_msg(struct usb_device *dev,
unsigned long pipe, void *buffer, int txlen,
struct devrequest *cmd);
struct dwc2_host_data dwc2_host;
static void dwc2_host_complete_urb(struct urb *urb)
{
urb->dev->status &= ~USB_ST_NOT_PROC;
urb->dev->act_len = urb->actual_length;
//printf("actual_length:%d\r\n", urb->actual_length);
urb->urb_complete = 1;
}
static void usb_urb_release(struct urb *urb)
{
if (NULL == urb)
return;
spin_lock(&dwc2_host.lock);
list_add_tail(&urb->urb_list, &dwc2_host.free_urb_list);
spin_unlock(&dwc2_host.lock);
}
static struct urb *usb_urb_alloc(struct dwc2_host_data *ctx,
int iso_desc_count,
gfp_t mem_flags)
{
struct urb *urb = NULL;
u32 size = sizeof(*urb);
ListItem_t *pxListItem = NULL;
int found = 0, flags;
spin_lock_irqsave(&ctx->lock, flags);
list_for_each_entry(pxListItem, urb, &ctx->free_urb_list) {
if (urb->number_of_packets == iso_desc_count) {
found = 1;
break;
}
}
if (found) {
list_del_init(&urb->urb_list);
spin_unlock_irqrestore(&ctx->lock, flags);
memset(urb, 0, sizeof(struct urb));
INIT_LIST_ITEM(&urb->urb_list);
listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
urb->urb_complete = 0;
return urb;
}
spin_unlock_irqrestore(&ctx->lock, flags);
urb = (struct urb *)kzalloc(size, mem_flags);
if (urb) {
urb->number_of_packets = iso_desc_count;
INIT_LIST_ITEM(&urb->urb_list);
listSET_LIST_ITEM_OWNER(&urb->urb_list, urb);
urb->urb_complete = 0;
}
return urb;
}
static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
struct usb_device *dev, int endpoint_type,
unsigned long pipe, void *buffer, int len,
struct devrequest *setup, int interval)
{
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
INIT_LIST_HEAD(&hep->urb_list);
INIT_LIST_ITEM(&urb->urb_list);
urb->urb_list.pvOwner = (void *)urb;
urb->ep = hep;
urb->complete = dwc2_host_complete_urb;
urb->status = -EINPROGRESS;
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = buffer;
urb->transfer_dma = (dma_addr_t)buffer;
urb->transfer_buffer_length = len;
urb->setup_packet = (unsigned char *)setup;
urb->setup_dma = (dma_addr_t)setup;
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
URB_DMA_SG_COMBINED);
urb->transfer_flags |= (is_in ? URB_DIR_IN : URB_DIR_OUT);
urb->ep->desc.wMaxPacketSize =
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
dev->epmaxpacketout[epnum]);
urb->ep->desc.bmAttributes = endpoint_type;
urb->ep->desc.bEndpointAddress =
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
urb->ep->desc.bInterval = interval;
}
static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
{
int ret;
ret = dwc2_urb_enqueue(hcd, urb, 0);
if (ret < 0) {
PrintVariableValueHex("Failed to enqueue URB to controller ret", ret);
return ret;
}
return ret;
}
static int _dwc2_submit_control_msg(struct dwc2_host_data *host,
struct usb_device *dev, unsigned long pipe,
void *buffer, int len, struct devrequest *setup, int timeout)
{
struct urb *urb = NULL;
struct usb_host_endpoint *hep = NULL;
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
int ret = 0;
unsigned int start_time;
if (epnum > 8 || epnum < 0)
return -EINVAL;
if (is_in) {
hep = &host->hep_in[epnum];
} else {
hep = &host->hep_out[epnum];
}
urb = usb_urb_alloc(host, 0, IRQ_NONE);
if (urb == NULL)
return -ENOMEM;
construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL,
pipe, buffer, len, setup, 0);
/* Fix speed for non hub-attached devices */
if (!usb_dev_get_parent(dev))
dev->speed = host->host_speed;
//unsigned char *a = urb->setup_packet;
//if (a)
//printf("setup-->%02x %02x %02x %02x %02x %02x %02x %02x\r\n", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
ret = submit_urb(&host->hcd, urb);
if (ret < 0) {
dwc2_urb_dequeue(&host->hcd, urb, 0);
goto exit;
}
start_time = get_timer(0);
ret = pdTRUE;
do {
if (get_timer(start_time) > timeout) {
ret = pdFALSE;
break;
}
} while(!urb->urb_complete);
if (ret != pdTRUE || 0 != urb->status) {//timeout
dwc2_urb_dequeue(&host->hcd, urb, 0);
if (0 != urb->status)
PrintVariableValueHex("usb control urb error", urb->status);
ret = urb->status;
} else {
ret = urb->actual_length;
}
exit:
usb_urb_release(urb);
return ret;
}
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int *actual_length, int timeout)
{
struct urb *urb = NULL;
struct usb_host_endpoint *hep = NULL;
int epnum = usb_pipeendpoint(pipe);
int is_in = usb_pipein(pipe);
int ret = 0;
struct dwc2_host_data *host = &dwc2_host;
unsigned int start_time;
if (epnum > 8 || epnum < 0)
return -EINVAL;
if (is_in) {
hep = &host->hep_in[epnum];
} else {
hep = &host->hep_out[epnum];
}
urb = usb_urb_alloc(host, 0, IRQ_NONE);
if (urb == NULL)
return -ENOMEM;
construct_urb(urb, hep, dev, USB_ENDPOINT_XFER_BULK,
pipe, buffer, transfer_len, NULL, 0);
ret = submit_urb(&host->hcd, urb);
if (ret < 0) {
dwc2_urb_dequeue(&host->hcd, urb, 0);
goto exit;
}
start_time = get_timer(0);
ret = pdTRUE;
do {
if (get_timer(start_time) > timeout) {
ret = pdFALSE;
break;
}
} while(!urb->urb_complete);
if (ret != pdTRUE || 0 != urb->status) {//timeout
dwc2_urb_dequeue(&host->hcd, urb, 0);
if (actual_length)
*actual_length = 0;
if (0 != urb->status)
PrintVariableValueHex("usb bulk urb error", urb->status);
ret = urb->status;
} else {
if (actual_length)
*actual_length = urb->actual_length;
}
exit:
usb_urb_release(urb);
return ret;
}
void usb_reset_endpoint()
{
int i;
struct dwc2_host_data *host = &dwc2_host;
if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_reset))
return;
for (i = 0; i < 16; i++) {
host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_in[i]);
host->dw2_hc_driver->endpoint_reset(&(host->hcd), &host->hep_out[i]);
}
}
void usb_disable_endpoint()
{
int i;
struct dwc2_host_data *host = &dwc2_host;
if ((NULL == host->dw2_hc_driver) || (NULL == host->dw2_hc_driver->endpoint_disable))
return;
for (i = 0; i < 16; i++) {
host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_in[i]);
host->dw2_hc_driver->endpoint_disable(&(host->hcd), &host->hep_out[i]);
}
}
void reset_usb_phy()
{
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
mdelay(10);
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
}
void usb_sysctrl_init()
{
vSysctlConfigure(SYS_ANA_CFG, 8, 0xff, 4);
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 0);//phy reset
vSysctlConfigure(SYS_SOFT_RST, 3, 1, 0);
mdelay(10);
vSysctlConfigure(SYS_SOFT_RST, 30, 1, 1);//phy reset
vSysctlConfigure(SYS_SOFT_RST, 3, 1, 1);
vSysctlConfigure(SYS_ANA_CFG, 24, 3, 1);
mdelay(10);
}
int hub_status_data(char buf[8])
{
int ret = 1;
struct dwc2_host_data *host = &dwc2_host;
//printf("prvUsbPortScanTimerCallback\r\n");
ret = host->dw2_hc_driver->hub_status_data(&(host->hcd), buf);
if (ret != 0) {
//printf("state:%d usb state changed now!\r\n", buf[0]);
}
return ret;
}
void usb_dwc2_lowlevel_restart()
{
struct dwc2_host_data *host = &dwc2_host;
if (host->dw2_hc_driver && host->dw2_hc_driver->stop) {
host->dw2_hc_driver->stop(&(host->hcd));
}
msleep(50);
if (host->dw2_hc_driver && host->dw2_hc_driver->start) {
host->dw2_hc_driver->start(&(host->hcd));
}
}
//#define mainTIMER_SCAN_FREQUENCY_MS pdMS_TO_TICKS( 1000UL )
int usb_dwc2_lowlevel_init()
{
struct dwc2_host_data *host = &dwc2_host;
int ret;
INIT_LIST_HEAD(&host->free_urb_list);
spin_lock_init(&host->lock);
ret = dwc2_driver_init(&host->host, &(host->hcd));
if (!host->host) {
SendUartString("MUSB host is not registered\n");
return -ENODEV;
}
host->dw2_hc_driver = dwc2_get_driver();
return ret;
}
int usb_dwc2_lowlevel_uninit()
{
if (!dwc2_host.host) {
SendUartString("MUSB host is not registered\n");
return -ENODEV;
}
dwc2_driver_uninit(dwc2_host.host);
return 0;
}
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int length, struct devrequest *setup, int timeout)
{
if (dev->parent == NULL) {
return dwc_otg_submit_rh_msg(dev, pipe, buffer, length, setup);
} else {
return _dwc2_submit_control_msg(&dwc2_host, dev, pipe, buffer, length, setup, timeout);
}
}
/*
* DWC2 to USB API interface
*/
/* Direction: In ; Request: Status */
static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer,
int txlen, struct devrequest *cmd)
{
int len = 0;
int stat = 0;
switch (cmd->requesttype & ~USB_DIR_IN) {
case 0:
*(uint16_t *)buffer = cpu_to_le16(1);
len = 2;
break;
case USB_RECIP_INTERFACE:
case USB_RECIP_ENDPOINT:
*(uint16_t *)buffer = cpu_to_le16(0);
len = 2;
break;
case USB_TYPE_CLASS:
*(uint32_t *)buffer = cpu_to_le32(0);
len = 4;
break;
case USB_RECIP_OTHER | USB_TYPE_CLASS:
len = 4;
stat = dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
cmd->value, cmd->index, (char*)buffer, len);
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
dev->act_len = min(len, txlen);
dev->status = stat;
return stat;
}
/* Direction: In ; Request: Descriptor */
/* roothub.a masks */
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
#define RH_A_PSM (1 << 8) /* power switching mode */
#define RH_A_NPS (1 << 9) /* no power switching */
#define RH_A_DT (1 << 10) /* device type (mbz) */
#define RH_A_OCPM (1 << 11) /* over current protection mode */
#define RH_A_NOCP (1 << 12) /* no over current protection */
#define RH_A_POTPGT (0xffUL << 24) /* power on to power good time */
/* roothub.b masks */
#define RH_B_DR 0x0000ffff /* device removable flags */
#define RH_B_PPCM 0xffff0000 /* port power control mask */
static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
{
unsigned char data[32];
uint32_t dsc;
int len = 0;
int stat = 0;
uint16_t wValue = cpu_to_le16(cmd->value);
uint16_t wLength = cpu_to_le16(cmd->length);
switch (cmd->requesttype & ~USB_DIR_IN) {
case 0:
{
switch (wValue & 0xff00) {
case 0x0100: /* device descriptor */
len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
memcpy(buffer, root_hub_dev_des, len);
break;
case 0x0200: /* configuration descriptor */
len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
memcpy(buffer, root_hub_config_des, len);
break;
case 0x0300: /* string descriptors */
switch (wValue & 0xff) {
case 0x00:
len = min3(txlen, (int)sizeof(root_hub_str_index0),
(int)wLength);
memcpy(buffer, root_hub_str_index0, len);
break;
case 0x01:
len = min3(txlen, (int)sizeof(root_hub_str_index1),
(int)wLength);
memcpy(buffer, root_hub_str_index1, len);
break;
}
break;
default:
stat = USB_ST_STALLED;
}
break;
}
case USB_TYPE_CLASS:
/* Root port config, set 1 port and nothing else. */
dsc = 0x00000001;
data[0] = 9; /* min length; */
data[1] = 0x29;
data[2] = dsc & RH_A_NDP;
data[3] = 0;
if (dsc & RH_A_PSM)
data[3] |= 0x1;
if (dsc & RH_A_NOCP)
data[3] |= 0x10;
else if (dsc & RH_A_OCPM)
data[3] |= 0x8;
/* corresponds to data[4-7] */
data[5] = (dsc & RH_A_POTPGT) >> 24;
data[7] = dsc & RH_B_DR;
if (data[2] < 7) {
data[8] = 0xff;
} else {
data[0] += 2;
data[8] = (dsc & RH_B_DR) >> 8;
data[9] = 0xff;
data[10] = data[9];
}
len = min3(txlen, (int)data[0], (int)wLength);
memcpy(buffer, data, len);
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
dev->act_len = min(len, txlen);
dev->status = stat;
return stat;
}
/* Direction: In ; Request: Configuration */
static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
{
int len = 0;
int stat = 0;
switch (cmd->requesttype & ~USB_DIR_IN) {
case 0:
*(uint8_t *)buffer = 0x01;
len = 1;
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
dev->act_len = min(len, txlen);
dev->status = stat;
return stat;
}
/* Direction: In */
static int dwc_otg_submit_rh_msg_in(
struct usb_device *dev, void *buffer,
int txlen, struct devrequest *cmd)
{
switch (cmd->request) {
case USB_REQ_GET_STATUS:
return dwc_otg_submit_rh_msg_in_status(dev, buffer,
txlen, cmd);
case USB_REQ_GET_DESCRIPTOR:
return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
txlen, cmd);
case USB_REQ_GET_CONFIGURATION:
return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
txlen, cmd);
default:
//puts("unsupported root hub command\n");
return USB_ST_STALLED;
}
}
/* Direction: Out */
static int dwc_otg_submit_rh_msg_out(
struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
{
int len = 0;
int stat = 0;
uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
uint16_t wValue = cpu_to_le16(cmd->value);
switch (bmrtype_breq & ~USB_DIR_IN) {
case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
break;
case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
cmd->value, cmd->index, (char*)buffer, txlen);
break;
case (USB_REQ_SET_ADDRESS << 8):
dwc2_host.root_hub_devnum = wValue;
dwc2_host.dw2_hc_driver->hub_control(&dwc2_host.hcd, (cmd->requesttype << 8) | (cmd->request),
cmd->value, cmd->index, (char*)buffer, txlen);
break;
case (USB_REQ_SET_CONFIGURATION << 8):
break;
default:
//puts("unsupported root hub command\n");
stat = USB_ST_STALLED;
}
len = min(len, txlen);
dev->act_len = len;
dev->status = stat;
return stat;
}
static int dwc_otg_submit_rh_msg(struct usb_device *dev,
unsigned long pipe, void *buffer, int txlen,
struct devrequest *cmd)
{
int stat = 0;
if (usb_pipeint(pipe)) {
//puts("Root-Hub submit IRQ: NOT implemented\n");
return 0;
}
if (cmd->requesttype & USB_DIR_IN)
stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd);
else
stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd);
stat = dev->act_len;
return stat;
}

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* MUSB OTG driver u-boot specific functions
*
* Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
*/
#ifndef __ARK_USB_DWC2_H__
#define __ARK_USB_DWC2_H__
int usb_dwc2_lowlevel_init();
int usb_dwc2_lowlevel_uninit();
void usb_sysctrl_init();
void reset_usb_phy();
void usb_disable_endpoint();
void usb_reset_endpoint();
void usb_dwc2_lowlevel_restart();
#endif

296
A27-STEPLDR/Src/usb/core.c Normal file
View File

@ -0,0 +1,296 @@
/*
* core.c - DesignWare HS OTG Controller common routines
*
* Copyright (C) 2004-2013 Synopsys, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* The Core code provides basic services for accessing and managing the
* DWC_otg hardware. These services are used by both the Host Controller
* Driver and the Peripheral Controller Driver.
*/
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
/**
* dwc2_wait_for_mode() - Waits for the controller mode.
* @hsotg: Programming view of the DWC_otg controller.
* @host_mode: If true, waits for host mode, otherwise device mode.
*/
static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg,
bool host_mode)
{
uint32_t tick = get_timer(0);
unsigned int timeout = 110;//ms
dev_vdbg(hsotg->dev, "Waiting for %s mode\n",
host_mode ? "host" : "device");
while (1) {
__s64 ms;
if (dwc2_is_host_mode(hsotg) == host_mode) {
dev_vdbg(hsotg->dev, "%s mode set\n",
host_mode ? "Host" : "Device");
break;
}
ms = get_timer(tick);
if (ms >= (__s64)timeout) {
dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n",
__func__, host_mode ? "host" : "device");
break;
}
//vTaskDelay(2000 / portTICK_RATE_MS);
mdelay(10);
}
}
/*
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*/
int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
{
u32 greset;
int count = 0;
bool wait_for_host_mode = false;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
/*
* If the current mode is host, either due to the force mode
* bit being set (which persists after core reset) or the
* connector id pin, a core soft reset will temporarily reset
* the mode to device. A delay from the IDDIG debounce filter
* will occur before going back to host mode.
*
* Determine whether we will go back into host mode after a
* reset and account for this delay after the reset.
*/
/* Core Soft Reset */
greset = dwc2_readl(hsotg->regs + GRSTCTL);
greset |= GRSTCTL_CSFTRST;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
udelay(1);
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 50) {
dev_warn(hsotg->dev,
"%s() HANG! Soft Reset GRSTCTL=%0x\n",
__func__, greset);
return -EBUSY;
}
} while (greset & GRSTCTL_CSFTRST);
/* Wait for AHB master IDLE state */
count = 0;
do {
udelay(1);
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 50) {
dev_warn(hsotg->dev,
"%s() HANG! AHB Idle GRSTCTL=%0x\n",
__func__, greset);
return -EBUSY;
}
} while (!(greset & GRSTCTL_AHBIDLE));
if (wait_for_host_mode && !skip_wait)
dwc2_wait_for_mode(hsotg, true);
return 0;
}
/*
* Sets or clears force mode based on the dr_mode parameter.
*/
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
{
switch (hsotg->dr_mode) {
case USB_DR_MODE_HOST:
/*
* NOTE: This is required for some rockchip soc based
* platforms on their host-only dwc2.
*/
msleep(50);
break;
default:
dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n",
__func__, hsotg->dr_mode);
break;
}
}
/*
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*
* Additionally this will apply force mode as per the hsotg->dr_mode
* parameter.
*/
int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
{
int retval;
retval = dwc2_core_reset(hsotg, false);
if (retval)
return retval;
dwc2_force_dr_mode(hsotg);
return 0;
}
/**
* dwc2_flush_tx_fifo() - Flushes a Tx FIFO
*
* @hsotg: Programming view of DWC_otg controller
* @num: Tx FIFO to flush
*/
void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
{
u32 greset;
int count = 0;
dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
greset = GRSTCTL_TXFFLSH;
greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 10000) {
dev_warn(hsotg->dev,
"%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
__func__, greset,
dwc2_readl(hsotg->regs + GNPTXSTS));
break;
}
udelay(1);
} while (greset & GRSTCTL_TXFFLSH);
/* Wait for at least 3 PHY Clocks */
udelay(1);
}
/**
* dwc2_flush_rx_fifo() - Flushes the Rx FIFO
*
* @hsotg: Programming view of DWC_otg controller
*/
void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
{
u32 greset;
int count = 0;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
greset = GRSTCTL_RXFFLSH;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
do {
greset = dwc2_readl(hsotg->regs + GRSTCTL);
if (++count > 10000) {
dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
__func__, greset);
break;
}
udelay(1);
} while (greset & GRSTCTL_RXFFLSH);
/* Wait for at least 3 PHY Clocks */
udelay(1);
}
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
{
if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff)
return false;
else
return true;
}
/**
* dwc2_enable_global_interrupts() - Enables the controller's Global
* Interrupt in the AHB Config register
*
* @hsotg: Programming view of DWC_otg controller
*/
void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
{
u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
ahbcfg |= GAHBCFG_GLBL_INTR_EN;
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
}
/**
* dwc2_disable_global_interrupts() - Disables the controller's Global
* Interrupt in the AHB Config register
*
* @hsotg: Programming view of DWC_otg controller
*/
void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
{
u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
}
/* Returns the controller's GHWCFG2.OTG_MODE. */
unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg)
{
u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
GHWCFG2_OP_MODE_SHIFT;
}
/* Returns true if the controller is host-only. */
bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg)
{
unsigned int op_mode = dwc2_op_mode(hsotg);
return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
}

1032
A27-STEPLDR/Src/usb/core.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,269 @@
/*
* core_intr.c - DesignWare HS OTG Controller common interrupt handling
*
* Copyright (C) 2004-2013 Synopsys, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file contains the common interrupt handlers
*/
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
{
switch (hsotg->op_state) {
case OTG_STATE_A_HOST:
return "a_host";
case OTG_STATE_A_SUSPEND:
return "a_suspend";
case OTG_STATE_A_PERIPHERAL:
return "a_peripheral";
case OTG_STATE_B_PERIPHERAL:
return "b_peripheral";
case OTG_STATE_B_HOST:
return "b_host";
default:
return "unknown";
}
}
/**
* dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message
*
* @hsotg: Programming view of DWC_otg controller
*/
static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
{
/* Clear interrupt */
dwc2_writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
}
/**
* dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG
* Interrupt Register (GOTGINT) to determine what interrupt has occurred.
*
* @hsotg: Programming view of DWC_otg controller
*/
static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
{
u32 gotgint;
gotgint = dwc2_readl(hsotg->regs + GOTGINT);
/* Clear GOTGINT */
dwc2_writel(gotgint, hsotg->regs + GOTGINT);
}
/**
* dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status
* Change Interrupt
*
* @hsotg: Programming view of DWC_otg controller
*
* Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a
* Device to Host Mode transition or a Host to Device Mode transition. This only
* occurs when the cable is connected/removed from the PHY connector.
*/
static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
{
u32 gintmsk;
/* Clear interrupt */
dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
/* Need to disable SOF interrupt immediately */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_SOF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
}
/**
* dwc2_handle_session_req_intr() - This interrupt indicates that a device is
* initiating the Session Request Protocol to request the host to turn on bus
* power so a new session can begin
*
* @hsotg: Programming view of DWC_otg controller
*
* This handler responds by turning on bus power. If the DWC_otg controller is
* in low power mode, this handler brings the controller out of low power mode
* before turning on bus power.
*/
static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
{
/* Clear interrupt */
dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
hsotg->lx_state);
}
/*
* This interrupt indicates that a device has been disconnected from the
* root port
*/
static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
{
dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device",
dwc2_op_state_str(hsotg));
if (hsotg->op_state == OTG_STATE_A_HOST)
dwc2_hcd_disconnect(hsotg, false);
}
/*
* This interrupt indicates that SUSPEND state has been detected on the USB.
*
* For HNP the USB Suspend interrupt signals the change from "a_peripheral"
* to "a_host".
*
* When power management is enabled the core will be put in low power mode.
*/
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
{
/* Clear interrupt */
dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
dev_dbg(hsotg->dev, "USB SUSPEND\n");
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
/* Clear the a_peripheral flag, back to a_host */
spin_unlock(&hsotg->lock);
dwc2_hcd_start_isr(hsotg);
spin_lock(&hsotg->lock);
hsotg->op_state = OTG_STATE_A_HOST;
}
}
#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT | \
GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \
GINTSTS_USBSUSP | GINTSTS_PRTINT)
/*
* This function returns the Core Interrupt register
*/
static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
{
u32 gintsts;
u32 gintmsk;
u32 gahbcfg;
u32 gintmsk_common = GINTMSK_COMMON;
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
/* If any common interrupts set */
if (gintsts & gintmsk_common)
dev_dbg(hsotg->dev, "gintsts=%08x gintmsk=%08x\n",
gintsts, gintmsk);
if (gahbcfg & GAHBCFG_GLBL_INTR_EN)
return gintsts & gintmsk & gintmsk_common;
else
return 0;
}
/*
* Common interrupt handler
*
* The common interrupts are those that occur in both Host and Device mode.
* This handler handles the following interrupts:
* - Mode Mismatch Interrupt
* - OTG Interrupt
* - Connector ID Status Change Interrupt
* - Disconnect Interrupt
* - Session Request Interrupt
* - Resume / Remote Wakeup Detected Interrupt
* - Suspend Interrupt
*/
irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
{
struct dwc2_hsotg *hsotg = dev;
u32 gintsts;
irqreturn_t retval = IRQ_NONE;
if (!dwc2_is_controller_alive(hsotg)) {
dev_warn(hsotg->dev, "Controller is dead\n");
goto out;
}
gintsts = dwc2_read_common_intr(hsotg);
if (gintsts & ~GINTSTS_PRTINT)
retval = IRQ_HANDLED;
if (gintsts & GINTSTS_MODEMIS)
dwc2_handle_mode_mismatch_intr(hsotg);
if (gintsts & GINTSTS_OTGINT)
dwc2_handle_otg_intr(hsotg);
if (gintsts & GINTSTS_CONIDSTSCHNG)
dwc2_handle_conn_id_status_change_intr(hsotg);
if (gintsts & GINTSTS_DISCONNINT)
dwc2_handle_disconnect_intr(hsotg);
if (gintsts & GINTSTS_SESSREQINT)
dwc2_handle_session_req_intr(hsotg);
if (gintsts & GINTSTS_USBSUSP)
dwc2_handle_usb_suspend_intr(hsotg);
if (gintsts & GINTSTS_PRTINT) {
/*
* The port interrupt occurs while in device mode with HPRT0
* Port Enable/Disable
*/
}
out:
return retval;
}

View File

@ -0,0 +1,138 @@
#ifndef _DWC2_COMPAT_H
#define _DWC2_COMPAT_H
/* OTG defines lots of enumeration states before device reset */
enum usb_otg_state {
OTG_STATE_UNDEFINED = 0,
/* single-role peripheral, and dual-role default-b */
OTG_STATE_B_IDLE,
OTG_STATE_B_SRP_INIT,
OTG_STATE_B_PERIPHERAL,
/* extra dual-role default-b states */
OTG_STATE_B_WAIT_ACON,
OTG_STATE_B_HOST,
/* dual-role default-a */
OTG_STATE_A_IDLE,
OTG_STATE_A_WAIT_VRISE,
OTG_STATE_A_WAIT_BCON,
OTG_STATE_A_HOST,
OTG_STATE_A_SUSPEND,
OTG_STATE_A_PERIPHERAL,
OTG_STATE_A_WAIT_VFALL,
OTG_STATE_A_VBUS_ERR,
};
enum usb_dr_mode {
USB_DR_MODE_UNKNOWN,
USB_DR_MODE_HOST,
USB_DR_MODE_PERIPHERAL,
USB_DR_MODE_OTG,
};
#define URB_DIR_IN 0x0200 /* Transfer from device to host */
#define URB_DIR_OUT 0
#define URB_DIR_MASK URB_DIR_IN
#define URB_DMA_MAP_SINGLE 0x00010000 /* Non-scatter-gather mapping */
#define URB_DMA_MAP_PAGE 0x00020000 /* HCD-unsupported S-G */
#define URB_DMA_MAP_SG 0x00040000 /* HCD-supported S-G */
#define URB_MAP_LOCAL 0x00080000 /* HCD-local-memory mapping */
#define URB_SETUP_MAP_SINGLE 0x00100000 /* Setup packet DMA mapped */
#define URB_SETUP_MAP_LOCAL 0x00200000 /* HCD-local setup packet */
#define URB_DMA_SG_COMBINED 0x00400000 /* S-G entries were combined */
#define URB_ALIGNED_TEMP_BUFFER 0x00800000 /* Temp buffer was alloc'd */
#define USB_RESUME_TIMEOUT 40 /* ms */
/* class requests from the USB 2.0 hub spec, table 11-15 */
#define HUB_CLASS_REQ(dir, type, request) ((((dir) | (type)) << 8) | (request))
/* GetBusState and SetHubDescriptor are optional, omitted */
#define ClearHubFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, USB_REQ_CLEAR_FEATURE)
#define ClearPortFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, USB_REQ_CLEAR_FEATURE)
#define GetHubDescriptor HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, USB_REQ_GET_DESCRIPTOR)
#define GetHubStatus HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, USB_REQ_GET_STATUS)
#define GetPortStatus HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, USB_REQ_GET_STATUS)
#define SetHubFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, USB_REQ_SET_FEATURE)
#define SetPortFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, USB_REQ_SET_FEATURE)
/*
* Port feature numbers
* See USB 2.0 spec Table 11-17
*/
#define USB_PORT_FEAT_CONNECTION 0
#define USB_PORT_FEAT_ENABLE 1
#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */
#define USB_PORT_FEAT_OVER_CURRENT 3
#define USB_PORT_FEAT_RESET 4
#define USB_PORT_FEAT_L1 5 /* L1 suspend */
#define USB_PORT_FEAT_POWER 8
#define USB_PORT_FEAT_LOWSPEED 9 /* Should never be used */
#define USB_PORT_FEAT_C_CONNECTION 16
#define USB_PORT_FEAT_C_ENABLE 17
#define USB_PORT_FEAT_C_SUSPEND 18
#define USB_PORT_FEAT_C_OVER_CURRENT 19
#define USB_PORT_FEAT_C_RESET 20
#define USB_PORT_FEAT_TEST 21
#define USB_PORT_FEAT_INDICATOR 22
#define USB_PORT_FEAT_C_PORT_L1 23
/*
* wPortChange bit field
* See USB 2.0 spec Table 11-22 and USB 2.0 LPM ECN Table-4.10
* Bits 0 to 5 shown, bits 6 to 15 are reserved
*/
#define USB_PORT_STAT_C_CONNECTION 0x0001
#define USB_PORT_STAT_C_ENABLE 0x0002
#define USB_PORT_STAT_C_SUSPEND 0x0004
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
#define USB_PORT_STAT_C_RESET 0x0010
#define USB_PORT_STAT_C_L1 0x0020
/*
* wPortStatus bit field
* See USB 2.0 spec Table 11-21
*/
#define USB_PORT_STAT_CONNECTION 0x0001
#define USB_PORT_STAT_ENABLE 0x0002
#define USB_PORT_STAT_SUSPEND 0x0004
#define USB_PORT_STAT_OVERCURRENT 0x0008
#define USB_PORT_STAT_RESET 0x0010
#define USB_PORT_STAT_L1 0x0020
/* bits 6 to 7 are reserved */
#define USB_PORT_STAT_POWER 0x0100
#define USB_PORT_STAT_LOW_SPEED 0x0200
#define USB_PORT_STAT_HIGH_SPEED 0x0400
#define USB_PORT_STAT_TEST 0x0800
#define USB_PORT_STAT_INDICATOR 0x1000
/* bits 13 to 15 are reserved */
/*
* wHubCharacteristics (masks)
* See USB 2.0 spec Table 11-13, offset 3
*/
#define HUB_CHAR_LPSM 0x0003 /* Logical Power Switching Mode mask */
#define HUB_CHAR_COMMON_LPSM 0x0000 /* All ports power control at once */
#define HUB_CHAR_INDV_PORT_LPSM 0x0001 /* per-port power control */
#define HUB_CHAR_NO_LPSM 0x0002 /* no power switching */
#define HUB_CHAR_COMPOUND 0x0004 /* hub is part of a compound device */
#define HUB_CHAR_OCPM 0x0018 /* Over-Current Protection Mode mask */
#define HUB_CHAR_COMMON_OCPM 0x0000 /* All ports Over-Current reporting */
#define HUB_CHAR_INDV_PORT_OCPM 0x0008 /* per-port Over-current reporting */
#define HUB_CHAR_NO_OCPM 0x0010 /* No Over-current Protection support */
#define HUB_CHAR_TTTT 0x0060 /* TT Think Time mask */
#define HUB_CHAR_PORTIND 0x0080 /* per-port indicators (LEDs) */
#endif

3703
A27-STEPLDR/Src/usb/hcd.c Normal file

File diff suppressed because it is too large Load Diff

793
A27-STEPLDR/Src/usb/hcd.h Normal file
View File

@ -0,0 +1,793 @@
/*
* hcd.h - DesignWare HS OTG Controller host-mode declarations
*
* Copyright (C) 2004-2013 Synopsys, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DWC2_HCD_H__
#define __DWC2_HCD_H__
#include "usb-compat.h"
/*
* This file contains the structures, constants, and interfaces for the
* Host Contoller Driver (HCD)
*
* The Host Controller Driver (HCD) is responsible for translating requests
* from the USB Driver into the appropriate actions on the DWC_otg controller.
* It isolates the USBD from the specifics of the controller by providing an
* API to the USBD.
*/
struct dwc2_qh;
/**
* struct dwc2_host_chan - Software host channel descriptor
*
* @hc_num: Host channel number, used for register address lookup
* @dev_addr: Address of the device
* @ep_num: Endpoint of the device
* @ep_is_in: Endpoint direction
* @speed: Device speed. One of the following values:
* - USB_SPEED_LOW
* - USB_SPEED_FULL
* - USB_SPEED_HIGH
* @ep_type: Endpoint type. One of the following values:
* - USB_ENDPOINT_XFER_CONTROL: 0
* - USB_ENDPOINT_XFER_ISOC: 1
* - USB_ENDPOINT_XFER_BULK: 2
* - USB_ENDPOINT_XFER_INTR: 3
* @max_packet: Max packet size in bytes
* @data_pid_start: PID for initial transaction.
* 0: DATA0
* 1: DATA2
* 2: DATA1
* 3: MDATA (non-Control EP),
* SETUP (Control EP)
* @multi_count: Number of additional periodic transactions per
* (micro)frame
* @xfer_buf: Pointer to current transfer buffer position
* @xfer_dma: DMA address of xfer_buf
* @align_buf: In Buffer DMA mode this will be used if xfer_buf is not
* DWORD aligned
* @xfer_len: Total number of bytes to transfer
* @xfer_count: Number of bytes transferred so far
* @start_pkt_count: Packet count at start of transfer
* @xfer_started: True if the transfer has been started
* @ping: True if a PING request should be issued on this channel
* @error_state: True if the error count for this transaction is non-zero
* @halt_on_queue: True if this channel should be halted the next time a
* request is queued for the channel. This is necessary in
* slave mode if no request queue space is available when
* an attempt is made to halt the channel.
* @halt_pending: True if the host channel has been halted, but the core
* is not finished flushing queued requests
* @do_split: Enable split for the channel
* @complete_split: Enable complete split
* @hub_addr: Address of high speed hub for the split
* @hub_port: Port of the low/full speed device for the split
* @xact_pos: Split transaction position. One of the following values:
* - DWC2_HCSPLT_XACTPOS_MID
* - DWC2_HCSPLT_XACTPOS_BEGIN
* - DWC2_HCSPLT_XACTPOS_END
* - DWC2_HCSPLT_XACTPOS_ALL
* @requests: Number of requests issued for this channel since it was
* assigned to the current transfer (not counting PINGs)
* @schinfo: Scheduling micro-frame bitmap
* @ntd: Number of transfer descriptors for the transfer
* @halt_status: Reason for halting the host channel
* @hcint Contents of the HCINT register when the interrupt came
* @qh: QH for the transfer being processed by this channel
* @hc_list_entry: For linking to list of host channels
* @desc_list_addr: Current QH's descriptor list DMA address
* @desc_list_sz: Current QH's descriptor list size
* @split_order_list_entry: List entry for keeping track of the order of splits
*
* This structure represents the state of a single host channel when acting in
* host mode. It contains the data items needed to transfer packets to an
* endpoint via a host channel.
*/
struct dwc2_host_chan {
u8 hc_num;
unsigned dev_addr:7;
unsigned ep_num:4;
unsigned ep_is_in:1;
unsigned speed:4;
unsigned ep_type:2;
unsigned max_packet:11;
unsigned data_pid_start:2;
#define DWC2_HC_PID_DATA0 TSIZ_SC_MC_PID_DATA0
#define DWC2_HC_PID_DATA2 TSIZ_SC_MC_PID_DATA2
#define DWC2_HC_PID_DATA1 TSIZ_SC_MC_PID_DATA1
#define DWC2_HC_PID_MDATA TSIZ_SC_MC_PID_MDATA
#define DWC2_HC_PID_SETUP TSIZ_SC_MC_PID_SETUP
unsigned multi_count:2;
u8 *xfer_buf;
dma_addr_t xfer_dma;
dma_addr_t align_buf;
u32 xfer_len;
u32 xfer_count;
u16 start_pkt_count;
u8 xfer_started;
u8 do_ping;
u8 error_state;
u8 halt_on_queue;
u8 halt_pending;
u8 do_split;
u8 complete_split;
u8 hub_addr;
u8 hub_port;
u8 xact_pos;
#define DWC2_HCSPLT_XACTPOS_MID HCSPLT_XACTPOS_MID
#define DWC2_HCSPLT_XACTPOS_END HCSPLT_XACTPOS_END
#define DWC2_HCSPLT_XACTPOS_BEGIN HCSPLT_XACTPOS_BEGIN
#define DWC2_HCSPLT_XACTPOS_ALL HCSPLT_XACTPOS_ALL
u8 requests;
u8 schinfo;
u16 ntd;
enum dwc2_halt_status halt_status;
u32 hcint;
struct dwc2_qh *qh;
ListItem_t hc_list_entry;
ListItem_t split_order_list_entry;
};
struct dwc2_hcd_pipe_info {
u8 dev_addr;
u8 ep_num;
u8 pipe_type;
u8 pipe_dir;
u16 mps;
};
struct dwc2_qtd;
struct dwc2_hcd_urb {
void *priv;
struct dwc2_qtd *qtd;
void *buf;
dma_addr_t dma;
void *setup_packet;
dma_addr_t setup_dma;
u32 length;
u32 actual_length;
int status;
u32 error_count;
u32 packet_count;
u32 flags;
u16 interval;
ListItem_t free_list_entry;
struct dwc2_hcd_pipe_info pipe_info;
};
/* Phases for control transfers */
enum dwc2_control_phase {
DWC2_CONTROL_SETUP,
DWC2_CONTROL_DATA,
DWC2_CONTROL_STATUS,
};
/* Transaction types */
enum dwc2_transaction_type {
DWC2_TRANSACTION_NONE,
DWC2_TRANSACTION_PERIODIC,
DWC2_TRANSACTION_NON_PERIODIC,
DWC2_TRANSACTION_ALL,
};
/* The number of elements per LS bitmap (per port on multi_tt) */
#define DWC2_ELEMENTS_PER_LS_BITMAP DIV_ROUND_UP(DWC2_LS_SCHEDULE_SLICES, \
BITS_PER_LONG)
/**
* struct dwc2_tt - dwc2 data associated with a usb_tt
*
* @refcount: Number of Queue Heads (QHs) holding a reference.
* @usb_tt: Pointer back to the official usb_tt.
* @periodic_bitmaps: Bitmap for which parts of the 1ms frame are accounted
* for already. Each is DWC2_ELEMENTS_PER_LS_BITMAP
* elements (so sizeof(long) times that in bytes).
*
* This structure is stored in the hcpriv of the official usb_tt.
*/
struct dwc2_tt {
int refcount;
struct usb_tt *usb_tt;
unsigned long periodic_bitmaps[];
};
/**
* struct dwc2_hs_transfer_time - Info about a transfer on the high speed bus.
*
* @start_schedule_usecs: The start time on the main bus schedule. Note that
* the main bus schedule is tightly packed and this
* time should be interpreted as tightly packed (so
* uFrame 0 starts at 0 us, uFrame 1 starts at 100 us
* instead of 125 us).
* @duration_us: How long this transfer goes.
*/
struct dwc2_hs_transfer_time {
u32 start_schedule_us;
u16 duration_us;
};
/**
* struct dwc2_qh - Software queue head structure
*
* @hsotg: The HCD state structure for the DWC OTG controller
* @ep_type: Endpoint type. One of the following values:
* - USB_ENDPOINT_XFER_CONTROL
* - USB_ENDPOINT_XFER_BULK
* - USB_ENDPOINT_XFER_INT
* - USB_ENDPOINT_XFER_ISOC
* @ep_is_in: Endpoint direction
* @maxp: Value from wMaxPacketSize field of Endpoint Descriptor
* @dev_speed: Device speed. One of the following values:
* - USB_SPEED_LOW
* - USB_SPEED_FULL
* - USB_SPEED_HIGH
* @data_toggle: Determines the PID of the next data packet for
* non-controltransfers. Ignored for control transfers.
* One of the following values:
* - DWC2_HC_PID_DATA0
* - DWC2_HC_PID_DATA1
* @ping_state: Ping state
* @do_split: Full/low speed endpoint on high-speed hub requires split
* @td_first: Index of first activated isochronous transfer descriptor
* @td_last: Index of last activated isochronous transfer descriptor
* @host_us: Bandwidth in microseconds per transfer as seen by host
* @device_us: Bandwidth in microseconds per transfer as seen by device
* @host_interval: Interval between transfers as seen by the host. If
* the host is high speed and the device is low speed this
* will be 8 times device interval.
* @device_interval: Interval between transfers as seen by the device.
* interval.
* @next_active_frame: (Micro)frame _before_ we next need to put something on
* the bus. We'll move the qh to active here. If the
* host is in high speed mode this will be a uframe. If
* the host is in low speed mode this will be a full frame.
* @start_active_frame: If we are partway through a split transfer, this will be
* what next_active_frame was when we started. Otherwise
* it should always be the same as next_active_frame.
* @num_hs_transfers: Number of transfers in hs_transfers.
* Normally this is 1 but can be more than one for splits.
* Always >= 1 unless the host is in low/full speed mode.
* @hs_transfers: Transfers that are scheduled as seen by the high speed
* bus. Not used if host is in low or full speed mode (but
* note that it IS USED if the device is low or full speed
* as long as the HOST is in high speed mode).
* @ls_start_schedule_slice: Start time (in slices) on the low speed bus
* schedule that's being used by this device. This
* will be on the periodic_bitmap in a
* "struct dwc2_tt". Not used if this device is high
* speed. Note that this is in "schedule slice" which
* is tightly packed.
* @ls_duration_us: Duration on the low speed bus schedule.
* @ntd: Actual number of transfer descriptors in a list
* @dw_align_buf: Used instead of original buffer if its physical address
* is not dword-aligned
* @dw_align_buf_dma: DMA address for dw_align_buf
* @qtd_list: List of QTDs for this QH
* @channel: Host channel currently processing transfers for this QH
* @qh_list_entry: Entry for QH in either the periodic or non-periodic
* schedule
* @desc_list: List of transfer descriptors
* @desc_list_dma: Physical address of desc_list
* @desc_list_sz: Size of descriptors list
* @n_bytes: Xfer Bytes array. Each element corresponds to a transfer
* descriptor and indicates original XferSize value for the
* descriptor
* @unreserve_timer: Timer for releasing periodic reservation.
* @dwc2_tt: Pointer to our tt info (or NULL if no tt).
* @ttport: Port number within our tt.
* @tt_buffer_dirty True if clear_tt_buffer_complete is pending
* @unreserve_pending: True if we planned to unreserve but haven't yet.
* @schedule_low_speed: True if we have a low/full speed component (either the
* host is in low/full speed mode or do_split).
*
* A Queue Head (QH) holds the static characteristics of an endpoint and
* maintains a list of transfers (QTDs) for that endpoint. A QH structure may
* be entered in either the non-periodic or periodic schedule.
*/
struct dwc2_qh {
struct dwc2_hsotg *hsotg;
u8 ep_type;
u8 ep_is_in;
u16 maxp;
u8 dev_speed;
u8 data_toggle;
u8 ping_state;
u8 do_split;
u8 td_first;
u8 td_last;
u16 host_us;
u16 device_us;
u16 host_interval;
u16 device_interval;
u16 next_active_frame;
u16 start_active_frame;
s16 num_hs_transfers;
struct dwc2_hs_transfer_time hs_transfers[DWC2_HS_SCHEDULE_UFRAMES];
u32 ls_start_schedule_slice;
u16 ntd;
u8 *dw_align_buf;
dma_addr_t dw_align_buf_dma;
List_t qtd_list;
struct dwc2_host_chan *channel;
ListItem_t qh_list_entry;
u32 *n_bytes;
struct timer_list unreserve_timer;
struct dwc2_tt *dwc_tt;
int ttport;
unsigned tt_buffer_dirty:1;
unsigned unreserve_pending:1;
unsigned schedule_low_speed:1;
};
/**
* struct dwc2_qtd - Software queue transfer descriptor (QTD)
*
* @control_phase: Current phase for control transfers (Setup, Data, or
* Status)
* @in_process: Indicates if this QTD is currently processed by HW
* @data_toggle: Determines the PID of the next data packet for the
* data phase of control transfers. Ignored for other
* transfer types. One of the following values:
* - DWC2_HC_PID_DATA0
* - DWC2_HC_PID_DATA1
* @complete_split: Keeps track of the current split type for FS/LS
* endpoints on a HS Hub
* @isoc_split_pos: Position of the ISOC split in full/low speed
* @isoc_frame_index: Index of the next frame descriptor for an isochronous
* transfer. A frame descriptor describes the buffer
* position and length of the data to be transferred in the
* next scheduled (micro)frame of an isochronous transfer.
* It also holds status for that transaction. The frame
* index starts at 0.
* @isoc_split_offset: Position of the ISOC split in the buffer for the
* current frame
* @ssplit_out_xfer_count: How many bytes transferred during SSPLIT OUT
* @error_count: Holds the number of bus errors that have occurred for
* a transaction within this transfer
* @n_desc: Number of DMA descriptors for this QTD
* @isoc_frame_index_last: Last activated frame (packet) index, used in
* descriptor DMA mode only
* @urb: URB for this transfer
* @qh: Queue head for this QTD
* @qtd_list_entry: For linking to the QH's list of QTDs
*
* A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
* interrupt, or isochronous transfer. A single QTD is created for each URB
* (of one of these types) submitted to the HCD. The transfer associated with
* a QTD may require one or multiple transactions.
*
* A QTD is linked to a Queue Head, which is entered in either the
* non-periodic or periodic schedule for execution. When a QTD is chosen for
* execution, some or all of its transactions may be executed. After
* execution, the state of the QTD is updated. The QTD may be retired if all
* its transactions are complete or if an error occurred. Otherwise, it
* remains in the schedule so more transactions can be executed later.
*/
struct dwc2_qtd {
enum dwc2_control_phase control_phase;
u8 in_process;
u8 data_toggle;
u8 complete_split;
u8 isoc_split_pos;
u32 ssplit_out_xfer_count;
u8 error_count;
u8 n_desc;
struct dwc2_hcd_urb *urb;
struct dwc2_qh *qh;
ListItem_t qtd_list_entry;
};
#ifdef DEBUG
struct hc_xfer_info {
struct dwc2_hsotg *hsotg;
struct dwc2_host_chan *chan;
};
#endif
u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */
static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
{
return (struct usb_hcd *)hsotg->priv;
}
/*
* Inline used to disable one channel interrupt. Channel interrupts are
* disabled when the channel is halted or released by the interrupt handler.
* There is no need to handle further interrupts of that type until the
* channel is re-assigned. In fact, subsequent handling may cause crashes
* because the channel structures are cleaned up when the channel is released.
*/
static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
{
u32 mask = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
mask &= ~intr;
dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
}
void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
enum dwc2_halt_status halt_status);
void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan);
/*
* Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
* are read as 1, they won't clear when written back.
*/
static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
{
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
return hprt0;
}
static inline u8 dwc2_hcd_get_ep_num(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->ep_num;
}
static inline u8 dwc2_hcd_get_pipe_type(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type;
}
static inline u16 dwc2_hcd_get_mps(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->mps;
}
static inline u8 dwc2_hcd_get_dev_addr(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->dev_addr;
}
static inline u8 dwc2_hcd_is_pipe_bulk(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type == USB_ENDPOINT_XFER_BULK;
}
static inline u8 dwc2_hcd_is_pipe_control(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_type == USB_ENDPOINT_XFER_CONTROL;
}
static inline u8 dwc2_hcd_is_pipe_in(struct dwc2_hcd_pipe_info *pipe)
{
return pipe->pipe_dir == USB_DIR_IN;
}
static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
{
return !dwc2_hcd_is_pipe_in(pipe);
}
void dwc2_hcd_irq(struct dwc2_hsotg *hsotg);
int dwc2_hcd_init(struct dwc2_hsotg *hsotg, struct usb_hcd *hcd);
void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
/* Transaction Execution Functions */
enum dwc2_transaction_type dwc2_hcd_select_transactions(
struct dwc2_hsotg *hsotg);
void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
enum dwc2_transaction_type tr_type);
/* Schedule Queue Functions */
/* Implemented in hcd_queue.c */
struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb,
gfp_t mem_flags);
void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
int sched_csplit);
void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
struct dwc2_qh *qh);
/* Unlinks and frees a QTD */
static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd,
struct dwc2_qh *qh)
{
list_del(&qtd->qtd_list_entry);
list_add_tail(&qtd->qtd_list_entry, &hsotg->free_qtd_list);
qtd = NULL;
}
/* Descriptor DMA support functions */
void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_qh *qh);
void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan, int chnum,
enum dwc2_halt_status halt_status);
int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
gfp_t mem_flags);
void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
/* Check if QH is non-periodic */
#define dwc2_qh_is_non_per(_qh_ptr_) \
((_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_BULK || \
(_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_CONTROL)
#ifdef CONFIG_USB_DWC2_DEBUG_PERIODIC
static inline bool dbg_hc(struct dwc2_host_chan *hc) { return true; }
static inline bool dbg_qh(struct dwc2_qh *qh) { return true; }
static inline bool dbg_urb(struct urb *urb) { return true; }
static inline bool dbg_perio(void) { return true; }
#else /* !CONFIG_USB_DWC2_DEBUG_PERIODIC */
static inline bool dbg_hc(struct dwc2_host_chan *hc)
{
return hc->ep_type == USB_ENDPOINT_XFER_BULK ||
hc->ep_type == USB_ENDPOINT_XFER_CONTROL;
}
static inline bool dbg_qh(struct dwc2_qh *qh)
{
return qh->ep_type == USB_ENDPOINT_XFER_BULK ||
qh->ep_type == USB_ENDPOINT_XFER_CONTROL;
}
static inline bool dbg_urb(struct urb *urb)
{
return true;
/*return usb_pipetype(urb->pipe) == PIPE_BULK ||
usb_pipetype(urb->pipe) == PIPE_CONTROL;*/
}
static inline bool dbg_perio(void) { return false; }
#endif
/* High bandwidth multiplier as encoded in highspeed endpoint descriptors */
#define dwc2_hb_mult(wmaxpacketsize) (1 + (((wmaxpacketsize) >> 11) & 0x03))
/* Packet size for any kind of endpoint descriptor */
#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff)
/*
* Returns true if frame1 index is greater than frame2 index. The comparison
* is done modulo FRLISTEN_64_SIZE. This accounts for the rollover of the
* frame number when the max index frame number is reached.
*/
static inline bool dwc2_frame_idx_num_gt(u16 fr_idx1, u16 fr_idx2)
{
u16 diff = fr_idx1 - fr_idx2;
u16 sign = diff & (FRLISTEN_64_SIZE >> 1);
return diff && !sign;
}
/*
* Returns true if frame1 is less than or equal to frame2. The comparison is
* done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the
* frame number when the max frame number is reached.
*/
static inline int dwc2_frame_num_le(u16 frame1, u16 frame2)
{
return ((frame2 - frame1) & HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM >> 1);
}
/*
* Returns true if frame1 is greater than frame2. The comparison is done
* modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
* number when the max frame number is reached.
*/
static inline int dwc2_frame_num_gt(u16 frame1, u16 frame2)
{
return (frame1 != frame2) &&
((frame1 - frame2) & HFNUM_MAX_FRNUM) < (HFNUM_MAX_FRNUM >> 1);
}
/*
* Increments frame by the amount specified by inc. The addition is done
* modulo HFNUM_MAX_FRNUM. Returns the incremented value.
*/
static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc)
{
return (frame + inc) & HFNUM_MAX_FRNUM;
}
static inline u16 dwc2_frame_num_dec(u16 frame, u16 dec)
{
return (frame + HFNUM_MAX_FRNUM + 1 - dec) & HFNUM_MAX_FRNUM;
}
static inline u16 dwc2_full_frame_num(u16 frame)
{
return (frame & HFNUM_MAX_FRNUM) >> 3;
}
static inline u16 dwc2_micro_frame_num(u16 frame)
{
return frame & 0x7;
}
/*
* Returns the Core Interrupt Status register contents, ANDed with the Core
* Interrupt Mask register contents
*/
static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
{
return dwc2_readl(hsotg->regs + GINTSTS) &
dwc2_readl(hsotg->regs + GINTMSK);
}
static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
{
return dwc2_urb->status;
}
static inline u32 dwc2_hcd_urb_get_actual_length(
struct dwc2_hcd_urb *dwc2_urb)
{
return dwc2_urb->actual_length;
}
static inline u32 dwc2_hcd_urb_get_error_count(struct dwc2_hcd_urb *dwc2_urb)
{
return dwc2_urb->error_count;
}
static inline int dwc2_hcd_is_bandwidth_allocated(struct dwc2_hsotg *hsotg,
struct usb_host_endpoint *ep)
{
struct dwc2_qh *qh = (struct dwc2_qh *)ep->hcpriv;
if (qh && !list_item_empty(&qh->qh_list_entry))
return 1;
return 0;
}
static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg,
struct usb_host_endpoint *ep)
{
struct dwc2_qh *qh = (struct dwc2_qh *)ep->hcpriv;
if (!qh) {
WARN_ON(1);
return 0;
}
return qh->host_us;
}
void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan, int chnum,
struct dwc2_qtd *qtd);
/* HCD Core API */
/**
* dwc2_handle_hcd_intr() - Called on every hardware interrupt
*
* @hsotg: The DWC2 HCD
*
* Returns IRQ_HANDLED if interrupt is handled
* Return IRQ_NONE if interrupt is not handled
*/
irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_stop() - Halts the DWC_otg host mode operation
*
* @hsotg: The DWC2 HCD
*/
void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
* and 0 otherwise
*
* @hsotg: The DWC2 HCD
*/
int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
/* URB interface */
/* Transfer flags */
#define URB_GIVEBACK_ASAP 0x1
#define URB_SEND_ZERO_PACKET 0x2
/* Host driver callbacks */
struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg,
void *context, gfp_t mem_flags,
int *ttport);
void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg,
struct dwc2_tt *dwc_tt);
int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
int status);
#ifdef DEBUG
/*
* Macro to sample the remaining PHY clocks left in the current frame. This
* may be used during debugging to determine the average time it takes to
* execute sections of code. There are two possible sample points, "a" and
* "b", so the _letter_ argument must be one of these values.
*
* To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
* example, "cat /sys/devices/lm0/hcd_frrem".
*/
#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) \
do { \
struct hfnum_data _hfnum_; \
struct dwc2_qtd *_qtd_; \
\
_qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd, \
qtd_list_entry); \
if (usb_pipeint(_qtd_->urb->pipe) && \
(_qh_)->start_active_frame != 0 && !_qtd_->complete_split) { \
_hfnum_.d32 = dwc2_readl((_hcd_)->regs + HFNUM); \
switch (_hfnum_.b.frnum & 0x7) { \
case 7: \
(_hcd_)->hfnum_7_samples_##_letter_++; \
(_hcd_)->hfnum_7_frrem_accum_##_letter_ += \
_hfnum_.b.frrem; \
break; \
case 0: \
(_hcd_)->hfnum_0_samples_##_letter_++; \
(_hcd_)->hfnum_0_frrem_accum_##_letter_ += \
_hfnum_.b.frrem; \
break; \
default: \
(_hcd_)->hfnum_other_samples_##_letter_++; \
(_hcd_)->hfnum_other_frrem_accum_##_letter_ += \
_hfnum_.b.frrem; \
break; \
} \
} \
} while (0)
#else
#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) do {} while (0)
#endif
void dwc2_hcd_start_isr(struct dwc2_hsotg *hsotg);
#endif /* __DWC2_HCD_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,429 @@
/*
* hcd_queue.c - DesignWare HS OTG Controller host queuing routines
*
* Copyright (C) 2004-2013 Synopsys, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file contains the functions to manage Queue Heads and Queue
* Transfer Descriptors for Host mode
*/
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
/* Wait this long before releasing periodic reservation */
#define DWC2_UNRESERVE_DELAY (5)
#define swap(a, b) do {unsigned long tmp = (a); (a) = (b); (b) = tmp;} while(0)
unsigned long gcd(unsigned long a, unsigned long b)
{
unsigned long r = a | b;
if (!a || !b)
return r;
/* Isolate lsbit of r */
r &= -r;
while (!(b & r))
b >>= 1;
if (b == r)
return r;
for (;;) {
while (!(a & r))
a >>= 1;
if (a == r)
return r;
if (a == b)
return a;
if (a < b)
swap(a, b);
a -= b;
a >>= 1;
if (a & r)
a += b;
a >>= 1;
}
}
/**
* dwc2_do_unreserve() - Actually release the periodic reservation
*
* This function actually releases the periodic bandwidth that was reserved
* by the given qh.
*
* @hsotg: The HCD state structure for the DWC OTG controller
* @qh: QH for the periodic transfer.
*/
static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
assert_spin_locked(&hsotg->lock);
WARN_ON(!qh->unreserve_pending);
/* No more unreserve pending--we're doing it */
qh->unreserve_pending = false;
if (!list_item_empty(&qh->qh_list_entry)) {
WARN_ON(!list_item_empty(&qh->qh_list_entry));
list_del_init(&qh->qh_list_entry);
}
}
/**
* dwc2_unreserve_timer_fn() - Timer function to release periodic reservation
*
* According to the kernel doc for usb_submit_urb() (specifically the part about
* "Reserved Bandwidth Transfers"), we need to keep a reservation active as
* long as a device driver keeps submitting. Since we're using HCD_BH to give
* back the URB we need to give the driver a little bit of time before we
* release the reservation. This worker is called after the appropriate
* delay.
*
* @work: Pointer to a qh unreserve_work.
*/
/* static void dwc2_unreserve_timer_fn(unsigned long data)
{
} */
/**
* dwc2_qh_init() - Initializes a QH structure
*
* @hsotg: The HCD state structure for the DWC OTG controller
* @qh: The QH to init
* @urb: Holds the information about the device/endpoint needed to initialize
* the QH
* @mem_flags: Flags for allocating memory.
*/
static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
struct dwc2_hcd_urb *urb, gfp_t mem_flags)
{
int dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
u8 ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
bool ep_is_in = !!dwc2_hcd_is_pipe_in(&urb->pipe_info);
u32 hprt = dwc2_readl(hsotg->regs + HPRT0);
u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED &&
dev_speed != USB_SPEED_HIGH);
int maxp = dwc2_hcd_get_mps(&urb->pipe_info);
int bytecount = dwc2_hb_mult(maxp) * dwc2_max_packet(maxp);
char *speed, *type;
/* Initialize QH */
qh->hsotg = hsotg;
qh->ep_type = ep_type;
qh->ep_is_in = ep_is_in;
qh->data_toggle = DWC2_HC_PID_DATA0;
qh->maxp = maxp;
INIT_LIST_HEAD(&qh->qtd_list);
INIT_LIST_ITEM(&qh->qh_list_entry);
qh->qh_list_entry.pvOwner = (void *)qh;
qh->do_split = do_split;
qh->dev_speed = dev_speed;
switch (dev_speed) {
case USB_SPEED_LOW:
speed = "low";
break;
case USB_SPEED_FULL:
speed = "full";
break;
case USB_SPEED_HIGH:
speed = "high";
break;
default:
speed = "?";
break;
}
switch (qh->ep_type) {
case USB_ENDPOINT_XFER_CONTROL:
type = "control";
break;
case USB_ENDPOINT_XFER_BULK:
type = "bulk";
break;
default:
type = "?";
break;
}
USB_UNUSED(bytecount);
USB_UNUSED(speed);
USB_UNUSED(type);
dwc2_sch_dbg(hsotg, "QH=%p Init %s, %s speed, %d bytes:\n", qh, type,
speed, bytecount);
dwc2_sch_dbg(hsotg, "QH=%p ...addr=%d, ep=%d, %s\n", qh,
dwc2_hcd_get_dev_addr(&urb->pipe_info),
dwc2_hcd_get_ep_num(&urb->pipe_info),
ep_is_in ? "IN" : "OUT");
}
/**
* dwc2_hcd_qh_create() - Allocates and initializes a QH
*
* @hsotg: The HCD state structure for the DWC OTG controller
* @urb: Holds the information about the device/endpoint needed
* to initialize the QH
* @atomic_alloc: Flag to do atomic allocation if needed
*
* Return: Pointer to the newly allocated QH, or NULL on error
*/
struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb,
gfp_t mem_flags)
{
struct dwc2_qh *qh;
if (!urb->priv)
return NULL;
/* Allocate memory */
qh = (struct dwc2_qh *)kzalloc(sizeof(*qh), mem_flags);
if (!qh)
return NULL;
dwc2_qh_init(hsotg, qh, urb, mem_flags);
/* if (hsotg->params.dma_desc_enable &&
dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
dwc2_hcd_qh_free(hsotg, qh);
return NULL;
} */
return qh;
}
/**
* dwc2_hcd_qh_free() - Frees the QH
*
* @hsotg: HCD instance
* @qh: The QH to free
*
* QH should already be removed from the list. QTD list should already be empty
* if called from URB Dequeue.
*
* Must NOT be called with interrupt disabled or spinlock held
*/
void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
/* Make sure any unreserve work is finished. */
if (0) {
unsigned long flags;
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_do_unreserve(hsotg, qh);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
kfree(qh);
}
/**
* dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic
* schedule if it is not already in the schedule. If the QH is already in
* the schedule, no action is taken.
*
* @hsotg: The HCD state structure for the DWC OTG controller
* @qh: The QH to add
*
* Return: 0 if successful, negative error code otherwise
*/
int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
u32 intr_mask;
if (dbg_qh(qh))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
if (!list_item_empty(&qh->qh_list_entry))
/* QH already in a schedule */
return 0;
/* Add the new QH to the appropriate schedule */
if (dwc2_qh_is_non_per(qh)) {
/* Schedule right away */
qh->start_active_frame = hsotg->frame_number;
qh->next_active_frame = qh->start_active_frame;
/* Always start in inactive schedule */
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_inactive);
return 0;
}
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
intr_mask |= GINTSTS_SOF;
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
return 0;
}
/**
* dwc2_hcd_qh_unlink() - Removes a QH from either the non-periodic or periodic
* schedule. Memory is not freed.
*
* @hsotg: The HCD state structure
* @qh: QH to remove from schedule
*/
void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
u32 intr_mask;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
if (list_item_empty(&qh->qh_list_entry))
/* QH is not in a schedule */
return;
if (dwc2_qh_is_non_per(qh)) {
if (hsotg->non_periodic_qh_ptr == &qh->qh_list_entry) {
hsotg->non_periodic_qh_ptr = listGET_NEXT(hsotg->non_periodic_qh_ptr);
}
list_del_init(&qh->qh_list_entry);
return;
}
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
intr_mask &= ~GINTSTS_SOF;
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
}
/*
* Deactivates a QH. For non-periodic QHs, removes the QH from the active
* non-periodic schedule. The QH is added to the inactive non-periodic
* schedule if any QTDs are still attached to the QH.
*
* For periodic QHs, the QH is removed from the periodic queued schedule. If
* there are any QTDs still attached to the QH, the QH is added to either the
* periodic inactive schedule or the periodic ready schedule and its next
* scheduled frame is calculated. The QH is placed in the ready schedule if
* the scheduled frame has been reached already. Otherwise it's placed in the
* inactive schedule. If there are no QTDs attached to the QH, the QH is
* completely removed from the periodic schedule.
*/
void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
int sched_next_periodic_split)
{
u16 old_frame = qh->next_active_frame;
dev_vdbg(hsotg->dev, "%s() ep_type:%d\n", __func__, qh->ep_type);
USB_UNUSED(old_frame);
if (dbg_qh(qh))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
if (dwc2_qh_is_non_per(qh)) {
dwc2_hcd_qh_unlink(hsotg, qh);
if (!list_empty(&qh->qtd_list))
/* Add back to inactive non-periodic schedule */
dwc2_hcd_qh_add(hsotg, qh);
return;
}
}
/**
* dwc2_hcd_qtd_init() - Initializes a QTD structure
*
* @qtd: The QTD to initialize
* @urb: The associated URB
*/
void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
{
qtd->urb = urb;
if (dwc2_hcd_get_pipe_type(&urb->pipe_info) ==
USB_ENDPOINT_XFER_CONTROL) {
/*
* The only time the QTD data toggle is used is on the data
* phase of control transfers. This phase always starts with
* DATA1.
*/
qtd->data_toggle = DWC2_HC_PID_DATA1;
qtd->control_phase = DWC2_CONTROL_SETUP;
}
/* Start split */
qtd->complete_split = 0;
qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
qtd->in_process = 0;
/* Store the qtd ptr in the urb to reference the QTD */
urb->qtd = qtd;
}
/**
* dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
* Caller must hold driver lock.
*
* @hsotg: The DWC HCD structure
* @qtd: The QTD to add
* @qh: Queue head to add qtd to
*
* Return: 0 if successful, negative error code otherwise
*
* If the QH to which the QTD is added is not currently scheduled, it is placed
* into the proper schedule based on its EP type.
*/
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
struct dwc2_qh *qh)
{
int retval;
if (unlikely(!qh)) {
dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
retval = -EINVAL;
goto fail;
}
retval = dwc2_hcd_qh_add(hsotg, qh);
if (retval)
goto fail;
qtd->qh = qh;
list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
return 0;
fail:
return retval;
}

867
A27-STEPLDR/Src/usb/hw.h Normal file
View File

@ -0,0 +1,867 @@
/*
* hw.h - DesignWare HS OTG Controller hardware definitions
*
* Copyright 2004-2013 Synopsys, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DWC2_HW_H__
#define __DWC2_HW_H__
#define HSOTG_REG(x) (x)
#define GOTGCTL HSOTG_REG(0x000)
#define GOTGCTL_CHIRPEN BIT(27)
#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
#define GOTGCTL_MULT_VALID_BC_SHIFT 22
#define GOTGCTL_OTGVER BIT(20)
#define GOTGCTL_BSESVLD BIT(19)
#define GOTGCTL_ASESVLD BIT(18)
#define GOTGCTL_DBNC_SHORT BIT(17)
#define GOTGCTL_CONID_B BIT(16)
#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15)
#define GOTGCTL_DEVHNPEN BIT(11)
#define GOTGCTL_HSTSETHNPEN BIT(10)
#define GOTGCTL_HNPREQ BIT(9)
#define GOTGCTL_HSTNEGSCS BIT(8)
#define GOTGCTL_SESREQ BIT(1)
#define GOTGCTL_SESREQSCS BIT(0)
#define GOTGINT HSOTG_REG(0x004)
#define GOTGINT_DBNCE_DONE BIT(19)
#define GOTGINT_A_DEV_TOUT_CHG BIT(18)
#define GOTGINT_HST_NEG_DET BIT(17)
#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9)
#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8)
#define GOTGINT_SES_END_DET BIT(2)
#define GAHBCFG HSOTG_REG(0x008)
#define GAHBCFG_AHB_SINGLE BIT(23)
#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22)
#define GAHBCFG_REM_MEM_SUPP BIT(21)
#define GAHBCFG_P_TXF_EMP_LVL BIT(8)
#define GAHBCFG_NP_TXF_EMP_LVL BIT(7)
#define GAHBCFG_DMA_EN BIT(5)
#define GAHBCFG_HBSTLEN_MASK (0xf << 1)
#define GAHBCFG_HBSTLEN_SHIFT 1
#define GAHBCFG_HBSTLEN_SINGLE 0
#define GAHBCFG_HBSTLEN_INCR 1
#define GAHBCFG_HBSTLEN_INCR4 3
#define GAHBCFG_HBSTLEN_INCR8 5
#define GAHBCFG_HBSTLEN_INCR16 7
#define GAHBCFG_GLBL_INTR_EN BIT(0)
#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \
GAHBCFG_NP_TXF_EMP_LVL | \
GAHBCFG_DMA_EN | \
GAHBCFG_GLBL_INTR_EN)
#define GUSBCFG HSOTG_REG(0x00C)
#define GUSBCFG_FORCEDEVMODE BIT(30)
#define GUSBCFG_FORCEHOSTMODE BIT(29)
#define GUSBCFG_TXENDDELAY BIT(28)
#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27)
#define GUSBCFG_ICUSBCAP BIT(26)
#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25)
#define GUSBCFG_INDICATORPASSTHROUGH BIT(24)
#define GUSBCFG_INDICATORCOMPLEMENT BIT(23)
#define GUSBCFG_TERMSELDLPULSE BIT(22)
#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21)
#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20)
#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19)
#define GUSBCFG_ULPI_AUTO_RES BIT(18)
#define GUSBCFG_ULPI_FS_LS BIT(17)
#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16)
#define GUSBCFG_PHY_LP_CLK_SEL BIT(15)
#define GUSBCFG_USBTRDTIM_MASK (0xf << 10)
#define GUSBCFG_USBTRDTIM_SHIFT 10
#define GUSBCFG_HNPCAP BIT(9)
#define GUSBCFG_SRPCAP BIT(8)
#define GUSBCFG_DDRSEL BIT(7)
#define GUSBCFG_PHYSEL BIT(6)
#define GUSBCFG_FSINTF BIT(5)
#define GUSBCFG_ULPI_UTMI_SEL BIT(4)
#define GUSBCFG_PHYIF16 BIT(3)
#define GUSBCFG_PHYIF8 (0 << 3)
#define GUSBCFG_TOUTCAL_MASK (0x7 << 0)
#define GUSBCFG_TOUTCAL_SHIFT 0
#define GUSBCFG_TOUTCAL_LIMIT 0x7
#define GUSBCFG_TOUTCAL(_x) ((_x) << 0)
#define GRSTCTL HSOTG_REG(0x010)
#define GRSTCTL_AHBIDLE BIT(31)
#define GRSTCTL_DMAREQ BIT(30)
#define GRSTCTL_TXFNUM_MASK (0x1f << 6)
#define GRSTCTL_TXFNUM_SHIFT 6
#define GRSTCTL_TXFNUM_LIMIT 0x1f
#define GRSTCTL_TXFNUM(_x) ((_x) << 6)
#define GRSTCTL_TXFFLSH BIT(5)
#define GRSTCTL_RXFFLSH BIT(4)
#define GRSTCTL_IN_TKNQ_FLSH BIT(3)
#define GRSTCTL_FRMCNTRRST BIT(2)
#define GRSTCTL_HSFTRST BIT(1)
#define GRSTCTL_CSFTRST BIT(0)
#define GINTSTS HSOTG_REG(0x014)
#define GINTMSK HSOTG_REG(0x018)
#define GINTSTS_WKUPINT BIT(31)
#define GINTSTS_SESSREQINT BIT(30)
#define GINTSTS_DISCONNINT BIT(29)
#define GINTSTS_CONIDSTSCHNG BIT(28)
#define GINTSTS_LPMTRANRCVD BIT(27)
#define GINTSTS_PTXFEMP BIT(26)
#define GINTSTS_HCHINT BIT(25)
#define GINTSTS_PRTINT BIT(24)
#define GINTSTS_RESETDET BIT(23)
#define GINTSTS_FET_SUSP BIT(22)
#define GINTSTS_INCOMPL_IP BIT(21)
#define GINTSTS_INCOMPL_SOOUT BIT(21)
#define GINTSTS_INCOMPL_SOIN BIT(20)
#define GINTSTS_OEPINT BIT(19)
#define GINTSTS_IEPINT BIT(18)
#define GINTSTS_EPMIS BIT(17)
#define GINTSTS_RESTOREDONE BIT(16)
#define GINTSTS_EOPF BIT(15)
#define GINTSTS_ISOUTDROP BIT(14)
#define GINTSTS_ENUMDONE BIT(13)
#define GINTSTS_USBRST BIT(12)
#define GINTSTS_USBSUSP BIT(11)
#define GINTSTS_ERLYSUSP BIT(10)
#define GINTSTS_I2CINT BIT(9)
#define GINTSTS_ULPI_CK_INT BIT(8)
#define GINTSTS_GOUTNAKEFF BIT(7)
#define GINTSTS_GINNAKEFF BIT(6)
#define GINTSTS_NPTXFEMP BIT(5)
#define GINTSTS_RXFLVL BIT(4)
#define GINTSTS_SOF BIT(3)
#define GINTSTS_OTGINT BIT(2)
#define GINTSTS_MODEMIS BIT(1)
#define GINTSTS_CURMODE_HOST BIT(0)
#define GRXSTSR HSOTG_REG(0x01C)
#define GRXSTSP HSOTG_REG(0x020)
#define GRXSTS_FN_MASK (0x7f << 25)
#define GRXSTS_FN_SHIFT 25
#define GRXSTS_PKTSTS_MASK (0xf << 17)
#define GRXSTS_PKTSTS_SHIFT 17
#define GRXSTS_PKTSTS_GLOBALOUTNAK 1
#define GRXSTS_PKTSTS_OUTRX 2
#define GRXSTS_PKTSTS_HCHIN 2
#define GRXSTS_PKTSTS_OUTDONE 3
#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3
#define GRXSTS_PKTSTS_SETUPDONE 4
#define GRXSTS_PKTSTS_DATATOGGLEERR 5
#define GRXSTS_PKTSTS_SETUPRX 6
#define GRXSTS_PKTSTS_HCHHALTED 7
#define GRXSTS_HCHNUM_MASK (0xf << 0)
#define GRXSTS_HCHNUM_SHIFT 0
#define GRXSTS_DPID_MASK (0x3 << 15)
#define GRXSTS_DPID_SHIFT 15
#define GRXSTS_BYTECNT_MASK (0x7ff << 4)
#define GRXSTS_BYTECNT_SHIFT 4
#define GRXSTS_EPNUM_MASK (0xf << 0)
#define GRXSTS_EPNUM_SHIFT 0
#define GRXFSIZ HSOTG_REG(0x024)
#define GRXFSIZ_DEPTH_MASK (0xffff << 0)
#define GRXFSIZ_DEPTH_SHIFT 0
#define GNPTXFSIZ HSOTG_REG(0x028)
/* Use FIFOSIZE_* constants to access this register */
#define GNPTXSTS HSOTG_REG(0x02C)
#define GNPTXSTS_NP_TXQ_TOP_MASK (0x7f << 24)
#define GNPTXSTS_NP_TXQ_TOP_SHIFT 24
#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK (0xff << 16)
#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT 16
#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v) (((_v) >> 16) & 0xff)
#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK (0xffff << 0)
#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT 0
#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff)
#define GI2CCTL HSOTG_REG(0x0030)
#define GI2CCTL_BSYDNE BIT(31)
#define GI2CCTL_RW BIT(30)
#define GI2CCTL_I2CDATSE0 BIT(28)
#define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26)
#define GI2CCTL_I2CDEVADDR_SHIFT 26
#define GI2CCTL_I2CSUSPCTL BIT(25)
#define GI2CCTL_ACK BIT(24)
#define GI2CCTL_I2CEN BIT(23)
#define GI2CCTL_ADDR_MASK (0x7f << 16)
#define GI2CCTL_ADDR_SHIFT 16
#define GI2CCTL_REGADDR_MASK (0xff << 8)
#define GI2CCTL_REGADDR_SHIFT 8
#define GI2CCTL_RWDATA_MASK (0xff << 0)
#define GI2CCTL_RWDATA_SHIFT 0
#define GPVNDCTL HSOTG_REG(0x0034)
#define GGPIO HSOTG_REG(0x0038)
#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16)
#define GUID HSOTG_REG(0x003c)
#define GSNPSID HSOTG_REG(0x0040)
#define GHWCFG1 HSOTG_REG(0x0044)
#define GHWCFG2 HSOTG_REG(0x0048)
#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31)
#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26)
#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26
#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24)
#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24
#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22)
#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22
#define GHWCFG2_MULTI_PROC_INT BIT(20)
#define GHWCFG2_DYNAMIC_FIFO BIT(19)
#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18)
#define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14)
#define GHWCFG2_NUM_HOST_CHAN_SHIFT 14
#define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10)
#define GHWCFG2_NUM_DEV_EP_SHIFT 10
#define GHWCFG2_FS_PHY_TYPE_MASK (0x3 << 8)
#define GHWCFG2_FS_PHY_TYPE_SHIFT 8
#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0
#define GHWCFG2_FS_PHY_TYPE_DEDICATED 1
#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI 2
#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI 3
#define GHWCFG2_HS_PHY_TYPE_MASK (0x3 << 6)
#define GHWCFG2_HS_PHY_TYPE_SHIFT 6
#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
#define GHWCFG2_HS_PHY_TYPE_UTMI 1
#define GHWCFG2_HS_PHY_TYPE_ULPI 2
#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
#define GHWCFG2_POINT2POINT BIT(5)
#define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3)
#define GHWCFG2_ARCHITECTURE_SHIFT 3
#define GHWCFG2_SLAVE_ONLY_ARCH 0
#define GHWCFG2_EXT_DMA_ARCH 1
#define GHWCFG2_INT_DMA_ARCH 2
#define GHWCFG2_OP_MODE_MASK (0x7 << 0)
#define GHWCFG2_OP_MODE_SHIFT 0
#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE 0
#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE 1
#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2
#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
#define GHWCFG2_OP_MODE_UNDEFINED 7
#define GHWCFG3 HSOTG_REG(0x004c)
#define GHWCFG3_DFIFO_DEPTH_MASK (0xffffUL << 16)
#define GHWCFG3_DFIFO_DEPTH_SHIFT 16
#define GHWCFG3_OTG_LPM_EN BIT(15)
#define GHWCFG3_BC_SUPPORT BIT(14)
#define GHWCFG3_OTG_ENABLE_HSIC BIT(13)
#define GHWCFG3_ADP_SUPP BIT(12)
#define GHWCFG3_SYNCH_RESET_TYPE BIT(11)
#define GHWCFG3_OPTIONAL_FEATURES BIT(10)
#define GHWCFG3_VENDOR_CTRL_IF BIT(9)
#define GHWCFG3_I2C BIT(8)
#define GHWCFG3_OTG_FUNC BIT(7)
#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4)
#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4
#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0)
#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0
#define GHWCFG4 HSOTG_REG(0x0050)
#define GHWCFG4_DESC_DMA_DYN BIT(31)
#define GHWCFG4_DESC_DMA BIT(30)
#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
#define GHWCFG4_NUM_IN_EPS_SHIFT 26
#define GHWCFG4_DED_FIFO_EN BIT(25)
#define GHWCFG4_DED_FIFO_SHIFT 25
#define GHWCFG4_SESSION_END_FILT_EN BIT(24)
#define GHWCFG4_B_VALID_FILT_EN BIT(23)
#define GHWCFG4_A_VALID_FILT_EN BIT(22)
#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21)
#define GHWCFG4_IDDIG_FILT_EN BIT(20)
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16)
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
#define GHWCFG4_XHIBER BIT(7)
#define GHWCFG4_HIBER BIT(6)
#define GHWCFG4_MIN_AHB_FREQ BIT(5)
#define GHWCFG4_POWER_OPTIMIZ BIT(4)
#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0)
#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0
#define GLPMCFG HSOTG_REG(0x0054)
#define GLPMCFG_INV_SEL_HSIC BIT(31)
#define GLPMCFG_HSIC_CONNECT BIT(30)
#define GLPMCFG_RETRY_COUNT_STS_MASK (0x7 << 25)
#define GLPMCFG_RETRY_COUNT_STS_SHIFT 25
#define GLPMCFG_SEND_LPM BIT(24)
#define GLPMCFG_RETRY_COUNT_MASK (0x7 << 21)
#define GLPMCFG_RETRY_COUNT_SHIFT 21
#define GLPMCFG_LPM_CHAN_INDEX_MASK (0xf << 17)
#define GLPMCFG_LPM_CHAN_INDEX_SHIFT 17
#define GLPMCFG_SLEEP_STATE_RESUMEOK BIT(16)
#define GLPMCFG_PRT_SLEEP_STS BIT(15)
#define GLPMCFG_LPM_RESP_MASK (0x3 << 13)
#define GLPMCFG_LPM_RESP_SHIFT 13
#define GLPMCFG_HIRD_THRES_MASK (0x1f << 8)
#define GLPMCFG_HIRD_THRES_SHIFT 8
#define GLPMCFG_HIRD_THRES_EN (0x10 << 8)
#define GLPMCFG_EN_UTMI_SLEEP BIT(7)
#define GLPMCFG_REM_WKUP_EN BIT(6)
#define GLPMCFG_HIRD_MASK (0xf << 2)
#define GLPMCFG_HIRD_SHIFT 2
#define GLPMCFG_APPL_RESP BIT(1)
#define GLPMCFG_LPM_CAP_EN BIT(0)
#define GPWRDN HSOTG_REG(0x0058)
#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24)
#define GPWRDN_MULT_VAL_ID_BC_SHIFT 24
#define GPWRDN_ADP_INT BIT(23)
#define GPWRDN_BSESSVLD BIT(22)
#define GPWRDN_IDSTS BIT(21)
#define GPWRDN_LINESTATE_MASK (0x3 << 19)
#define GPWRDN_LINESTATE_SHIFT 19
#define GPWRDN_STS_CHGINT_MSK BIT(18)
#define GPWRDN_STS_CHGINT BIT(17)
#define GPWRDN_SRP_DET_MSK BIT(16)
#define GPWRDN_SRP_DET BIT(15)
#define GPWRDN_CONNECT_DET_MSK BIT(14)
#define GPWRDN_CONNECT_DET BIT(13)
#define GPWRDN_DISCONN_DET_MSK BIT(12)
#define GPWRDN_DISCONN_DET BIT(11)
#define GPWRDN_RST_DET_MSK BIT(10)
#define GPWRDN_RST_DET BIT(9)
#define GPWRDN_LNSTSCHG_MSK BIT(8)
#define GPWRDN_LNSTSCHG BIT(7)
#define GPWRDN_DIS_VBUS BIT(6)
#define GPWRDN_PWRDNSWTCH BIT(5)
#define GPWRDN_PWRDNRSTN BIT(4)
#define GPWRDN_PWRDNCLMP BIT(3)
#define GPWRDN_RESTORE BIT(2)
#define GPWRDN_PMUACTV BIT(1)
#define GPWRDN_PMUINTSEL BIT(0)
#define GDFIFOCFG HSOTG_REG(0x005c)
#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16)
#define GDFIFOCFG_EPINFOBASE_SHIFT 16
#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0)
#define GDFIFOCFG_GDFIFOCFG_SHIFT 0
#define ADPCTL HSOTG_REG(0x0060)
#define ADPCTL_AR_MASK (0x3 << 27)
#define ADPCTL_AR_SHIFT 27
#define ADPCTL_ADP_TMOUT_INT_MSK BIT(26)
#define ADPCTL_ADP_SNS_INT_MSK BIT(25)
#define ADPCTL_ADP_PRB_INT_MSK BIT(24)
#define ADPCTL_ADP_TMOUT_INT BIT(23)
#define ADPCTL_ADP_SNS_INT BIT(22)
#define ADPCTL_ADP_PRB_INT BIT(21)
#define ADPCTL_ADPENA BIT(20)
#define ADPCTL_ADPRES BIT(19)
#define ADPCTL_ENASNS BIT(18)
#define ADPCTL_ENAPRB BIT(17)
#define ADPCTL_RTIM_MASK (0x7ff << 6)
#define ADPCTL_RTIM_SHIFT 6
#define ADPCTL_PRB_PER_MASK (0x3 << 4)
#define ADPCTL_PRB_PER_SHIFT 4
#define ADPCTL_PRB_DELTA_MASK (0x3 << 2)
#define ADPCTL_PRB_DELTA_SHIFT 2
#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0)
#define ADPCTL_PRB_DSCHRG_SHIFT 0
#define HPTXFSIZ HSOTG_REG(0x100)
/* Use FIFOSIZE_* constants to access this register */
#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4))
/* Use FIFOSIZE_* constants to access this register */
/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */
#define FIFOSIZE_DEPTH_MASK (0xffffUL << 16)
#define FIFOSIZE_DEPTH_SHIFT 16
#define FIFOSIZE_STARTADDR_MASK (0xffff << 0)
#define FIFOSIZE_STARTADDR_SHIFT 0
#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff)
/* Device mode registers */
#define DCFG HSOTG_REG(0x800)
#define DCFG_DESCDMA_EN BIT(23)
#define DCFG_EPMISCNT_MASK (0x1f << 18)
#define DCFG_EPMISCNT_SHIFT 18
#define DCFG_EPMISCNT_LIMIT 0x1f
#define DCFG_EPMISCNT(_x) ((_x) << 18)
#define DCFG_PERFRINT_MASK (0x3 << 11)
#define DCFG_PERFRINT_SHIFT 11
#define DCFG_PERFRINT_LIMIT 0x3
#define DCFG_PERFRINT(_x) ((_x) << 11)
#define DCFG_DEVADDR_MASK (0x7f << 4)
#define DCFG_DEVADDR_SHIFT 4
#define DCFG_DEVADDR_LIMIT 0x7f
#define DCFG_DEVADDR(_x) ((_x) << 4)
#define DCFG_NZ_STS_OUT_HSHK BIT(2)
#define DCFG_DEVSPD_MASK (0x3 << 0)
#define DCFG_DEVSPD_SHIFT 0
#define DCFG_DEVSPD_HS 0
#define DCFG_DEVSPD_FS 1
#define DCFG_DEVSPD_LS 2
#define DCFG_DEVSPD_FS48 3
#define DCTL HSOTG_REG(0x804)
#define DCTL_PWRONPRGDONE BIT(11)
#define DCTL_CGOUTNAK BIT(10)
#define DCTL_SGOUTNAK BIT(9)
#define DCTL_CGNPINNAK BIT(8)
#define DCTL_SGNPINNAK BIT(7)
#define DCTL_TSTCTL_MASK (0x7 << 4)
#define DCTL_TSTCTL_SHIFT 4
#define DCTL_GOUTNAKSTS BIT(3)
#define DCTL_GNPINNAKSTS BIT(2)
#define DCTL_SFTDISCON BIT(1)
#define DCTL_RMTWKUPSIG BIT(0)
#define DSTS HSOTG_REG(0x808)
#define DSTS_SOFFN_MASK (0x3fff << 8)
#define DSTS_SOFFN_SHIFT 8
#define DSTS_SOFFN_LIMIT 0x3fff
#define DSTS_SOFFN(_x) ((_x) << 8)
#define DSTS_ERRATICERR BIT(3)
#define DSTS_ENUMSPD_MASK (0x3 << 1)
#define DSTS_ENUMSPD_SHIFT 1
#define DSTS_ENUMSPD_HS 0
#define DSTS_ENUMSPD_FS 1
#define DSTS_ENUMSPD_LS 2
#define DSTS_ENUMSPD_FS48 3
#define DSTS_SUSPSTS BIT(0)
#define DIEPMSK HSOTG_REG(0x810)
#define DIEPMSK_NAKMSK BIT(13)
#define DIEPMSK_BNAININTRMSK BIT(9)
#define DIEPMSK_TXFIFOUNDRNMSK BIT(8)
#define DIEPMSK_TXFIFOEMPTY BIT(7)
#define DIEPMSK_INEPNAKEFFMSK BIT(6)
#define DIEPMSK_INTKNEPMISMSK BIT(5)
#define DIEPMSK_INTKNTXFEMPMSK BIT(4)
#define DIEPMSK_TIMEOUTMSK BIT(3)
#define DIEPMSK_AHBERRMSK BIT(2)
#define DIEPMSK_EPDISBLDMSK BIT(1)
#define DIEPMSK_XFERCOMPLMSK BIT(0)
#define DOEPMSK HSOTG_REG(0x814)
#define DOEPMSK_BNAMSK BIT(9)
#define DOEPMSK_BACK2BACKSETUP BIT(6)
#define DOEPMSK_STSPHSERCVDMSK BIT(5)
#define DOEPMSK_OUTTKNEPDISMSK BIT(4)
#define DOEPMSK_SETUPMSK BIT(3)
#define DOEPMSK_AHBERRMSK BIT(2)
#define DOEPMSK_EPDISBLDMSK BIT(1)
#define DOEPMSK_XFERCOMPLMSK BIT(0)
#define DAINT HSOTG_REG(0x818)
#define DAINTMSK HSOTG_REG(0x81C)
#define DAINT_OUTEP_SHIFT 16
#define DAINT_OUTEP(_x) (1 << ((_x) + 16))
#define DAINT_INEP(_x) (1 << (_x))
#define DTKNQR1 HSOTG_REG(0x820)
#define DTKNQR2 HSOTG_REG(0x824)
#define DTKNQR3 HSOTG_REG(0x830)
#define DTKNQR4 HSOTG_REG(0x834)
#define DIEPEMPMSK HSOTG_REG(0x834)
#define DVBUSDIS HSOTG_REG(0x828)
#define DVBUSPULSE HSOTG_REG(0x82C)
#define DIEPCTL0 HSOTG_REG(0x900)
#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20))
#define DOEPCTL0 HSOTG_REG(0xB00)
#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20))
/* EP0 specialness:
* bits[29..28] - reserved (no SetD0PID, SetD1PID)
* bits[25..22] - should always be zero, this isn't a periodic endpoint
* bits[10..0] - MPS setting different for EP0
*/
#define D0EPCTL_MPS_MASK (0x3 << 0)
#define D0EPCTL_MPS_SHIFT 0
#define D0EPCTL_MPS_64 0
#define D0EPCTL_MPS_32 1
#define D0EPCTL_MPS_16 2
#define D0EPCTL_MPS_8 3
#define DXEPCTL_EPENA BIT(31)
#define DXEPCTL_EPDIS BIT(30)
#define DXEPCTL_SETD1PID BIT(29)
#define DXEPCTL_SETODDFR BIT(29)
#define DXEPCTL_SETD0PID BIT(28)
#define DXEPCTL_SETEVENFR BIT(28)
#define DXEPCTL_SNAK BIT(27)
#define DXEPCTL_CNAK BIT(26)
#define DXEPCTL_TXFNUM_MASK (0xf << 22)
#define DXEPCTL_TXFNUM_SHIFT 22
#define DXEPCTL_TXFNUM_LIMIT 0xf
#define DXEPCTL_TXFNUM(_x) ((_x) << 22)
#define DXEPCTL_STALL BIT(21)
#define DXEPCTL_SNP BIT(20)
#define DXEPCTL_EPTYPE_MASK (0x3 << 18)
#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18)
#define DXEPCTL_EPTYPE_ISO (0x1 << 18)
#define DXEPCTL_EPTYPE_BULK (0x2 << 18)
#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18)
#define DXEPCTL_NAKSTS BIT(17)
#define DXEPCTL_DPID BIT(16)
#define DXEPCTL_EOFRNUM BIT(16)
#define DXEPCTL_USBACTEP BIT(15)
#define DXEPCTL_NEXTEP_MASK (0xf << 11)
#define DXEPCTL_NEXTEP_SHIFT 11
#define DXEPCTL_NEXTEP_LIMIT 0xf
#define DXEPCTL_NEXTEP(_x) ((_x) << 11)
#define DXEPCTL_MPS_MASK (0x7ff << 0)
#define DXEPCTL_MPS_SHIFT 0
#define DXEPCTL_MPS_LIMIT 0x7ff
#define DXEPCTL_MPS(_x) ((_x) << 0)
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
#define DXEPINT_SETUP_RCVD BIT(15)
#define DXEPINT_NYETINTRPT BIT(14)
#define DXEPINT_NAKINTRPT BIT(13)
#define DXEPINT_BBLEERRINTRPT BIT(12)
#define DXEPINT_PKTDRPSTS BIT(11)
#define DXEPINT_BNAINTR BIT(9)
#define DXEPINT_TXFIFOUNDRN BIT(8)
#define DXEPINT_OUTPKTERR BIT(8)
#define DXEPINT_TXFEMP BIT(7)
#define DXEPINT_INEPNAKEFF BIT(6)
#define DXEPINT_BACK2BACKSETUP BIT(6)
#define DXEPINT_INTKNEPMIS BIT(5)
#define DXEPINT_STSPHSERCVD BIT(5)
#define DXEPINT_INTKNTXFEMP BIT(4)
#define DXEPINT_OUTTKNEPDIS BIT(4)
#define DXEPINT_TIMEOUT BIT(3)
#define DXEPINT_SETUP BIT(3)
#define DXEPINT_AHBERR BIT(2)
#define DXEPINT_EPDISBLD BIT(1)
#define DXEPINT_XFERCOMPL BIT(0)
#define DIEPTSIZ0 HSOTG_REG(0x910)
#define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19)
#define DIEPTSIZ0_PKTCNT_SHIFT 19
#define DIEPTSIZ0_PKTCNT_LIMIT 0x3
#define DIEPTSIZ0_PKTCNT(_x) ((_x) << 19)
#define DIEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
#define DIEPTSIZ0_XFERSIZE_SHIFT 0
#define DIEPTSIZ0_XFERSIZE_LIMIT 0x7f
#define DIEPTSIZ0_XFERSIZE(_x) ((_x) << 0)
#define DOEPTSIZ0 HSOTG_REG(0xB10)
#define DOEPTSIZ0_SUPCNT_MASK (0x3 << 29)
#define DOEPTSIZ0_SUPCNT_SHIFT 29
#define DOEPTSIZ0_SUPCNT_LIMIT 0x3
#define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29)
#define DOEPTSIZ0_PKTCNT BIT(19)
#define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
#define DOEPTSIZ0_XFERSIZE_SHIFT 0
#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20))
#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20))
#define DXEPTSIZ_MC_MASK (0x3 << 29)
#define DXEPTSIZ_MC_SHIFT 29
#define DXEPTSIZ_MC_LIMIT 0x3
#define DXEPTSIZ_MC(_x) ((_x) << 29)
#define DXEPTSIZ_PKTCNT_MASK (0x3ff << 19)
#define DXEPTSIZ_PKTCNT_SHIFT 19
#define DXEPTSIZ_PKTCNT_LIMIT 0x3ff
#define DXEPTSIZ_PKTCNT_GET(_v) (((_v) >> 19) & 0x3ff)
#define DXEPTSIZ_PKTCNT(_x) ((_x) << 19)
#define DXEPTSIZ_XFERSIZE_MASK (0x7ffff << 0)
#define DXEPTSIZ_XFERSIZE_SHIFT 0
#define DXEPTSIZ_XFERSIZE_LIMIT 0x7ffff
#define DXEPTSIZ_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7ffff)
#define DXEPTSIZ_XFERSIZE(_x) ((_x) << 0)
#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20))
#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20))
#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20))
#define PCGCTL HSOTG_REG(0x0e00)
#define PCGCTL_IF_DEV_MODE BIT(31)
#define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29)
#define PCGCTL_P2HD_PRT_SPD_SHIFT 29
#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27)
#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
#define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20)
#define PCGCTL_MAC_DEV_ADDR_SHIFT 20
#define PCGCTL_MAX_TERMSEL BIT(19)
#define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17)
#define PCGCTL_MAX_XCVRSELECT_SHIFT 17
#define PCGCTL_PORT_POWER BIT(16)
#define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14)
#define PCGCTL_PRT_CLK_SEL_SHIFT 14
#define PCGCTL_ESS_REG_RESTORED BIT(13)
#define PCGCTL_EXTND_HIBER_SWITCH BIT(12)
#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11)
#define PCGCTL_ENBL_EXTND_HIBER BIT(10)
#define PCGCTL_RESTOREMODE BIT(9)
#define PCGCTL_RESETAFTSUSP BIT(8)
#define PCGCTL_DEEP_SLEEP BIT(7)
#define PCGCTL_PHY_IN_SLEEP BIT(6)
#define PCGCTL_ENBL_SLEEP_GATING BIT(5)
#define PCGCTL_RSTPDWNMODULE BIT(3)
#define PCGCTL_PWRCLMP BIT(2)
#define PCGCTL_GATEHCLK BIT(1)
#define PCGCTL_STOPPCLK BIT(0)
#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
/* Host Mode Registers */
#define HCFG HSOTG_REG(0x0400)
#define HCFG_MODECHTIMEN BIT(31)
#define HCFG_PERSCHEDENA BIT(26)
#define HCFG_FRLISTEN_MASK (0x3 << 24)
#define HCFG_FRLISTEN_SHIFT 24
#define HCFG_FRLISTEN_8 (0 << 24)
#define FRLISTEN_8_SIZE 8
#define HCFG_FRLISTEN_16 BIT(24)
#define FRLISTEN_16_SIZE 16
#define HCFG_FRLISTEN_32 (2 << 24)
#define FRLISTEN_32_SIZE 32
#define HCFG_FRLISTEN_64 (3 << 24)
#define FRLISTEN_64_SIZE 64
#define HCFG_DESCDMA BIT(23)
#define HCFG_RESVALID_MASK (0xff << 8)
#define HCFG_RESVALID_SHIFT 8
#define HCFG_ENA32KHZ BIT(7)
#define HCFG_FSLSSUPP BIT(2)
#define HCFG_FSLSPCLKSEL_MASK (0x3 << 0)
#define HCFG_FSLSPCLKSEL_SHIFT 0
#define HCFG_FSLSPCLKSEL_30_60_MHZ 0
#define HCFG_FSLSPCLKSEL_48_MHZ 1
#define HCFG_FSLSPCLKSEL_6_MHZ 2
#define HFIR HSOTG_REG(0x0404)
#define HFIR_FRINT_MASK (0xffff << 0)
#define HFIR_FRINT_SHIFT 0
#define HFIR_RLDCTRL BIT(16)
#define HFNUM HSOTG_REG(0x0408)
#define HFNUM_FRREM_MASK (0xffffUL << 16)
#define HFNUM_FRREM_SHIFT 16
#define HFNUM_FRNUM_MASK (0xffff << 0)
#define HFNUM_FRNUM_SHIFT 0
#define HFNUM_MAX_FRNUM 0x3fff
#define HPTXSTS HSOTG_REG(0x0410)
#define TXSTS_QTOP_ODD BIT(31)
#define TXSTS_QTOP_CHNEP_MASK (0xf << 27)
#define TXSTS_QTOP_CHNEP_SHIFT 27
#define TXSTS_QTOP_TOKEN_MASK (0x3 << 25)
#define TXSTS_QTOP_TOKEN_SHIFT 25
#define TXSTS_QTOP_TERMINATE BIT(24)
#define TXSTS_QSPCAVAIL_MASK (0xff << 16)
#define TXSTS_QSPCAVAIL_SHIFT 16
#define TXSTS_FSPCAVAIL_MASK (0xffff << 0)
#define TXSTS_FSPCAVAIL_SHIFT 0
#define HAINT HSOTG_REG(0x0414)
#define HAINTMSK HSOTG_REG(0x0418)
#define HFLBADDR HSOTG_REG(0x041c)
#define HPRT0 HSOTG_REG(0x0440)
#define HPRT0_SPD_MASK (0x3 << 17)
#define HPRT0_SPD_SHIFT 17
#define HPRT0_SPD_HIGH_SPEED 0
#define HPRT0_SPD_FULL_SPEED 1
#define HPRT0_SPD_LOW_SPEED 2
#define HPRT0_TSTCTL_MASK (0xf << 13)
#define HPRT0_TSTCTL_SHIFT 13
#define HPRT0_PWR BIT(12)
#define HPRT0_LNSTS_MASK (0x3 << 10)
#define HPRT0_LNSTS_SHIFT 10
#define HPRT0_RST BIT(8)
#define HPRT0_SUSP BIT(7)
#define HPRT0_RES BIT(6)
#define HPRT0_OVRCURRCHG BIT(5)
#define HPRT0_OVRCURRACT BIT(4)
#define HPRT0_ENACHG BIT(3)
#define HPRT0_ENA BIT(2)
#define HPRT0_CONNDET BIT(1)
#define HPRT0_CONNSTS BIT(0)
#define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch))
#define HCCHAR_CHENA BIT(31)
#define HCCHAR_CHDIS BIT(30)
#define HCCHAR_ODDFRM BIT(29)
#define HCCHAR_DEVADDR_MASK (0x7f << 22)
#define HCCHAR_DEVADDR_SHIFT 22
#define HCCHAR_MULTICNT_MASK (0x3 << 20)
#define HCCHAR_MULTICNT_SHIFT 20
#define HCCHAR_EPTYPE_MASK (0x3 << 18)
#define HCCHAR_EPTYPE_SHIFT 18
#define HCCHAR_LSPDDEV BIT(17)
#define HCCHAR_EPDIR BIT(15)
#define HCCHAR_EPNUM_MASK (0xf << 11)
#define HCCHAR_EPNUM_SHIFT 11
#define HCCHAR_MPS_MASK (0x7ff << 0)
#define HCCHAR_MPS_SHIFT 0
#define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch))
#define HCSPLT_SPLTENA BIT(31)
#define HCSPLT_COMPSPLT BIT(16)
#define HCSPLT_XACTPOS_MASK (0x3 << 14)
#define HCSPLT_XACTPOS_SHIFT 14
#define HCSPLT_XACTPOS_MID 0
#define HCSPLT_XACTPOS_END 1
#define HCSPLT_XACTPOS_BEGIN 2
#define HCSPLT_XACTPOS_ALL 3
#define HCSPLT_HUBADDR_MASK (0x7f << 7)
#define HCSPLT_HUBADDR_SHIFT 7
#define HCSPLT_PRTADDR_MASK (0x7f << 0)
#define HCSPLT_PRTADDR_SHIFT 0
#define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch))
#define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch))
#define HCINTMSK_RESERVED14_31 (0x3ffff << 14)
#define HCINTMSK_FRM_LIST_ROLL BIT(13)
#define HCINTMSK_XCS_XACT BIT(12)
#define HCINTMSK_BNA BIT(11)
#define HCINTMSK_DATATGLERR BIT(10)
#define HCINTMSK_FRMOVRUN BIT(9)
#define HCINTMSK_BBLERR BIT(8)
#define HCINTMSK_XACTERR BIT(7)
#define HCINTMSK_NYET BIT(6)
#define HCINTMSK_ACK BIT(5)
#define HCINTMSK_NAK BIT(4)
#define HCINTMSK_STALL BIT(3)
#define HCINTMSK_AHBERR BIT(2)
#define HCINTMSK_CHHLTD BIT(1)
#define HCINTMSK_XFERCOMPL BIT(0)
#define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch))
#define TSIZ_DOPNG BIT(31)
#define TSIZ_SC_MC_PID_MASK (0x3 << 29)
#define TSIZ_SC_MC_PID_SHIFT 29
#define TSIZ_SC_MC_PID_DATA0 0
#define TSIZ_SC_MC_PID_DATA2 1
#define TSIZ_SC_MC_PID_DATA1 2
#define TSIZ_SC_MC_PID_MDATA 3
#define TSIZ_SC_MC_PID_SETUP 3
#define TSIZ_PKTCNT_MASK (0x3ff << 19)
#define TSIZ_PKTCNT_SHIFT 19
#define TSIZ_NTD_MASK (0xff << 8)
#define TSIZ_NTD_SHIFT 8
#define TSIZ_SCHINFO_MASK (0xff << 0)
#define TSIZ_SCHINFO_SHIFT 0
#define TSIZ_XFERSIZE_MASK (0x7ffff << 0)
#define TSIZ_XFERSIZE_SHIFT 0
#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch))
#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch))
#define HCFIFO(_ch) HSOTG_REG(0x1000 + 0x1000 * (_ch))
/**
* struct dwc2_dma_desc - DMA descriptor structure,
* used for both host and gadget modes
*
* @status: DMA descriptor status quadlet
* @buf: DMA descriptor data buffer pointer
*
* DMA Descriptor structure contains two quadlets:
* Status quadlet and Data buffer pointer.
*/
struct dwc2_dma_desc {
u32 status;
u32 buf;
};//__packed
/* Host Mode DMA descriptor status quadlet */
#define HOST_DMA_A BIT(31)
#define HOST_DMA_STS_MASK (0x3 << 28)
#define HOST_DMA_STS_SHIFT 28
#define HOST_DMA_STS_PKTERR BIT(28)
#define HOST_DMA_EOL BIT(26)
#define HOST_DMA_IOC BIT(25)
#define HOST_DMA_SUP BIT(24)
#define HOST_DMA_ALT_QTD BIT(23)
#define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17)
#define HOST_DMA_QTD_OFFSET_SHIFT 17
#define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0)
#define HOST_DMA_ISOC_NBYTES_SHIFT 0
#define HOST_DMA_NBYTES_MASK (0x1ffff << 0)
#define HOST_DMA_NBYTES_SHIFT 0
#define HOST_DMA_NBYTES_LIMIT 131071
/* Device Mode DMA descriptor status quadlet */
#define DEV_DMA_BUFF_STS_MASK (0x3 << 30)
#define DEV_DMA_BUFF_STS_SHIFT 30
#define DEV_DMA_BUFF_STS_HREADY 0
#define DEV_DMA_BUFF_STS_DMABUSY 1
#define DEV_DMA_BUFF_STS_DMADONE 2
#define DEV_DMA_BUFF_STS_HBUSY 3UL
#define DEV_DMA_STS_MASK (0x3 << 28)
#define DEV_DMA_STS_SHIFT 28
#define DEV_DMA_STS_SUCC 0
#define DEV_DMA_STS_BUFF_FLUSH 1
#define DEV_DMA_STS_BUFF_ERR 3
#define DEV_DMA_L BIT(27)
#define DEV_DMA_SHORT BIT(26)
#define DEV_DMA_IOC BIT(25)
#define DEV_DMA_SR BIT(24)
#define DEV_DMA_MTRF BIT(23)
#define DEV_DMA_ISOC_PID_MASK (0x3 << 23)
#define DEV_DMA_ISOC_PID_SHIFT 23
#define DEV_DMA_ISOC_PID_DATA0 0
#define DEV_DMA_ISOC_PID_DATA2 1
#define DEV_DMA_ISOC_PID_DATA1 2
#define DEV_DMA_ISOC_PID_MDATA 3
#define DEV_DMA_ISOC_FRNUM_MASK (0x7ff << 12)
#define DEV_DMA_ISOC_FRNUM_SHIFT 12
#define DEV_DMA_ISOC_TX_NBYTES_MASK (0xfff << 0)
#define DEV_DMA_ISOC_TX_NBYTES_LIMIT 0xfff
#define DEV_DMA_ISOC_RX_NBYTES_MASK (0x7ff << 0)
#define DEV_DMA_ISOC_RX_NBYTES_LIMIT 0x7ff
#define DEV_DMA_ISOC_NBYTES_SHIFT 0
#define DEV_DMA_NBYTES_MASK (0xffff << 0)
#define DEV_DMA_NBYTES_SHIFT 0
#define DEV_DMA_NBYTES_LIMIT 0xffff
#define MAX_DMA_DESC_NUM_GENERIC 64
#define MAX_DMA_DESC_NUM_HS_ISOC 256
#endif /* __DWC2_HW_H__ */

View File

@ -0,0 +1,65 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2007
* Stelian Pop <stelian@popies.net>
* Lead Tech Design <www.leadtechdesign.com>
*/
#ifndef __ASM_ARM_DMA_MAPPING_H
#define __ASM_ARM_DMA_MAPPING_H
#include <linux/dma-direction.h>
#define dma_mapping_error(x, y) 0
struct device;
static inline void *dma_alloc_coherent(struct device *dev, size_t len, dma_addr_t *handle, gfp_t flag)
{
(void)flag;
//*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
*handle = (unsigned long)malloc(len + ARCH_DMA_MINALIGN);
return (void *)*handle;
}
static inline void dma_free_coherent(struct device *dev, size_t size, void *addr, dma_addr_t handle)
{
free(addr);
}
static inline void *dmam_alloc_coherent(struct device *dev, size_t len, dma_addr_t *handle, gfp_t flag)
{
(void)flag;
(void)dev;
*handle = (dma_addr_t)malloc(len + ARCH_DMA_MINALIGN);
return (void *)*handle;
}
static inline void dmam_free_coherent(struct device *dev, size_t len, void *vaddr, dma_addr_t handle)
{
free(vaddr);
}
static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
enum dma_data_direction dir)
{
return (unsigned long)vaddr;
}
static inline void dma_unmap_single(volatile void *vaddr, size_t len,
unsigned long paddr)
{
}
static inline void dma_sync_single_for_device(struct device *dev,
dma_addr_t addr, size_t size, enum dma_data_direction dir)
{
}
static inline void dma_sync_single_for_cpu(struct device *dev,
dma_addr_t addr, size_t size, enum dma_data_direction dir)
{
}
#endif /* __ASM_ARM_DMA_MAPPING_H */

View File

@ -0,0 +1,13 @@
#ifndef _LINUX_DMA_DIRECTION_H
#define _LINUX_DMA_DIRECTION_H
/*
* These definitions mirror those in pci.h, so they can be used
* interchangeably with their PCI_ counterparts.
*/
enum dma_data_direction {
DMA_BIDIRECTIONAL = 0,
DMA_TO_DEVICE = 1,
DMA_FROM_DEVICE = 2,
DMA_NONE = 3,
};
#endif

View File

@ -0,0 +1,168 @@
#ifndef _LINUX_ERRNO_H
#define _LINUX_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Invalid system call number */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ECANCELED 125 /* Operation Canceled */
#define ENOKEY 126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service */
/* for robust mutexes */
#define EOWNERDEAD 130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */
#define ERFKILL 132 /* Operation not possible due to RF-kill */
#define EHWPOISON 133 /* Memory page has hardware error */
#define ERESTARTSYS 512
#define ERESTARTNOINTR 513
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#define ENOIOCTLCMD 515 /* No ioctl command */
#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
#define EPROBE_DEFER 517 /* Driver requests probe retry */
#define EOPENSTALE 518 /* open found a stale dentry */
/* Defined for the NFSv3 protocol */
#define EBADHANDLE 521 /* Illegal NFS file handle */
#define ENOTSYNC 522 /* Update synchronization mismatch */
#define EBADCOOKIE 523 /* Cookie is stale */
#define ENOTSUPP 524 /* Operation is not supported */
#define ETOOSMALL 525 /* Buffer or request is too small */
#define ESERVERFAULT 526 /* An untranslatable error occurred */
#define EBADTYPE 527 /* Type not supported by server */
#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */
#define EIOCBQUEUED 529 /* iocb queued, will get completion event */
#define ERECALLCONFLICT 530 /* conflict with recalled state */
#endif

View File

@ -0,0 +1,981 @@
/*
* This file holds USB constants and structures that are needed for
* USB device APIs. These are used by the USB device model, which is
* defined in chapter 9 of the USB 2.0 specification and in the
* Wireless USB 1.0 (spread around). Linux has several APIs in C that
* need these:
*
* - the master/host side Linux-USB kernel driver API;
* - the "usbfs" user space API; and
* - the Linux "gadget" slave/device/peripheral side driver API.
*
* USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
* act either as a USB master/host or as a USB slave/device. That means
* the master and slave side APIs benefit from working well together.
*
* There's also "Wireless USB", using low power short range radios for
* peripheral interconnection but otherwise building on the USB framework.
*
* Note all descriptors are declared '__attribute__((packed))' so that:
*
* [a] they never get padded, either internally (USB spec writers
* probably handled that) or externally;
*
* [b] so that accessing bigger-than-a-bytes fields will never
* generate bus errors on any platform, even when the location of
* its descriptor inside a bundle isn't "naturally aligned", and
*
* [c] for consistency, removing all doubt even when it appears to
* someone that the two other points are non-issues for that
* particular descriptor type.
*/
#ifndef __LINUX_USB_CH9_H
#define __LINUX_USB_CH9_H
//#include <linux/types.h> /* __u8 etc */
/*-------------------------------------------------------------------------*/
/* CONTROL REQUEST SUPPORT */
/*
* USB directions
*
* This bit flag is used in endpoint descriptors' bEndpointAddress field.
* It's also one of three fields in control requests bRequestType.
*/
#define USB_DIR_OUT 0 /* to device */
#define USB_DIR_IN 0x80 /* to host */
/*
* USB types, the second of three bRequestType fields
*/
#define USB_TYPE_MASK (0x03 << 5)
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
/*
* USB recipients, the third of three bRequestType fields
*/
#define USB_RECIP_MASK 0x1f
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
/* From Wireless USB 1.0 */
#define USB_RECIP_PORT 0x04
#define USB_RECIP_RPIPE 0x05
/*
* Standard requests, for the bRequest field of a SETUP packet.
*
* These are qualified by the bRequestType field, so that for example
* TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
* by a GET_STATUS request.
*/
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_SEL 0x30
#define USB_REQ_SET_ISOCH_DELAY 0x31
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_RPIPE_ABORT 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_RPIPE_RESET 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
/* The Link Power Management (LPM) ECN defines USB_REQ_TEST_AND_SET command,
* used by hubs to put ports into a new L1 suspend state, except that it
* forgot to define its number ...
*/
/*
* USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
* are read as a bit array returned by USB_REQ_GET_STATUS. (So there
* are at most sixteen features of each type.) Hubs may also support a
* new USB_REQ_TEST_AND_SET_FEATURE to put ports into L1 suspend.
*/
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
#define USB_DEVICE_BATTERY 2 /* (wireless) */
#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/
#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
/*
* Test Mode Selectors
* See USB 2.0 spec Table 9-7
*/
#define TEST_J 1
#define TEST_K 2
#define TEST_SE0_NAK 3
#define TEST_PACKET 4
#define TEST_FORCE_EN 5
/*
* New Feature Selectors as added by USB 3.0
* See USB 3.0 spec Table 9-6
*/
#define USB_DEVICE_U1_ENABLE 48 /* dev may initiate U1 transition */
#define USB_DEVICE_U2_ENABLE 49 /* dev may initiate U2 transition */
#define USB_DEVICE_LTM_ENABLE 50 /* dev may send LTM */
#define USB_INTRF_FUNC_SUSPEND 0 /* function suspend */
#define USB_INTR_FUNC_SUSPEND_OPT_MASK 0xFF00
/*
* Suspend Options, Table 9-7 USB 3.0 spec
*/
#define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0))
#define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1))
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
/* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
#define USB_DEV_STAT_U1_ENABLED 2 /* transition into U1 state */
#define USB_DEV_STAT_U2_ENABLED 3 /* transition into U2 state */
#define USB_DEV_STAT_LTM_ENABLED 4 /* Latency tolerance messages */
/**
* struct usb_ctrlrequest - SETUP data for a USB device control request
* @bRequestType: matches the USB bmRequestType field
* @bRequest: matches the USB bRequest field
* @wValue: matches the USB wValue field (le16 byte order)
* @wIndex: matches the USB wIndex field (le16 byte order)
* @wLength: matches the USB wLength field (le16 byte order)
*
* This structure is used to send control requests to a USB device. It matches
* the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the
* USB spec for a fuller description of the different fields, and what they are
* used for.
*
* Note that the driver for any interface can issue control requests.
* For most devices, interfaces don't coordinate with each other, so
* such requests may be made at any time.
*/
struct usb_ctrlrequest {
__u8 bRequestType;
__u8 bRequest;
__le16 wValue;
__le16 wIndex;
__le16 wLength;
} ;
/*-------------------------------------------------------------------------*/
/*
* STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
* (rarely) accepted by SET_DESCRIPTOR.
*
* Note that all multi-byte values here are encoded in little endian
* byte order "on the wire". Within the kernel and when exposed
* through the Linux-USB APIs, they are not converted to cpu byte
* order; it is the responsibility of the client code to do this.
* The single exception is when device and configuration descriptors (but
* not other descriptors) are read from usbfs (i.e. /proc/bus/usb/BBB/DDD);
* in this case the fields are converted to host endianness by the kernel.
*/
/*
* Descriptor types ... USB 2.0 spec table 9.5
*/
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_INTERFACE_POWER 0x08
/* these are from a minor usb 2.0 revision (ECN) */
#define USB_DT_OTG 0x09
#define USB_DT_DEBUG 0x0a
#define USB_DT_INTERFACE_ASSOCIATION 0x0b
/* these are from the Wireless USB spec */
#define USB_DT_SECURITY 0x0c
#define USB_DT_KEY 0x0d
#define USB_DT_ENCRYPTION_TYPE 0x0e
#define USB_DT_BOS 0x0f
#define USB_DT_DEVICE_CAPABILITY 0x10
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
#define USB_DT_WIRE_ADAPTER 0x21
#define USB_DT_RPIPE 0x22
#define USB_DT_CS_RADIO_CONTROL 0x23
/* From the T10 UAS specification */
#define USB_DT_PIPE_USAGE 0x24
/* From the USB 3.0 spec */
#define USB_DT_SS_ENDPOINT_COMP 0x30
/* From HID 1.11 spec */
#define USB_DT_HID_REPORT 0x22
/* Conventional codes for class-specific descriptors. The convention is
* defined in the USB "Common Class" Spec (3.11). Individual class specs
* are authoritative for their usage, not the "common class" writeup.
*/
#define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE)
#define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG)
#define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING)
#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)
/* All standard descriptors have these 2 fields at the beginning */
struct usb_descriptor_header {
__u8 bLength;
__u8 bDescriptorType;
} ;
/*-------------------------------------------------------------------------*/
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__le16 idVendor;
__le16 idProduct;
__le16 bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
} ;
#define USB_DT_DEVICE_SIZE 18
/*
* Device and/or Interface Class codes
* as found in bDeviceClass or bInterfaceClass
* and defined by www.usb.org documents
*/
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_STILL_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
#define USB_SUBCLASS_VENDOR_SPEC 0xff
/*-------------------------------------------------------------------------*/
/* USB_DT_CONFIG: Configuration descriptor information.
*
* USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
* descriptor type is different. Highspeed-capable devices can look
* different depending on what speed they're currently running. Only
* devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
* descriptors.
*/
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} ;
#define USB_DT_CONFIG_SIZE 9
/* from config descriptor bmAttributes */
#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */
#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */
#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */
#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
/*-------------------------------------------------------------------------*/
/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wData[1]; /* UTF-16LE encoded */
} ;
/* note that "string" zero is special, it holds language codes that
* the device supports, not Unicode characters.
*/
/*-------------------------------------------------------------------------*/
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} ;
#define USB_DT_INTERFACE_SIZE 9
/*-------------------------------------------------------------------------*/
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;
__u8 bmAttributes;
__le16 wMaxPacketSize;
__u8 bInterval;
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} ;
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
/* Used to access common fields */
struct usb_generic_descriptor {
__u8 bLength;
__u8 bDescriptorType;
};
struct usb_class_hid_descriptor {
u8 bLength;
u8 bDescriptorType;
u16 bcdCDC;
u8 bCountryCode;
u8 bNumDescriptors; /* 0x01 */
u8 bDescriptorType0;
u16 wDescriptorLength0;
/* optional descriptors are not supported. */
};
struct usb_class_report_descriptor {
u8 bLength; /* dummy */
u8 bDescriptorType;
u16 wLength;
u8 bData[0];
};
/*
* Endpoints
*/
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
#define USB_ENDPOINT_MAXP_MASK 0x07ff
#define USB_EP_MAXP_MULT_SHIFT 11
#define USB_EP_MAXP_MULT_MASK (3 << USB_EP_MAXP_MULT_SHIFT)
#define USB_EP_MAXP_MULT(m) \
(((m) & USB_EP_MAXP_MULT_MASK) >> USB_EP_MAXP_MULT_SHIFT)
/* The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type. */
#define USB_ENDPOINT_INTRTYPE 0x30
#define USB_ENDPOINT_INTR_PERIODIC (0 << 4)
#define USB_ENDPOINT_INTR_NOTIFICATION (1 << 4)
#define USB_ENDPOINT_SYNCTYPE 0x0c
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2)
#define USB_ENDPOINT_SYNC_SYNC (3 << 2)
#define USB_ENDPOINT_USAGE_MASK 0x30
#define USB_ENDPOINT_USAGE_DATA 0x00
#define USB_ENDPOINT_USAGE_FEEDBACK 0x10
#define USB_ENDPOINT_USAGE_IMPLICIT_FB 0x20 /* Implicit feedback Data endpoint */
/*-------------------------------------------------------------------------*/
/**
* usb_endpoint_num - get the endpoint's number
* @epd: endpoint to be checked
*
* Returns @epd's number: 0 to 15.
*/
static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
{
return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
/**
* usb_endpoint_type - get the endpoint's transfer type
* @epd: endpoint to be checked
*
* Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according
* to @epd's transfer type.
*/
static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
{
return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
}
/**
* usb_endpoint_dir_in - check if the endpoint has IN direction
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type IN, otherwise it returns false.
*/
static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
}
/**
* usb_endpoint_dir_out - check if the endpoint has OUT direction
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type OUT, otherwise it returns false.
*/
static inline int usb_endpoint_dir_out(
const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
}
/**
* usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type bulk, otherwise it returns false.
*/
static inline int usb_endpoint_xfer_bulk(
const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK);
}
/**
* usb_endpoint_xfer_control - check if the endpoint has control transfer type
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type control, otherwise it returns false.
*/
static inline int usb_endpoint_xfer_control(
const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL);
}
/**
* usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
* @epd: endpoint to be checked
*
* Returns true if the endpoint has bulk transfer type and IN direction,
* otherwise it returns false.
*/
static inline int usb_endpoint_is_bulk_in(
const struct usb_endpoint_descriptor *epd)
{
return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd);
}
/**
* usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
* @epd: endpoint to be checked
*
* Returns true if the endpoint has bulk transfer type and OUT direction,
* otherwise it returns false.
*/
static inline int usb_endpoint_is_bulk_out(
const struct usb_endpoint_descriptor *epd)
{
return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd);
}
/**
* usb_endpoint_maxp - get endpoint's max packet size
* @epd: endpoint to be checked
*
* Returns @epd's max packet
*/
static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
{
return __le16_to_cpu(get_unaligned(&epd->wMaxPacketSize));
}
/**
* usb_endpoint_maxp_mult - get endpoint's transactional opportunities
* @epd: endpoint to be checked
*
* Return @epd's wMaxPacketSize[12:11] + 1
*/
static inline int
usb_endpoint_maxp_mult(const struct usb_endpoint_descriptor *epd)
{
int maxp = __le16_to_cpu(epd->wMaxPacketSize);
return USB_EP_MAXP_MULT(maxp) + 1;
}
static inline int usb_endpoint_interrupt_type(
const struct usb_endpoint_descriptor *epd)
{
return epd->bmAttributes & USB_ENDPOINT_INTRTYPE;
}
/*-------------------------------------------------------------------------*/
/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
struct usb_ss_ep_comp_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bMaxBurst;
__u8 bmAttributes;
__le16 wBytesPerInterval;
} ;
#define USB_DT_SS_EP_COMP_SIZE 6
/* Bits 4:0 of bmAttributes if this is a bulk endpoint */
static inline int
usb_ss_max_streams(const struct usb_ss_ep_comp_descriptor *comp)
{
int max_streams;
if (!comp)
return 0;
max_streams = comp->bmAttributes & 0x1f;
if (!max_streams)
return 0;
max_streams = 1 << max_streams;
return max_streams;
}
/* Bits 1:0 of bmAttributes if this is an isoc endpoint */
#define USB_SS_MULT(p) (1 + ((p) & 0x3))
/*-------------------------------------------------------------------------*/
/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
struct usb_qualifier_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__u8 bNumConfigurations;
__u8 bRESERVED;
} ;
/*-------------------------------------------------------------------------*/
/* USB_DT_OTG (from OTG 1.0a supplement) */
struct usb_otg_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bmAttributes; /* support for HNP, SRP, etc */
} ;
/* from usb_otg_descriptor.bmAttributes */
#define USB_OTG_SRP (1 << 0)
#define USB_OTG_HNP (1 << 1) /* swap host/device roles */
/*-------------------------------------------------------------------------*/
/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */
struct usb_debug_descriptor {
__u8 bLength;
__u8 bDescriptorType;
/* bulk endpoints with 8 byte maxpacket */
__u8 bDebugInEndpoint;
__u8 bDebugOutEndpoint;
};
/*-------------------------------------------------------------------------*/
/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
struct usb_interface_assoc_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bFirstInterface;
__u8 bInterfaceCount;
__u8 bFunctionClass;
__u8 bFunctionSubClass;
__u8 bFunctionProtocol;
__u8 iFunction;
} ;
/*-------------------------------------------------------------------------*/
/* USB_DT_SECURITY: group of wireless security descriptors, including
* encryption types available for setting up a CC/association.
*/
struct usb_security_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumEncryptionTypes;
};
/*-------------------------------------------------------------------------*/
/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys
* may be retrieved.
*/
struct usb_key_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 tTKID[3];
__u8 bReserved;
__u8 bKeyData[0];
};
/*-------------------------------------------------------------------------*/
/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */
struct usb_encryption_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEncryptionType;
#define USB_ENC_TYPE_UNSECURE 0
#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */
#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */
#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */
__u8 bEncryptionValue; /* use in SET_ENCRYPTION */
__u8 bAuthKeyIndex;
};
/*-------------------------------------------------------------------------*/
/* USB_DT_BOS: group of device-level capabilities */
struct usb_bos_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumDeviceCaps;
};
#define USB_DT_BOS_SIZE 5
/*-------------------------------------------------------------------------*/
/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */
struct usb_dev_cap_header {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
};
#define USB_CAP_TYPE_WIRELESS_USB 1
struct usb_wireless_cap_descriptor { /* Ultra Wide Band */
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
__u8 bmAttributes;
#define USB_WIRELESS_P2P_DRD (1 << 1)
#define USB_WIRELESS_BEACON_MASK (3 << 2)
#define USB_WIRELESS_BEACON_SELF (1 << 2)
#define USB_WIRELESS_BEACON_DIRECTED (2 << 2)
#define USB_WIRELESS_BEACON_NONE (3 << 2)
__le16 wPHYRates; /* bit rates, Mbps */
#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */
#define USB_WIRELESS_PHY_80 (1 << 1)
#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */
#define USB_WIRELESS_PHY_160 (1 << 3)
#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */
#define USB_WIRELESS_PHY_320 (1 << 5)
#define USB_WIRELESS_PHY_400 (1 << 6)
#define USB_WIRELESS_PHY_480 (1 << 7)
__u8 bmTFITXPowerInfo; /* TFI power levels */
__u8 bmFFITXPowerInfo; /* FFI power levels */
__le16 bmBandGroup;
__u8 bReserved;
};
/* USB 2.0 Extension descriptor */
#define USB_CAP_TYPE_EXT 2
struct usb_ext_cap_descriptor { /* Link Power Management */
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
__le32 bmAttributes;
#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */
#define USB_BESL_SUPPORT (1 << 2) /* supports BESL */
#define USB_BESL_BASELINE_VALID (1 << 3) /* Baseline BESL valid*/
#define USB_BESL_DEEP_VALID (1 << 4) /* Deep BESL valid */
#define USB_GET_BESL_BASELINE(p) (((p) & (0xf << 8)) >> 8)
#define USB_GET_BESL_DEEP(p) (((p) & (0xf << 12)) >> 12)
};
#define USB_DT_USB_EXT_CAP_SIZE 7
/*
* SuperSpeed USB Capability descriptor: Defines the set of SuperSpeed USB
* specific device level capabilities
*/
#define USB_SS_CAP_TYPE 3
struct usb_ss_cap_descriptor { /* Link Power Management */
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
__u8 bmAttributes;
#define USB_LTM_SUPPORT (1 << 1) /* supports LTM */
__le16 wSpeedSupported;
#define USB_LOW_SPEED_OPERATION (1) /* Low speed operation */
#define USB_FULL_SPEED_OPERATION (1 << 1) /* Full speed operation */
#define USB_HIGH_SPEED_OPERATION (1 << 2) /* High speed operation */
#define USB_5GBPS_OPERATION (1 << 3) /* Operation at 5Gbps */
__u8 bFunctionalitySupport;
__u8 bU1devExitLat;
__le16 bU2DevExitLat;
};
#define USB_DT_USB_SS_CAP_SIZE 10
/*
* Container ID Capability descriptor: Defines the instance unique ID used to
* identify the instance across all operating modes
*/
#define CONTAINER_ID_TYPE 4
struct usb_ss_container_id_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
__u8 bReserved;
__u8 ContainerID[16]; /* 128-bit number */
};
#define USB_DT_USB_SS_CONTN_ID_SIZE 20
/*-------------------------------------------------------------------------*/
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
* each endpoint descriptor for a wireless device
*/
struct usb_wireless_ep_comp_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bMaxBurst;
__u8 bMaxSequence;
__le16 wMaxStreamDelay;
__le16 wOverTheAirPacketSize;
__u8 bOverTheAirInterval;
__u8 bmCompAttributes;
#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */
#define USB_ENDPOINT_SWITCH_NO 0
#define USB_ENDPOINT_SWITCH_SWITCH 1
#define USB_ENDPOINT_SWITCH_SCALE 2
};
/*-------------------------------------------------------------------------*/
/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
* host and a device for connection set up, mutual authentication, and
* exchanging short lived session keys. The handshake depends on a CC.
*/
struct usb_handshake {
__u8 bMessageNumber;
__u8 bStatus;
__u8 tTKID[3];
__u8 bReserved;
__u8 CDID[16];
__u8 nonce[16];
__u8 MIC[8];
};
/*-------------------------------------------------------------------------*/
/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
* A CC may also be set up using non-wireless secure channels (including
* wired USB!), and some devices may support CCs with multiple hosts.
*/
struct usb_connection_context {
__u8 CHID[16]; /* persistent host id */
__u8 CDID[16]; /* device id (unique w/in host context) */
__u8 CK[16]; /* connection key */
};
/*-------------------------------------------------------------------------*/
/* USB 2.0 defines three speeds, here's how Linux identifies them */
enum usb_device_speed {
USB_SPEED_UNKNOWN = 0, /* enumerating */
USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
USB_SPEED_HIGH, /* usb 2.0 */
USB_SPEED_WIRELESS, /* wireless (usb 2.5) */
USB_SPEED_SUPER, /* usb 3.0 */
};
#ifdef __KERNEL__
/**
* usb_speed_string() - Returns human readable-name of the speed.
* @speed: The speed to return human-readable name for. If it's not
* any of the speeds defined in usb_device_speed enum, string for
* USB_SPEED_UNKNOWN will be returned.
*/
extern const char *usb_speed_string(enum usb_device_speed speed);
#endif
enum usb_device_state {
/* NOTATTACHED isn't in the USB spec, and this state acts
* the same as ATTACHED ... but it's clearer this way.
*/
USB_STATE_NOTATTACHED = 0,
/* chapter 9 and authentication (wireless) device states */
USB_STATE_ATTACHED,
USB_STATE_POWERED, /* wired */
USB_STATE_RECONNECTING, /* auth */
USB_STATE_UNAUTHENTICATED, /* auth */
USB_STATE_DEFAULT, /* limited function */
USB_STATE_ADDRESS,
USB_STATE_CONFIGURED, /* most functions */
USB_STATE_SUSPENDED
/* NOTE: there are actually four different SUSPENDED
* states, returning to POWERED, DEFAULT, ADDRESS, or
* CONFIGURED respectively when SOF tokens flow again.
* At this level there's no difference between L1 and L2
* suspend states. (L2 being original USB 1.1 suspend.)
*/
};
enum usb3_link_state {
USB3_LPM_U0 = 0,
USB3_LPM_U1,
USB3_LPM_U2,
USB3_LPM_U3
};
/*
* A U1 timeout of 0x0 means the parent hub will reject any transitions to U1.
* 0xff means the parent hub will accept transitions to U1, but will not
* initiate a transition.
*
* A U1 timeout of 0x1 to 0x7F also causes the hub to initiate a transition to
* U1 after that many microseconds. Timeouts of 0x80 to 0xFE are reserved
* values.
*
* A U2 timeout of 0x0 means the parent hub will reject any transitions to U2.
* 0xff means the parent hub will accept transitions to U2, but will not
* initiate a transition.
*
* A U2 timeout of 0x1 to 0xFE also causes the hub to initiate a transition to
* U2 after N*256 microseconds. Therefore a U2 timeout value of 0x1 means a U2
* idle timer of 256 microseconds, 0x2 means 512 microseconds, 0xFE means
* 65.024ms.
*/
#define USB3_LPM_DISABLED 0x0
#define USB3_LPM_U1_MAX_TIMEOUT 0x7F
#define USB3_LPM_U2_MAX_TIMEOUT 0xFE
#define USB3_LPM_DEVICE_INITIATED 0xFF
struct usb_set_sel_req {
__u8 u1_sel;
__u8 u1_pel;
__le16 u2_sel;
__le16 u2_pel;
} ;
/*
* The Set System Exit Latency control transfer provides one byte each for
* U1 SEL and U1 PEL, so the max exit latency is 0xFF. U2 SEL and U2 PEL each
* are two bytes long.
*/
#define USB3_LPM_MAX_U1_SEL_PEL 0xFF
#define USB3_LPM_MAX_U2_SEL_PEL 0xFFFF
/*-------------------------------------------------------------------------*/
/*
* As per USB compliance update, a device that is actively drawing
* more than 100mA from USB must report itself as bus-powered in
* the GetStatus(DEVICE) call.
* http://compliance.usb.org/index.asp?UpdateFile=Electrical&Format=Standard#34
*/
#define USB_SELF_POWER_VBUS_MAX_DRAW 100
/**
* struct usb_string - wraps a C string and its USB id
* @id:the (nonzero) ID for this string
* @s:the string, in UTF-8 encoding
*
* If you're using usb_gadget_get_string(), use this to wrap a string
* together with its ID.
*/
struct usb_string {
u8 id;
const char *s;
};
#endif /* __LINUX_USB_CH9_H */

View File

@ -0,0 +1,327 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* composite.h -- framework for usb gadgets which are composite devices
*
* Copyright (C) 2006-2008 David Brownell
*/
#ifndef __LINUX_USB_COMPOSITE_H
#define __LINUX_USB_COMPOSITE_H
/*
* This framework is an optional layer on top of the USB Gadget interface,
* making it easier to build (a) Composite devices, supporting multiple
* functions within any single configuration, and (b) Multi-configuration
* devices, also supporting multiple functions but without necessarily
* having more than one function per configuration.
*
* Example: a device with a single configuration supporting both network
* link and mass storage functions is a composite device. Those functions
* might alternatively be packaged in individual configurations, but in
* the composite model the host can use both functions at the same time.
*/
#include <common.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <usb/lin_gadget_compat.h>
/*
* USB function drivers should return USB_GADGET_DELAYED_STATUS if they
* wish to delay the data/status stages of the control transfer till they
* are ready. The control transfer will then be kept from completing till
* all the function drivers that requested for USB_GADGET_DELAYED_STAUS
* invoke usb_composite_setup_continue().
*/
#define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */
struct usb_configuration;
/**
* struct usb_function - describes one function of a configuration
* @name: For diagnostics, identifies the function.
* @strings: tables of strings, keyed by identifiers assigned during bind()
* and by language IDs provided in control requests
* @descriptors: Table of full (or low) speed descriptors, using interface and
* string identifiers assigned during @bind(). If this pointer is null,
* the function will not be available at full speed (or at low speed).
* @hs_descriptors: Table of high speed descriptors, using interface and
* string identifiers assigned during @bind(). If this pointer is null,
* the function will not be available at high speed.
* @config: assigned when @usb_add_function() is called; this is the
* configuration with which this function is associated.
* @bind: Before the gadget can register, all of its functions bind() to the
* available resources including string and interface identifiers used
* in interface or class descriptors; endpoints; I/O buffers; and so on.
* @unbind: Reverses @bind; called as a side effect of unregistering the
* driver which added this function.
* @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
* initialize usb_ep.driver data at this time (when it is used).
* Note that setting an interface to its current altsetting resets
* interface state, and that all interfaces have a disabled state.
* @get_alt: Returns the active altsetting. If this is not provided,
* then only altsetting zero is supported.
* @disable: (REQUIRED) Indicates the function should be disabled. Reasons
* include host resetting or reconfiguring the gadget, and disconnection.
* @setup: Used for interface-specific control requests.
* @suspend: Notifies functions when the host stops sending USB traffic.
* @resume: Notifies functions when the host restarts USB traffic.
*
* A single USB function uses one or more interfaces, and should in most
* cases support operation at both full and high speeds. Each function is
* associated by @usb_add_function() with a one configuration; that function
* causes @bind() to be called so resources can be allocated as part of
* setting up a gadget driver. Those resources include endpoints, which
* should be allocated using @usb_ep_autoconfig().
*
* To support dual speed operation, a function driver provides descriptors
* for both high and full speed operation. Except in rare cases that don't
* involve bulk endpoints, each speed needs different endpoint descriptors.
*
* Function drivers choose their own strategies for managing instance data.
* The simplest strategy just declares it "static', which means the function
* can only be activated once. If the function needs to be exposed in more
* than one configuration at a given speed, it needs to support multiple
* usb_function structures (one for each configuration).
*
* A more complex strategy might encapsulate a @usb_function structure inside
* a driver-specific instance structure to allows multiple activations. An
* example of multiple activations might be a CDC ACM function that supports
* two or more distinct instances within the same configuration, providing
* several independent logical data links to a USB host.
*/
struct usb_function {
const char *name;
struct usb_descriptor_header **descriptors;
struct usb_descriptor_header **hs_descriptors;
struct usb_configuration *config;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
* we can't restructure things to avoid mismatching.
* Related: unbind() may kfree() but bind() won't...
*/
/* configuration management: bind/unbind */
int (*bind)(struct usb_configuration *,
struct usb_function *);
void (*unbind)(struct usb_configuration *,
struct usb_function *);
/* runtime state management */
int (*set_alt)(struct usb_function *,
unsigned interface, unsigned alt);
int (*get_alt)(struct usb_function *,
unsigned interface);
void (*disable)(struct usb_function *);
int (*setup)(struct usb_function *,
const struct usb_ctrlrequest *);
void (*suspend)(struct usb_function *);
void (*resume)(struct usb_function *);
/* private: */
/* internals */
struct list_head list;
DECLARE_BITMAP(endpoints, 32);
};
int usb_add_function(struct usb_configuration *, struct usb_function *);
int usb_function_deactivate(struct usb_function *);
int usb_function_activate(struct usb_function *);
int usb_interface_id(struct usb_configuration *, struct usb_function *);
#define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */
/**
* struct usb_configuration - represents one gadget configuration
* @label: For diagnostics, describes the configuration.
* @strings: Tables of strings, keyed by identifiers assigned during @bind()
* and by language IDs provided in control requests.
* @descriptors: Table of descriptors preceding all function descriptors.
* Examples include OTG and vendor-specific descriptors.
* @bind: Called from @usb_add_config() to allocate resources unique to this
* configuration and to call @usb_add_function() for each function used.
* @unbind: Reverses @bind; called as a side effect of unregistering the
* driver which added this configuration.
* @setup: Used to delegate control requests that aren't handled by standard
* device infrastructure or directed at a specific interface.
* @bConfigurationValue: Copied into configuration descriptor.
* @iConfiguration: Copied into configuration descriptor.
* @bmAttributes: Copied into configuration descriptor.
* @bMaxPower: Copied into configuration descriptor.
* @cdev: assigned by @usb_add_config() before calling @bind(); this is
* the device associated with this configuration.
*
* Configurations are building blocks for gadget drivers structured around
* function drivers. Simple USB gadgets require only one function and one
* configuration, and handle dual-speed hardware by always providing the same
* functionality. Slightly more complex gadgets may have more than one
* single-function configuration at a given speed; or have configurations
* that only work at one speed.
*
* Composite devices are, by definition, ones with configurations which
* include more than one function.
*
* The lifecycle of a usb_configuration includes allocation, initialization
* of the fields described above, and calling @usb_add_config() to set up
* internal data and bind it to a specific device. The configuration's
* @bind() method is then used to initialize all the functions and then
* call @usb_add_function() for them.
*
* Those functions would normally be independant of each other, but that's
* not mandatory. CDC WMC devices are an example where functions often
* depend on other functions, with some functions subsidiary to others.
* Such interdependency may be managed in any way, so long as all of the
* descriptors complete by the time the composite driver returns from
* its bind() routine.
*/
struct usb_configuration {
const char *label;
const struct usb_descriptor_header **descriptors;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
* we can't restructure things to avoid mismatching...
*/
/* configuration management: bind/unbind */
int (*bind)(struct usb_configuration *);
void (*unbind)(struct usb_configuration *);
int (*setup)(struct usb_configuration *,
const struct usb_ctrlrequest *);
/* fields in the config descriptor */
u8 bConfigurationValue;
u8 iConfiguration;
u8 bmAttributes;
u8 bMaxPower;
struct usb_composite_dev *cdev;
/* private: */
/* internals */
struct list_head list;
struct list_head functions;
u8 next_interface_id;
unsigned highspeed:1;
unsigned fullspeed:1;
struct usb_function *interface[MAX_CONFIG_INTERFACES];
};
int usb_add_config(struct usb_composite_dev *,
struct usb_configuration *);
/**
* struct usb_composite_driver - groups configurations into a gadget
* @name: For diagnostics, identifies the driver.
* @dev: Template descriptor for the device, including default device
* identifiers.
* @strings: tables of strings, keyed by identifiers assigned during bind()
* and language IDs provided in control requests
* @bind: (REQUIRED) Used to allocate resources that are shared across the
* whole device, such as string IDs, and add its configurations using
* @usb_add_config(). This may fail by returning a negative errno
* value; it should return zero on successful initialization.
* @unbind: Reverses @bind(); called as a side effect of unregistering
* this driver.
* @disconnect: optional driver disconnect method
* @suspend: Notifies when the host stops sending USB traffic,
* after function notifications
* @resume: Notifies configuration when the host restarts USB traffic,
* before function notifications
*
* Devices default to reporting self powered operation. Devices which rely
* on bus powered operation should report this in their @bind() method.
*
* Before returning from @bind, various fields in the template descriptor
* may be overridden. These include the idVendor/idProduct/bcdDevice values
* normally to bind the appropriate host side driver, and the three strings
* (iManufacturer, iProduct, iSerialNumber) normally used to provide user
* meaningful device identifiers. (The strings will not be defined unless
* they are defined in @dev and @strings.) The correct ep0 maxpacket size
* is also reported, as defined by the underlying controller driver.
*/
struct usb_composite_driver {
const char *name;
const struct usb_device_descriptor *dev;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
* we can't restructure things to avoid mismatching...
*/
int (*bind)(struct usb_composite_dev *);
int (*unbind)(struct usb_composite_dev *);
void (*disconnect)(struct usb_composite_dev *);
/* global suspend hooks */
void (*suspend)(struct usb_composite_dev *);
void (*resume)(struct usb_composite_dev *);
};
extern int usb_composite_register(struct usb_composite_driver *);
extern void usb_composite_unregister(struct usb_composite_driver *);
/**
* struct usb_composite_device - represents one composite usb gadget
* @gadget: read-only, abstracts the gadget's usb peripheral controller
* @req: used for control responses; buffer is pre-allocated
* @bufsiz: size of buffer pre-allocated in @req
* @config: the currently active configuration
*
* One of these devices is allocated and initialized before the
* associated device driver's bind() is called.
*
* OPEN ISSUE: it appears that some WUSB devices will need to be
* built by combining a normal (wired) gadget with a wireless one.
* This revision of the gadget framework should probably try to make
* sure doing that won't hurt too much.
*
* One notion for how to handle Wireless USB devices involves:
* (a) a second gadget here, discovery mechanism TBD, but likely
* needing separate "register/unregister WUSB gadget" calls;
* (b) updates to usb_gadget to include flags "is it wireless",
* "is it wired", plus (presumably in a wrapper structure)
* bandgroup and PHY info;
* (c) presumably a wireless_ep wrapping a usb_ep, and reporting
* wireless-specific parameters like maxburst and maxsequence;
* (d) configurations that are specific to wireless links;
* (e) function drivers that understand wireless configs and will
* support wireless for (additional) function instances;
* (f) a function to support association setup (like CBAF), not
* necessarily requiring a wireless adapter;
* (g) composite device setup that can create one or more wireless
* configs, including appropriate association setup support;
* (h) more, TBD.
*/
struct usb_composite_dev {
struct usb_request *req;
unsigned bufsiz;
struct usb_configuration *config;
/* private: */
/* internals */
unsigned int suspended:1;
struct usb_device_descriptor __aligned(CONFIG_SYS_CACHELINE_SIZE) desc;
struct list_head configs;
struct usb_composite_driver *driver;
u8 next_string_id;
/* the gadget driver won't enable the data pullup
* while the deactivation count is nonzero.
*/
unsigned deactivations;
};
extern int usb_string_id(struct usb_composite_dev *c);
extern int usb_string_ids_tab(struct usb_composite_dev *c,
struct usb_string *str);
extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
#endif /* __LINUX_USB_COMPOSITE_H */

View File

@ -0,0 +1,441 @@
/*
* <linux/usb/gadget.h>
*
* We call the USB code inside a Linux-based peripheral device a "gadget"
* driver, except for the hardware-specific bus glue. One USB host can
* master many USB gadgets, but the gadgets are only slaved to one host.
*
*
* (C) Copyright 2002-2004 by David Brownell
* All Rights Reserved.
*
* This software is licensed under the GNU GPL version 2.
*
* Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and
* Remy Bohmer <linux@bohmer.net>
*/
#ifndef __LINUX_USB_GADGET_H
#define __LINUX_USB_GADGET_H
/*
#include <errno.h>
#include <linux/compat.h>
#include <linux/list.h>*/
#include "usb_os_adapter.h"
#include <linux/errno.h>
#include <stdbool.h>
struct usb_ep;
/**
* struct usb_request - describes one i/o request
* @buf: Buffer used for data. Always provide this; some controllers
* only use PIO, or don't use DMA for some endpoints.
* @dma: DMA address corresponding to 'buf'. If you don't set this
* field, and the usb controller needs one, it is responsible
* for mapping and unmapping the buffer.
* @stream_id: The stream id, when USB3.0 bulk streams are being used
* @length: Length of that data
* @no_interrupt: If true, hints that no completion irq is needed.
* Helpful sometimes with deep request queues that are handled
* directly by DMA controllers.
* @zero: If true, when writing data, makes the last packet be "short"
* by adding a zero length packet as needed;
* @short_not_ok: When reading data, makes short packets be
* treated as errors (queue stops advancing till cleanup).
* @complete: Function called when request completes, so this request and
* its buffer may be re-used.
* Reads terminate with a short packet, or when the buffer fills,
* whichever comes first. When writes terminate, some data bytes
* will usually still be in flight (often in a hardware fifo).
* Errors (for reads or writes) stop the queue from advancing
* until the completion function returns, so that any transfers
* invalidated by the error may first be dequeued.
* @context: For use by the completion callback
* @list: For use by the gadget driver.
* @status: Reports completion code, zero or a negative errno.
* Normally, faults block the transfer queue from advancing until
* the completion callback returns.
* Code "-ESHUTDOWN" indicates completion caused by device disconnect,
* or when the driver disabled the endpoint.
* @actual: Reports bytes transferred to/from the buffer. For reads (OUT
* transfers) this may be less than the requested length. If the
* short_not_ok flag is set, short reads are treated as errors
* even when status otherwise indicates successful completion.
* Note that for writes (IN transfers) some data bytes may still
* reside in a device-side FIFO when the request is reported as
* complete.
*
* These are allocated/freed through the endpoint they're used with. The
* hardware's driver can add extra per-request data to the memory it returns,
* which often avoids separate memory allocations (potential failures),
* later when the request is queued.
*
* Request flags affect request handling, such as whether a zero length
* packet is written (the "zero" flag), whether a short read should be
* treated as an error (blocking request queue advance, the "short_not_ok"
* flag), or hinting that an interrupt is not required (the "no_interrupt"
* flag, for use with deep request queues).
*
* Bulk endpoints can use any size buffers, and can also be used for interrupt
* transfers. interrupt-only endpoints can be much less functional.
*
* NOTE: this is analagous to 'struct urb' on the host side, except that
* it's thinner and promotes more pre-allocation.
*/
struct usb_request {
void *buf;
unsigned length;
dma_addr_t dma;
unsigned stream_id:16;
unsigned no_interrupt:1;
unsigned zero:1;
unsigned short_not_ok:1;
void (*complete)(struct usb_ep *ep,
struct usb_request *req);
void *context;
ListItem_t list;
void* powner;
int status;
unsigned actual;
};
/*-------------------------------------------------------------------------*/
/* endpoint-specific parts of the api to the usb controller hardware.
* unlike the urb model, (de)multiplexing layers are not required.
* (so this api could slash overhead if used on the host side...)
*
* note that device side usb controllers commonly differ in how many
* endpoints they support, as well as their capabilities.
*/
struct usb_ep_ops {
int (*enable) (struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc);
int (*disable) (struct usb_ep *ep);
struct usb_request *(*alloc_request) (struct usb_ep *ep,
gfp_t gfp_flags);
void (*free_request) (struct usb_ep *ep, struct usb_request *req);
int (*queue) (struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags);
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
int (*set_halt) (struct usb_ep *ep, int value);
int (*set_wedge)(struct usb_ep *ep);
int (*fifo_status) (struct usb_ep *ep);
void (*fifo_flush) (struct usb_ep *ep);
};
/**
* struct usb_ep - device side representation of USB endpoint
* @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
* @ops: Function pointers used to access hardware-specific operations.
* @ep_list:the gadget's ep_list holds all of its endpoints
* @maxpacket:The maximum packet size used on this endpoint. The initial
* value can sometimes be reduced (hardware allowing), according to
* the endpoint descriptor used to configure the endpoint.
* @maxpacket_limit:The maximum packet size value which can be handled by this
* endpoint. It's set once by UDC driver when endpoint is initialized, and
* should not be changed. Should not be confused with maxpacket.
* @max_streams: The maximum number of streams supported
* by this EP (0 - 16, actual number is 2^n)
* @maxburst: the maximum number of bursts supported by this EP (for usb3)
* @driver_data:for use by the gadget driver. all other fields are
* read-only to gadget drivers.
* @desc: endpoint descriptor. This pointer is set before the endpoint is
* enabled and remains valid until the endpoint is disabled.
* @comp_desc: In case of SuperSpeed support, this is the endpoint companion
* descriptor that is used to configure the endpoint
*
* the bus controller driver lists all the general purpose endpoints in
* gadget->ep_list. the control endpoint (gadget->ep0) is not in that list,
* and is accessed only in response to a driver setup() callback.
*/
struct usb_ep {
void *driver_data;
const char *name;
const struct usb_ep_ops *ops;
ListItem_t ep_list;
void* powner;
unsigned maxpacket:16;
unsigned maxpacket_limit:16;
unsigned max_streams:16;
unsigned maxburst:5;
const struct usb_endpoint_descriptor *desc;
const struct usb_ss_ep_comp_descriptor *comp_desc;
};
/*-------------------------------------------------------------------------*/
/**
* usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint
* @ep:the endpoint being configured
* @maxpacket_limit:value of maximum packet size limit
*
* This function shoud be used only in UDC drivers to initialize endpoint
* (usually in probe function).
*/
static inline void usb_ep_set_maxpacket_limit(struct usb_ep *ep,
unsigned maxpacket_limit)
{
ep->maxpacket_limit = maxpacket_limit;
ep->maxpacket = maxpacket_limit;
}
/**
* usb_ep_enable - configure endpoint, making it usable
* @ep:the endpoint being configured. may not be the endpoint named "ep0".
* drivers discover endpoints through the ep_list of a usb_gadget.
* @desc:descriptor for desired behavior. caller guarantees this pointer
* remains valid until the endpoint is disabled; the data byte order
* is little-endian (usb-standard).
*
* when configurations are set, or when interface settings change, the driver
* will enable or disable the relevant endpoints. while it is enabled, an
* endpoint may be used for i/o until the driver receives a disconnect() from
* the host or until the endpoint is disabled.
*
* the ep0 implementation (which calls this routine) must ensure that the
* hardware capabilities of each endpoint match the descriptor provided
* for it. for example, an endpoint named "ep2in-bulk" would be usable
* for interrupt transfers as well as bulk, but it likely couldn't be used
* for iso transfers or for endpoint 14. some endpoints are fully
* configurable, with more generic names like "ep-a". (remember that for
* USB, "in" means "towards the USB master".)
*
* returns zero, or a negative error code.
*/
static inline int usb_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
return ep->ops->enable(ep, desc);
}
/**
* usb_ep_disable - endpoint is no longer usable
* @ep:the endpoint being unconfigured. may not be the endpoint named "ep0".
*
* no other task may be using this endpoint when this is called.
* any pending and uncompleted requests will complete with status
* indicating disconnect (-ESHUTDOWN) before this call returns.
* gadget drivers must call usb_ep_enable() again before queueing
* requests to the endpoint.
*
* returns zero, or a negative error code.
*/
static inline int usb_ep_disable(struct usb_ep *ep)
{
return ep->ops->disable(ep);
}
/**
* usb_ep_alloc_request - allocate a request object to use with this endpoint
* @ep:the endpoint to be used with with the request
* @gfp_flags:GFP_* flags to use
*
* Request objects must be allocated with this call, since they normally
* need controller-specific setup and may even need endpoint-specific
* resources such as allocation of DMA descriptors.
* Requests may be submitted with usb_ep_queue(), and receive a single
* completion callback. Free requests with usb_ep_free_request(), when
* they are no longer needed.
*
* Returns the request, or null if one could not be allocated.
*/
static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,
gfp_t gfp_flags)
{
return ep->ops->alloc_request(ep, gfp_flags);
}
/**
* usb_ep_free_request - frees a request object
* @ep:the endpoint associated with the request
* @req:the request being freed
*
* Reverses the effect of usb_ep_alloc_request().
* Caller guarantees the request is not queued, and that it will
* no longer be requeued (or otherwise used).
*/
static inline void usb_ep_free_request(struct usb_ep *ep,
struct usb_request *req)
{
ep->ops->free_request(ep, req);
}
/**
* usb_ep_queue - queues (submits) an I/O request to an endpoint.
* @ep:the endpoint associated with the request
* @req:the request being submitted
* @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
* pre-allocate all necessary memory with the request.
*
* This tells the device controller to perform the specified request through
* that endpoint (reading or writing a buffer). When the request completes,
* including being canceled by usb_ep_dequeue(), the request's completion
* routine is called to return the request to the driver. Any endpoint
* (except control endpoints like ep0) may have more than one transfer
* request queued; they complete in FIFO order. Once a gadget driver
* submits a request, that request may not be examined or modified until it
* is given back to that driver through the completion callback.
*
* Each request is turned into one or more packets. The controller driver
* never merges adjacent requests into the same packet. OUT transfers
* will sometimes use data that's already buffered in the hardware.
* Drivers can rely on the fact that the first byte of the request's buffer
* always corresponds to the first byte of some USB packet, for both
* IN and OUT transfers.
*
* Bulk endpoints can queue any amount of data; the transfer is packetized
* automatically. The last packet will be short if the request doesn't fill it
* out completely. Zero length packets (ZLPs) should be avoided in portable
* protocols since not all usb hardware can successfully handle zero length
* packets. (ZLPs may be explicitly written, and may be implicitly written if
* the request 'zero' flag is set.) Bulk endpoints may also be used
* for interrupt transfers; but the reverse is not true, and some endpoints
* won't support every interrupt transfer. (Such as 768 byte packets.)
*
* Interrupt-only endpoints are less functional than bulk endpoints, for
* example by not supporting queueing or not handling buffers that are
* larger than the endpoint's maxpacket size. They may also treat data
* toggle differently.
*
* Control endpoints ... after getting a setup() callback, the driver queues
* one response (even if it would be zero length). That enables the
* status ack, after transfering data as specified in the response. Setup
* functions may return negative error codes to generate protocol stalls.
* (Note that some USB device controllers disallow protocol stall responses
* in some cases.) When control responses are deferred (the response is
* written after the setup callback returns), then usb_ep_set_halt() may be
* used on ep0 to trigger protocol stalls.
*
* For periodic endpoints, like interrupt or isochronous ones, the usb host
* arranges to poll once per interval, and the gadget driver usually will
* have queued some data to transfer at that time.
*
* Returns zero, or a negative error code. Endpoints that are not enabled
* report errors; errors will also be
* reported when the usb peripheral is disconnected.
*/
static inline int usb_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags)
{
return ep->ops->queue(ep, req, gfp_flags);
}
/**
* usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint
* @ep:the endpoint associated with the request
* @req:the request being canceled
*
* if the request is still active on the endpoint, it is dequeued and its
* completion routine is called (with status -ECONNRESET); else a negative
* error code is returned.
*
* note that some hardware can't clear out write fifos (to unlink the request
* at the head of the queue) except as part of disconnecting from usb. such
* restrictions prevent drivers from supporting configuration changes,
* even to configuration zero (a "chapter 9" requirement).
*/
static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
return ep->ops->dequeue(ep, req);
}
/**
* usb_ep_set_halt - sets the endpoint halt feature.
* @ep: the non-isochronous endpoint being stalled
*
* Use this to stall an endpoint, perhaps as an error report.
* Except for control endpoints,
* the endpoint stays halted (will not stream any data) until the host
* clears this feature; drivers may need to empty the endpoint's request
* queue first, to make sure no inappropriate transfers happen.
*
* Note that while an endpoint CLEAR_FEATURE will be invisible to the
* gadget driver, a SET_INTERFACE will not be. To reset endpoints for the
* current altsetting, see usb_ep_clear_halt(). When switching altsettings,
* it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
*
* Returns zero, or a negative error code. On success, this call sets
* underlying hardware state that blocks data transfers.
* Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
* transfer requests are still queued, or if the controller hardware
* (usually a FIFO) still holds bytes that the host hasn't collected.
*/
static inline int usb_ep_set_halt(struct usb_ep *ep)
{
return ep->ops->set_halt(ep, 1);
}
/**
* usb_ep_clear_halt - clears endpoint halt, and resets toggle
* @ep:the bulk or interrupt endpoint being reset
*
* Use this when responding to the standard usb "set interface" request,
* for endpoints that aren't reconfigured, after clearing any other state
* in the endpoint's i/o queue.
*
* Returns zero, or a negative error code. On success, this call clears
* the underlying hardware state reflecting endpoint halt and data toggle.
* Note that some hardware can't support this request (like pxa2xx_udc),
* and accordingly can't correctly implement interface altsettings.
*/
static inline int usb_ep_clear_halt(struct usb_ep *ep)
{
return ep->ops->set_halt(ep, 0);
}
/**
* usb_ep_fifo_status - returns number of bytes in fifo, or error
* @ep: the endpoint whose fifo status is being checked.
*
* FIFO endpoints may have "unclaimed data" in them in certain cases,
* such as after aborted transfers. Hosts may not have collected all
* the IN data written by the gadget driver (and reported by a request
* completion). The gadget driver may not have collected all the data
* written OUT to it by the host. Drivers that need precise handling for
* fault reporting or recovery may need to use this call.
*
* This returns the number of such bytes in the fifo, or a negative
* errno if the endpoint doesn't use a FIFO or doesn't support such
* precise handling.
*/
static inline int usb_ep_fifo_status(struct usb_ep *ep)
{
if (ep->ops->fifo_status)
return ep->ops->fifo_status(ep);
else
return -EOPNOTSUPP;
}
/**
* usb_ep_fifo_flush - flushes contents of a fifo
* @ep: the endpoint whose fifo is being flushed.
*
* This call may be used to flush the "unclaimed data" that may exist in
* an endpoint fifo after abnormal transaction terminations. The call
* must never be used except when endpoint is not being used for any
* protocol translation.
*/
static inline void usb_ep_fifo_flush(struct usb_ep *ep)
{
if (ep->ops->fifo_flush)
ep->ops->fifo_flush(ep);
}
/*-------------------------------------------------------------------------*/
/* utility to simplify managing config descriptors */
/* write vector of descriptors into buffer */
int usb_descriptor_fillbuf(void *, unsigned,
const struct usb_descriptor_header **);
#endif /* __LINUX_USB_GADGET_H */

View File

@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* include/linux/usb/otg.h
*
* Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com
*
* USB OTG (On The Go) defines
*/
#ifndef __LINUX_USB_OTG_H
#define __LINUX_USB_OTG_H
enum usb_dr_mode {
USB_DR_MODE_UNKNOWN,
USB_DR_MODE_HOST,
USB_DR_MODE_PERIPHERAL,
USB_DR_MODE_OTG,
};
/**
* usb_get_dr_mode() - Get dual role mode for given device
* @node: Node offset to the given device
*
* The function gets phy interface string from property 'dr_mode',
* and returns the correspondig enum usb_dr_mode
*/
enum usb_dr_mode usb_get_dr_mode(int node);
/**
* usb_get_maximum_speed() - Get maximum speed for given device
* @node: Node offset to the given device
*
* The function gets phy interface string from property 'maximum-speed',
* and returns the correspondig enum usb_device_speed
*/
enum usb_device_speed usb_get_maximum_speed(int node);
#endif /* __LINUX_USB_OTG_H */

View File

@ -0,0 +1,244 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2001
* Denis Peter, MPL AG Switzerland
*/
#ifndef _SCSI_H
#define _SCSI_H
struct scsi_cmd {
unsigned char cmd[16]; /* command */
/* for request sense */
#pragma pack(ARCH_DMA_MINALIGN)
unsigned char sense_buf[64];
unsigned char status; /* SCSI Status */
unsigned char target; /* Target ID */
unsigned char lun; /* Target LUN */
unsigned char cmdlen; /* command len */
unsigned long datalen; /* Total data length */
unsigned char * pdata; /* pointer to data */
unsigned char msgout[12]; /* Messge out buffer (NOT USED) */
unsigned char msgin[12]; /* Message in buffer */
unsigned char sensecmdlen; /* Sense command len */
unsigned long sensedatalen; /* Sense data len */
unsigned char sensecmd[6]; /* Sense command */
unsigned long contr_stat; /* Controller Status */
unsigned long trans_bytes; /* tranfered bytes */
unsigned int priv;
};
/*-----------------------------------------------------------
**
** SCSI constants.
**
**-----------------------------------------------------------
*/
/*
** Messages
*/
#define M_COMPLETE (0x00)
#define M_EXTENDED (0x01)
#define M_SAVE_DP (0x02)
#define M_RESTORE_DP (0x03)
#define M_DISCONNECT (0x04)
#define M_ID_ERROR (0x05)
#define M_ABORT (0x06)
#define M_REJECT (0x07)
#define M_NOOP (0x08)
#define M_PARITY (0x09)
#define M_LCOMPLETE (0x0a)
#define M_FCOMPLETE (0x0b)
#define M_RESET (0x0c)
#define M_ABORT_TAG (0x0d)
#define M_CLEAR_QUEUE (0x0e)
#define M_INIT_REC (0x0f)
#define M_REL_REC (0x10)
#define M_TERMINATE (0x11)
#define M_SIMPLE_TAG (0x20)
#define M_HEAD_TAG (0x21)
#define M_ORDERED_TAG (0x22)
#define M_IGN_RESIDUE (0x23)
#define M_IDENTIFY (0x80)
#define M_X_MODIFY_DP (0x00)
#define M_X_SYNC_REQ (0x01)
#define M_X_WIDE_REQ (0x03)
#define M_X_PPR_REQ (0x04)
/*
** Status
*/
#define S_GOOD (0x00)
#define S_CHECK_COND (0x02)
#define S_COND_MET (0x04)
#define S_BUSY (0x08)
#define S_INT (0x10)
#define S_INT_COND_MET (0x14)
#define S_CONFLICT (0x18)
#define S_TERMINATED (0x20)
#define S_QUEUE_FULL (0x28)
#define S_ILLEGAL (0xff)
#define S_SENSE (0x80)
/*
* Sense_keys
*/
#define SENSE_NO_SENSE 0x0
#define SENSE_RECOVERED_ERROR 0x1
#define SENSE_NOT_READY 0x2
#define SENSE_MEDIUM_ERROR 0x3
#define SENSE_HARDWARE_ERROR 0x4
#define SENSE_ILLEGAL_REQUEST 0x5
#define SENSE_UNIT_ATTENTION 0x6
#define SENSE_DATA_PROTECT 0x7
#define SENSE_BLANK_CHECK 0x8
#define SENSE_VENDOR_SPECIFIC 0x9
#define SENSE_COPY_ABORTED 0xA
#define SENSE_ABORTED_COMMAND 0xB
#define SENSE_VOLUME_OVERFLOW 0xD
#define SENSE_MISCOMPARE 0xE
#define SCSI_CHANGE_DEF 0x40 /* Change Definition (Optional) */
#define SCSI_COMPARE 0x39 /* Compare (O) */
#define SCSI_COPY 0x18 /* Copy (O) */
#define SCSI_COP_VERIFY 0x3A /* Copy and Verify (O) */
#define SCSI_INQUIRY 0x12 /* Inquiry (MANDATORY) */
#define SCSI_LOG_SELECT 0x4C /* Log Select (O) */
#define SCSI_LOG_SENSE 0x4D /* Log Sense (O) */
#define SCSI_MODE_SEL6 0x15 /* Mode Select 6-byte (Device Specific) */
#define SCSI_MODE_SEL10 0x55 /* Mode Select 10-byte (Device Specific) */
#define SCSI_MODE_SEN6 0x1A /* Mode Sense 6-byte (Device Specific) */
#define SCSI_MODE_SEN10 0x5A /* Mode Sense 10-byte (Device Specific) */
#define SCSI_READ_BUFF 0x3C /* Read Buffer (O) */
#define SCSI_REQ_SENSE 0x03 /* Request Sense (MANDATORY) */
#define SCSI_SEND_DIAG 0x1D /* Send Diagnostic (O) */
#define SCSI_TST_U_RDY 0x00 /* Test Unit Ready (MANDATORY) */
#define SCSI_WRITE_BUFF 0x3B /* Write Buffer (O) */
/***************************************************************************
* %%% Commands Unique to Direct Access Devices %%%
***************************************************************************/
#define SCSI_COMPARE 0x39 /* Compare (O) */
#define SCSI_FORMAT 0x04 /* Format Unit (MANDATORY) */
#define SCSI_LCK_UN_CAC 0x36 /* Lock Unlock Cache (O) */
#define SCSI_PREFETCH 0x34 /* Prefetch (O) */
#define SCSI_MED_REMOVL 0x1E /* Prevent/Allow medium Removal (O) */
#define SCSI_READ6 0x08 /* Read 6-byte (MANDATORY) */
#define SCSI_READ10 0x28 /* Read 10-byte (MANDATORY) */
#define SCSI_READ16 0x48
#define SCSI_RD_CAPAC 0x25 /* Read Capacity (MANDATORY) */
#define SCSI_RD_CAPAC10 SCSI_RD_CAPAC /* Read Capacity (10) */
#define SCSI_RD_CAPAC16 0x9e /* Read Capacity (16) */
#define SCSI_RD_DEFECT 0x37 /* Read Defect Data (O) */
#define SCSI_READ_LONG 0x3E /* Read Long (O) */
#define SCSI_REASS_BLK 0x07 /* Reassign Blocks (O) */
#define SCSI_RCV_DIAG 0x1C /* Receive Diagnostic Results (O) */
#define SCSI_RELEASE 0x17 /* Release Unit (MANDATORY) */
#define SCSI_REZERO 0x01 /* Rezero Unit (O) */
#define SCSI_SRCH_DAT_E 0x31 /* Search Data Equal (O) */
#define SCSI_SRCH_DAT_H 0x30 /* Search Data High (O) */
#define SCSI_SRCH_DAT_L 0x32 /* Search Data Low (O) */
#define SCSI_SEEK6 0x0B /* Seek 6-Byte (O) */
#define SCSI_SEEK10 0x2B /* Seek 10-Byte (O) */
#define SCSI_SEND_DIAG 0x1D /* Send Diagnostics (MANDATORY) */
#define SCSI_SET_LIMIT 0x33 /* Set Limits (O) */
#define SCSI_START_STP 0x1B /* Start/Stop Unit (O) */
#define SCSI_SYNC_CACHE 0x35 /* Synchronize Cache (O) */
#define SCSI_VERIFY 0x2F /* Verify (O) */
#define SCSI_WRITE6 0x0A /* Write 6-Byte (MANDATORY) */
#define SCSI_WRITE10 0x2A /* Write 10-Byte (MANDATORY) */
#define SCSI_WRT_VERIFY 0x2E /* Write and Verify (O) */
#define SCSI_WRITE_LONG 0x3F /* Write Long (O) */
#define SCSI_WRITE_SAME 0x41 /* Write Same (O) */
/**
* struct scsi_platdata - stores information about SCSI controller
*
* @base: Controller base address
* @max_lun: Maximum number of logical units
* @max_id: Maximum number of target ids
*/
struct scsi_platdata {
unsigned long base;
unsigned long max_lun;
unsigned long max_id;
};
#if 0
/* Operations for SCSI */
struct scsi_ops {
/**
* exec() - execute a command
*
* @dev: SCSI bus
* @cmd: Command to execute
* @return 0 if OK, -ve on error
*/
int (*exec)(struct udevice *dev, struct scsi_cmd *cmd);
/**
* bus_reset() - reset the bus
*
* @dev: SCSI bus to reset
* @return 0 if OK, -ve on error
*/
int (*bus_reset)(struct udevice *dev);
};
#define scsi_get_ops(dev) ((struct scsi_ops *)(dev)->driver->ops)
extern struct scsi_ops scsi_ops;
/**
* scsi_exec() - execute a command
*
* @dev: SCSI bus
* @cmd: Command to execute
* @return 0 if OK, -ve on error
*/
int scsi_exec(struct udevice *dev, struct scsi_cmd *cmd);
/**
* scsi_bus_reset() - reset the bus
*
* @dev: SCSI bus to reset
* @return 0 if OK, -ve on error
*/
int scsi_bus_reset(struct udevice *dev);
/**
* scsi_scan() - Scan all SCSI controllers for available devices
*
* @vebose: true to show information about each device found
*/
int scsi_scan(bool verbose);
/**
* scsi_scan_dev() - scan a SCSI bus and create devices
*
* @dev: SCSI bus
* @verbose: true to show information about each device found
*/
int scsi_scan_dev(struct udevice *dev, bool verbose);
#endif
void scsi_low_level_init(int busdevfunc);
void scsi_init(void);
#define SCSI_IDENTIFY 0xC0 /* not used */
/* Hardware errors */
#define SCSI_SEL_TIME_OUT 0x00000101 /* Selection time out */
#define SCSI_HNS_TIME_OUT 0x00000102 /* Handshake */
#define SCSI_MA_TIME_OUT 0x00000103 /* Phase error */
#define SCSI_UNEXP_DIS 0x00000104 /* unexpected disconnect */
#define SCSI_INT_STATE 0x00010000 /* unknown Interrupt number is stored in 16 LSB */
#endif /* _SCSI_H */

View File

@ -0,0 +1,900 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2001
* Denis Peter, MPL AG Switzerland
*
* Adapted for U-Boot driver model
* (C) Copyright 2015 Google, Inc
* Note: Part of this code has been derived from linux
*
*/
#ifndef _USB_H_
#define _USB_H_
//#include <fdtdec.h>
#include <usb_defs.h>
#include <linux/usb/ch9.h>
//#include <asm/cache.h>
//#include <part.h>
/*
* The EHCI spec says that we must align to at least 32 bytes. However,
* some platforms require larger alignment.
*/
#if ARCH_DMA_MINALIGN > 32
#define USB_DMA_MINALIGN ARCH_DMA_MINALIGN
#else
#define USB_DMA_MINALIGN 32
#endif
/* Everything is aribtrary */
#define USB_ALTSETTINGALLOC 4
#define USB_MAXALTSETTING 128 /* Hard limit */
#define USB_MAX_DEVICE 32
#define USB_MAXCONFIG 8
#define USB_MAXINTERFACES 8
#define USB_MAXENDPOINTS 16
#define USB_MAXCHILDREN 8 /* This is arbitrary */
#define USB_MAX_HUB 16
#define USB_CNTL_TIMEOUT 10000 /* 100ms timeout */
/*
* This is the timeout to allow for submitting an urb in ms. We allow more
* time for a BULK device to react - some are slow.
*/
#define USB_TIMEOUT_MS(pipe) (usb_pipebulk(pipe) ? 5000 : 1000)
/* device request (setup) */
struct devrequest {
__u8 requesttype;
__u8 request;
__le16 value;
__le16 index;
__le16 length;
};
/* Interface */
struct usb_interface {
struct usb_interface_descriptor desc;
__u8 no_of_ep;
__u8 num_altsetting;
__u8 act_altsetting;
struct usb_endpoint_descriptor ep_desc[USB_MAXENDPOINTS];
/*
* Super Speed Device will have Super Speed Endpoint
* Companion Descriptor (section 9.6.7 of usb 3.0 spec)
* Revision 1.0 June 6th 2011
*/
struct usb_ss_ep_comp_descriptor ss_ep_comp_desc[USB_MAXENDPOINTS];
};
/* Configuration information.. */
struct usb_config {
struct usb_config_descriptor desc;
__u8 no_of_if; /* number of interfaces */
struct usb_interface if_desc[USB_MAXINTERFACES];
};
enum {
/* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */
PACKET_SIZE_8 = 0,
PACKET_SIZE_16 = 1,
PACKET_SIZE_32 = 2,
PACKET_SIZE_64 = 3,
};
/**
* struct usb_device - information about a USB device
*
* With driver model both UCLASS_USB (the USB controllers) and UCLASS_USB_HUB
* (the hubs) have this as parent data. Hubs are children of controllers or
* other hubs and there is always a single root hub for each controller.
* Therefore struct usb_device can always be accessed with
* dev_get_parent_priv(dev), where dev is a USB device.
*
* Pointers exist for obtaining both the device (could be any uclass) and
* controller (UCLASS_USB) from this structure. The controller does not have
* a struct usb_device since it is not a device.
*/
struct usb_device {
int devnum; /* Device number on USB bus */
int speed; /* full/low/high */
char mf[32]; /* manufacturer */
char prod[32]; /* product */
char serial[32]; /* serial number */
struct usb_tt *tt;
int ttport;
/* Maximum packet size; one of: PACKET_SIZE_* */
int maxpacketsize;
/* one bit for each endpoint ([0] = IN, [1] = OUT) */
unsigned int toggle[2];
/* endpoint halts; one bit per endpoint # & direction;
* [0] = IN, [1] = OUT
*/
unsigned int halted[2];
int epmaxpacketin[16]; /* INput endpoint specific maximums */
int epmaxpacketout[16]; /* OUTput endpoint specific maximums */
int configno; /* selected config number */
/* Device Descriptor */
struct usb_device_descriptor descriptor;
struct usb_config config; /* config descriptor */
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
int (*irq_handle)(struct usb_device *dev);
unsigned long irq_status;
int irq_act_len; /* transferred bytes */
void *privptr;
/*
* Child devices - if this is a hub device
* Each instance needs its own set of data structures.
*/
unsigned long status;
unsigned long int_pending; /* 1 bit per ep, used by int_queue */
int act_len; /* transferred bytes */
int maxchild; /* Number of ports if hub */
int portnr; /* Port number, 1=first */
#ifndef CONFIG_DM_USB
/* parent hub, or NULL if this is the root hub */
struct usb_device *parent;
struct usb_device *children[USB_MAXCHILDREN];
void *controller; /* hardware controller private data */
#endif
/* slot_id - for xHCI enabled devices */
unsigned int slot_id;
#ifdef CONFIG_DM_USB
struct udevice *dev; /* Pointer to associated device */
struct udevice *controller_dev; /* Pointer to associated controller */
#endif
};
struct int_queue;
/*
* You can initialize platform's USB host or device
* ports by passing this enum as an argument to
* board_usb_init().
*/
enum usb_init_type {
USB_INIT_HOST,
USB_INIT_DEVICE
};
/**********************************************************************
* this is how the lowlevel part communicate with the outer world
*/
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller);
int usb_lowlevel_stop(int index);
#if defined(CONFIG_USB_MUSB_HOST) || defined(CONFIG_DM_USB)
int usb_reset_root_port(struct usb_device *dev);
#else
#define usb_reset_root_port(dev)
#endif
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int transfer_len, int *actual_length, int timeout);
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int transfer_len, struct devrequest *setup, int timeout);
/* Defines */
#define USB_UHCI_VEND_ID 0x8086
#define USB_UHCI_DEV_ID 0x7112
/*
* PXA25x can only act as USB device. There are drivers
* which works with USB CDC gadgets implementations.
* Some of them have common routines which can be used
* in boards init functions e.g. udc_disconnect() used for
* forced device disconnection from host.
*/
extern void udc_disconnect(void);
/*
* board-specific hardware initialization, called by
* usb drivers and u-boot commands
*
* @param index USB controller number
* @param init initializes controller as USB host or device
*/
int board_usb_init(int index, enum usb_init_type init);
/*
* can be used to clean up after failed USB initialization attempt
* vide: board_usb_init()
*
* @param index USB controller number for selective cleanup
* @param init usb_init_type passed to board_usb_init()
*/
int board_usb_cleanup(int index, enum usb_init_type init);
#ifdef CONFIG_USB_STORAGE
#define USB_MAX_STOR_DEV 7
int usb_stor_scan(int mode);
int usb_stor_info(void);
#endif
#ifdef CONFIG_USB_HOST_ETHER
#define USB_MAX_ETH_DEV 5
int usb_host_eth_scan(int mode);
#endif
#ifdef CONFIG_USB_KEYBOARD
int drv_usb_kbd_init(void);
int usb_kbd_deregister(int force);
#endif
/* routines */
int usb_init(void); /* initialize the USB Controller */
int usb_stop(void); /* stop the USB Controller */
int usb_detect_change(void); /* detect if a USB device has been (un)plugged */
int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol);
int usb_set_idle(struct usb_device *dev, int ifnum, int duration,
int report_id);
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
unsigned char request, unsigned char requesttype,
unsigned short value, unsigned short index,
void *data, unsigned short size, int timeout);
int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout);
int usb_disable_asynch(int disable);
int usb_maxpacket(struct usb_device *dev, unsigned long pipe);
int usb_get_configuration_no(struct usb_device *dev, int cfgno,
unsigned char *buffer, int length);
int usb_get_configuration_len(struct usb_device *dev, int cfgno);
int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type,
unsigned char id, void *buf, int size);
int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
unsigned char type, unsigned char id, void *buf,
int size);
int usb_clear_halt(struct usb_device *dev, int pipe);
int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
int usb_set_interface(struct usb_device *dev, int interface, int alternate);
int usb_get_port_status(struct usb_device *dev, int port, void *data);
/* big endian -> little endian conversion */
/* some CPUs are already little endian e.g. the ARM920T */
#define __swap_16(x) \
({ unsigned short x_ = (unsigned short)x; \
(unsigned short)( \
((x_ & 0x00FFU) << 8) | ((x_ & 0xFF00U) >> 8)); \
})
#define __swap_32(x) \
({ unsigned long x_ = (unsigned long)x; \
(unsigned long)( \
((x_ & 0x000000FFUL) << 24) | \
((x_ & 0x0000FF00UL) << 8) | \
((x_ & 0x00FF0000UL) >> 8) | \
((x_ & 0xFF000000UL) >> 24)); \
})
#ifdef __LITTLE_ENDIAN
# define swap_16(x) (x)
# define swap_32(x) (x)
#else
# define swap_16(x) __swap_16(x)
# define swap_32(x) __swap_32(x)
#endif
/*
* Calling this entity a "pipe" is glorifying it. A USB pipe
* is something embarrassingly simple: it basically consists
* of the following information:
* - device number (7 bits)
* - endpoint number (4 bits)
* - current Data0/1 state (1 bit)
* - direction (1 bit)
* - speed (2 bits)
* - max packet size (2 bits: 8, 16, 32 or 64)
* - pipe type (2 bits: control, interrupt, bulk, isochronous)
*
* That's 18 bits. Really. Nothing more. And the USB people have
* documented these eighteen bits as some kind of glorious
* virtual data structure.
*
* Let's not fall in that trap. We'll just encode it as a simple
* unsigned int. The encoding is:
*
* - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64)
* - direction: bit 7 (0 = Host-to-Device [Out],
* (1 = Device-to-Host [In])
* - device: bits 8-14
* - endpoint: bits 15-18
* - Data0/1: bit 19
* - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt,
* 10 = control, 11 = bulk)
*
* Why? Because it's arbitrary, and whatever encoding we select is really
* up to us. This one happens to share a lot of bit positions with the UHCI
* specification, so that much of the uhci driver can just mask the bits
* appropriately.
*/
/* Create various pipes... */
#define create_pipe(dev,endpoint) \
(((dev)->devnum << 8) | ((endpoint) << 15) | \
(dev)->maxpacketsize)
#define default_pipe(dev) ((dev)->speed << 26)
#define usb_sndctrlpipe(dev, endpoint) ((PIPE_CONTROL << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvctrlpipe(dev, endpoint) ((PIPE_CONTROL << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_sndisocpipe(dev, endpoint) ((PIPE_ISOCHRONOUS << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvisocpipe(dev, endpoint) ((PIPE_ISOCHRONOUS << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_sndbulkpipe(dev, endpoint) ((PIPE_BULK << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvbulkpipe(dev, endpoint) ((PIPE_BULK << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_sndintpipe(dev, endpoint) ((PIPE_INTERRUPT << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvintpipe(dev, endpoint) ((PIPE_INTERRUPT << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30) | \
default_pipe(dev))
#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | \
default_pipe(dev) | \
USB_DIR_IN)
/* The D0/D1 toggle bits */
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1)
#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << ep))
#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = \
((dev)->toggle[out] & \
~(1 << ep)) | ((bit) << ep))
/* Endpoint halt control/status */
#define usb_endpoint_out(ep_dir) (((ep_dir >> 7) & 1) ^ 1)
#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
#define usb_packetid(pipe) (((pipe) & USB_DIR_IN) ? USB_PID_IN : \
USB_PID_OUT)
//#define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1)
//#define usb_pipein(pipe) (((pipe) >> 7) & 1)
#define usb_pipein(pipe) ((pipe) & USB_DIR_IN)
#define usb_pipeout(pipe) (!usb_pipein(pipe))
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
#define usb_pipedata(pipe) (((pipe) >> 19) & 1)
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT)
#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL)
#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK)
#define usb_pipe_ep_index(pipe) \
usb_pipecontrol(pipe) ? (usb_pipeendpoint(pipe) * 2) : \
((usb_pipeendpoint(pipe) * 2) - \
(usb_pipein(pipe) ? 0 : 1))
/**
* struct usb_device_id - identifies USB devices for probing and hotplugging
* @match_flags: Bit mask controlling which of the other fields are used to
* match against new devices. Any field except for driver_info may be
* used, although some only make sense in conjunction with other fields.
* This is usually set by a USB_DEVICE_*() macro, which sets all
* other fields in this structure except for driver_info.
* @idVendor: USB vendor ID for a device; numbers are assigned
* by the USB forum to its members.
* @idProduct: Vendor-assigned product ID.
* @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
* This is also used to identify individual product versions, for
* a range consisting of a single device.
* @bcdDevice_hi: High end of version number range. The range of product
* versions is inclusive.
* @bDeviceClass: Class of device; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Device classes specify behavior of all
* the interfaces on a device.
* @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
* @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
* @bInterfaceClass: Class of interface; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Interface classes specify behavior only
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
* @bInterfaceNumber: Number of interface; composite devices may use
* fixed interface numbers to differentiate between vendor-specific
* interfaces.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
*
* In most cases, drivers will create a table of device IDs by using
* USB_DEVICE(), or similar macros designed for that purpose.
* They will then export it to userspace using MODULE_DEVICE_TABLE(),
* and provide it to the USB core through their usb_driver structure.
*
* See the usb_match_id() function for information about how matches are
* performed. Briefly, you will normally use one of several macros to help
* construct these entries. Each entry you provide will either identify
* one or more specific products, or will identify a class of products
* which have agreed to behave the same. You should put the more specific
* matches towards the beginning of your table, so that driver_info can
* record quirks of specific products.
*/
struct usb_device_id {
/* which fields to match against? */
u16 match_flags;
/* Used for product specific matches; range is inclusive */
u16 idVendor;
u16 idProduct;
u16 bcdDevice_lo;
u16 bcdDevice_hi;
/* Used for device class matches */
u8 bDeviceClass;
u8 bDeviceSubClass;
u8 bDeviceProtocol;
/* Used for interface class matches */
u8 bInterfaceClass;
u8 bInterfaceSubClass;
u8 bInterfaceProtocol;
/* Used for vendor-specific interface matches */
u8 bInterfaceNumber;
/* not matched against */
ulong driver_info;
};
/* Some useful macros to use to create struct usb_device_id */
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400
/* Match anything, indicates this is a valid entry even if everything is 0 */
#define USB_DEVICE_ID_MATCH_NONE 0x0800
#define USB_DEVICE_ID_MATCH_ALL 0x07ff
/**
* struct usb_driver_entry - Matches a driver to its usb_device_ids
* @driver: Driver to use
* @match: List of match records for this driver, terminated by {}
*/
struct usb_driver_entry {
struct driver *driver;
const struct usb_device_id *match;
};
#define USB_DEVICE_ID_MATCH_DEVICE \
(USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
/**
* USB_DEVICE - macro used to describe a specific usb device
* @vend: the 16 bit USB Vendor ID
* @prod: the 16 bit USB Product ID
*
* This macro is used to create a struct usb_device_id that matches a
* specific device.
*/
#define USB_DEVICE(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
.idProduct = (prod)
#define U_BOOT_USB_DEVICE(__name, __match) \
ll_entry_declare(struct usb_driver_entry, __name, usb_driver_entry) = {\
.driver = llsym(struct driver, __name, driver), \
.match = __match, \
}
/*************************************************************************
* Hub Stuff
*/
struct usb_port_status {
unsigned short wPortStatus;
unsigned short wPortChange;
};
struct usb_hub_status {
unsigned short wHubStatus;
unsigned short wHubChange;
};
/*
* Hub Device descriptor
* USB Hub class device protocols
*/
#define USB_HUB_PR_FS 0 /* Full speed hub */
#define USB_HUB_PR_HS_NO_TT 0 /* Hi-speed hub without TT */
#define USB_HUB_PR_HS_SINGLE_TT 1 /* Hi-speed hub with single TT */
#define USB_HUB_PR_HS_MULTI_TT 2 /* Hi-speed hub with multiple TT */
#define USB_HUB_PR_SS 3 /* Super speed hub */
/* Transaction Translator Think Times, in bits */
#define HUB_TTTT_8_BITS 0x00
#define HUB_TTTT_16_BITS 0x20
#define HUB_TTTT_24_BITS 0x40
#define HUB_TTTT_32_BITS 0x60
/* Hub descriptor */
struct usb_hub_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bNbrPorts;
unsigned short wHubCharacteristics;
unsigned char bPwrOn2PwrGood;
unsigned char bHubContrCurrent;
/* 2.0 and 3.0 hubs differ here */
union {
struct {
/* add 1 bit for hub status change; round to bytes */
__u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
__u8 PortPowerCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
}hs;
struct {
__u8 bHubHdrDecLat;
__le16 wHubDelay;
__le16 DeviceRemovable;
}ss;
} u;
};
struct usb_hub_device {
struct usb_device *pusb_dev;
struct usb_hub_descriptor desc;
ulong connect_timeout; /* Device connection timeout in ms */
ulong query_delay; /* Device query delay in ms */
int overcurrent_count[USB_MAXCHILDREN]; /* Over-current counter */
int hub_depth; /* USB 3.0 hub depth */
struct usb_tt tt; /* Transaction Translator */
};
#ifdef CONFIG_DM_USB
/**
* struct usb_platdata - Platform data about a USB controller
*
* Given a USB controller (UCLASS_USB) dev this is dev_get_platdata(dev)
*/
struct usb_platdata {
enum usb_init_type init_type;
};
/**
* struct usb_dev_platdata - Platform data about a USB device
*
* Given a USB device dev this structure is dev_get_parent_platdata(dev).
* This is used by sandbox to provide emulation data also.
*
* @id: ID used to match this device
* @devnum: Device address on the USB bus
* @udev: usb-uclass internal use only do NOT use
* @strings: List of descriptor strings (for sandbox emulation purposes)
* @desc_list: List of descriptors (for sandbox emulation purposes)
*/
struct usb_dev_platdata {
struct usb_device_id id;
int devnum;
/*
* This pointer is used to pass the usb_device used in usb_scan_device,
* to get the usb descriptors before the driver is known, to the
* actual udevice once the driver is known and the udevice is created.
* This will be NULL except during probe, do NOT use.
*
* This should eventually go away.
*/
struct usb_device *udev;
int configno;
};
/**
* struct usb_bus_priv - information about the USB controller
*
* Given a USB controller (UCLASS_USB) 'dev', this is
* dev_get_uclass_priv(dev).
*
* @next_addr: Next device address to allocate minus 1. Incremented by 1
* each time a new device address is set, so this holds the
* number of devices on the bus
* @desc_before_addr: true if we can read a device descriptor before it
* has been assigned an address. For XHCI this is not possible
* so this will be false.
* @companion: True if this is a companion controller to another USB
* controller
*/
struct usb_bus_priv {
int next_addr;
bool desc_before_addr;
bool companion;
};
/**
* struct usb_emul_platdata - platform data about the USB emulator
*
* Given a USB emulator (UCLASS_USB_EMUL) 'dev', this is
* dev_get_uclass_platdata(dev).
*
* @port1: USB emulator device port number on the parent hub
*/
struct usb_emul_platdata {
int port1; /* Port number (numbered from 1) */
};
/**
* struct dm_usb_ops - USB controller operations
*
* This defines the operations supoorted on a USB controller. Common
* arguments are:
*
* @bus: USB bus (i.e. controller), which is in UCLASS_USB.
* @udev: USB device parent data. Controllers are not expected to need
* this, since the device address on the bus is encoded in @pipe.
* It is used for sandbox, and can be handy for debugging and
* logging.
* @pipe: An assortment of bitfields which provide address and packet
* type information. See create_pipe() above for encoding
* details
* @buffer: A buffer to use for sending/receiving. This should be
* DMA-aligned.
* @length: Buffer length in bytes
*/
struct dm_usb_ops {
/**
* control() - Send a control message
*
* Most parameters are as above.
*
* @setup: Additional setup information required by the message
*/
int (*control)(struct udevice *bus, struct usb_device *udev,
unsigned long pipe, void *buffer, int length,
struct devrequest *setup);
/**
* bulk() - Send a bulk message
*
* Parameters are as above.
*/
int (*bulk)(struct udevice *bus, struct usb_device *udev,
unsigned long pipe, void *buffer, int length);
/**
* interrupt() - Send an interrupt message
*
* Most parameters are as above.
*
* @interval: Interrupt interval
*/
int (*interrupt)(struct udevice *bus, struct usb_device *udev,
unsigned long pipe, void *buffer, int length,
int interval);
/**
* alloc_device() - Allocate a new device context (XHCI)
*
* Before sending packets to a new device on an XHCI bus, a device
* context must be created. If this method is not NULL it will be
* called before the device is enumerated (even before its descriptor
* is read). This should be NULL for EHCI, which does not need this.
*/
int (*alloc_device)(struct udevice *bus, struct usb_device *udev);
/**
* reset_root_port() - Reset usb root port
*/
int (*reset_root_port)(struct udevice *bus, struct usb_device *udev);
/**
* get_max_xfer_size() - Get HCD's maximum transfer bytes
*
* The HCD may have limitation on the maximum bytes to be transferred
* in a USB transfer. USB class driver needs to be aware of this.
*/
int (*get_max_xfer_size)(struct udevice *bus, size_t *size);
};
#define usb_get_ops(dev) ((struct dm_usb_ops *)(dev)->driver->ops)
#define usb_get_emul_ops(dev) ((struct dm_usb_ops *)(dev)->driver->ops)
/**
* usb_get_dev_index() - look up a device index number
*
* Look up devices using their index number (starting at 0). This works since
* in U-Boot device addresses are allocated starting at 1 with no gaps.
*
* TODO(sjg@chromium.org): Remove this function when usb_ether.c is modified
* to work better with driver model.
*
* @bus: USB bus to check
* @index: Index number of device to find (0=first). This is just the
* device address less 1.
*/
struct usb_device *usb_get_dev_index(struct udevice *bus, int index);
/**
* usb_setup_device() - set up a device ready for use
*
* @dev: USB device pointer. This need not be a real device - it is
* common for it to just be a local variable with its ->dev
* member (i.e. @dev->dev) set to the parent device and
* dev->portnr set to the port number on the hub (1=first)
* @do_read: true to read the device descriptor before an address is set
* (should be false for XHCI buses, true otherwise)
* @parent: Parent device (either UCLASS_USB or UCLASS_USB_HUB)
* @return 0 if OK, -ve on error */
int usb_setup_device(struct usb_device *dev, bool do_read,
struct usb_device *parent);
/**
* usb_hub_is_root_hub() - Test whether a hub device is root hub or not
*
* @hub: USB hub device to test
* @return: true if the hub device is root hub, false otherwise.
*/
bool usb_hub_is_root_hub(struct udevice *hub);
/**
* usb_hub_scan() - Scan a hub and find its devices
*
* @hub: Hub device to scan
*/
int usb_hub_scan(struct udevice *hub);
/**
* usb_scan_device() - Scan a device on a bus
*
* Scan a device on a bus. It has already been detected and is ready to
* be enumerated. This may be either the root hub (@parent is a bus) or a
* normal device (@parent is a hub)
*
* @parent: Parent device
* @port: Hub port number (numbered from 1)
* @speed: USB speed to use for this device
* @devp: Returns pointer to device if all is well
* @return 0 if OK, -ve on error
*/
int usb_scan_device(struct udevice *parent, int port,
enum usb_device_speed speed, struct udevice **devp);
/**
* usb_get_bus() - Find the bus for a device
*
* Search up through parents to find the bus this device is connected to. This
* will be a device with uclass UCLASS_USB.
*
* @dev: Device to check
* @return The bus, or NULL if not found (this indicates a critical error in
* the USB stack
*/
struct udevice *usb_get_bus(struct udevice *dev);
/**
* usb_select_config() - Set up a device ready for use
*
* This function assumes that the device already has an address and a driver
* bound, and is ready to be set up.
*
* This re-reads the device and configuration descriptors and sets the
* configuration
*
* @dev: Device to set up
*/
int usb_select_config(struct usb_device *dev);
/**
* usb_child_pre_probe() - Pre-probe function for USB devices
*
* This is called on all children of hubs and USB controllers (i.e. UCLASS_USB
* and UCLASS_USB_HUB) when a new device is about to be probed. It sets up the
* device from the saved platform data and calls usb_select_config() to
* finish set up.
*
* Once this is done, the device's normal driver can take over, knowing the
* device is accessible on the USB bus.
*
* This function is for use only by the internal USB stack.
*
* @dev: Device to set up
*/
int usb_child_pre_probe(struct udevice *dev);
struct ehci_ctrl;
/**
* usb_stor_reset() - Prepare to scan USB storage devices
*
* Empty the list of USB storage devices in preparation for scanning them.
* This must be called before a USB scan.
*/
void usb_stor_reset(void);
#else /* !CONFIG_DM_USB */
struct usb_device *usb_get_dev_index(int index);
#endif
bool usb_device_has_child_on_port(struct usb_device *parent, int port);
int usb_hub_probe(struct usb_device *dev, int ifnum);
void usb_hub_reset(void);
/**
* usb_alloc_new_device() - Allocate a new device
*
* @devp: returns a pointer of a new device structure. With driver model this
* is a device pointer, but with legacy USB this pointer is
* driver-specific.
* @return 0 if OK, -ENOSPC if we have found out of room for new devices
*/
int usb_alloc_new_device(void *controller, struct usb_device **devp);
/**
* usb_free_device() - Free a partially-inited device
*
* This is an internal function. It is used to reverse the action of
* usb_alloc_new_device() when we hit a problem during init.
*/
void usb_free_device(void *controller);
int usb_new_device(struct usb_device *dev);
int usb_alloc_device(struct usb_device *dev);
/**
* usb_get_max_xfer_size() - Get HCD's maximum transfer bytes
*
* The HCD may have limitation on the maximum bytes to be transferred
* in a USB transfer. USB class driver needs to be aware of this.
*
* @dev: USB device
* @size: maximum transfer bytes
* @return 0 if OK, -ve on error
*/
int usb_get_max_xfer_size(struct usb_device *dev, size_t *size);
/**
* usb_show_tree() - show the USB device tree
*
* This shows a list of active USB devices along with basic information about
* each.
*/
void usb_show_tree(void);
#define USB_DEV_PLUGED 0
#define USB_DEV_UNPLUGED 1
int usb_wait_dev_pluged(uint32_t timeout);
#endif /*_USB_H_ */

View File

@ -0,0 +1,380 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2001
* Denis Peter, MPL AG Switzerland
*
* Note: Part of this code has been derived from linux
*/
#ifndef _USB_DEFS_H_
#define _USB_DEFS_H_
/* USB constants */
/* Device and/or Interface Class codes */
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_DATA 10
#define USB_CLASS_VENDOR_SPEC 0xff
/* some HID sub classes */
#define USB_SUB_HID_NONE 0
#define USB_SUB_HID_BOOT 1
/* some UID Protocols */
#define USB_PROT_HID_NONE 0
#define USB_PROT_HID_KEYBOARD 1
#define USB_PROT_HID_MOUSE 2
/* Sub STORAGE Classes */
#define US_SC_RBC 1 /* Typically, flash devices */
#define US_SC_8020 2 /* CD-ROM */
#define US_SC_QIC 3 /* QIC-157 Tapes */
#define US_SC_UFI 4 /* Floppy */
#define US_SC_8070 5 /* Removable media */
#define US_SC_SCSI 6 /* Transparent */
#define US_SC_MIN US_SC_RBC
#define US_SC_MAX US_SC_SCSI
/* STORAGE Protocols */
#define US_PR_CB 1 /* Control/Bulk w/o interrupt */
#define US_PR_CBI 0 /* Control/Bulk/Interrupt */
#define US_PR_BULK 0x50 /* bulk only */
/* USB types */
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
/* USB recipients */
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
/* USB directions */
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
/*
* bmRequestType: USB Device Requests, table 9.2 USB 2.0 spec.
* (shifted) direction/type/recipient.
*/
#define DeviceRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
#define DeviceOutRequest \
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
#define InterfaceRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
#define EndpointRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
#define EndpointOutRequest \
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
/* Descriptor types */
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
#define USB_DT_SS_HUB (USB_TYPE_CLASS | 0x0a)
/* Descriptor sizes per descriptor type */
#define USB_DT_DEVICE_SIZE 18
#define USB_DT_CONFIG_SIZE 9
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
#define USB_DT_HUB_NONVAR_SIZE 7
#define USB_DT_HID_SIZE 9
/* Endpoints */
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
/* USB Packet IDs (PIDs) */
#define USB_PID_UNDEF_0 0xf0
#define USB_PID_OUT 0xe1
#define USB_PID_ACK 0xd2
#define USB_PID_DATA0 0xc3
#define USB_PID_UNDEF_4 0xb4
#define USB_PID_SOF 0xa5
#define USB_PID_UNDEF_6 0x96
#define USB_PID_UNDEF_7 0x87
#define USB_PID_UNDEF_8 0x78
#define USB_PID_IN 0x69
#define USB_PID_NAK 0x5a
#define USB_PID_DATA1 0x4b
#define USB_PID_PREAMBLE 0x3c
#define USB_PID_SETUP 0x2d
#define USB_PID_STALL 0x1e
#define USB_PID_UNDEF_F 0x0f
/* Standard requests */
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
/* HID requests */
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_GET_IDLE 0x02
#define USB_REQ_GET_PROTOCOL 0x03
#define USB_REQ_SET_REPORT 0x09
#define USB_REQ_SET_IDLE 0x0A
#define USB_REQ_SET_PROTOCOL 0x0B
/* Device features */
#define USB_FEAT_HALT 0x00
#define USB_FEAT_WAKEUP 0x01
#define USB_FEAT_TEST 0x02
/* Test modes */
#define USB_TEST_MODE_J 0x01
#define USB_TEST_MODE_K 0x02
#define USB_TEST_MODE_SE0_NAK 0x03
#define USB_TEST_MODE_PACKET 0x04
#define USB_TEST_MODE_FORCE_ENABLE 0x05
/*
* "pipe" definitions, use unsigned so we can compare reliably, since this
* value is shifted up to bits 30/31.
*/
#define PIPE_ISOCHRONOUS 0U
#define PIPE_INTERRUPT 1U
#define PIPE_CONTROL 2U
#define PIPE_BULK 3U
#define PIPE_DEVEP_MASK 0x0007ff00
#define USB_ISOCHRONOUS 0
#define USB_INTERRUPT 1
#define USB_CONTROL 2
#define USB_BULK 3
#define USB_PIPE_TYPE_SHIFT 30
#define USB_PIPE_TYPE_MASK (3 << USB_PIPE_TYPE_SHIFT)
#define USB_PIPE_DEV_SHIFT 8
#define USB_PIPE_DEV_MASK (0x7f << USB_PIPE_DEV_SHIFT)
#define USB_PIPE_EP_SHIFT 15
#define USB_PIPE_EP_MASK (0xf << USB_PIPE_EP_SHIFT)
/* USB-status codes: */
#define USB_ST_ACTIVE 0x1 /* TD is active */
#define USB_ST_STALLED 0x2 /* TD is stalled */
#define USB_ST_BUF_ERR 0x4 /* buffer error */
#define USB_ST_BABBLE_DET 0x8 /* Babble detected */
#define USB_ST_NAK_REC 0x10 /* NAK Received*/
#define USB_ST_CRC_ERR 0x20 /* CRC/timeout Error */
#define USB_ST_BIT_ERR 0x40 /* Bitstuff error */
#define USB_ST_NOT_PROC 0x80000000L /* Not yet processed */
/*************************************************************************
* Hub defines
*/
/*
* Hub request types
*/
#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
/*
* Hub Class feature numbers
*/
#define C_HUB_LOCAL_POWER 0
#define C_HUB_OVER_CURRENT 1
/*
* Port feature numbers
*/
#define USB_PORT_FEAT_CONNECTION 0
#define USB_PORT_FEAT_ENABLE 1
#define USB_PORT_FEAT_SUSPEND 2
#define USB_PORT_FEAT_OVER_CURRENT 3
#define USB_PORT_FEAT_RESET 4
#define USB_PORT_FEAT_POWER 8
#define USB_PORT_FEAT_LOWSPEED 9
#define USB_PORT_FEAT_HIGHSPEED 10
#define USB_PORT_FEAT_C_CONNECTION 16
#define USB_PORT_FEAT_C_ENABLE 17
#define USB_PORT_FEAT_C_SUSPEND 18
#define USB_PORT_FEAT_C_OVER_CURRENT 19
#define USB_PORT_FEAT_C_RESET 20
#define USB_PORT_FEAT_TEST 21
/*
* Changes to Port feature numbers for Super speed,
* from USB 3.0 spec Table 10-8
*/
#define USB_SS_PORT_FEAT_U1_TIMEOUT 23
#define USB_SS_PORT_FEAT_U2_TIMEOUT 24
#define USB_SS_PORT_FEAT_C_LINK_STATE 25
#define USB_SS_PORT_FEAT_C_CONFIG_ERROR 26
#define USB_SS_PORT_FEAT_BH_RESET 28
#define USB_SS_PORT_FEAT_C_BH_RESET 29
/* wPortStatus bits */
#define USB_PORT_STAT_CONNECTION 0x0001
#define USB_PORT_STAT_ENABLE 0x0002
#define USB_PORT_STAT_SUSPEND 0x0004
#define USB_PORT_STAT_OVERCURRENT 0x0008
#define USB_PORT_STAT_RESET 0x0010
#define USB_PORT_STAT_POWER 0x0100
#define USB_PORT_STAT_LOW_SPEED 0x0200
#define USB_PORT_STAT_HIGH_SPEED 0x0400 /* support for EHCI */
#define USB_PORT_STAT_SUPER_SPEED 0x0600 /* faking support to XHCI */
#define USB_PORT_STAT_SPEED_MASK \
(USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED)
/*
* Changes to wPortStatus bit field in USB 3.0
* See USB 3.0 spec Table 10-10
*/
#define USB_SS_PORT_STAT_LINK_STATE 0x01e0
#define USB_SS_PORT_STAT_POWER 0x0200
#define USB_SS_PORT_STAT_SPEED 0x1c00
#define USB_SS_PORT_STAT_SPEED_5GBPS 0x0000
/* Bits that are the same from USB 2.0 */
#define USB_SS_PORT_STAT_MASK (USB_PORT_STAT_CONNECTION | \
USB_PORT_STAT_ENABLE | \
USB_PORT_STAT_OVERCURRENT | \
USB_PORT_STAT_RESET)
/* wPortChange bits */
#define USB_PORT_STAT_C_CONNECTION 0x0001
#define USB_PORT_STAT_C_ENABLE 0x0002
#define USB_PORT_STAT_C_SUSPEND 0x0004
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
#define USB_PORT_STAT_C_RESET 0x0010
/*
* Changes to wPortChange bit fields in USB 3.0
* See USB 3.0 spec Table 10-12
*/
#define USB_SS_PORT_STAT_C_BH_RESET 0x0020
#define USB_SS_PORT_STAT_C_LINK_STATE 0x0040
#define USB_SS_PORT_STAT_C_CONFIG_ERROR 0x0080
/* wHubCharacteristics (masks) */
#define HUB_CHAR_LPSM 0x0003
#define HUB_CHAR_COMPOUND 0x0004
#define HUB_CHAR_OCPM 0x0018
#define HUB_CHAR_TTTT 0x0060 /* TT Think Time mask */
/*
* Hub Status & Hub Change bit masks
*/
#define HUB_STATUS_LOCAL_POWER 0x0001
#define HUB_STATUS_OVERCURRENT 0x0002
#define HUB_CHANGE_LOCAL_POWER 0x0001
#define HUB_CHANGE_OVERCURRENT 0x0002
/* Mask for wIndex in get/set port feature */
#define USB_HUB_PORT_MASK 0xf
/* Hub class request codes */
#define USB_REQ_SET_HUB_DEPTH 0x0c
/*
* As of USB 2.0, full/low speed devices are segregated into trees.
* One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
* The other type grows from high speed hubs when they connect to
* full/low speed devices using "Transaction Translators" (TTs).
*/
#if 0
struct usb_tt {
bool multi; /* true means one TT per port */
unsigned think_time; /* think time in ns */
};
#else
struct usb_device;
struct usb_tt {
struct usb_device *hub; /* upstream highspeed hub */
int multi; /* true means one TT per port */
unsigned think_time; /* think time in ns */
void *hcpriv; /* HCD private data */
/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
spinlock_t lock;
//struct list_head clear_list; /* of usb_tt_clear */
};
#endif
/*
* CBI style
*/
#define US_CBI_ADSC 0
/* Command Block Wrapper */
struct umass_bbb_cbw {
__u32 dCBWSignature;
# define CBWSIGNATURE 0x43425355
__u32 dCBWTag;
__u32 dCBWDataTransferLength;
__u8 bCBWFlags;
# define CBWFLAGS_OUT 0x00
# define CBWFLAGS_IN 0x80
# define CBWFLAGS_SBZ 0x7f
__u8 bCBWLUN;
__u8 bCDBLength;
# define CBWCDBLENGTH 16
__u8 CBWCDB[CBWCDBLENGTH];
};
#define UMASS_BBB_CBW_SIZE 31
/* Command Status Wrapper */
struct umass_bbb_csw {
__u32 dCSWSignature;
# define CSWSIGNATURE 0x53425355
__u32 dCSWTag;
__u32 dCSWDataResidue;
__u8 bCSWStatus;
# define CSWSTATUS_GOOD 0x0
# define CSWSTATUS_FAILED 0x1
# define CSWSTATUS_PHASE 0x2
};
#define UMASS_BBB_CSW_SIZE 13
/*
* BULK only
*/
#define US_BBB_RESET 0xff
#define US_BBB_GET_MAX_LUN 0xfe
#endif /*_USB_DEFS_H_ */

View File

@ -0,0 +1,534 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
*
* Based on
* linux/drivers/usbd/usb-function.h - USB Function
*
* Copyright (c) 2000, 2001, 2002 Lineo
* Copyright (c) 2001 Hewlett Packard
*
* By:
* Stuart Lynne <sl@lineo.com>,
* Tom Rushworth <tbr@lineo.com>,
* Bruce Balden <balden@lineo.com>
*/
/* USB Descriptors - Create a complete description of all of the
* function driver capabilities. These map directly to the USB descriptors.
*
* This heirarchy is created by the functions drivers and is passed to the
* usb-device driver when the function driver is registered.
*
* device
* configuration
* interface
* alternate
* class
* class
* alternate
* endpoint
* endpoint
* interface
* alternate
* endpoint
* endpoint
* configuration
* interface
* alternate
* endpoint
* endpoint
*
*
* The configuration structures refer to the USB Configurations that will be
* made available to a USB HOST during the enumeration process.
*
* The USB HOST will select a configuration and optionally an interface with
* the usb set configuration and set interface commands.
*
* The selected interface (or the default interface if not specifically
* selected) will define the list of endpoints that will be used.
*
* The configuration and interfaces are stored in an array that is indexed
* by the specified configuratin or interface number minus one.
*
* A configuration number of zero is used to specify a return to the unconfigured
* state.
*
*/
#ifndef __USBDESCRIPTORS_H__
#define __USBDESCRIPTORS_H__
#include <asm/types.h>
/*
* communications class types
*
* c.f. CDC USB Class Definitions for Communications Devices
* c.f. WMCD USB CDC Subclass Specification for Wireless Mobile Communications Devices
*
*/
#define CLASS_BCD_VERSION 0x0110
/* c.f. CDC 4.1 Table 14 */
#define COMMUNICATIONS_DEVICE_CLASS 0x02
/* c.f. CDC 4.2 Table 15 */
#define COMMUNICATIONS_INTERFACE_CLASS_CONTROL 0x02
#define COMMUNICATIONS_INTERFACE_CLASS_DATA 0x0A
#define COMMUNICATIONS_INTERFACE_CLASS_VENDOR 0x0FF
/* c.f. CDC 4.3 Table 16 */
#define COMMUNICATIONS_NO_SUBCLASS 0x00
#define COMMUNICATIONS_DLCM_SUBCLASS 0x01
#define COMMUNICATIONS_ACM_SUBCLASS 0x02
#define COMMUNICATIONS_TCM_SUBCLASS 0x03
#define COMMUNICATIONS_MCCM_SUBCLASS 0x04
#define COMMUNICATIONS_CCM_SUBCLASS 0x05
#define COMMUNICATIONS_ENCM_SUBCLASS 0x06
#define COMMUNICATIONS_ANCM_SUBCLASS 0x07
/* c.f. WMCD 5.1 */
#define COMMUNICATIONS_WHCM_SUBCLASS 0x08
#define COMMUNICATIONS_DMM_SUBCLASS 0x09
#define COMMUNICATIONS_MDLM_SUBCLASS 0x0a
#define COMMUNICATIONS_OBEX_SUBCLASS 0x0b
/* c.f. CDC 4.4 Table 17 */
#define COMMUNICATIONS_NO_PROTOCOL 0x00
#define COMMUNICATIONS_V25TER_PROTOCOL 0x01 /*Common AT Hayes compatible*/
/* c.f. CDC 4.5 Table 18 */
#define DATA_INTERFACE_CLASS 0x0a
/* c.f. CDC 4.6 No Table */
#define DATA_INTERFACE_SUBCLASS_NONE 0x00 /* No subclass pertinent */
/* c.f. CDC 4.7 Table 19 */
#define DATA_INTERFACE_PROTOCOL_NONE 0x00 /* No class protcol required */
/* c.f. CDC 5.2.3 Table 24 */
#define CS_INTERFACE 0x24
#define CS_ENDPOINT 0x25
/*
* bDescriptorSubtypes
*
* c.f. CDC 5.2.3 Table 25
* c.f. WMCD 5.3 Table 5.3
*/
#define USB_ST_HEADER 0x00
#define USB_ST_CMF 0x01
#define USB_ST_ACMF 0x02
#define USB_ST_DLMF 0x03
#define USB_ST_TRF 0x04
#define USB_ST_TCLF 0x05
#define USB_ST_UF 0x06
#define USB_ST_CSF 0x07
#define USB_ST_TOMF 0x08
#define USB_ST_USBTF 0x09
#define USB_ST_NCT 0x0a
#define USB_ST_PUF 0x0b
#define USB_ST_EUF 0x0c
#define USB_ST_MCMF 0x0d
#define USB_ST_CCMF 0x0e
#define USB_ST_ENF 0x0f
#define USB_ST_ATMNF 0x10
#define USB_ST_WHCM 0x11
#define USB_ST_MDLM 0x12
#define USB_ST_MDLMD 0x13
#define USB_ST_DMM 0x14
#define USB_ST_OBEX 0x15
#define USB_ST_CS 0x16
#define USB_ST_CSD 0x17
#define USB_ST_TCM 0x18
/* endpoint modifiers
* static struct usb_endpoint_description function_default_A_1[] = {
*
* {this_endpoint: 0, attributes: CONTROL, max_size: 8, polling_interval: 0 },
* {this_endpoint: 1, attributes: BULK, max_size: 64, polling_interval: 0, direction: IN},
* {this_endpoint: 2, attributes: BULK, max_size: 64, polling_interval: 0, direction: OUT},
* {this_endpoint: 3, attributes: INTERRUPT, max_size: 8, polling_interval: 0},
*
*
*/
#define OUT 0x00
#define IN 0x80
#define CONTROL 0x00
#define ISOCHRONOUS 0x01
#define BULK 0x02
#define INTERRUPT 0x03
/* configuration modifiers
*/
#define BMATTRIBUTE_RESERVED 0x80
#define BMATTRIBUTE_SELF_POWERED 0x40
/*
* standard usb descriptor structures
*/
struct usb_endpoint_descriptor {
u8 bLength;
u8 bDescriptorType; /* 0x5 */
u8 bEndpointAddress;
u8 bmAttributes;
u16 wMaxPacketSize;
u8 bInterval;
} __attribute__ ((packed));
struct usb_interface_descriptor {
u8 bLength;
u8 bDescriptorType; /* 0x04 */
u8 bInterfaceNumber;
u8 bAlternateSetting;
u8 bNumEndpoints;
u8 bInterfaceClass;
u8 bInterfaceSubClass;
u8 bInterfaceProtocol;
u8 iInterface;
} __attribute__ ((packed));
struct usb_configuration_descriptor {
u8 bLength;
u8 bDescriptorType; /* 0x2 */
u16 wTotalLength;
u8 bNumInterfaces;
u8 bConfigurationValue;
u8 iConfiguration;
u8 bmAttributes;
u8 bMaxPower;
} __attribute__ ((packed));
struct usb_device_descriptor {
u8 bLength;
u8 bDescriptorType; /* 0x01 */
u16 bcdUSB;
u8 bDeviceClass;
u8 bDeviceSubClass;
u8 bDeviceProtocol;
u8 bMaxPacketSize0;
u16 idVendor;
u16 idProduct;
u16 bcdDevice;
u8 iManufacturer;
u8 iProduct;
u8 iSerialNumber;
u8 bNumConfigurations;
} __attribute__ ((packed));
#if defined(CONFIG_USBD_HS)
struct usb_qualifier_descriptor {
u8 bLength;
u8 bDescriptorType;
u16 bcdUSB;
u8 bDeviceClass;
u8 bDeviceSubClass;
u8 bDeviceProtocol;
u8 bMaxPacketSize0;
u8 bNumConfigurations;
u8 breserved;
} __attribute__ ((packed));
#endif
struct usb_string_descriptor {
u8 bLength;
u8 bDescriptorType; /* 0x03 */
u16 wData[0];
} __attribute__ ((packed));
struct usb_generic_descriptor {
u8 bLength;
u8 bDescriptorType;
u8 bDescriptorSubtype;
} __attribute__ ((packed));
/*
* communications class descriptor structures
*
* c.f. CDC 5.2 Table 25c
*/
struct usb_class_function_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype;
} __attribute__ ((packed));
struct usb_class_function_descriptor_generic {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype;
u8 bmCapabilities;
} __attribute__ ((packed));
struct usb_class_header_function_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x00 */
u16 bcdCDC;
} __attribute__ ((packed));
struct usb_class_call_management_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x01 */
u8 bmCapabilities;
u8 bDataInterface;
} __attribute__ ((packed));
struct usb_class_abstract_control_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x02 */
u8 bmCapabilities;
} __attribute__ ((packed));
struct usb_class_direct_line_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x03 */
} __attribute__ ((packed));
struct usb_class_telephone_ringer_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x04 */
u8 bRingerVolSeps;
u8 bNumRingerPatterns;
} __attribute__ ((packed));
struct usb_class_telephone_call_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x05 */
u8 bmCapabilities;
} __attribute__ ((packed));
struct usb_class_union_function_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x06 */
u8 bMasterInterface;
/* u8 bSlaveInterface0[0]; */
u8 bSlaveInterface0;
} __attribute__ ((packed));
struct usb_class_country_selection_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x07 */
u8 iCountryCodeRelDate;
u16 wCountryCode0[0];
} __attribute__ ((packed));
struct usb_class_telephone_operational_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x08 */
u8 bmCapabilities;
} __attribute__ ((packed));
struct usb_class_usb_terminal_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x09 */
u8 bEntityId;
u8 bInterfaceNo;
u8 bOutInterfaceNo;
u8 bmOptions;
u8 bChild0[0];
} __attribute__ ((packed));
struct usb_class_network_channel_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x0a */
u8 bEntityId;
u8 iName;
u8 bChannelIndex;
u8 bPhysicalInterface;
} __attribute__ ((packed));
struct usb_class_protocol_unit_function_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x0b */
u8 bEntityId;
u8 bProtocol;
u8 bChild0[0];
} __attribute__ ((packed));
struct usb_class_extension_unit_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x0c */
u8 bEntityId;
u8 bExtensionCode;
u8 iName;
u8 bChild0[0];
} __attribute__ ((packed));
struct usb_class_multi_channel_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x0d */
u8 bmCapabilities;
} __attribute__ ((packed));
struct usb_class_capi_control_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x0e */
u8 bmCapabilities;
} __attribute__ ((packed));
struct usb_class_ethernet_networking_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x0f */
u8 iMACAddress;
u32 bmEthernetStatistics;
u16 wMaxSegmentSize;
u16 wNumberMCFilters;
u8 bNumberPowerFilters;
} __attribute__ ((packed));
struct usb_class_atm_networking_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x10 */
u8 iEndSystermIdentifier;
u8 bmDataCapabilities;
u8 bmATMDeviceStatistics;
u16 wType2MaxSegmentSize;
u16 wType3MaxSegmentSize;
u16 wMaxVC;
} __attribute__ ((packed));
struct usb_class_mdlm_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x12 */
u16 bcdVersion;
u8 bGUID[16];
} __attribute__ ((packed));
struct usb_class_mdlmd_descriptor {
u8 bFunctionLength;
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x13 */
u8 bGuidDescriptorType;
u8 bDetailData[0];
} __attribute__ ((packed));
/*
* HID class descriptor structures
*
* c.f. HID 6.2.1
*/
struct usb_class_hid_descriptor {
u8 bLength;
u8 bDescriptorType;
u16 bcdCDC;
u8 bCountryCode;
u8 bNumDescriptors; /* 0x01 */
u8 bDescriptorType0;
u16 wDescriptorLength0;
/* optional descriptors are not supported. */
} __attribute__((packed));
struct usb_class_report_descriptor {
u8 bLength; /* dummy */
u8 bDescriptorType;
u16 wLength;
u8 bData[0];
} __attribute__((packed));
/*
* descriptor union structures
*/
struct usb_descriptor {
union {
struct usb_generic_descriptor generic;
struct usb_endpoint_descriptor endpoint;
struct usb_interface_descriptor interface;
struct usb_configuration_descriptor configuration;
struct usb_device_descriptor device;
struct usb_string_descriptor string;
} descriptor;
} __attribute__ ((packed));
struct usb_class_descriptor {
union {
struct usb_class_function_descriptor function;
struct usb_class_function_descriptor_generic generic;
struct usb_class_header_function_descriptor header_function;
struct usb_class_call_management_descriptor call_management;
struct usb_class_abstract_control_descriptor abstract_control;
struct usb_class_direct_line_descriptor direct_line;
struct usb_class_telephone_ringer_descriptor telephone_ringer;
struct usb_class_telephone_operational_descriptor telephone_operational;
struct usb_class_telephone_call_descriptor telephone_call;
struct usb_class_union_function_descriptor union_function;
struct usb_class_country_selection_descriptor country_selection;
struct usb_class_usb_terminal_descriptor usb_terminal;
struct usb_class_network_channel_descriptor network_channel;
struct usb_class_extension_unit_descriptor extension_unit;
struct usb_class_multi_channel_descriptor multi_channel;
struct usb_class_capi_control_descriptor capi_control;
struct usb_class_ethernet_networking_descriptor ethernet_networking;
struct usb_class_atm_networking_descriptor atm_networking;
struct usb_class_mdlm_descriptor mobile_direct;
struct usb_class_mdlmd_descriptor mobile_direct_detail;
struct usb_class_hid_descriptor hid;
} descriptor;
} __attribute__ ((packed));
#ifdef DEBUG
static inline void print_device_descriptor(struct usb_device_descriptor *d)
{
serial_printf("usb device descriptor \n");
serial_printf("\tbLength %2.2x\n", d->bLength);
serial_printf("\tbDescriptorType %2.2x\n", d->bDescriptorType);
serial_printf("\tbcdUSB %4.4x\n", d->bcdUSB);
serial_printf("\tbDeviceClass %2.2x\n", d->bDeviceClass);
serial_printf("\tbDeviceSubClass %2.2x\n", d->bDeviceSubClass);
serial_printf("\tbDeviceProtocol %2.2x\n", d->bDeviceProtocol);
serial_printf("\tbMaxPacketSize0 %2.2x\n", d->bMaxPacketSize0);
serial_printf("\tidVendor %4.4x\n", d->idVendor);
serial_printf("\tidProduct %4.4x\n", d->idProduct);
serial_printf("\tbcdDevice %4.4x\n", d->bcdDevice);
serial_printf("\tiManufacturer %2.2x\n", d->iManufacturer);
serial_printf("\tiProduct %2.2x\n", d->iProduct);
serial_printf("\tiSerialNumber %2.2x\n", d->iSerialNumber);
serial_printf("\tbNumConfigurations %2.2x\n", d->bNumConfigurations);
}
#else
/* stubs */
#define print_device_descriptor(d)
#endif /* DEBUG */
#endif

View File

@ -0,0 +1,777 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
*
* Based on linux/drivers/usbd/usbd.h
*
* Copyright (c) 2000, 2001, 2002 Lineo
* Copyright (c) 2001 Hewlett Packard
*
* By:
* Stuart Lynne <sl@lineo.com>,
* Tom Rushworth <tbr@lineo.com>,
* Bruce Balden <balden@lineo.com>
*/
#ifndef __USBDCORE_H__
#define __USBDCORE_H__
#include <common.h>
#include "usbdescriptors.h"
#define MAX_URBS_QUEUED 5
#if 1
#define usberr(fmt,args...) serial_printf("ERROR: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
#else
#define usberr(fmt,args...) do{}while(0)
#endif
#if 0
#define usbdbg(fmt,args...) serial_printf("debug: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
#else
#define usbdbg(fmt,args...) do{}while(0)
#endif
#if 0
#define usbinfo(fmt,args...) serial_printf("info: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
#else
#define usbinfo(fmt,args...) do{}while(0)
#endif
#ifndef le16_to_cpu
#define le16_to_cpu(x) (x)
#endif
#ifndef inb
#define inb(p) (*(volatile u8*)(p))
#endif
#ifndef outb
#define outb(val,p) (*(volatile u8*)(p) = (val))
#endif
#ifndef inw
#define inw(p) (*(volatile u16*)(p))
#endif
#ifndef outw
#define outw(val,p) (*(volatile u16*)(p) = (val))
#endif
#ifndef inl
#define inl(p) (*(volatile u32*)(p))
#endif
#ifndef outl
#define outl(val,p) (*(volatile u32*)(p) = (val))
#endif
#ifndef insw
#define insw(p,to,len) mmio_insw(p,to,len)
#endif
#ifndef outsw
#define outsw(p,from,len) mmio_outsw(p,from,len)
#endif
#ifndef insb
#define insb(p,to,len) mmio_insb(p,to,len)
#endif
#ifndef mmio_insw
#define mmio_insw(r,b,l) ({ int __i ; \
u16 *__b2; \
__b2 = (u16 *) b; \
for (__i = 0; __i < l; __i++) { \
*(__b2 + __i) = inw(r); \
}; \
})
#endif
#ifndef mmio_outsw
#define mmio_outsw(r,b,l) ({ int __i; \
u16 *__b2; \
__b2 = (u16 *) b; \
for (__i = 0; __i < l; __i++) { \
outw( *(__b2 + __i), r); \
} \
})
#endif
#ifndef mmio_insb
#define mmio_insb(r,b,l) ({ int __i ; \
u8 *__b2; \
__b2 = (u8 *) b; \
for (__i = 0; __i < l; __i++) { \
*(__b2 + __i) = inb(r); \
}; \
})
#endif
/*
* Structure member address manipulation macros.
* These are used by client code (code using the urb_link routines), since
* the urb_link structure is embedded in the client data structures.
*
* Note: a macro offsetof equivalent to member_offset is defined in stddef.h
* but this is kept here for the sake of portability.
*
* p2surround returns a pointer to the surrounding structure given
* type of the surrounding structure, the name memb of the structure
* member pointed at by ptr. For example, if you have:
*
* struct foo {
* int x;
* float y;
* char z;
* } thingy;
*
* char *cp = &thingy.z;
*
* then
*
* &thingy == p2surround(struct foo, z, cp)
*
* Clear?
*/
#define _cv_(ptr) ((char*)(void*)(ptr))
#define member_offset(type,memb) (_cv_(&(((type*)0)->memb))-(char*)0)
#define p2surround(type,memb,ptr) ((type*)(void*)(_cv_(ptr)-member_offset(type,memb)))
struct urb;
struct usb_endpoint_instance;
struct usb_interface_instance;
struct usb_configuration_instance;
struct usb_device_instance;
struct usb_bus_instance;
/*
* Device and/or Interface Class codes
*/
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_DATA 10
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
/*
* USB types
*/
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
/*
* USB recipients
*/
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
/*
* USB directions
*/
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
/*
* Descriptor types
*/
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#if defined(CONFIG_USBD_HS)
#define USB_DT_QUAL 0x06
#endif
#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
/*
* Descriptor sizes per descriptor type
*/
#define USB_DT_DEVICE_SIZE 18
#define USB_DT_CONFIG_SIZE 9
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
#define USB_DT_HUB_NONVAR_SIZE 7
#define USB_DT_HID_SIZE 9
/*
* Endpoints
*/
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
/*
* USB Packet IDs (PIDs)
*/
#define USB_PID_UNDEF_0 0xf0
#define USB_PID_OUT 0xe1
#define USB_PID_ACK 0xd2
#define USB_PID_DATA0 0xc3
#define USB_PID_PING 0xb4 /* USB 2.0 */
#define USB_PID_SOF 0xa5
#define USB_PID_NYET 0x96 /* USB 2.0 */
#define USB_PID_DATA2 0x87 /* USB 2.0 */
#define USB_PID_SPLIT 0x78 /* USB 2.0 */
#define USB_PID_IN 0x69
#define USB_PID_NAK 0x5a
#define USB_PID_DATA1 0x4b
#define USB_PID_PREAMBLE 0x3c /* Token mode */
#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
#define USB_PID_SETUP 0x2d
#define USB_PID_STALL 0x1e
#define USB_PID_MDATA 0x0f /* USB 2.0 */
/*
* Standard requests
*/
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN")
/*
* HID requests
*/
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_GET_IDLE 0x02
#define USB_REQ_GET_PROTOCOL 0x03
#define USB_REQ_SET_REPORT 0x09
#define USB_REQ_SET_IDLE 0x0A
#define USB_REQ_SET_PROTOCOL 0x0B
/*
* USB Spec Release number
*/
#if defined(CONFIG_USBD_HS)
#define USB_BCD_VERSION 0x0200
#else
#define USB_BCD_VERSION 0x0110
#endif
/*
* Device Requests (c.f Table 9-2)
*/
#define USB_REQ_DIRECTION_MASK 0x80
#define USB_REQ_TYPE_MASK 0x60
#define USB_REQ_RECIPIENT_MASK 0x1f
#define USB_REQ_DEVICE2HOST 0x80
#define USB_REQ_HOST2DEVICE 0x00
#define USB_REQ_TYPE_STANDARD 0x00
#define USB_REQ_TYPE_CLASS 0x20
#define USB_REQ_TYPE_VENDOR 0x40
#define USB_REQ_RECIPIENT_DEVICE 0x00
#define USB_REQ_RECIPIENT_INTERFACE 0x01
#define USB_REQ_RECIPIENT_ENDPOINT 0x02
#define USB_REQ_RECIPIENT_OTHER 0x03
/*
* get status bits
*/
#define USB_STATUS_SELFPOWERED 0x01
#define USB_STATUS_REMOTEWAKEUP 0x02
#define USB_STATUS_HALT 0x01
/*
* descriptor types
*/
#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
#define USB_DESCRIPTOR_TYPE_STRING 0x03
#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06
#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 0x07
#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 0x08
#define USB_DESCRIPTOR_TYPE_HID 0x21
#define USB_DESCRIPTOR_TYPE_REPORT 0x22
#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \
usbd_device_descriptors[x] : "UNKNOWN")
/*
* standard feature selectors
*/
#define USB_ENDPOINT_HALT 0x00
#define USB_DEVICE_REMOTE_WAKEUP 0x01
#define USB_TEST_MODE 0x02
/* USB Requests
*
*/
struct usb_device_request {
u8 bmRequestType;
u8 bRequest;
u16 wValue;
u16 wIndex;
u16 wLength;
} __attribute__ ((packed));
/* USB Status
*
*/
typedef enum urb_send_status {
SEND_IN_PROGRESS,
SEND_FINISHED_OK,
SEND_FINISHED_ERROR,
RECV_READY,
RECV_OK,
RECV_ERROR
} urb_send_status_t;
/*
* Device State (c.f USB Spec 2.0 Figure 9-1)
*
* What state the usb device is in.
*
* Note the state does not change if the device is suspended, we simply set a
* flag to show that it is suspended.
*
*/
typedef enum usb_device_state {
STATE_INIT, /* just initialized */
STATE_CREATED, /* just created */
STATE_ATTACHED, /* we are attached */
STATE_POWERED, /* we have seen power indication (electrical bus signal) */
STATE_DEFAULT, /* we been reset */
STATE_ADDRESSED, /* we have been addressed (in default configuration) */
STATE_CONFIGURED, /* we have seen a set configuration device command */
STATE_UNKNOWN, /* destroyed */
} usb_device_state_t;
#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN")
/*
* Device status
*
* Overall state
*/
typedef enum usb_device_status {
USBD_OPENING, /* we are currently opening */
USBD_OK, /* ok to use */
USBD_SUSPENDED, /* we are currently suspended */
USBD_CLOSING, /* we are currently closing */
} usb_device_status_t;
#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN")
/*
* Device Events
*
* These are defined in the USB Spec (c.f USB Spec 2.0 Figure 9-1).
*
* There are additional events defined to handle some extra actions we need
* to have handled.
*
*/
typedef enum usb_device_event {
DEVICE_UNKNOWN, /* bi - unknown event */
DEVICE_INIT, /* bi - initialize */
DEVICE_CREATE, /* bi - */
DEVICE_HUB_CONFIGURED, /* bi - bus has been plugged int */
DEVICE_RESET, /* bi - hub has powered our port */
DEVICE_ADDRESS_ASSIGNED, /* ep0 - set address setup received */
DEVICE_CONFIGURED, /* ep0 - set configure setup received */
DEVICE_SET_INTERFACE, /* ep0 - set interface setup received */
DEVICE_SET_FEATURE, /* ep0 - set feature setup received */
DEVICE_CLEAR_FEATURE, /* ep0 - clear feature setup received */
DEVICE_DE_CONFIGURED, /* ep0 - set configure setup received for ?? */
DEVICE_BUS_INACTIVE, /* bi - bus in inactive (no SOF packets) */
DEVICE_BUS_ACTIVITY, /* bi - bus is active again */
DEVICE_POWER_INTERRUPTION, /* bi - hub has depowered our port */
DEVICE_HUB_RESET, /* bi - bus has been unplugged */
DEVICE_DESTROY, /* bi - device instance should be destroyed */
DEVICE_HOTPLUG, /* bi - a hotplug event has occurred */
DEVICE_FUNCTION_PRIVATE, /* function - private */
} usb_device_event_t;
typedef struct urb_link {
struct urb_link *next;
struct urb_link *prev;
} urb_link;
/* USB Data structure - for passing data around.
*
* This is used for both sending and receiving data.
*
* The callback function is used to let the function driver know when
* transmitted data has been sent.
*
* The callback function is set by the alloc_recv function when an urb is
* allocated for receiving data for an endpoint and used to call the
* function driver to inform it that data has arrived.
*/
/* in linux we'd malloc this, but in u-boot we prefer static data */
#define URB_BUF_SIZE 512
struct urb {
struct usb_endpoint_instance *endpoint;
struct usb_device_instance *device;
struct usb_device_request device_request; /* contents of received SETUP packet */
struct urb_link link; /* embedded struct for circular doubly linked list of urbs */
u8* buffer;
unsigned int buffer_length;
unsigned int actual_length;
urb_send_status_t status;
int data;
u16 buffer_data[URB_BUF_SIZE]; /* data received (OUT) or being sent (IN) */
};
/* Endpoint configuration
*
* Per endpoint configuration data. Used to track which function driver owns
* an endpoint.
*
*/
struct usb_endpoint_instance {
int endpoint_address; /* logical endpoint address */
/* control */
int status; /* halted */
int state; /* available for use by bus interface driver */
/* receive side */
struct urb_link rcv; /* received urbs */
struct urb_link rdy; /* empty urbs ready to receive */
struct urb *rcv_urb; /* active urb */
int rcv_attributes; /* copy of bmAttributes from endpoint descriptor */
int rcv_packetSize; /* maximum packet size from endpoint descriptor */
int rcv_transferSize; /* maximum transfer size from function driver */
int rcv_queue;
/* transmit side */
struct urb_link tx; /* urbs ready to transmit */
struct urb_link done; /* transmitted urbs */
struct urb *tx_urb; /* active urb */
int tx_attributes; /* copy of bmAttributes from endpoint descriptor */
int tx_packetSize; /* maximum packet size from endpoint descriptor */
int tx_transferSize; /* maximum transfer size from function driver */
int tx_queue;
int sent; /* data already sent */
int last; /* data sent in last packet XXX do we need this */
};
struct usb_alternate_instance {
struct usb_interface_descriptor *interface_descriptor;
int endpoints;
int *endpoint_transfersize_array;
struct usb_endpoint_descriptor **endpoints_descriptor_array;
};
struct usb_interface_instance {
int alternates;
struct usb_alternate_instance *alternates_instance_array;
};
struct usb_configuration_instance {
int interfaces;
struct usb_configuration_descriptor *configuration_descriptor;
struct usb_interface_instance *interface_instance_array;
};
/* USB Device Instance
*
* For each physical bus interface we create a logical device structure. This
* tracks all of the required state to track the USB HOST's view of the device.
*
* Keep track of the device configuration for a real physical bus interface,
* this includes the bus interface, multiple function drivers, the current
* configuration and the current state.
*
* This will show:
* the specific bus interface driver
* the default endpoint 0 driver
* the configured function driver
* device state
* device status
* endpoint list
*/
struct usb_device_instance {
/* generic */
char *name;
struct usb_device_descriptor *device_descriptor; /* per device descriptor */
#if defined(CONFIG_USBD_HS)
struct usb_qualifier_descriptor *qualifier_descriptor;
#endif
void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data);
/* Do cdc device specific control requests */
int (*cdc_recv_setup)(struct usb_device_request *request, struct urb *urb);
/* bus interface */
struct usb_bus_instance *bus; /* which bus interface driver */
/* configuration descriptors */
int configurations;
struct usb_configuration_instance *configuration_instance_array;
/* device state */
usb_device_state_t device_state; /* current USB Device state */
usb_device_state_t device_previous_state; /* current USB Device state */
u8 address; /* current address (zero is default) */
u8 configuration; /* current show configuration (zero is default) */
u8 interface; /* current interface (zero is default) */
u8 alternate; /* alternate flag */
usb_device_status_t status; /* device status */
int urbs_queued; /* number of submitted urbs */
/* Shouldn't need to make this atomic, all we need is a change indicator */
unsigned long usbd_rxtx_timestamp;
unsigned long usbd_last_rxtx_timestamp;
};
/* Bus Interface configuration structure
*
* This is allocated for each configured instance of a bus interface driver.
*
* The privdata pointer may be used by the bus interface driver to store private
* per instance state information.
*/
struct usb_bus_instance {
struct usb_device_instance *device;
struct usb_endpoint_instance *endpoint_array; /* array of available configured endpoints */
int max_endpoints; /* maximimum number of rx enpoints */
unsigned char maxpacketsize;
unsigned int serial_number;
char *serial_number_str;
void *privdata; /* private data for the bus interface */
};
extern char *usbd_device_events[];
extern char *usbd_device_states[];
extern char *usbd_device_status[];
extern char *usbd_device_requests[];
extern char *usbd_device_descriptors[];
void urb_link_init (urb_link * ul);
void urb_detach (struct urb *urb);
urb_link *first_urb_link (urb_link * hd);
struct urb *first_urb (urb_link * hd);
struct urb *first_urb_detached (urb_link * hd);
void urb_append (urb_link * hd, struct urb *urb);
struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint);
void usbd_dealloc_urb (struct urb *urb);
/*
* usbd_device_event is used by bus interface drivers to tell the higher layers that
* certain events have taken place.
*/
void usbd_device_event_irq (struct usb_device_instance *conf, usb_device_event_t, int);
void usbd_device_event (struct usb_device_instance *conf, usb_device_event_t, int);
/* descriptors
*
* Various ways of finding descriptors based on the current device and any
* possible configuration / interface / endpoint for it.
*/
struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct usb_device_instance *, int, int);
struct usb_function_instance *usbd_device_function_instance (struct usb_device_instance *, unsigned int);
struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *, int, int, int);
struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *, int, int, int, int);
struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance *, int, int, int, int);
struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance *, int, int, int, int, int);
struct usb_class_descriptor *usbd_device_class_descriptor_index (struct usb_device_instance *, int, int, int, int, int);
struct usb_class_report_descriptor *usbd_device_class_report_descriptor_index( struct usb_device_instance *, int , int , int , int , int );
struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *, int, int, int, int, int);
int usbd_device_endpoint_transfersize (struct usb_device_instance *, int, int, int, int, int);
struct usb_string_descriptor *usbd_get_string (u8);
struct usb_device_descriptor *usbd_device_device_descriptor(struct
usb_device_instance *, int);
#if defined(CONFIG_USBD_HS)
/*
* is_usbd_high_speed routine needs to be defined by specific gadget driver
* It returns true if device enumerates at High speed
* Retuns false otherwise
*/
int is_usbd_high_speed(void);
#endif
int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint);
void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad);
void usbd_tx_complete (struct usb_endpoint_instance *endpoint);
/* These are macros used in debugging */
#ifdef DEBUG
static inline void print_urb(struct urb *u)
{
serial_printf("urb %p\n", (u));
serial_printf("\tendpoint %p\n", u->endpoint);
serial_printf("\tdevice %p\n", u->device);
serial_printf("\tbuffer %p\n", u->buffer);
serial_printf("\tbuffer_length %d\n", u->buffer_length);
serial_printf("\tactual_length %d\n", u->actual_length);
serial_printf("\tstatus %d\n", u->status);
serial_printf("\tdata %d\n", u->data);
}
static inline void print_usb_device_request(struct usb_device_request *r)
{
serial_printf("usb request\n");
serial_printf("\tbmRequestType 0x%2.2x\n", r->bmRequestType);
if ((r->bmRequestType & USB_REQ_DIRECTION_MASK) == 0)
serial_printf("\t\tDirection : To device\n");
else
serial_printf("\t\tDirection : To host\n");
if ((r->bmRequestType & USB_TYPE_STANDARD) == USB_TYPE_STANDARD)
serial_printf("\t\tType : Standard\n");
if ((r->bmRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS)
serial_printf("\t\tType : Standard\n");
if ((r->bmRequestType & USB_TYPE_VENDOR) == USB_TYPE_VENDOR)
serial_printf("\t\tType : Standard\n");
if ((r->bmRequestType & USB_TYPE_RESERVED) == USB_TYPE_RESERVED)
serial_printf("\t\tType : Standard\n");
if ((r->bmRequestType & USB_REQ_RECIPIENT_MASK) ==
USB_REQ_RECIPIENT_DEVICE)
serial_printf("\t\tRecipient : Device\n");
if ((r->bmRequestType & USB_REQ_RECIPIENT_MASK) ==
USB_REQ_RECIPIENT_INTERFACE)
serial_printf("\t\tRecipient : Interface\n");
if ((r->bmRequestType & USB_REQ_RECIPIENT_MASK) ==
USB_REQ_RECIPIENT_ENDPOINT)
serial_printf("\t\tRecipient : Endpoint\n");
if ((r->bmRequestType & USB_REQ_RECIPIENT_MASK) ==
USB_REQ_RECIPIENT_OTHER)
serial_printf("\t\tRecipient : Other\n");
serial_printf("\tbRequest 0x%2.2x\n", r->bRequest);
if (r->bRequest == USB_REQ_GET_STATUS)
serial_printf("\t\tGET_STATUS\n");
else if (r->bRequest == USB_REQ_SET_ADDRESS)
serial_printf("\t\tSET_ADDRESS\n");
else if (r->bRequest == USB_REQ_SET_FEATURE)
serial_printf("\t\tSET_FEATURE\n");
else if (r->bRequest == USB_REQ_GET_DESCRIPTOR)
serial_printf("\t\tGET_DESCRIPTOR\n");
else if (r->bRequest == USB_REQ_SET_CONFIGURATION)
serial_printf("\t\tSET_CONFIGURATION\n");
else if (r->bRequest == USB_REQ_SET_INTERFACE)
serial_printf("\t\tUSB_REQ_SET_INTERFACE\n");
else
serial_printf("\tUNKNOWN %d\n", r->bRequest);
serial_printf("\twValue 0x%4.4x\n", r->wValue);
if (r->bRequest == USB_REQ_GET_DESCRIPTOR) {
switch (r->wValue >> 8) {
case USB_DESCRIPTOR_TYPE_DEVICE:
serial_printf("\tDEVICE\n");
break;
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
serial_printf("\tCONFIGURATION\n");
break;
case USB_DESCRIPTOR_TYPE_STRING:
serial_printf("\tSTRING\n");
break;
case USB_DESCRIPTOR_TYPE_INTERFACE:
serial_printf("\tINTERFACE\n");
break;
case USB_DESCRIPTOR_TYPE_ENDPOINT:
serial_printf("\tENDPOINT\n");
break;
case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
serial_printf("\tDEVICE_QUALIFIER\n");
break;
case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
serial_printf("\tOTHER_SPEED_CONFIGURATION\n");
break;
case USB_DESCRIPTOR_TYPE_INTERFACE_POWER:
serial_printf("\tINTERFACE_POWER\n");
break;
case USB_DESCRIPTOR_TYPE_HID:
serial_printf("\tHID\n");
break;
case USB_DESCRIPTOR_TYPE_REPORT:
serial_printf("\tREPORT\n");
break;
default:
serial_printf("\tUNKNOWN TYPE\n");
break;
}
}
serial_printf("\twIndex 0x%4.4x\n", r->wIndex);
serial_printf("\twLength 0x%4.4x\n", r->wLength);
}
#else
/* stubs */
#define print_urb(u)
#define print_usb_device_request(r)
#endif /* DEBUG */
#endif

View File

@ -0,0 +1,128 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* USB virtual root hub descriptors
*
* (C) Copyright 2014
* Stephen Warren swarren@wwwdotorg.org
*
* Based on ohci-hcd.c
*/
#ifndef __USBROOTHUBDES_H__
#define __USBROOTHUBDES_H__
/* Device descriptor */
static __u8 root_hub_dev_des[] = {
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x10, /* __u16 bcdUSB; v1.1 */
0x01,
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; */
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
0x00, /* __u16 idVendor; */
0x00,
0x00, /* __u16 idProduct; */
0x00,
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
0x01, /* __u8 iProduct; */
0x00, /* __u8 iSerialNumber; */
0x01, /* __u8 bNumConfigurations; */
};
/* Configuration descriptor */
static __u8 root_hub_config_des[] = {
0x09, /* __u8 bLength; */
0x02, /* __u8 bDescriptorType; Configuration */
0x19, /* __u16 wTotalLength; */
0x00,
0x01, /* __u8 bNumInterfaces; */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes;
* Bit 7: Bus-powered
* 6: Self-powered,
* 5 Remote-wakwup,
* 4..0: resvd
*/
0x00, /* __u8 MaxPower; */
/* interface */
0x09, /* __u8 if_bLength; */
0x04, /* __u8 if_bDescriptorType; Interface */
0x00, /* __u8 if_bInterfaceNumber; */
0x00, /* __u8 if_bAlternateSetting; */
0x01, /* __u8 if_bNumEndpoints; */
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* __u8 if_bInterfaceSubClass; */
0x00, /* __u8 if_bInterfaceProtocol; */
0x00, /* __u8 if_iInterface; */
/* endpoint */
0x07, /* __u8 ep_bLength; */
0x05, /* __u8 ep_bDescriptorType; Endpoint */
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
0x00,
0xff, /* __u8 ep_bInterval; 255 ms */
};
#ifdef WANT_USB_ROOT_HUB_HUB_DES
static unsigned char root_hub_hub_des[] = {
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */
0x00, /* __u16 wHubCharacteristics; */
0x00,
0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
0xff, /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
};
#endif
static unsigned char root_hub_str_index0[] = {
0x04, /* __u8 bLength; */
0x03, /* __u8 bDescriptorType; String-descriptor */
0x09, /* __u8 lang ID */
0x04, /* __u8 lang ID */
};
static unsigned char root_hub_str_index1[] = {
32, /* __u8 bLength; */
0x03, /* __u8 bDescriptorType; String-descriptor */
'U', /* __u8 Unicode */
0, /* __u8 Unicode */
'-', /* __u8 Unicode */
0, /* __u8 Unicode */
'B', /* __u8 Unicode */
0, /* __u8 Unicode */
'o', /* __u8 Unicode */
0, /* __u8 Unicode */
'o', /* __u8 Unicode */
0, /* __u8 Unicode */
't', /* __u8 Unicode */
0, /* __u8 Unicode */
' ', /* __u8 Unicode */
0, /* __u8 Unicode */
'R', /* __u8 Unicode */
0, /* __u8 Unicode */
'o', /* __u8 Unicode */
0, /* __u8 Unicode */
'o', /* __u8 Unicode */
0, /* __u8 Unicode */
't', /* __u8 Unicode */
0, /* __u8 Unicode */
' ', /* __u8 Unicode */
0, /* __u8 Unicode */
'H', /* __u8 Unicode */
0, /* __u8 Unicode */
'u', /* __u8 Unicode */
0, /* __u8 Unicode */
'b', /* __u8 Unicode */
0, /* __u8 Unicode */
};
#endif

View File

@ -0,0 +1,382 @@
/*
* Copyright (C) 2004-2016 Synopsys, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "board.h"
/* static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->host_rx_fifo_size = 774;
p->max_transfer_size = 65535;
p->max_packet_count = 511;
p->ahbcfg = 0x10;
p->uframe_sched = false;
}
static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
p->speed = DWC2_SPEED_PARAM_HIGH;
p->host_rx_fifo_size = 512;
p->host_nperio_tx_fifo_size = 512;
p->host_perio_tx_fifo_size = 512;
p->max_transfer_size = 65535;
p->max_packet_count = 511;
p->host_channels = 16;
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->phy_utmi_width = 8;
p->i2c_enable = false;
p->reload_ctl = false;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT;
p->uframe_sched = false;
p->change_speed_quirk = true;
}
static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
p->host_rx_fifo_size = 525;
p->host_nperio_tx_fifo_size = 128;
p->host_perio_tx_fifo_size = 256;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT;
}
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_cap = 2;
p->host_rx_fifo_size = 288;
p->host_nperio_tx_fifo_size = 128;
p->host_perio_tx_fifo_size = 96;
p->max_transfer_size = 65535;
p->max_packet_count = 511;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT;
}
static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
p->speed = DWC2_SPEED_PARAM_HIGH;
p->host_rx_fifo_size = 512;
p->host_nperio_tx_fifo_size = 500;
p->host_perio_tx_fifo_size = 500;
p->host_channels = 16;
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
GAHBCFG_HBSTLEN_SHIFT;
p->uframe_sched = false;
}
static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
}
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
p->speed = DWC2_SPEED_PARAM_FULL;
p->host_rx_fifo_size = 128;
p->host_nperio_tx_fifo_size = 96;
p->host_perio_tx_fifo_size = 96;
p->max_packet_count = 256;
p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
p->i2c_enable = false;
p->uframe_sched = false;
p->activate_stm_fs_transceiver = true;
} */
static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg)
{
u8 val;
switch (hsotg->hw_params.op_mode) {
case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
break;
case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE;
break;
default:
val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
break;
}
hsotg->params.otg_cap = val;
}
static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg)
{
int val;
u32 hs_phy_type = hsotg->hw_params.hs_phy_type;
val = DWC2_PHY_TYPE_PARAM_FS;
if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) {
if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)
val = DWC2_PHY_TYPE_PARAM_UTMI;
else
val = DWC2_PHY_TYPE_PARAM_ULPI;
}
if (dwc2_is_fs_iot(hsotg))
hsotg->params.phy_type = DWC2_PHY_TYPE_PARAM_FS;
hsotg->params.phy_type = val;
}
static void dwc2_set_param_speed(struct dwc2_hsotg *hsotg)
{
int val;
val = hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS ?
DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH;
if (dwc2_is_fs_iot(hsotg))
val = DWC2_SPEED_PARAM_FULL;
if (dwc2_is_hs_iot(hsotg))
val = DWC2_SPEED_PARAM_HIGH;
hsotg->params.speed = val;
}
static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg)
{
int val;
val = (hsotg->hw_params.utmi_phy_data_width ==
GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
hsotg->params.phy_utmi_width = val;
}
/**
* dwc2_set_default_params() - Set all core parameters to their
* auto-detected default values.
*/
static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_hw_params *hw = &hsotg->hw_params;
struct dwc2_core_params *p = &hsotg->params;
#ifdef USB_DMA
bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH);
#endif
dwc2_set_param_otg_cap(hsotg);
dwc2_set_param_phy_type(hsotg);
dwc2_set_param_speed(hsotg);
dwc2_set_param_phy_utmi_width(hsotg);
p->enable_dynamic_fifo = hw->enable_dynamic_fifo;
p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo;
p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a);
p->max_packet_count = hw->max_packet_count;
p->max_transfer_size = hw->max_transfer_size;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT;
if ((hsotg->dr_mode == USB_DR_MODE_HOST) ||
(hsotg->dr_mode == USB_DR_MODE_OTG)) {
p->host_channels = hw->host_channels;
p->host_rx_fifo_size = hw->rx_fifo_size;
p->host_nperio_tx_fifo_size = hw->host_nperio_tx_fifo_size;
p->host_perio_tx_fifo_size = hw->host_perio_tx_fifo_size;
}
}
/*
* Gets host hardware parameters. Forces host mode if not currently in
* host mode. Should be called immediately after a core soft reset in
* order to get the reset values.
*/
static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg)
{
struct dwc2_hw_params *hw = &hsotg->hw_params;
u32 gnptxfsiz;
u32 hptxfsiz;
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
FIFOSIZE_DEPTH_SHIFT;
hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
FIFOSIZE_DEPTH_SHIFT;
}
/*
* Gets device hardware parameters. Forces device mode if not
* currently in device mode. Should be called immediately after a core
* soft reset in order to get the reset values.
*/
static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
{
struct dwc2_hw_params *hw = &hsotg->hw_params;
u32 gnptxfsiz;
if (hsotg->dr_mode == USB_DR_MODE_HOST)
return;
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
hw->dev_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
FIFOSIZE_DEPTH_SHIFT;
}
/**
* During device initialization, read various hardware configuration
* registers and interpret the contents.
*/
int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
{
struct dwc2_hw_params *hw = &hsotg->hw_params;
unsigned int width;
u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
u32 grxfsiz;
/*
* Attempt to ensure this device is really a DWC_otg Controller.
* Read and verify the GSNPSID register contents. The value should be
* 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
* as in "OTG version 2.xx" or "OTG version 3.xx".
*/
hw->snpsid = dwc2_readl(hsotg->regs + GSNPSID);
if ((hw->snpsid & 0xfffff000) != 0x4f542000 &&
(hw->snpsid & 0xfffff000) != 0x4f543000 &&
(hw->snpsid & 0xffff0000) != 0x55310000 &&
(hw->snpsid & 0xffff0000) != 0x55320000) {
dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
hw->snpsid);
return -ENODEV;
}
dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
hwcfg1 = dwc2_readl(hsotg->regs + GHWCFG1);
hwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
hwcfg3 = dwc2_readl(hsotg->regs + GHWCFG3);
hwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
/*
* Host specific hardware parameters. Reading these parameters
* requires the controller to be in host mode. The mode will
* be forced, if necessary, to read these values.
*/
dwc2_get_host_hwparams(hsotg);
dwc2_get_dev_hwparams(hsotg);
/* hwcfg1 */
hw->dev_ep_dirs = hwcfg1;
/* hwcfg2 */
hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
GHWCFG2_OP_MODE_SHIFT;
hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >>
GHWCFG2_ARCHITECTURE_SHIFT;
hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >>
GHWCFG2_NUM_HOST_CHAN_SHIFT);
hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >>
GHWCFG2_HS_PHY_TYPE_SHIFT;
hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >>
GHWCFG2_FS_PHY_TYPE_SHIFT;
hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >>
GHWCFG2_NUM_DEV_EP_SHIFT;
hw->nperio_tx_q_depth =
(hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >>
GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1;
hw->host_perio_tx_q_depth =
(hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >>
GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1;
hw->dev_token_q_depth =
(hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >>
GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT;
/* hwcfg3 */
width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
hw->max_transfer_size = (1 << (width + 11)) - 1;
width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
hw->max_packet_count = (1 << (width + 4)) - 1;
hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
GHWCFG3_DFIFO_DEPTH_SHIFT;
/* hwcfg4 */
hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >>
GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
/* fifo sizes */
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
GRXFSIZ_DEPTH_SHIFT;
return 0;
}
int dwc2_init_params(struct dwc2_hsotg *hsotg)
{
dwc2_set_default_params(hsotg);
return 0;
}

View File

@ -0,0 +1,176 @@
/*
* platform.c - DesignWare HS OTG Controller platform driver
*
* Copyright (C) Matthijs Kooijman <matthijs@stdin.nl>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "usb_os_adapter.h"
#include "trace.h"
#include <asm/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "core.h"
#include "hcd.h"
#include "amt630h.h"
#include "aic.h"
static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg)
{
hsotg->dr_mode = USB_DR_MODE_HOST;
return 0;
}
//static QueueHandle_t usb_irq_queue;
//static TaskHandle_t usb_irq_task;
//static char first_irq = 1;
static void ark_usb_interrupt(void *param)
{
struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)param;
//printf("ark_usb_interrupt\r\n");
dwc2_handle_common_intr(hsotg->irq, param);
dwc2_hcd_irq(hsotg);
/*if (first_irq) {
dwc2_hcd_irq(hsotg);
first_irq = 0;
} else {
portDISABLE_INTERRUPTS();
xQueueSendFromISR(usb_irq_queue, NULL, 0);
}*/
}
#if 0
static void usb_irq_task_proc(void *pvParameters)
{
struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)pvParameters;
int ret = -1;
while(1) {
ret = xQueueReceive(usb_irq_queue, NULL, portMAX_DELAY);
if (pdFALSE == ret) {
continue;
}
//portENTER_CRITICAL();
dwc2_hcd_irq(hsotg);
portENABLE_INTERRUPTS();
//portEXIT_CRITICAL();
}
}
#endif
int dwc2_driver_init(struct dwc2_hsotg **dev, struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg;
int retval = -1;
u32 size = sizeof(struct device);
hsotg = devm_kzalloc(NULL, sizeof(*hsotg), GFP_KERNEL);
if (!hsotg)
return -ENOMEM;
hsotg->dev = (struct device *)kzalloc(size, (__GFP_ZERO | GFP_KERNEL));
if (NULL == hsotg->dev)
goto error;
hsotg->phyif = GUSBCFG_PHYIF16;
hsotg->regs = REGS_USB_BASE;
spin_lock_init(&(hsotg->lock));
hsotg->irq = USB_IRQn;
retval = request_irq(hsotg->irq, 0, ark_usb_interrupt, (void*)hsotg);
if (retval)
goto error;
retval = dwc2_get_dr_mode(hsotg);
if (retval)
goto error;
/*
* Reset before dwc2_get_hwparams() then it could get power-on real
* reset value form registers.
*/
dwc2_core_reset_and_force_dr_mode(hsotg);
/* Detect config values from hardware */
retval = dwc2_get_hwparams(hsotg);
if (retval)
goto error;
dwc2_force_dr_mode(hsotg);
retval = dwc2_init_params(hsotg);
if (retval)
goto error;
if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
//usb_irq_queue = xQueueCreate(1, 0);
//xTaskCreate(usb_irq_task_proc, "usb_irq_proc", configMINIMAL_STACK_SIZE * 5, (void*)dev, configMAX_PRIORITIES, &usb_irq_task);
retval = dwc2_hcd_init(hsotg, hcd);
if (retval) {
goto error;
}
hsotg->hcd_enabled = 1;
}
if (dev) {
*dev = hsotg;
}
return 0;
error:
if (hsotg && hsotg->dev) {
kfree(hsotg->dev);
}
if (hsotg) {
kfree(hsotg);
}
return retval;
}
int dwc2_driver_uninit(struct dwc2_hsotg *hsotg)
{
if (NULL == hsotg)
return 0;
if (hsotg->hcd_enabled)
dwc2_hcd_remove(hsotg);
if (hsotg->dev)
kfree(hsotg->dev);
kfree(hsotg);
return 0;
}

View File

@ -0,0 +1,253 @@
#ifndef __USB_COMPAT_H__
#define __USB_COMPAT_H__
//#include <dm.h>
#include "usb.h"
#include "timer.h"
struct usb_bus {
int busnum; /* Bus number (in order of reg) */
const char *bus_name; /* stable id (PCI slot_name etc) */
u8 uses_dma; /* Does the host controller use DMA? */
u8 uses_pio_for_control; /*
* Does the host controller use PIO
* for control transfers?
*/
u8 otg_port; /* 0, or number of OTG/HNP port */
unsigned is_b_host:1; /* true during some HNP roleswitches */
unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
unsigned no_stop_on_short:1; /*
* Quirk: some controllers don't stop
* the ep queue on a short transfer
* with the URB_SHORT_NOT_OK flag set.
*/
unsigned no_sg_constraint:1; /* no sg constraint */
unsigned sg_tablesize; /* 0 or largest number of sg list entries */
int devnum_next; /* Next open device number in
* round-robin allocation */
int bandwidth_allocated; /* on this bus: how much of the time
* reserved for periodic (intr/iso)
* requests is used, on average?
* Units: microseconds/frame.
* Limits: Full/low speed reserve 90%,
* while high speed reserves 80%.
*/
int bandwidth_int_reqs; /* number of Interrupt requests */
int bandwidth_isoc_reqs; /* number of Isoc. requests */
unsigned resuming_ports; /* bit array: resuming root-hub ports */
};
struct usb_hcd {
struct usb_bus self;
int has_tt;
void *hcd_priv;
};
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
List_t urb_list;
void *hcpriv;
};
/*
* urb->transfer_flags:
*
* Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
*/
#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt*/
struct urb;
typedef void (*usb_complete_t)(struct urb *);
struct urb {
void *hcpriv; /* private data for host controller */
ListItem_t urb_list;
int urb_complete;
struct usb_device *dev; /* (in) pointer to associated device */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
u32 transfer_buffer_length; /* (in) data buffer length */
u32 actual_length; /* (return) actual transfer length */
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma;
int start_frame; /* (modify) start frame (ISO) */
void *context;
usb_complete_t complete; /* (in) completion routine */
int interval;
int error_count; /* (return) number of ISO errors */
int number_of_packets; /* (in) number of ISO packets */
};
struct hc_driver {
const char *description; /* "ehci-hcd" etc */
const char *product_desc; /* product/vendor string */
size_t hcd_priv_size; /* size of private data */
/* irq handler */
irqreturn_t (*irq) (struct usb_hcd *hcd);
int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
#define HCD_SHARED 0x0004 /* Two (or more) usb_hcds share HW */
#define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */
#define HCD_USB25 0x0030 /* Wireless USB 1.0 (USB 2.5)*/
#define HCD_USB3 0x0040 /* USB 3.0 */
#define HCD_USB31 0x0050 /* USB 3.1 */
#define HCD_MASK 0x0070
#define HCD_BH 0x0100 /* URB complete in BH context */
/* called to init HCD and root hub */
int (*start) (struct usb_hcd *hcd);
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue)(struct usb_hcd *hcd,
struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd,
struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
struct usb_host_endpoint *ep);
/* (optional) reset any endpoint state such as sequence number
and current window */
void (*endpoint_reset)(struct usb_hcd *hcd,
struct usb_host_endpoint *ep);
/* root hub support */
int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
int (*hub_control) (struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
};
#define usb_hcd_link_urb_to_ep(hcd, urb) do { \
list_add_tail(&urb->urb_list, &urb->ep->urb_list); \
} while(0)
#define usb_hcd_unlink_urb_from_ep(hcd, urb) list_del_init(&urb->urb_list)
#define usb_hcd_check_unlink_urb(hdc, urb, status) 0
static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd,
struct urb *urb,
int status)
{
urb->status = status;
if (urb->complete)
urb->complete(urb);
}
static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd,
struct urb *urb)
{
/* TODO: add cache invalidation here */
return 0;
}
static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
{
return &hcd->self;
}
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
(void)hcd;
return;
}
/*
* Generic bandwidth allocation constants/support
*/
#define FRAME_TIME_USECS 1000L
#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
/* Trying not to use worst-case bit-stuffing
* of (7/6 * 8 * bytecount) = 9.33 * bytecount */
/* bytecount = data payload byte count */
#define NS_TO_US(ns) DIV_ROUND_UP(ns, 1000L)
/* convert nanoseconds to microseconds, rounding up */
/*
* Full/low speed bandwidth allocation constants/support.
*/
#define BW_HOST_DELAY 1000L /* nanoseconds */
#define BW_HUB_LS_SETUP 333L /* nanoseconds */
/* 4 full-speed bit times (est.) */
#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
/*
* Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
* ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
* to preallocate bandwidth)
*/
#define USB2_HOST_DELAY 5 /* nsec, guess */
#define HS_NSECS(bytes) (((55 * 8 * 2083) \
+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ USB2_HOST_DELAY)
#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \
+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ USB2_HOST_DELAY)
#define HS_USECS(bytes) NS_TO_US(HS_NSECS(bytes))
#define HS_USECS_ISO(bytes) NS_TO_US(HS_NSECS_ISO(bytes))
#ifdef CONFIG_DM_USB
static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
{
struct udevice *parent = udev->dev->parent;
/*
* When called from usb-uclass.c: usb_scan_device() udev->dev points
* to the parent udevice, not the actual udevice belonging to the
* udev as the device is not instantiated yet.
*
* If dev is an usb-bus, then we are called from usb_scan_device() for
* an usb-device plugged directly into the root port, return NULL.
*/
if (device_get_uclass_id(udev->dev) == UCLASS_USB)
return NULL;
/*
* If these 2 are not the same we are being called from
* usb_scan_device() and udev itself is the parent.
*/
if (dev_get_parent_priv(udev->dev) != udev)
return udev;
/* We are being called normally, use the parent pointer */
if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
return dev_get_parent_priv(parent);
return NULL;
}
#else
static inline struct usb_device *usb_dev_get_parent(struct usb_device *dev)
{
return dev->parent;
}
#endif
#endif /* __USB_COMPAT_H__ */

1705
A27-STEPLDR/Src/usb/usb.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,847 @@
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdbool.h>
#define CONFIG_USB_STORAGE
#include "usb_os_adapter.h"
#include "trace.h"
#include <linux/usb/ch9.h>
#include "scsi.h"
#include "usb.h"
#include "dwc2_compat.h"
#include <linux/errno.h>
#include "ark_dwc2.h"
#include "usb_massstorage.h"
#include "timer.h"
#include "fs/ff.h"
#include "fs/diskio.h"
/* direction table -- this indicates the direction of the data
* transfer for each command code -- a 1 indicates input
*/
static const unsigned char us_direction[256/8] = {
0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
#pragma pack(ARCH_DMA_MINALIGN)
static struct scsi_cmd usb_ccb;
static u32 CBWTag;
static int usb_max_devs; /* number of highest available usb device */
struct blk_desc usb_dev_desc[6];
struct us_data;
typedef int (*trans_cmnd)(struct scsi_cmd *cb, struct us_data *data);
typedef int (*trans_reset)(struct us_data *data);
#define USB_READY (1 << 0)
struct us_data {
struct usb_device *pusb_dev; /* this usb_device */
unsigned int flags; /* from filter initially */
unsigned char ifnum; /* interface number */
unsigned char ep_in; /* in endpoint */
unsigned char ep_out; /* out ....... */
unsigned char ep_int; /* interrupt . */
unsigned char subclass; /* as in overview */
unsigned char protocol; /* .............. */
unsigned char attention_done; /* force attn on first cmd */
unsigned short ip_data; /* interrupt data */
int action; /* what to do */
int ip_wanted; /* needed */
int *irq_handle; /* for USB int requests */
unsigned int irqpipe; /* pipe for release_irq */
unsigned char irqmaxp; /* max packed for irq Pipe */
unsigned char irqinterval; /* Intervall for IRQ Pipe */
struct scsi_cmd *srb; /* current srb */
trans_reset transport_reset; /* reset routine */
trans_cmnd transport; /* transport routine */
unsigned short max_xfer_blk; /* maximum transfer blocks */
};
static struct us_data usb_stor[USB_MAX_STOR_DEV];
#define USB_STOR_TRANSPORT_GOOD 0
#define USB_STOR_TRANSPORT_FAILED -1
#define USB_STOR_TRANSPORT_ERROR -2
static int usb_media_ready = 0;
/***********************************************************************
* Data transfer routines
***********************************************************************/
static unsigned int usb_get_max_lun(struct us_data *us)
{
int len;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1);
len = usb_control_msg(us->pusb_dev,
usb_rcvctrlpipe(us->pusb_dev, 0),
US_BBB_GET_MAX_LUN,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
0, us->ifnum,
result, sizeof(char),
USB_CNTL_TIMEOUT * 5);
//debug("Get Max LUN -> len = %i, result = %i\n", len, (int) *result);
return (len > 0) ? *result : 0;
}
static int usb_stor_BBB_reset(struct us_data *us)
{
int result;
unsigned int pipe;
/*
* Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
*
* For Reset Recovery the host shall issue in the following order:
* a) a Bulk-Only Mass Storage Reset
* b) a Clear Feature HALT to the Bulk-In endpoint
* c) a Clear Feature HALT to the Bulk-Out endpoint
*
* This is done in 3 steps.
*
* If the reset doesn't succeed, the device should be port reset.
*
* This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
*/
//debug("BBB_reset\n");
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
US_BBB_RESET,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0, USB_CNTL_TIMEOUT * 5);
if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
//debug("RESET:stall\n");
return -1;
}
if (usb_media_ready == 0)
return -1;
/* long wait for reset */
mdelay(150);
/* debug("BBB_reset result %d: status %lX reset\n",
result, us->pusb_dev->status); */
pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
result = usb_clear_halt(us->pusb_dev, pipe);
/* long wait for reset */
mdelay(150);
/* debug("BBB_reset result %d: status %lX clearing IN endpoint\n",
result, us->pusb_dev->status); */
/* long wait for reset */
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
result = usb_clear_halt(us->pusb_dev, pipe);
mdelay(150);
/* debug("BBB_reset result %d: status %lX clearing OUT endpoint\n",
result, us->pusb_dev->status);
debug("BBB_reset done\n"); */
return 0;
}
/*
* Set up the command for a BBB device. Note that the actual SCSI
* command is copied into cbw.CBWCDB.
*/
static int usb_stor_BBB_comdat(struct scsi_cmd *srb, struct us_data *us)
{
int result;
int actlen;
int dir_in;
unsigned int pipe;
ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
dir_in = US_DIRECTION(srb->cmd[0]);
/* sanity checks */
if (!(srb->cmdlen <= CBWCDBLENGTH)) {
//debug("usb_stor_BBB_comdat:cmdlen too large\n");
return -1;
}
/* always OUT to the ep */
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE);
cbw->dCBWTag = cpu_to_le32(CBWTag++);
cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen);
cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
cbw->bCBWLUN = srb->lun;
cbw->bCDBLength = srb->cmdlen;
/* copy the command data into the CBW command data buffer */
/* DST SRC LEN!!! */
memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE,
&actlen, USB_CNTL_TIMEOUT * 5);
if (result < 0)
;//debug("usb_stor_BBB_comdat:usb_bulk_msg error\n");
return result;
}
#define USB_TRANSPORT_UNKNOWN_RETRY 5
#define USB_TRANSPORT_NOT_READY_RETRY 10
/* clear a stall on an endpoint - special for BBB devices */
static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, u8 endpt)
{
/* ENDPOINT_HALT = 0, so set value to 0 */
return usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
}
static int usb_stor_BBB_transport(struct scsi_cmd *srb, struct us_data *us)
{
int result, retry;
int dir_in;
int actlen, data_actlen;
unsigned int pipe, pipein, pipeout;
ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
dir_in = US_DIRECTION(srb->cmd[0]);
/* COMMAND phase */
//debug("COMMAND phase\n");
result = usb_stor_BBB_comdat(srb, us);
if (result < 0) {
/* debug("failed to send CBW status %ld\n",
us->pusb_dev->status); */
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
}
if (!(us->flags & USB_READY))
mdelay(5);
pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
/* DATA phase + error handling */
data_actlen = 0;
/* no data, go immediately to the STATUS phase */
if (srb->datalen == 0)
goto st;
//debug("DATA phase\n");
if (dir_in)
pipe = pipein;
else
pipe = pipeout;
result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
&data_actlen, USB_CNTL_TIMEOUT * 5);
/* special handling of STALL in DATA phase */
if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
//debug("DATA:stall\n");
/* clear the STALL on the endpoint */
result = usb_stor_BBB_clear_endpt_stall(us,
dir_in ? us->ep_in : us->ep_out);
if (result >= 0)
/* continue on to STATUS phase */
goto st;
}
if (result < 0) {
/* debug("usb_bulk_msg error status %ld\n",
us->pusb_dev->status); */
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
}
/* STATUS phase + error handling */
char *tmpcsw;
st:
retry = 0;
again:
//debug("STATUS phase\n");
tmpcsw = (char *)csw;
tmpcsw[0] = 0x55;
tmpcsw[1] = 0x53;
tmpcsw[2] = 0x42;
tmpcsw[3] = 0x43;
tmpcsw[4] = 0x01;
tmpcsw[5] = 0x00;
tmpcsw[6] = 0x00;
tmpcsw[7] = 0x00;
tmpcsw[8] = 0x24;
tmpcsw[9] = 0x00;
tmpcsw[10] = 0x00;
tmpcsw[11] = 0x00;
tmpcsw[12] = 0x80;
result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE,
&actlen, USB_CNTL_TIMEOUT);
/* special handling of STALL in STATUS phase */
if ((result < 0) && (retry < 1) &&
(us->pusb_dev->status & USB_ST_STALLED)) {
//debug("STATUS:stall\n");
/* clear the STALL on the endpoint */
result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
if (result >= 0 && (retry++ < 1))
/* do a retry */
goto again;
}
if (result < 0) {
/* debug("usb_bulk_msg error status %ld\n",
us->pusb_dev->status); */
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
}
/* misuse pipe to get the residue */
pipe = le32_to_cpu(csw->dCSWDataResidue);
if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
pipe = srb->datalen - data_actlen;
if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) {
//debug("!CSWSIGNATURE\n");
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) {
//debug("!Tag\n");
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if (csw->bCSWStatus > CSWSTATUS_PHASE) {
//debug(">PHASE\n");
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if (csw->bCSWStatus == CSWSTATUS_PHASE) {
//debug("=PHASE\n");
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if (data_actlen > srb->datalen) {
/* debug("transferred %dB instead of %ldB\n",
data_actlen, srb->datalen); */
return USB_STOR_TRANSPORT_FAILED;
} else if (csw->bCSWStatus == CSWSTATUS_FAILED) {
//debug("FAILED\n");
return USB_STOR_TRANSPORT_FAILED;
}
return result;
}
static int usb_stor_irq(struct usb_device *dev)
{
struct us_data *us;
us = (struct us_data *)dev->privptr;
if (us->ip_wanted)
us->ip_wanted = 0;
return 0;
}
static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
struct us_data *us)
{
unsigned short blk = 20;
us->max_xfer_blk = blk;
}
static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
{
int retry, i;
retry = 5;
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_INQUIRY;
srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 36;
srb->datalen = 36;
srb->cmdlen = 12;
i = ss->transport(srb, ss);
//debug("inquiry returns %d\n", i);
if (i == 0)
break;
} while (--retry);
if (!retry) {
//printf("error in inquiry\n");
return -1;
}
return 0;
}
static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss)
{
char *ptr;
int ret = -1;
ptr = (char *)srb->pdata;
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_REQ_SENSE;
srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 18;
srb->datalen = 18;
srb->pdata = &srb->sense_buf[0];
srb->cmdlen = 12;
ret = ss->transport(srb, ss);
/* debug("Request Sense returned %02X %02X %02X\n",
srb->sense_buf[2], srb->sense_buf[12],
srb->sense_buf[13]); */
srb->pdata = (unsigned char *)ptr;
return ret;
}
static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss)
{
int retries = 10;
int ret = -1;
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_TST_U_RDY;
srb->cmd[1] = srb->lun << 5;
srb->datalen = 0;
srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
ss->flags |= USB_READY;
return 0;
}
ret = usb_request_sense(srb, ss);
if (ret != USB_STOR_TRANSPORT_GOOD)
break;
/*
* Check the Key Code Qualifier, if it matches
* "Not Ready - medium not present"
* (the sense Key equals 0x2 and the ASC is 0x3a)
* return immediately as the medium being absent won't change
* unless there is a user action.
*/
if ((srb->sense_buf[2] == 0x02) &&
(srb->sense_buf[12] == 0x3a))
return -1;
if (usb_media_ready == 0)
break;
mdelay(100);
} while (retries--);
return -1;
}
static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss)
{
int retry;
/* XXX retries */
retry = 3;
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_RD_CAPAC;
srb->cmd[1] = srb->lun << 5;
srb->datalen = 8;
srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
return 0;
} while (retry--);
return -1;
}
static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss,
unsigned long start, unsigned short blocks)
{
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_READ10;
srb->cmd[1] = srb->lun << 5;
srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
srb->cmd[5] = ((unsigned char) (start)) & 0xff;
srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
srb->cmd[8] = (unsigned char) blocks & 0xff;
srb->cmdlen = 12;
//debug("read10: start %lx blocks %x\n", start, blocks);
return ss->transport(srb, ss);
}
/* Probe to see if a new device is actually a Storage device */
int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
struct us_data *ss)
{
struct usb_interface *iface;
int i;
struct usb_endpoint_descriptor *ep_desc;
unsigned int flags = 0;
/* let's examine the device now */
iface = &dev->config.if_desc[ifnum];
if (dev->descriptor.bDeviceClass != 0 ||
iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
iface->desc.bInterfaceSubClass < US_SC_MIN ||
iface->desc.bInterfaceSubClass > US_SC_MAX) {
//SendUartString("Not mass storage\r\n");
/* if it's not a mass storage, we go no further */
return 0;
}
memset(ss, 0, sizeof(struct us_data));
usb_media_ready = 1;
/* At this point, we know we've got a live one */
//debug("\n\nUSB Mass Storage device detected\n");
/* Initialize the us_data structure with some useful info */
ss->flags = flags;
ss->ifnum = ifnum;
ss->pusb_dev = dev;
ss->attention_done = 0;
ss->subclass = iface->desc.bInterfaceSubClass;
ss->protocol = iface->desc.bInterfaceProtocol;
/* set the handler pointers based on the protocol */
//debug("Transport: ");
switch (ss->protocol) {
case US_PR_BULK:
//debug("Bulk/Bulk/Bulk\n");
ss->transport = usb_stor_BBB_transport;
ss->transport_reset = usb_stor_BBB_reset;
break;
default:
//printf("USB Storage Transport unknown / not yet implemented\n");
return 0;
break;
}
/*
* We are expecting a minimum of 2 endpoints - in and out (bulk).
* An optional interrupt is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < iface->desc.bNumEndpoints; i++) {
ep_desc = &iface->ep_desc[i];
/* is it an BULK endpoint? */
if ((ep_desc->bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (ep_desc->bEndpointAddress & USB_DIR_IN)
ss->ep_in = ep_desc->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
else
ss->ep_out =
ep_desc->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
}
/* is it an interrupt endpoint? */
if ((ep_desc->bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
ss->ep_int = ep_desc->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
ss->irqinterval = ep_desc->bInterval;
}
}
/* debug("Endpoints In %d Out %d Int %d\n",
ss->ep_in, ss->ep_out, ss->ep_int); */
/* Do some basic sanity checks, and bail if we find a problem */
if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
!ss->ep_in || !ss->ep_out ||
(ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
//debug("Problems with device\n");
return 0;
}
/* set class specific stuff */
/* We only handle certain protocols. Currently, these are
* the only ones.
* The SFF8070 accepts the requests used in u-boot
*/
if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
ss->subclass != US_SC_8070) {
//printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
return 0;
}
if (ss->ep_int) {
/* we had found an interrupt endpoint, prepare irq pipe
* set up the IRQ pipe and handler
*/
ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
dev->irq_handle = usb_stor_irq;
}
/* Set the maximum transfer size per host controller setting */
usb_stor_set_max_xfer_blk(dev, ss);
dev->privptr = (void *)ss;
return 1;
}
int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
struct blk_desc *dev_desc)
{
unsigned char perq, modi;
ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
u32 capacity, blksz;
struct scsi_cmd *pccb = &usb_ccb;
memset(usb_stor_buf, 0, 36);
pccb->pdata = usb_stor_buf;
dev_desc->target = dev->devnum;
pccb->lun = dev_desc->lun;
//debug(" address %d\n", dev_desc->target);
if (usb_inquiry(pccb, ss)) {
//debug("%s: usb_inquiry() failed\n", __func__);
return -1;
}
perq = usb_stor_buf[0];
modi = usb_stor_buf[1];
/*
* Skip unknown devices (0x1f) and enclosure service devices (0x0d),
* they would not respond to test_unit_ready .
*/
if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
//debug("%s: unknown/unsupported device\n", __func__);
return 0;
}
if ((modi&0x80) == 0x80) {
/* drive is removable */
dev_desc->removable = 1;
}
memcpy(dev_desc->vendor, (const void *)&usb_stor_buf[8], 8);
memcpy(dev_desc->product, (const void *)&usb_stor_buf[16], 16);
memcpy(dev_desc->revision, (const void *)&usb_stor_buf[32], 4);
dev_desc->vendor[8] = 0;
dev_desc->product[16] = 0;
dev_desc->revision[4] = 0;
/* debug("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
usb_stor_buf[3]); */
if (usb_test_unit_ready(pccb, ss)) {
/* printf("Device NOT ready\n"
" Request Sense returned %02X %02X %02X\n",
pccb->sense_buf[2], pccb->sense_buf[12],
pccb->sense_buf[13]); */
if (dev_desc->removable == 1)
dev_desc->type = perq;
return 0;
}
pccb->pdata = (unsigned char *)cap;
memset(pccb->pdata, 0, 8);
if (usb_read_capacity(pccb, ss) != 0) {
//printf("READ_CAP ERROR\n");
cap[0] = 2880;
cap[1] = 0x200;
}
ss->flags &= ~USB_READY;
//debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
#if 0
if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
cap[0] >>= 16;
cap[0] = cpu_to_be32(cap[0]);
cap[1] = cpu_to_be32(cap[1]);
#endif
capacity = be32_to_cpu(cap[0]) + 1;
blksz = be32_to_cpu(cap[1]);
dev_desc->lba = capacity;
dev_desc->blksz = blksz;
dev_desc->log2blksz = LOG2(dev_desc->blksz);
dev_desc->type = perq;
return 1;
}
static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
lbaint_t blkcnt, void *buffer)
{
lbaint_t start, blks;
uintptr_t buf_addr;
unsigned short smallblks;
struct usb_device *udev;
struct us_data *ss;
int retry;
struct scsi_cmd *srb = &usb_ccb;
if (blkcnt == 0)
return 0;
/* Setup device */
udev = usb_dev_desc[block_dev->devnum].priv;
if (!udev) {
return 0;
}
ss = (struct us_data *)udev->privptr;
usb_disable_asynch(1); /* asynch transfer not allowed */
srb->lun = block_dev->lun;
buf_addr = (uintptr_t)buffer;
start = blknr;
blks = blkcnt;
do {
retry = 2;
srb->pdata = (unsigned char *)buf_addr;
if (blks > ss->max_xfer_blk)
smallblks = ss->max_xfer_blk;
else
smallblks = (unsigned short) blks;
retry_it:
if (usb_media_ready == 0)
break;
/* if (smallblks == ss->max_xfer_blk)
usb_show_progress(); */
srb->datalen = block_dev->blksz * smallblks;
srb->pdata = (unsigned char *)buf_addr;
if (usb_read_10(srb, ss, start, smallblks)) {
usb_request_sense(srb, ss);
if (retry--)
goto retry_it;
blkcnt -= blks;
break;
}
start += smallblks;
blks -= smallblks;
buf_addr += srb->datalen;
} while (blks != 0);
ss->flags &= ~USB_READY;
usb_disable_asynch(0);
return blkcnt;
}
static int usb_stor_probe_device(struct usb_device *udev)
{
int lun, max_lun;
int start;
if (udev == NULL)
return -ENOENT; /* no more devices available */
//debug("\n\nProbing for storage\n");
/* We don't have space to even probe if we hit the maximum */
if (usb_max_devs == USB_MAX_STOR_DEV) {
/* printf("max USB Storage Device reached: %d stopping\n",
usb_max_devs); */
return -ENOSPC;
}
if (!usb_storage_probe(udev, 0, &usb_stor[usb_max_devs]))
return 0;
/*
* OK, it's a storage device. Iterate over its LUNs and populate
* usb_dev_desc'
*/
start = usb_max_devs;
max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
for (lun = 0; lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
lun++) {
struct blk_desc *blkdev;
blkdev = &usb_dev_desc[usb_max_devs];
memset(blkdev, '\0', sizeof(struct blk_desc));
blkdev->if_type = IF_TYPE_USB;
blkdev->devnum = usb_max_devs;
blkdev->part_type = PART_TYPE_UNKNOWN;
blkdev->target = 0xff;
blkdev->type = DEV_TYPE_UNKNOWN;
blkdev->block_read = usb_stor_read;
//blkdev->block_write = usb_stor_write;
blkdev->lun = lun;
blkdev->priv = udev;
if (usb_stor_get_info(udev, &usb_stor[start],
&usb_dev_desc[usb_max_devs]) == 1) {
//debug("partype: %d\n", blkdev->part_type);
//part_init(blkdev);
//debug("partype: %d\n", blkdev->part_type);
usb_max_devs++;
//debug("%s: Found device %p\n", __func__, udev);
/* blkdev->disk_priv = (void *)FF_USBDiskInit("/usb");
if (NULL == blkdev->disk_priv) {
printf("FF_USBDiskInit failed\r\n");
continue;
}
mdelay(200);
usb_disk_file_test(); */
}
}
return 0;
}
void usb_stor_reset(void)
{
usb_max_devs = 0;
CBWTag = 0;
}
/*******************************************************************************
* scan the usb and reports device info
* to the user if mode = 1
* returns current device or -1 if no
*/
int usb_stor_scan(int mode)
{
unsigned char i;
if (mode == 1)
SendUartString("scanning usb for storage devices... ");
usb_disable_asynch(1); /* asynch transfer not allowed */
usb_stor_reset();
for (i = 0; i < USB_MAX_DEVICE; i++) {
struct usb_device *dev;
dev = usb_get_dev_index(i); /* get device */
//debug("i=%d\n", i);
if (usb_stor_probe_device(dev))
break;
} /* for */
usb_disable_asynch(0); /* asynch transfer allowed */
if (usb_max_devs > 0) {
SendUartString("Storage Device(s) found\r\n");
return 0;
}
return -1;
}
void usb_stor_disconnect()
{
usb_media_ready = 0;
}
int USB_disk_initialize(void)
{
return 0;
}
int USB_disk_read(void *buff, DWORD sector, BYTE count)
{
struct blk_desc *dev_desc = &usb_dev_desc[0];
return dev_desc->block_read(dev_desc, sector, count, buff);
}
int USB_disk_ioctl(BYTE ctrl, void *buff)
{
struct blk_desc *dev_desc = &usb_dev_desc[0];
switch(ctrl)
{
case CTRL_SYNC:
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = dev_desc->lba;
break;
case GET_BLOCK_SIZE:
*(DWORD*)buff = 512;
break;
default:
return -1;
}
return 0;
}

View File

@ -0,0 +1,110 @@
#ifndef __USB_MASS_STORAGE_H
#define __USB_MASS_STORAGE_H
/* Part types */
#define PART_TYPE_UNKNOWN 0x00
#define PART_TYPE_MAC 0x01
#define PART_TYPE_DOS 0x02
#define PART_TYPE_ISO 0x03
#define PART_TYPE_AMIGA 0x04
#define PART_TYPE_EFI 0x05
/* device types */
#define DEV_TYPE_UNKNOWN 0xff /* not connected */
#define DEV_TYPE_HARDDISK 0x00 /* harddisk */
#define DEV_TYPE_TAPE 0x01 /* Tape */
#define DEV_TYPE_CDROM 0x05 /* CD-ROM */
#define DEV_TYPE_OPDISK 0x07 /* optical disk */
#define PART_NAME_LEN 32
#define PART_TYPE_LEN 32
#define MAX_SEARCH_PARTITIONS 64
typedef unsigned long lbaint_t;
typedef struct {
u8 b[16];
} efi_guid_t;
/* Interface types: */
enum if_type {
IF_TYPE_UNKNOWN = 0,
IF_TYPE_IDE,
IF_TYPE_SCSI,
IF_TYPE_ATAPI,
IF_TYPE_USB,
IF_TYPE_DOC,
IF_TYPE_MMC,
IF_TYPE_SD,
IF_TYPE_SATA,
IF_TYPE_HOST,
IF_TYPE_NVME,
IF_TYPE_EFI,
IF_TYPE_COUNT, /* Number of interface types */
};
#define BLK_VEN_SIZE 40
#define BLK_PRD_SIZE 20
#define BLK_REV_SIZE 8
/*
* Identifies the partition table type (ie. MBR vs GPT GUID) signature
*/
enum sig_type {
SIG_TYPE_NONE,
SIG_TYPE_MBR,
SIG_TYPE_GUID,
SIG_TYPE_COUNT /* Number of signature types */
};
/*
* With driver model (CONFIG_BLK) this is uclass platform data, accessible
* with dev_get_uclass_platdata(dev)
*/
struct blk_desc {
/*
* TODO: With driver model we should be able to use the parent
* device's uclass instead.
*/
enum if_type if_type; /* type of the interface */
int devnum; /* device number */
unsigned char part_type; /* partition type */
unsigned char target; /* target SCSI ID */
unsigned char lun; /* target LUN */
unsigned char hwpart; /* HW partition, e.g. for eMMC */
unsigned char type; /* device type */
unsigned char removable; /* removable device */
lbaint_t lba; /* number of blocks */
unsigned long blksz; /* block size */
int log2blksz; /* for convenience: log2(blksz) */
char vendor[BLK_VEN_SIZE + 1]; /* device vendor string */
char product[BLK_PRD_SIZE + 1]; /* device product number */
char revision[BLK_REV_SIZE + 1]; /* firmware revision */
enum sig_type sig_type; /* Partition table signature type */
union {
u32 mbr_sig; /* MBR integer signature */
efi_guid_t guid_sig; /* GPT GUID Signature */
};
unsigned long (*block_read)(struct blk_desc *block_dev,
lbaint_t start,
lbaint_t blkcnt,
void *buffer);
unsigned long (*block_write)(struct blk_desc *block_dev,
lbaint_t start,
lbaint_t blkcnt,
const void *buffer);
unsigned long (*block_erase)(struct blk_desc *block_dev,
lbaint_t start,
lbaint_t blkcnt);
void *priv; /* driver private struct pointer */
void *disk_priv;
};
extern struct blk_desc usb_dev_desc[6];
#endif

View File

@ -0,0 +1,228 @@
#include "usb_os_adapter.h"
void *kmem_cache_alloc(struct kmem_cache *obj, int flag)
{
(void)flag;
return pvPortMalloc(obj->sz);
}
void kmem_cache_free(struct kmem_cache *cachep, void *obj)
{
(void)cachep;
vPortFree(obj);
}
void kmem_cache_destroy(struct kmem_cache *cachep)
{
free(cachep);
}
static void *kmalloc_array(size_t n, size_t size, gfp_t flags)
{
void* ptr = NULL;
if (size != 0 && n > SIZE_MAX / size)
return NULL;
ptr = pvPortMalloc(n * size);
if (flags & __GFP_ZERO) {
memset(ptr, 0, n * size);
}
return ptr;
}
void *kcalloc(size_t n, size_t size, gfp_t flags)
{
return kmalloc_array(n, size, flags | __GFP_ZERO);
}
void *kmalloc(size_t size, int flags)
{
void *p;
p = pvPortMalloc(size);
if (flags & __GFP_ZERO)
memset(p, 0, size);
return p;
}
void *kzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
//struct device;
void *devm_kzalloc(struct device *dev, size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
void kfree(void* addr)
{
vPortFree(addr);
}
struct kmem_cache *get_mem(int element_sz)
{
struct kmem_cache *ret;
ret = pvPortMalloc(sizeof(struct kmem_cache));
ret->sz = element_sz;
return ret;
}
static unsigned long _find_next_bit(const unsigned long *addr1,
const unsigned long *addr2, unsigned long nbits,
unsigned long start, unsigned long invert)
{
unsigned long tmp;
if (unlikely(start >= nbits))
return nbits;
tmp = addr1[start / BITS_PER_LONG];
if (addr2)
tmp &= addr2[start / BITS_PER_LONG];
tmp ^= invert;
/* Handle 1st word. */
tmp &= BITMAP_FIRST_WORD_MASK(start);
start = round_down(start, BITS_PER_LONG);
while (!tmp) {
start += BITS_PER_LONG;
if (start >= nbits)
return nbits;
tmp = addr1[start / BITS_PER_LONG];
if (addr2)
tmp &= addr2[start / BITS_PER_LONG];
tmp ^= invert;
}
return min(start + __ffs(tmp), nbits);
}
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
unsigned long offset)
{
return _find_next_bit(addr, NULL, size, offset, 0UL);
}
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
unsigned long offset)
{
return _find_next_bit(addr, NULL, size, offset, ~0UL);
}
unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
unsigned long size,
unsigned long start,
unsigned int nr,
unsigned long align_mask,
unsigned long align_offset)
{
unsigned long index, end, i;
again:
index = find_next_zero_bit(map, size, start);
/* Align allocation */
index = __ALIGN_MASK(index + align_offset, align_mask) - align_offset;
end = index + nr;
if (end > size)
return end;
i = find_next_bit(map, end, index);
if (i < end) {
start = i + 1;
goto again;
}
return index;
}
unsigned long
bitmap_find_next_zero_area(unsigned long *map,
unsigned long size,
unsigned long start,
unsigned int nr,
unsigned long align_mask)
{
return bitmap_find_next_zero_area_off(map, size, start, nr, align_mask, 0);
}
void bitmap_set(unsigned long *map, unsigned int start, int len)
{
unsigned long *p = map + BIT_WORD(start);
const unsigned int size = start + len;
int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
while (len - bits_to_set >= 0) {
*p |= mask_to_set;
len -= bits_to_set;
bits_to_set = BITS_PER_LONG;
mask_to_set = ~0UL;
p++;
}
if (len) {
mask_to_set &= BITMAP_LAST_WORD_MASK(size);
*p |= mask_to_set;
}
}
void bitmap_clear(unsigned long *map, unsigned int start, int len)
{
unsigned long *p = map + BIT_WORD(start);
const unsigned int size = start + len;
int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
while (len - bits_to_clear >= 0) {
*p &= ~mask_to_clear;
len -= bits_to_clear;
bits_to_clear = BITS_PER_LONG;
mask_to_clear = ~0UL;
p++;
}
if (len) {
mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
*p &= ~mask_to_clear;
}
}
void writesl(u32 addr, const void *buffer, unsigned int count)
{
if (count) {
const u32 *buf = (u32 *)buffer;
do {
writel(*buf++, addr);
} while (--count);
}
}
void readsl(u32 addr, void *buffer, unsigned int count)
{
if (count) {
u32 *buf = (u32 *)buffer;
do {
u32 x = readl(addr);
*buf++ = x;
} while (--count);
}
}
void iowrite32_rep(u32 addr, const void *buffer, unsigned int count)
{
writesl(addr, buffer, count);
}
void ioread32_rep(u32 addr, void *buffer, unsigned int count)
{
readsl(addr, buffer, count);
}

View File

@ -0,0 +1,332 @@
#ifndef _USB_OS_ADAPTER_H
#define _USB_OS_ADAPTER_H
#include "os_adapt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define pr_err(...) TRACE_ERROR(__VA_ARGS__)
#define WARN_ON_ONCE(condition) WARN_ON(condition)
#define USB_UNUSED(x) ((void) x)
typedef INT8 __s8;
typedef UINT8 __u8;
typedef INT16 __s16;
typedef UINT16 __u16;
typedef INT32 __s32;
typedef UINT32 __u32;
typedef long long __s64;
typedef unsigned long long __u64;
typedef __u16 __le16;
typedef __u16 __be16;
//typedef __u32 __le32;
typedef __u32 __be32;
typedef __u64 __le64;
typedef __u64 __be64;
typedef unsigned long ulong;
typedef __u32 dev_t;
#define __cpu_to_le16(x) (x)
#define cpu_to_le16(x) (x)
#define __le16_to_cpu le16_to_cpu
#define get_unaligned(x) (*x)
void iowrite32_rep(u32 addr, const void *buffer, unsigned int count);
void ioread32_rep(u32 addr, void *buffer, unsigned int count);
unsigned long bitmap_find_next_zero_area(unsigned long *map,
unsigned long size,
unsigned long start,
unsigned int nr,
unsigned long align_mask);
void bitmap_set(unsigned long *map, unsigned int start, int len);
void bitmap_clear(unsigned long *map, unsigned int start, int len);
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(ListItem_t *item, List_t *list)
{
if (!listIS_CONTAINED_WITHIN(NULL, item))
uxListRemove(item);
vListInsertEnd(list, item);
}
static inline void list_del_init(ListItem_t *item)
{
if (!listIS_CONTAINED_WITHIN(NULL, item))//maybe item has removed from list
uxListRemove(item);
//vListInitialiseItem(item);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(ListItem_t *item, List_t *list)
{
vListInsertEnd(list, item);
}
static inline void INIT_LIST_HEAD(List_t *list)
{
vListInitialise(list);
}
static inline void INIT_LIST_ITEM(ListItem_t *item)
{
vListInitialiseItem(item);
}
#define list_for_each_entry_safe(pxListItem, nListItem, pvOwner, list) \
for (pxListItem = listGET_HEAD_ENTRY(list), \
nListItem = listGET_NEXT(pxListItem), \
pvOwner = listGET_LIST_ITEM_OWNER(pxListItem); \
pxListItem != listGET_END_MARKER(list); \
pxListItem = nListItem, \
nListItem = listGET_NEXT(pxListItem), \
pvOwner = listGET_LIST_ITEM_OWNER(pxListItem))
#define list_for_each_safe(pxListItem, nListItem, list) \
for (pxListItem = listGET_HEAD_ENTRY(list), \
nListItem = listGET_NEXT(pxListItem); \
pxListItem != listGET_END_MARKER(list); \
pxListItem = nListItem, \
nListItem = listGET_NEXT(pxListItem))
#define list_del(pxListItem) uxListRemove(pxListItem)
#define list_empty(pxList) listLIST_IS_EMPTY(pxList)
#define list_item_empty(pxListItem) ((pxListItem)->pxContainer == NULL)
#define __ARG_PLACEHOLDER_1 0,
#define config_enabled(cfg) _config_enabled(cfg)
#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
#define ___config_enabled(__ignored, val, ...) val
/*
* IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
* 0 otherwise.
*
*/
#define IS_ENABLED(option) \
(config_enabled(option) || config_enabled(option##_MODULE))
struct timer_list
{
int a;
};
struct unused {
int a;
};
typedef struct unused unused_t;
#define task_pid_nr(x) 0
#define set_freezable(...) do { } while (0)
#define try_to_freeze(...) 0
#define set_current_state(...) do { } while (0)
#define kthread_should_stop(...) 0
#define schedule() do { } while (0)
#define setup_timer(timer, func, data) do {} while (0)
#define del_timer_sync(timer) do {} while (0)
#define schedule_work(work) do {} while (0)
#define INIT_WORK(work, fun) do {} while (0)
#define local_irq_save(flag) do {(void)flag;} while (0)
#define local_irq_restore(flag) do {(void)flag;} while (0)
//#define local_irq_save(flag) do {portENTER_CRITICAL(); (void)flag;} while(0)
//#define local_irq_restore(flag) do {portEXIT_CRITICAL(); (void)flag;} while(0)
struct work_struct {
int a;
};
struct kmem_cache {
int sz;
};
typedef int wait_queue_head_t;
typedef struct {
volatile unsigned int slock;
} spinlock_t;
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
//TODO
unsigned volatile long y;
switch(size){
case 1:
y = (*(char *)ptr) & 0x000000ff;
*((char *)ptr) = (char)x;
break;
case 2:
y = (*(short *)ptr) & 0x0000ffff;
*((short *)ptr) = (short)x;
break;
default: // 4
y = (*(unsigned long *)ptr) & 0xffffffff;
*((unsigned long *)ptr) = x;
break;
}
return y;
}
#define ARCH_SPIN_LOCK_UNLOCKED 1
#define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) <= 0)
#define arch_spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
#define xchg(ptr,v) ((unsigned int)__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
#define __xg(x) ((volatile long *)(x))
static inline void _raw_spin_unlock(spinlock_t *lock)
{
xchg(&lock->slock, 1);
}
static inline int _raw_spin_trylock(spinlock_t *lock)
{
return xchg(&lock->slock, 0) != 0 ? 1 : 0;
}
static inline void _raw_spin_lock(spinlock_t *lock)
{
volatile int was_locked;
do {
was_locked = xchg(&lock->slock, 0) == 0 ? 1 : 0;
} while(was_locked);
}
#define SPINLOCK_MAGIC 0xdead4ead
#define SPIN_LOCK_UNLOCKED ARCH_SPIN_LOCK_UNLOCKED
#define spin_lock_init(x) do { (x)->slock = SPIN_LOCK_UNLOCKED; } while(0)
#define spin_is_locked(x) arch_spin_is_locked(x)
#define spin_unlock_wait(x) arch_spin_unlock_wait(x)
#define _spin_trylock(lock) ({_raw_spin_trylock(lock) ? \
1 : ({ 0;});})
#define _spin_lock(lock) \
do { \
_raw_spin_lock(lock); \
} while(0)
#define _spin_unlock(lock) \
do { \
_raw_spin_unlock(lock); \
} while (0)
#define spin_lock(lock) _spin_lock(lock)
#define spin_unlock(lock) _spin_unlock(lock)
#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
#define spin_lock_irqsave(lock, flags) \
do { \
flags = __get_interrupt_state(); __disable_irq(); \
} while (0)
#define spin_unlock_irqrestore(lock, flags) \
do { \
__set_interrupt_state(flags); \
} while (0)
#define assert_spin_locked(lock) do {} while (0)
#define irqreturn_t int
#define IRQ_NONE 0
#define IRQ_HANDLED 1
#define IRQ_WAKE_THREAD 2
#define GFP_ATOMIC ((gfp_t) 0)
#define GFP_KERNEL ((gfp_t) 0)
#define GFP_NOFS ((gfp_t) 0)
#define GFP_USER ((gfp_t) 0)
#define __GFP_NOWARN ((gfp_t) 0)
#define __GFP_ZERO ((gfp_t)0x8000u)
#define UINT_MAX (~0U)
void *kmem_cache_alloc(struct kmem_cache *obj, int flag);
void kmem_cache_free(struct kmem_cache *cachep, void *obj);
void kmem_cache_destroy(struct kmem_cache *cachep);
void *kcalloc(size_t n, size_t size, gfp_t flags);
void *kmalloc(size_t size, int flags);
void *kzalloc(size_t size, gfp_t flags);
void kfree(void* addr);
struct device;
void *devm_kzalloc(struct device *dev, size_t size, gfp_t flags);
struct kmem_cache *get_mem(int element_sz);
#define kmem_cache_create(a, sz, c, d, e) get_mem(sz)
#define min_t(type, x, y) (x < y ? x: y)
#define max_t(type, x, y) (x > y ? x: y)
#define msleep mdelay
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
#define __round_mask(x, y) ((unsigned long)((y)-1))
#define round_down(x, y) ((x) & ~(__round_mask((x), (y))))
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
//#define min(x,y) ((x) < (y) ? x : y)
#define max(x,y) ((x) > (y) ? x : y)
#define min3(x, y, z) min(min(x, y), z)
#define max3(x, y, z) max(max(x, y), z)
#define ROUND(a,b) (((a) + (b) - 1) & ~((b) - 1))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define ALIGN(x,a) __ALIGN_MASK((x),(uintptr_t)(a)-1)
//#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
//typedef unsigned long uintptr_t;
#define PAD_COUNT(s, pad) (((s) - 1) / (pad) + 1)
#define PAD_SIZE(s, pad) (PAD_COUNT(s, pad) * pad)
#define ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, pad) \
char __##name[ROUND(PAD_SIZE((size) * sizeof(type), pad), align) \
+ (align - 1)]; \
\
type *name = (type *)ALIGN((uintptr_t)__##name, align)
#define ALLOC_ALIGN_BUFFER(type, name, size, align) \
ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, 1)
#define ALLOC_CACHE_ALIGN_BUFFER_PAD(type, name, size, pad) \
ALLOC_ALIGN_BUFFER_PAD(type, name, size, ARCH_DMA_MINALIGN, pad)
#define ALLOC_CACHE_ALIGN_BUFFER(type, name, size) \
ALLOC_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
#define be32_to_cpu(x) ((uint32_t)( \
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
#define LOG2(x) (((x & 0xaaaaaaaa) ? 1 : 0) + ((x & 0xcccccccc) ? 2 : 0) + \
((x & 0xf0f0f0f0) ? 4 : 0) + ((x & 0xff00ff00) ? 8 : 0) + \
((x & 0xffff0000) ? 16 : 0))
#ifdef __cplusplus
}
#endif
#endif

142
A27-STEPLDR/Src/wdt.c Normal file
View File

@ -0,0 +1,142 @@
#include "amt630h.h"
#include "uart.h"
#define WTCON 0x00
#define WTPSR 0x04
#define WTCNT 0x08
#define WTCLRINT 0x10
#define WTRCR 0x14
#define WTCNT_MAXCNT 0xffff
#define WTCON_MAXDIV 0x80
#define WTCON_ENABLE (1 << 0)
#define WTCON_RSTEN (1 << 1)
#define WTCON_INTEN (1 << 2)
#define WTCON_DIV16 (0 << 4)
#define WTCON_DIV32 (1 << 4)
#define WTCON_DIV64 (2 << 4)
#define WTCON_DIV128 (3 << 4)
#define WTCON_DIVMASK (0x3 << 4)
#define WTCON_PRESCALE_MAX 0x10000
#define WATCHDOG_DEFAULT_TIME (3)
#define CLK_APB_FREQ 198000000
static int wdt_timeout = WATCHDOG_DEFAULT_TIME;
static int soft_noboot = 0; /* 1: not reboot when watchdog timer expired */
static int wdt_count;
static inline unsigned int wdt_max_timeout()
{
unsigned long freq = CLK_APB_FREQ;
return WTCNT_MAXCNT / (freq / WTCON_PRESCALE_MAX
/ WTCON_MAXDIV);
}
int wdt_set_heartbeat(unsigned int timeout)
{
unsigned long freq = CLK_APB_FREQ;
unsigned int count;
unsigned int divisor = 1;
if (timeout < 1 || timeout > wdt_max_timeout())
return -EINVAL;
freq = DIV_ROUND_UP(freq, 128);
count = timeout * freq;
/* TRACE_DEBUG("Heartbeat: count=%d, timeout=%d, freq=%lu\n",
count, timeout, freq); */
/* if the count is bigger than the watchdog register,
then work out what we need to do (and if) we can
actually make this value
*/
if (count >= 0x10000) {
divisor = DIV_ROUND_UP(count, 0xffff);
if (divisor > WTCON_PRESCALE_MAX) {
SendUartString("timeout too big\n");
return -EINVAL;
}
}
/* TRACE_DEBUG("Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n",
timeout, divisor, count, DIV_ROUND_UP(count, divisor)); */
count = DIV_ROUND_UP(count, divisor);
wdt_count = count;
/* update the pre-scaler */
writel(divisor - 1, WDT_BASE + WTPSR);
writel(count, WDT_BASE + WTCNT);
wdt_timeout = timeout;
return 0;
}
void wdt_stop(void)
{
unsigned long wtcon;
wtcon = readl(WDT_BASE + WTCON);
wtcon &= ~(WTCON_ENABLE | WTCON_RSTEN);
writel(wtcon, WDT_BASE + WTCON);
}
void wdt_start(void)
{
unsigned long wtcon;
wdt_stop();
wtcon = readl(WDT_BASE + WTCON);
wtcon &= ~WTCON_DIVMASK;
wtcon |= WTCON_ENABLE | WTCON_DIV128;
if (soft_noboot) {
wtcon |= WTCON_INTEN;
wtcon &= ~WTCON_RSTEN;
} else {
wtcon &= ~WTCON_INTEN;
wtcon |= WTCON_RSTEN;
}
/* TRACE_DEBUG("Starting watchdog: count=0x%08x, wtcon=%08lx\n",
wdt_count, wtcon); */
writel(wdt_count, WDT_BASE + WTCNT);
writel(wtcon, WDT_BASE + WTCON);
}
int wdt_init(void)
{
int ret;
wdt_stop();
ret = wdt_set_heartbeat(wdt_timeout);
if (ret) {
SendUartString("failed to set timeout value\n");
}
wdt_start();
return 0;
}
void wdt_cpu_reboot(void)
{
SendUartString("cpu reboot...\n");
soft_noboot = 0;
wdt_count = 300;
wdt_start();
while(1);
}