之前写了那么多关于系统时钟的机制,说到底,就那么回事,初始化系统时钟,初始化软中断,
以及初始化那个tvec_base,就这些,其他的也没有什么了,这篇主要关于每个外部设备的时钟的初始化,及获取。
首先贴上源码
arch/arm/mach-s3c64xx/mach-smdk6410.c
1145 MACHINE_START(SMDK6410, "SMDK6410")
1146 /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
1147 //.phys_io = S3C_PA_UART & 0xfff00000,
1148 //.io_pg_offst = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
1149 .boot_params = S3C64XX_PA_SDRAM + 0x100,
1150
1151 .init_irq = s3c6410_init_irq,
1152 .map_io = smdk6410_map_io,
1153 .init_machine = smdk6410_machine_init,
1154 .timer = &s3c24xx_timer,
1155 MACHINE_END
1053 static void __init smdk6410_map_io(void)
1054 {
1055 u32 tmp;
1056
1057 s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc));
1058 s3c24xx_init_clocks(12000000);
1059 s3c24xx_init_uarts(smdk6410_uartcfgs, ARRAY_SIZE(smdk6410_uartcfgs));
1060
1061 /* set the LCD type */
1062
1063 tmp = __raw_readl(S3C64XX_SPCON);
1064 tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
1065 tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
1066 __raw_writel(tmp, S3C64XX_SPCON);
1067
1068 /* remove the lcd bypass */
1069 tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
1070 tmp &= ~MIFPCON_LCD_BYPASS;
1071 __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
1072
1073 #ifdef CONFIG_VIDEO_SAMSUNG
1074 s3c64xx_reserve_bootmem();
1075 #endif
1076 }
void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
{
unsigned long idcode;
/* initialise the io descriptors we need for initialisation */
iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); //完成地址的虚实转换
iotable_init(mach_desc, size); //完成物理地址到虚拟地址的映射
idcode = __raw_readl(S3C_VA_SYS + 0x118); //读出本MCU的ID
if (!idcode) {
/* S3C6400 has the ID register in a different place,
* and needs a write before it can be read. */
__raw_writel(0x0, S3C_VA_SYS + 0xA1C);
idcode = __raw_readl(S3C_VA_SYS + 0xA1C);
}
s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids)); //根据之前读出的ID对CPU进行初始化
}
#define UART_OFFS (S3C_PA_UART & 0xfffff)
static struct map_desc s3c_iodesc[] __initdata = {
{
.virtual = (unsigned long)S3C_VA_SYS,
.pfn = __phys_to_pfn(S3C64XX_PA_SYSCON),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S3C_VA_MEM,
.pfn = __phys_to_pfn(S3C64XX_PA_SROM),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)(S3C_VA_UART + UART_OFFS),
.pfn = __phys_to_pfn(S3C_PA_UART),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)VA_VIC0,
.pfn = __phys_to_pfn(S3C64XX_PA_VIC0),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)VA_VIC1,
.pfn = __phys_to_pfn(S3C64XX_PA_VIC1),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S3C_VA_TIMER,
.pfn = __phys_to_pfn(S3C_PA_TIMER),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S3C64XX_VA_GPIO,
.pfn = __phys_to_pfn(S3C64XX_PA_GPIO),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S3C64XX_VA_MODEM,
.pfn = __phys_to_pfn(S3C64XX_PA_MODEM),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S3C_VA_WATCHDOG,
.pfn = __phys_to_pfn(S3C64XX_PA_WATCHDOG),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S3C_VA_USB_HSPHY,
.pfn = __phys_to_pfn(S3C64XX_PA_USB_HSPHY),
.length = SZ_1K,
.type = MT_DEVICE,
},
};
arch/arm/mach-s3c64xx/mach-smdk6410.c
529 static struct map_desc smdk6410_iodesc[] = {
530 {
531 /* LCD support */
532 .virtual = (unsigned long)S3C_VA_LCD,
533 .pfn = __phys_to_pfn(S3C_PA_FB),
534 .length = SZ_16K,
535 .type = MT_DEVICE,
536 },
537 };
arch/arm/mach-s3c64xx/cpu.c
static struct cpu_table cpu_ids[] __initdata = {
{
.idcode = 0x36400000,
.idmask = 0xfffff000,
.map_io = s3c6400_map_io,
.init_clocks = s3c6400_init_clocks,
.init_uarts = s3c6400_init_uarts,
.init = s3c6400_init,
.name = name_s3c6400,
}, {
.idcode = 0x36410100,
.idmask = 0xffffff00,
.map_io = s3c6410_map_io, //这里有点搞不清,最后为什么要调用
.init_clocks = s3c6410_init_clocks, //初始化外设时钟
.init_uarts = s3c6410_init_uarts,
.init = s3c6410_init,
.name = name_s3c6410,
},
};
arch/arm/plat-samsung/init.c
void __init s3c_init_cpu(unsigned long idcode,
struct cpu_table *cputab, unsigned int cputab_size)
{
cpu = s3c_lookup_cpu(idcode, cputab, cputab_size); //寻找与本CPU相同ID的那个玩意
if (cpu == NULL) {
printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
panic("Unknown S3C24XX CPU");
}
printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
if (cpu->map_io == NULL || cpu->init == NULL) {
printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
panic("Unsupported Samsung CPU");
}
cpu->map_io(); //这里的东西不是很明白,之前已经调用了map_io.完成了IO口的映射,可这里搞的这玩意,是不清楚了
}
arch/arm/mach-s3c64xx/s3c6410.c
void __init s3c6410_map_io(void)
{
/* initialise device information early */
s3c6410_default_sdhci0();
s3c6410_default_sdhci1();
s3c6410_default_sdhci2();
/* the i2c devices are directly compatible with s3c2440 */
s3c_i2c0_setname("s3c2440-i2c");
s3c_i2c1_setname("s3c2440-i2c");
s3c_adc_setname("s3c64xx-adc");
s3c_device_nand.name = "s3c6410-nand"; // gjl s3c6400-nand
s3c_onenand_setname("s3c6410-onenand");
s3c64xx_onenand1_setname("s3c6410-onenand");
s3c_cfcon_setname("s3c64xx-pata");
}
上面的不是很清楚,希望有懂得人,指点一下,接下来看看他的s3c24xx_init_clocks
1053 static void __init smdk6410_map_io(void)
1054 {
1055 u32 tmp;
1056
1057 s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc)); //找到了和本MCU匹配的cpu列表,然后将寄存器地址进行了重新映射
1058 s3c24xx_init_clocks(12000000);
1059 s3c24xx_init_uarts(smdk6410_uartcfgs, ARRAY_SIZE(smdk6410_uartcfgs));
1060
1061 /* set the LCD type */
1062
...............................................................................................................................................................
}
arch/arm/plat-samsung/init.c
void __init s3c24xx_init_clocks(int xtal)
{
if (xtal == 0)
xtal = 12*1000*1000;
if (cpu == NULL)
panic("s3c24xx_init_clocks: no cpu setup?\n");
if (cpu->init_clocks == NULL)
panic("s3c24xx_init_clocks: cpu has no clock init\n");
else
(cpu->init_clocks)(xtal); //这里调用的就是下面的s3c6410_init_clocks,在之前的map_io里有一个函数,找到与本地MCU匹配的cpu
}
arch/arm/mach-s3c64xx/s3c6410.c
void __init s3c6410_init_clocks(int xtal)
{
printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
s3c64xx_register_clocks(xtal, S3C6410_CLKDIV0_ARM_MASK);
s3c6400_setup_clocks();
}
arch/arm/mach-s3c64xx/clock.c
void __init s3c64xx_register_clocks(unsigned long xtal,
unsigned armclk_divlimit)
{
struct clk *clkp;
int ret;
int ptr;
armclk_mask = armclk_divlimit;
s3c24xx_register_baseclocks(xtal); //注册主要的时钟,例如HCLK PCLK, MPLL ,DPLL等等
s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); //注册了时钟部分
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); //注册了时钟部分
clkp = init_clocks_disable;
for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
ret = s3c24xx_register_clock(clkp);
if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
clkp->name, ret);
}
(clkp->enable)(clkp, 0);
}
s3c24xx_register_clocks(clks1, ARRAY_SIZE(clks1));
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_pwmclk_init();
}
arch/arm/plat-samsung/clock.c
int __init s3c24xx_register_baseclocks(unsigned long xtal)
{
printk(KERN_INFO "S3C24XX Clocks, Copyright 2004 Simtec Electronics\n");
clk_xtal.rate = xtal;
/* register our clocks */
if (s3c24xx_register_clock(&clk_xtal) < 0)
printk(KERN_ERR "failed to register master xtal\n");
if (s3c24xx_register_clock(&clk_mpll) < 0)
printk(KERN_ERR "failed to register mpll clock\n");
if (s3c24xx_register_clock(&clk_upll) < 0)
printk(KERN_ERR "failed to register upll clock\n");
if (s3c24xx_register_clock(&clk_f) < 0)
printk(KERN_ERR "failed to register cpu fclk\n");
if (s3c24xx_register_clock(&clk_h) < 0)
printk(KERN_ERR "failed to register cpu hclk\n");
if (s3c24xx_register_clock(&clk_p) < 0)
printk(KERN_ERR "failed to register cpu pclk\n");
return 0;
}
static struct clk init_clocks[] = { //要注册的时钟
{
.name = "lcd",
.id = -1,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_LCD,
}, {
.name = "gpio",
.id = -1,
.parent = &clk_p,
.enable = s3c64xx_pclk_ctrl,
.ctrlbit = S3C_CLKCON_PCLK_GPIO,
}, {
.name = "usb-host",
.id = -1,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_UHOST,
}, {
.name = "hsmmc",
.id = 0,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_HSMMC0,
}, {
.name = "hsmmc",
.id = 1,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_HSMMC1,
}, {
.name = "hsmmc",
.id = 2,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_HSMMC2,
}, {
.name = "otg",
.id = -1,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_USB,
}, {
.name = "timers",
.id = -1,
.parent = &clk_p,
.enable = s3c64xx_pclk_ctrl,
.ctrlbit = S3C_CLKCON_PCLK_PWM,
}, {
.name = "uart",
.id = 0,
.parent = &clk_p,
.enable = s3c64xx_pclk_ctrl,
.ctrlbit = S3C_CLKCON_PCLK_UART0,
}, {
.name = "uart",
.id = 1,
.parent = &clk_p,
.enable = s3c64xx_pclk_ctrl,
.ctrlbit = S3C_CLKCON_PCLK_UART1,
}, {
.name = "uart",
.id = 2,
.parent = &clk_p,
.enable = s3c64xx_pclk_ctrl,
.ctrlbit = S3C_CLKCON_PCLK_UART2,
}, {
.name = "uart",
.id = 3,
.parent = &clk_p,
.enable = s3c64xx_pclk_ctrl,
.ctrlbit = S3C_CLKCON_PCLK_UART3,
}, {
.name = "watchdog",
.id = -1,
.parent = &clk_p,
.ctrlbit = S3C_CLKCON_PCLK_WDT,
}, {
.name = "ac97",
.id = -1,
.parent = &clk_p,
.ctrlbit = S3C_CLKCON_PCLK_AC97,
}, {
.name = "cfcon",
.id = -1,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_IHOST,
},
#ifdef CONFIG_VIDEO_SAMSUNG
{
.name = "fimc",
.id = -1,
.parent = &clk_h,
.ctrlbit = S3C_CLKCON_HCLK_CAMIF,
}, {
.name = "hclk_mfc",
.id = -1,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_MFC,
}, {
.name = "sclk_mfc",
.id = -1,
.parent = &clk_h2,
.enable = s3c64xx_sclk_ctrl,
.ctrlbit = S3C_CLKCON_SCLK_MFC,
.usage = 0,
.rate = 48*1000*1000,
}, {
.name = "pclk_mfc",
.id = -1,
.parent = &clk_p,
.enable = s3c64xx_pclk_ctrl,
.ctrlbit = S3C_CLKCON_PCLK_MFC,
}, {
.name = "hclk_jpeg",
.id = -1,
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_JPEG,
}, {
.name = "sclk_jpeg",
.id = -1,
.parent = &clk_h2,
.enable = s3c64xx_sclk_ctrl,
.ctrlbit = S3C_CLKCON_SCLK_JPEG,
.usage = 0,
.rate = 48*1000*1000,
}, {
.name = "sclk_cam",
.id = -1,
.parent = &clk_h2,
.enable = s3c64xx_sclk_ctrl,
.ctrlbit = S3C_CLKCON_SCLK_CAM,
.ops = &(struct clk_ops) {
.set_rate = s3c64xx_setrate_sclk_cam,
},
},
#endif
};
int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
{
int fails = 0;
for (; nr_clks > 0; nr_clks--, clks++) {
if (s3c24xx_register_clock(*clks) < 0) {
struct clk *clk = *clks;
printk(KERN_ERR "%s: failed to register %p: %s\n",
__func__, clk, clk->name);
fails++;
}
}
return fails;
}
int s3c24xx_register_clock(struct clk *clk)
{
if (clk->enable == NULL)
clk->enable = clk_null_enable;
/* add to the list of available clocks */
/* Quick check to see if this clock has already been registered. */
BUG_ON(clk->list.prev != clk->list.next);
spin_lock(&clocks_lock);
list_add(&clk->list, &clocks);
spin_unlock(&clocks_lock);
return 0;
}