2009年2月13日 星期五

Linux USB & S3C24xx USB

Linux 2.6.27.4


arch/arm/mach-s3c2400/include/mach/map.h:17:#define S3C2400_PA_USBHOST (0x14200000)
arch/arm/mach-s3c2400/include/mach/map.h:53:#define S3C24XX_PA_USBHOST S3C2400_PA_USBHOST

arch/arm/mach-s3c2410/include/mach/map.h:33:#define S3C2410_PA_USBHOST (0x49000000)
arch/arm/mach-s3c2410/include/mach/map.h:34:#define S3C24XX_SZ_USBHOST SZ_1M
arch/arm/mach-s3c2410/include/mach/map.h:147:#define S3C24XX_PA_USBHOST S3C2410_PA_USBHOST

arch/arm/plat-s3c24xx/devs.c
static struct resource s3c_usb_resource[] = {
[0] = {
.start = S3C24XX_PA_USBHOST,
.end = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_USBH,
.end = IRQ_USBH,
.flags = IORESOURCE_IRQ,
}
};

static u64 s3c_device_usb_dmamask = 0xffffffffUL;

struct platform_device s3c_device_usb = {
.name = "s3c2410-ohci",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_usb_resource),
.resource = s3c_usb_resource,
.dev = {
.dma_mask = &s3c_device_usb_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};


arch/arm/mach-s3c2410/mach-smdk2410.c:89
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};

arch/arm/mach-s3c2440/mach-smdk2440.c:170: platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));


arch/arm/configs/s3c2410_defconfig:168:CONFIG_MACH_SMDK=y
arch/arm/configs/s3c2410_defconfig:200:CONFIG_ARCH_SMDK2410=y
CONFIG_ARCH_S3C2410=y
CONFIG_PLAT_S3C24XX=y
CONFIG_CPU_S3C244X=y
CONFIG_PM_SIMTEC=y
CONFIG_MACH_SMDK=y
CONFIG_PLAT_S3C=y
CONFIG_USB_OHCI_HCD=y


drivers/usb/host/Makefile
obj-$(CONFIG_USB_OHCI_HCD)      += ohci-hcd.o


./drivers/usb/host/ohci-hcd.c:1004:#include "ohci-s3c2410.c"
#ifdef CONFIG_ARCH_S3C2410
#include "ohci-s3c2410.c"
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif


drivers/usb/host/ohci-s3c2410.c:499: .name = "s3c2410-ohci",
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-ohci",
},
};


drivers/usb/host/ohci-hcd.c:1117
#ifdef PLATFORM_DRIVER
retval = platform_driver_register(&PLATFORM_DRIVER);
if (retval < 0)
goto error_platform;
#endif



EHCI/OHCI registers are defined by structure instead of macros.

drivers/usb/host/ohci.h
/*
* This is the structure of the OHCI controller's memory mapped I/O region.
* You must use readl() and writel() (in <asm/io.h>) to access these fields!!
* Layout is in section 7 (and appendix B) of the spec.
*/
struct ohci_regs {
/* control and status registers (section 7.1) */
__hc32 revision;
__hc32 control;
__hc32 cmdstatus;
__hc32 intrstatus;
__hc32 intrenable;
__hc32 intrdisable;

/* memory pointers (section 7.2) */
__hc32 hcca;
__hc32 ed_periodcurrent;
__hc32 ed_controlhead;
__hc32 ed_controlcurrent;
__hc32 ed_bulkhead;
__hc32 ed_bulkcurrent;
__hc32 donehead;

/* frame counters (section 7.3) */
__hc32 fminterval;
__hc32 fmremaining;
__hc32 fmnumber;
__hc32 periodicstart;
__hc32 lsthresh;

/* Root hub ports (section 7.4) */
struct ohci_roothub_regs {
__hc32 a;
__hc32 b;
__hc32 status;
#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports (RH_A_NDP) */
__hc32 portstatus [MAX_ROOT_PORTS];
} roothub;

/* and optional "legacy support" registers (appendix B) at 0x0100 */

} __attribute__ ((aligned(32)));



drivers/usb/host/ehci.h
/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */

/* Section 2.2 Host Controller Capability Registers */
struct ehci_caps {
/* these fields are specified as 8 and 16 bit registers,
* but some hosts can't perform 8 or 16 bit PCI accesses.
*/
u32 hc_capbase;
#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
u32 hcs_params; /* HCSPARAMS - offset 0x4 */
#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */

u32 hcc_params; /* HCCPARAMS - offset 0x8 */
#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
u8 portroute [8]; /* nibbles for routing - offset 0xC */
} __attribute__ ((packed));



An Overview of Linux USB
http://www.linuxjournal.com/node/8093/print

13 則留言:

大頭鰱 提到...

你好
我有急事一問,這一篇文章就是 2410 的USB Host porting 方法嗎?

如果我按照這樣去porting 的話,可以嗎?
因為我們公司有自己的IP ,我要以2410 為sample 去porting 後,在去修改我們的IP設定,可以嗎?
謝謝
救救我吧!
my msn : tzeng0152002@hotmail.com

mkl 提到...

這只是我trace code的紀錄
但是的確是可以的
只要確定該IP為EHCI/OHCI相容的controller
可參考drivers/usb/host/ehci-*.c and drivers/usb/host/ohci-*.c

大頭鰱 提到...

你好
謝謝你的答案,我已經對應相關的地方要到我們的[platform] 去。你建議我說,找一個/host/ohci-*.c去參考,
我參考的就是這個ohci-s3c2410.c再去修改,成跟我們platform IP 相關的register.

可是我稍微看一下我們IP的 register 和再去對照 2410 的,發覺關於 OHCI 的register 幾乎所有名稱都一樣,只有下面這個的位置不一樣
:#define S3C2410_PA_USBHOST (0x49000000)

我得作法是想說把S3C2410_PA_USBHOST 這個address 去改成我們IP的位置,這樣應該可以跟上面kernel 接合的起來才是。
你說呢?

再來就是我去trace ohci-s3c2410.c時發現[不到]跟硬體有關的設定等等,
http://blog.udn.com/Howl0730/2855599

上面那個blog 說 [s3c2410_hcd_info *info 呼叫power_control這個成員,對應到usb-simtec.c這個檔案]

我看一下code,發覺號像是跟GPIO有關,我仔細看一下發覺 ohci-s3c2410.c裡面好像都在弄GPIO的東西,我感不到解!

你有建議嗎?

我除了按照你網頁上面把2410 porting 上去外,ohci-s3c2410.c裡面的東西,你有tarce過嗎?我有以上問題想跟你請教
方便嗎?
thank you

mkl 提到...

EHCI/OHCI 是一個標準介面
所有ehci/ohci compatible 的 controller都要有同樣的register definition.
因此大部分的driver都是共用的,如ehci-hcd.c.
你可以找找他們的spec

當然各個controller也都有自己不同的地方
這些不同處則主要是在ehci-XXXX.c裡面
只須參考其架構,細節則應該是你們的IP特有的
以s3c2410來說,可能是它線路上使用gpio(or function ping shared with gpio pin) 來設定這個IP. 這在其他chip上通常不適用

所以你不需要找那麼複雜的,找最簡單、最短的開始即可

大頭鰱 提到...

不好意思!在請教你一下,因為我是參考 2410 的 去實現到我們platform 的OHCI。

但是我在EHCI 那邊就沒看到囉!
你得解說裡
arch/arm/plat-s3c24xx/devs.c

這裡面的東西,應該是 OHCI and EHCI 共用是嗎?
謝謝你

mkl 提到...

看起來2410的確沒有ehci driver

通常在arch下會定義platform_device, irq, register...etc

雖然都在一個檔案裡,但ohci與ehci各有不同的irq與register設定

大頭鰱 提到...

你好
我後來把你網頁所提及的部分, 依樣畫葫蘆, 其實我發覺, 整個 ohci-s3c2410.c 裡面sample, 最重要的跟我 platform 不一樣的設定是 , PLL 要設定和 USB reset 等等.

但是下面你講的這些,我就感到好奇, 因為那個 0x49000000, 我有去看 2410 OHCI 的一部分的 registers, 沒錯是 0x49000000, 後面就跟著一群 OHCI 的 register. 所以我在porting 時, 我就改那個地方改為我們 IP 的設定. 我比較不解的事
他怎樣跟整個 OHCI 接起來

arch/arm/mach-s3c2410/include/mach/map.h:33:#define S3C2410_PA_USBHOST (0x49000000)
arch/arm/mach-s3c2410/include/mach/map.h:34:#define S3C24XX_SZ_USBHOST SZ_1M
arch/arm/mach-s3c2410/include/mach/map.h:147:#define S3C24XX_PA_USBHOST S3C2410_PA_USBHOST


struct ohci_regs 裡面的 registers 怎樣知道base address 是 0x49000000, 這一點我還是不解, 正在努力, 你可以分享給我嗎?
謝謝你大力幫忙

mkl 提到...

請參照本文的code
map.h定義ohci的address
devs.c定義platform_device與其resource, resource 指定 irq 與 address

ohci 是一個platform_driver, 發現有相對應的platform_device
則request 它的 resource以得到irq與address

大頭鰱 提到...

你好!
謝謝你的幫忙˙我已經可以porting 到我們的platform 去了,插拔都可以有訊息出來!

偶而會當機,這個我後續再找!

不過我有一個問題請教你, 你後來是怎做測試, 我現在[隨身碟]插到我們的 platform 去後有認到後, 但是好像要去insmod usb-storage.ko 等等.

我在我們的platform make menuconfig 裡面看不到 USB Mass Storage 的選項焊 SCSI driver 的選項, 所以請問你是如何測試的呢?
謝謝

mkl 提到...

你可以可以把那些driver都build in就不用insert了

大頭鰱 提到...

我在我們的platform make menuconfig 裡面看不到 USB Mass Storage 的選項焊 SCSI driver 的選項???

大頭鰱 提到...

你好
又一個問題在請教你一下!我後來有找到 SCSI 的選項build 進去.

# cd lib
# ls
usb-storage.ko
ar6000.ko
# insmod usb-storage.ko
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
# usb 1-1: new full speed USB device using im98_s3c2410-ohci and address 2
usb 1-1: configuration #1 chosen from 1 choice
scsi0 : SCSI emulation for USB Mass Storage devices
scsi 0:0:0:0: Direct-Access USB 2.0 SD MMC Reader PQ: 0 ANSI: 0 CCS
sd 0:0:0:0: Attached scsi generic sg0 type 0
sd 0:0:0:0: [sda] 3862528 512-byte logical blocks: (1.97 GB/1.84 GiB)
sd 0:0:0:0: [sda] Write Protect is off
sd 0:0:0:0: [sda] Assuming drive cache: write through
sd 0:0:0:0: [sda] Assuming drive cache: write through
sda: sda1
sd 0:0:0:0: [sda] Assuming drive cache: write through
sd 0:0:0:0: [sda] Attached SCSI removable disk
#

上面是我把隨身碟插進去我們的platform 的狀況, 看一下狀況, 應該事都對! 我隨身碟裡面的 T-flash是大約2G. 所以訊息都對!

我有找到 隨身碟我們platform 那邊的
/dev/block/sda1

# cd dev
# cd block
# ls
sda1
sda
vold
mtdblock8
mtdblock7
mtdblock6
mtdblock5
mtdblock4
mtdblock3
mtdblock2
mtdblock1
mtdblock0
loop7
loop6
loop5
loop4
loop3
loop2
loop1
loop0
# cat /proc/partitions
major minor #blocks name

31 0 2048 mtdblock0
31 1 4096 mtdblock1
31 2 2048 mtdblock2
31 3 3072 mtdblock3
31 4 3072 mtdblock4
31 5 131072 mtdblock5
31 6 327680 mtdblock6
31 7 49152 mtdblock7
31 8 2048 mtdblock8
8 0 1931264 sda
8 1 1929244 sda1
# pwd
/dev/block


我現在把 sda1 掛載在 /data/tmp/usb 這個目錄時

# mount -t fat /dev/block/sda1 /data/tmp/usb
mount: No such device

出現找不到device, 我就不知道該如何, 不過我判斷我 mount 不到的話, 應該是跟 block driver或是 SD driver 有關, 跟我的usb host 就比較沒關西, 你覺得呢?

大頭鰱 提到...

你好!
我之前問的問題陸陸續續我都得到解答!我有一件事想請問你一下!

我按照2410 的 OHCI 移植到我們platform 去!是可以的!
但是我在找一個範例,ehci 的!ehci-XXXX.c
我發覺即使我在make menuconfig 裡面把 ehci 選進去,我所指定的那一個 ehci-XXXX.c,怎樣都跑不到裡面去ㄟ!

我一開機有去印訊息但是都沒有裡面的訊息,可是我compiler 時!我有確定有加進去,你有類似經驗嗎?
謝謝