idea6410开发手册中提到使用usb-host功能必须将无源晶振改为48MHz有源晶振,最近看了一下,使用OHCI兼容的USB-Host功能,可以通过EPLL提供时钟,也就是说外接晶振完全无用。果然,经过一晚的奋斗,USB-HOST功能搞定,记录一下过程。
(1)首先看了S3C6410的数据手册,25章USB-HOST就薄薄两页,和S3C2410基本一样,大意是你去参考OHCI手册吧。
这说明S3C6410的USB基本上是做好的,兼容OHCI,不需要我们做太多修改。
(2)修改内核,添加USB支持,添加OHCI HOST HCD支持,添加U盘等支持。发现以前写的帖子还蛮管用的:
http://hi.baidu.com/aokikyon/blog/item/8545893e3a8a6ffc838b1307.html
还得修改/drivers/usb/kconfig
添加config USB_ARCH_HAS_OHCI对S3C64XX的支持
default y if ARCH_S3C64XX
(3)选择完毕,开始编译,发现以下问题:
CC drivers/usb/host/ohci-hcd.o
drivers/usb/host/ohci-hcd.c:1091:2: error: #error "missing bus glue for ohci-hcd"
make[3]: *** [drivers/usb/host/ohci-hcd.o] 错误 1
make[2]: *** [drivers/usb/host] 错误 2
make[1]: *** [drivers/usb] 错误 2
make: *** [drivers] 错误 2
看了一下OHCI文件,发现要想三星芯片使用,需要包含ohci-s3c2410.c文件,如果没哟包含这个文件,就会提示找不到hcd的以上错误。
这段代码在ohci-hcd.c中是这样定义的
#ifdef CONFIG_ARCH_S3C2410
#include "ohci-s3c2410.c"
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
由于我们使用的是S3C6410,并没有CONFIG_ARCH_S3C2410,手动修改一下好了:
#ifdef CONFIG_ARCH_S3C64XX
#include "ohci-s3c2410.c"
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
(4)编译完毕后完全没有反应,参考2.6.24代码,发现需要添加platform-device注册信息:
/plat-s3c64xx/devs.c
/* USB Host Controller */
static struct resource s3c_usb_resource[] = {
[0] = {
.start = S3C24XX_PA_USBHOST,
.end = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
.flags = IORESOURCE_MEM,
},
#if !defined(CONFIG_CPU_S3C6400) && !defined(CONFIG_CPU_S3C6410)
[1] = {
.start = IRQ_USBH,
.end = IRQ_USBH,
.flags = IORESOURCE_IRQ,
}
#else
[1] = {
.start = IRQ_UHOST,
.end = IRQ_UHOST,
.flags = IORESOURCE_IRQ,
}
#endif
};
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
}
};
EXPORT_SYMBOL(s3c_device_usb);
编译后还是发现错误,S3C24XX_PA_USBHOST、S3C24XX_PA_USBHOST、IRQ_USBH都没有定义。
查找半天后发现HOST的物理地址0x74300000没有定义,手动填入这个地址好了。
SIZE大概写一个尺寸,比如1K就可以(实际上用到很少)。
至于中断号,开始我填了中断控制器中的位置47,可惜不对,后来发现头文件中有定义,填IRQ_USBH.
一下是修改后代码:
/* USB Host Controller add by rockie */
static struct resource s3c_usb_resource[] = {
[0] = {
.start = 0x74300000,//S3C24XX_PA_USBHOST,
.end = 0x74301000,//S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_USBH,//IRQ_UHOST,
.end = IRQ_USBH,//IRQ_UHOST,
.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
}
};
EXPORT_SYMBOL(s3c_device_usb);
还需要注册进平台设备:
/mach-smdk6410/mach-s3c6410.c添加
static struct platform_device *smdk6410_devices[] __initdata = {
...
&s3c_device_usb, //<——添加这句即可
...
}
(5)编译完毕,初始化怎么还是错误?
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 79, io mem 0x74300000
s3c2410-ohci s3c2410-ohci: init err (00000000 0000)
ohci_hcd: can't start s3c24xx
s3c2410-ohci s3c2410-ohci: startup error -75
s3c2410-ohci s3c2410-ohci: USB bus 1 deregistered
s3c2410-ohci: probe of s3c2410-ohci failed with error -75
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
原来还要完成初始化时钟的函数:
/mach-smdk6410/mach-s3c6410.c
#if defined(CONFIG_USB_GADGET_S3C_OTGD) || defined(CONFIG_USB_OHCI_HCD)
#include <plat/regs-otg.h>
#include <linux/usb/ch9.h>
#endif
/*************************************************************************************
* USB HOST
**************************************************************************************/
#ifdef CONFIG_USB_OHCI_HCD
void usb_host_clk_en(int usb_host_clksrc)
{
printk("Usb Host CLK enable! 2009 by Rockie /n");
switch (usb_host_clksrc)
{
case 0: // epll clk
writel((readl(S3C_CLK_SRC)& ~S3C_CLKSRC_UHOST_MASK) | S3C_CLKSRC_EPLL_CLKSEL | S3C_CLKSRC_UHOST_EPLL, S3C_CLK_SRC);
// USB host colock divider ratio is 2 /
//writel((readl(S3C_CLK_DIV1)& ~S3C_CLKDIVN_UHOST_MASK) | S3C_CLKDIV1_USBDIV2, S3C_CLK_DIV1);
*(volatile unsigned long*) S3C_CLK_DIV1 |= (0<<20);
break;
case 1: // oscillator 48M clk /
writel(readl(S3C_CLK_SRC)& ~S3C_CLKSRC_UHOST_MASK, S3C_CLK_SRC);
//otg_phy_init(otg_phy_clk);
// USB host colock divider ratio is 1 /
//writel(readl(S3C_CLK_DIV1)& ~S3C_CLKDIVN_UHOST_MASK, S3C_CLK_DIV1);
*(volatile unsigned long*) S3C_CLK_DIV1 |= (0<<20);
break;
default:
printk(KERN_INFO "Unknown USB Host Clock Source/n");
BUG();
break;
}
writel(readl(S3C_HCLK_GATE)|S3C_CLKCON_HCLK_UHOST|S3C_CLKCON_HCLK_SECUR, S3C_HCLK_GATE);
writel(readl(S3C_SCLK_GATE)|S3C_CLKCON_SCLK_UHOST, S3C_SCLK_GATE);
}
EXPORT_SYMBOL(usb_host_clk_en);
#endif
最后别忘了初始化时调用这个函数(在smdk6410_machine_init函数中调用,用前需声明):
usb_host_clk_en(0);
最好用宏圈住
#ifdef CONFIG_USB_OHCI_HCD
usb_host_clk_en(0);
#endif
(6)初始化通过
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 79, io mem 0x74300000
usb usb1: New USB device found, idVendor=1d6b, idProduct=0001
usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: S3C24XX OHCI
usb usb1: Manufacturer: Linux 2.6.29 ohci_hcd
usb usb1: SerialNumber: s3c24xx
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
但是插上U盘提示错误:
/ # usb 1-1: new full speed USB device using s3c2410-ohci and address 2
usb 1-1: device descriptor read/64, error -62
usb 1-1: device descriptor read/64, error -62
usb 1-1: new full speed USB device using s3c2410-ohci and address 3
usb 1-1: device descriptor read/64, error -62
usb 1-1: device descriptor read/64, error -62
usb 1-1: new full speed USB device using s3c2410-ohci and address 4
usb 1-1: device not accepting address 4, error -62
usb 1-1: new full speed USB device using s3c2410-ohci and address 5
usb 1-1: device not accepting address 5, error -62
hub 1-0:1.0: unable to enumerate USB device on port 1
怎么回事呢?原来EPLL初始化时只有24MHz,怎么分频也到不了48MHz啊!
S3C24XX Clocks, (c) 2004 Simtec Electronics
S3C64XX: PLL settings, A=666000000, M=532000000, E=24000000
S3C64XX: HCLK2=266000000, HCLK=133000000, PCLK=66500000
mout_apll: source is fout_apll (1), rate is 666000000
mout_epll: source is fout_epll (1), rate is 24000000
mout_mpll: source is mpll (1), rate is 532000000
mmc_bus: source is mout_epll (0), rate is 24000000
mmc_bus: source is mout_epll (0), rate is 24000000
mmc_bus: source is mout_epll (0), rate is 24000000
usb-bus-host: source is clk_48m (0), rate is 48000000
uclk1: source is dout_mpll (1), rate is 66500000
spi-bus: source is mout_epll (0), rate is 24000000
spi-bus: source is mout_epll (0), rate is 24000000
audio-bus: source is mout_epll (0), rate is 24000000
audio-bus: source is mout_epll (0), rate is 24000000
irda-bus: source is mout_epll (0), rate is 24000000
在Linux内核里尝试修改EPLL_CON0,M=0x20 P=1 S=3,计算出32*12MHz/(2^3)=48MHz
可是Linux中总是写这个寄存器不成功,最后怒了,直接修改U-boot,从汇编了改了回来。
在board/samsung/smdk6410/lowlevel_init.S(这里是编译u-boot-nand的源码)中有用到
ldr r1, =APLL_VAL
str r1, [r0, #APLL_CON_OFFSET] //这里写APLL_CON寄存器
ldr r1, =MPLL_VAL
str r1, [r0, #MPLL_CON_OFFSET] //这里写MPLL_CON寄存器
ldr r1, =0x80200203 /* FOUT of EPLL is 96MHz */
str r1, [r0, #EPLL_CON0_OFFSET]
ldr r1, =0x0
str r1, [r0, #EPLL_CON1_OFFSET]
ldr r1, [r0, #CLK_SRC_OFFSET] /* APLL, MPLL, EPLL select to Fout */
看这段,注释EPLL是96MHz,实际这样配置只有24MHz。
ldr r1, =0x80200203 /* FOUT of EPLL is 24MHz */
修改为
ldr r1, =0x80200103 /* FOUT of EPLL is 48MHz */
s3c6410支持三个PLL分别是APLL,MPLL和EPLL。APLL为ARM提供时钟,产生ARMCLK,MPLL为所有和AXI/AHB/APB相连的模块提供时钟,产生HCLK和PCLK,EPLL为特殊的外设提供时钟,产生SCLK。详见S3C6410处理器介绍
(7)编译,通过。
S3C24XX Clocks, (c) 2004 Simtec Electronics
S3C64XX: PLL settings, A=666000000, M=532000000, E=48000000
S3C64XX: HCLK2=266000000, HCLK=133000000, PCLK=66500000
mout_apll: source is fout_apll (1), rate is 666000000
mout_epll: source is fout_epll (1), rate is 48000000
mout_mpll: source is mpll (1), rate is 532000000
mmc_bus: source is mout_epll (0), rate is 48000000
mmc_bus: source is mout_epll (0), rate is 48000000
mmc_bus: source is mout_epll (0), rate is 48000000
usb-bus-host: source is clk_48m (0), rate is 48000000
uclk1: source is dout_mpll (1), rate is 66500000
spi-bus: source is mout_epll (0), rate is 48000000
spi-bus: source is mout_epll (0), rate is 48000000
audio-bus: source is mout_epll (0), rate is 48000000
audio-bus: source is mout_epll (0), rate is 48000000
irda-bus: source is mout_epll (0), rate is 48000000
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 79, io mem 0x74300000
usb usb1: New USB device found, idVendor=1d6b, idProduct=0001
usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: S3C24XX OHCI
usb usb1: Manufacturer: Linux 2.6.29 ohci_hcd
usb usb1: SerialNumber: s3c24xx
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
Initializing USB Mass Storage driver...
至此USB-HOST功能可以正常使用:
/ # usb 1-1: new full speed USB device using s3c2410-ohci and address 2
usb 1-1: New USB device found, idVendor=1976, idProduct=1307
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: USB Reader
usb 1-1: Manufacturer: ChipsBnk
usb 1-1: SerialNumber: 110074973765
usb 1-1: configuration #1 chosen from 1 choice
uba: unknown partition table
/ # mount -t vfat /dev/uba1 /mnt
/ # cd mnt
/mnt # ls
4020 NorFlash_bootloader
??
?????
??????
??ACM????200?
?tcp ip?????? ????????????(???????).pdf
ARMKiller???????????.doc
Jlink Driver
TCPIP list
elf
elf2
elf3
elf5
elf6
elf7
ieka
linux-2.6.28.tar.bz2
modsile
reserve_mmu
test_sdram.elf
xme30.zip
/mnt # cd ..
/ # umount /mnt
/ # usb 1-1: USB disconnect, address 2
接下来调试VIAUSBMODEM,除了修改VIAUSBModem.c和VIAUSBModem.h两个文件外还需要修改:
/driver/usb/serial/kconfig
/driver/usb/serial/makefile两个文件