diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 7b786d725636cb86dc82781a2d28fce1ca166eb2..f5d9cd498a5fdaf567435e00fc9eb43101cd438f 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -81,6 +81,12 @@ config SMDK2440_CPU2442 depends on ARCH_S3C2440 select CPU_S3C2442 +config MACH_SMDK2413 + bool "SMDK2413" + select CPU_S3C2412 + select MACH_SMDK + help + Say Y here if you are using an SMDK2413 config MACH_VR1000 bool "Thorcom VR1000" @@ -127,6 +133,20 @@ config CPU_S3C2410 Support for S3C2410 and S3C2410A family from the S3C24XX line of Samsung Mobile CPUs. +# internal node to signify if we are only dealing with an S3C2412 + +config CPU_S3C2412_ONLY + bool + depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ + !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412 + default y if CPU_S3C2412 + +config CPU_S3C2412 + bool + depends on ARCH_S3C2410 + help + Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line + config CPU_S3C244X bool depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 372dbcea1434ca45069a718610e90da385353ae9..0c7938645df6e9b3a8d1bc041e060a66197b95bc 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o +# S3C2412 support +obj-$(CONFIG_CPU_S3C2412) += s3c2412.o +obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o + +# # S3C244X support obj-$(CONFIG_CPU_S3C244X) += s3c244x.o @@ -57,6 +62,7 @@ obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o obj-$(CONFIG_ARCH_H1940) += mach-h1940.o obj-$(CONFIG_MACH_N30) += mach-n30.o obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o +obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index c5c93c333ac637e2eabc1af663956810b7f9bcc8..e13fb6778890d6559f2a57e532cf16f4cf13dd38 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -213,7 +213,7 @@ EXPORT_SYMBOL(clk_set_parent); /* base clocks */ -static struct clk clk_xtal = { +struct clk clk_xtal = { .name = "xtal", .id = -1, .rate = 0, @@ -221,6 +221,11 @@ static struct clk clk_xtal = { .ctrlbit = 0, }; +struct clk clk_mpll = { + .name = "mpll", + .id = -1, +}; + struct clk clk_upll = { .name = "upll", .id = -1, @@ -232,7 +237,7 @@ struct clk clk_f = { .name = "fclk", .id = -1, .rate = 0, - .parent = NULL, + .parent = &clk_mpll, .ctrlbit = 0, }; @@ -263,14 +268,14 @@ struct clk clk_usb_bus = { static int s3c24xx_dclk_enable(struct clk *clk, int enable) { - unsigned long dclkcon = __raw_readl(S3C2410_DCLKCON); + unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); if (enable) dclkcon |= clk->ctrlbit; else dclkcon &= ~clk->ctrlbit; - __raw_writel(dclkcon, S3C2410_DCLKCON); + __raw_writel(dclkcon, S3C24XX_DCLKCON); return 0; } @@ -289,7 +294,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) clk->parent = parent; - dclkcon = __raw_readl(S3C2410_DCLKCON); + dclkcon = __raw_readl(S3C24XX_DCLKCON); if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { if (uclk) @@ -303,7 +308,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; } - __raw_writel(dclkcon, S3C2410_DCLKCON); + __raw_writel(dclkcon, S3C24XX_DCLKCON); return 0; } @@ -413,6 +418,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal, clk_xtal.rate = xtal; clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); + clk_mpll.rate = fclk; clk_h.rate = hclk; clk_p.rate = pclk; clk_f.rate = fclk; @@ -424,6 +430,9 @@ int __init s3c24xx_setup_clocks(unsigned long xtal, 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"); diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h index 9456c81eb5d3fa67ee64227aba628ab7e640a087..7f0ea03e1d49398df37f5e843982b769635dd583 100644 --- a/arch/arm/mach-s3c2410/clock.h +++ b/arch/arm/mach-s3c2410/clock.h @@ -42,7 +42,9 @@ extern struct clk clk_usb_bus; extern struct clk clk_f; extern struct clk clk_h; extern struct clk clk_p; +extern struct clk clk_mpll; extern struct clk clk_upll; +extern struct clk clk_xtal; /* exports for arch/arm/mach-s3c2410 * diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c index 52842e6e86e6ce6954f0515db99e8257d4ff55af..1c3c6adae6c4c11b69339eebc46650c58f57ccce 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/mach-s3c2410/cpu.c @@ -44,6 +44,7 @@ #include "clock.h" #include "s3c2400.h" #include "s3c2410.h" +#include "s3c2412.h" #include "s3c244x.h" #include "s3c2440.h" #include "s3c2442.h" @@ -62,6 +63,7 @@ struct cpu_table { static const char name_s3c2400[] = "S3C2400"; static const char name_s3c2410[] = "S3C2410"; +static const char name_s3c2412[] = "S3C2412"; static const char name_s3c2440[] = "S3C2440"; static const char name_s3c2442[] = "S3C2442"; static const char name_s3c2410a[] = "S3C2410A"; @@ -113,6 +115,15 @@ static struct cpu_table cpu_ids[] __initdata = { .init = s3c2442_init, .name = name_s3c2442 }, + { + .idcode = 0x32412001, + .idmask = 0xffffffff, + .map_io = s3c2412_map_io, + .init_clocks = s3c2412_init_clocks, + .init_uarts = s3c2412_init_uarts, + .init = s3c2412_init, + .name = name_s3c2412, + }, { .idcode = 0x0, /* S3C2400 doesn't have an idcode */ .idmask = 0xffffffff, @@ -171,6 +182,24 @@ void s3c24xx_set_board(struct s3c24xx_board *b) static struct cpu_table *cpu; +static unsigned long s3c24xx_read_idcode_v5(void) +{ +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + return __raw_readl(S3C2412_GSTATUS1); +#else + return 1UL; /* don't look like an 2400 */ +#endif +} + +static unsigned long s3c24xx_read_idcode_v4(void) +{ +#ifndef CONFIG_CPU_S3C2400 + return __raw_readl(S3C2410_GSTATUS1); +#else + return 0UL; +#endif +} + void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) { unsigned long idcode = 0x0; @@ -178,9 +207,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) /* initialise the io descriptors we need for initialisation */ iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); -#ifndef CONFIG_CPU_S3C2400 - idcode = __raw_readl(S3C2410_GSTATUS1); -#endif + if (cpu_architecture() >= CPU_ARCH_ARMv5) { + idcode = s3c24xx_read_idcode_v5(); + } else { + idcode = s3c24xx_read_idcode_v4(); + } cpu = s3c_lookup_cpu(idcode); diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h index 21c62dc29bb254abe2782f665ef4aea081166fef..b0ed9d2d141b06dc9c8ef36d711c940f8268cc59 100644 --- a/arch/arm/mach-s3c2410/cpu.h +++ b/arch/arm/mach-s3c2410/cpu.h @@ -74,5 +74,6 @@ extern struct sys_timer s3c24xx_timer; /* system device classes */ extern struct sysdev_class s3c2410_sysclass; +extern struct sysdev_class s3c2412_sysclass; extern struct sysdev_class s3c2440_sysclass; extern struct sysdev_class s3c2442_sysclass; diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 66d8c068e940b9436693361f7bdd5dc5f941bc6e..6822dc7f779953f072ab8873fd770bcfcc5e2da3 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -191,13 +191,9 @@ static struct irqchip s3c_irq_chip = { .ack = s3c_irq_ack, .mask = s3c_irq_mask, .unmask = s3c_irq_unmask, - .set_wake = s3c_irq_wake + .set_wake = s3c_irq_wake }; -/* S3C2410_EINTMASK - * S3C2410_EINTPEND - */ - static void s3c_irqext_mask(unsigned int irqno) { @@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno) irqno -= EXTINT_OFF; - mask = __raw_readl(S3C2410_EINTMASK); + mask = __raw_readl(S3C24XX_EINTMASK); mask |= ( 1UL << irqno); - __raw_writel(mask, S3C2410_EINTMASK); + __raw_writel(mask, S3C24XX_EINTMASK); if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) { /* check to see if all need masking */ @@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno) bit = 1UL << (irqno - EXTINT_OFF); - mask = __raw_readl(S3C2410_EINTMASK); + mask = __raw_readl(S3C24XX_EINTMASK); - __raw_writel(bit, S3C2410_EINTPEND); + __raw_writel(bit, S3C24XX_EINTPEND); - req = __raw_readl(S3C2410_EINTPEND); + req = __raw_readl(S3C24XX_EINTPEND); req &= ~mask; /* not sure if we should be acking the parent irq... */ @@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno) irqno -= EXTINT_OFF; - mask = __raw_readl(S3C2410_EINTMASK); + mask = __raw_readl(S3C24XX_EINTMASK); mask &= ~( 1UL << irqno); - __raw_writel(mask, S3C2410_EINTMASK); + __raw_writel(mask, S3C24XX_EINTMASK); s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); } @@ -275,28 +271,28 @@ s3c_irqext_type(unsigned int irq, unsigned int type) if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) { gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C2410_EXTINT0; + extint_reg = S3C24XX_EXTINT0; gpcon_offset = (irq - IRQ_EINT0) * 2; extint_offset = (irq - IRQ_EINT0) * 4; } else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) { gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C2410_EXTINT0; + extint_reg = S3C24XX_EXTINT0; gpcon_offset = (irq - (EXTINT_OFF)) * 2; extint_offset = (irq - (EXTINT_OFF)) * 4; } else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) { gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C2410_EXTINT1; + extint_reg = S3C24XX_EXTINT1; gpcon_offset = (irq - IRQ_EINT8) * 2; extint_offset = (irq - IRQ_EINT8) * 4; } else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) { gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C2410_EXTINT2; + extint_reg = S3C24XX_EXTINT2; gpcon_offset = (irq - IRQ_EINT8) * 2; extint_offset = (irq - IRQ_EINT16) * 4; } else @@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq, s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); } +static void +s3c_irq_demux_extint(unsigned int irq, + struct irqdesc *desc, + struct pt_regs *regs) +{ + unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); + unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); + + eintpnd &= ~eintmsk; + + if (eintpnd) { + irq = fls(eintpnd); + irq += (IRQ_EINT4 - (4 + 1)); + + desc_handle_irq(irq, irq_desc + irq, regs); + } +} /* s3c24xx_init_irq * @@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void) last = 0; for (i = 0; i < 4; i++) { - pend = __raw_readl(S3C2410_EINTPEND); + pend = __raw_readl(S3C24XX_EINTPEND); if (pend == 0 || pend == last) break; - __raw_writel(pend, S3C2410_EINTPEND); + __raw_writel(pend, S3C24XX_EINTPEND); printk("irq: clearing pending ext status %08x\n", (int)pend); last = pend; } @@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void) irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); - for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { + for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { /* set all the s3c2410 internal irqs */ switch (irqno) { /* deal with the special IRQs (cascaded) */ + case IRQ_EINT4t7: + case IRQ_EINT8t23: case IRQ_UART0: case IRQ_UART1: case IRQ_UART2: @@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void) /* setup the cascade irq handlers */ + set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint); + set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint); + set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); - /* external interrupts */ for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2410/mach-smdk2413.c new file mode 100644 index 0000000000000000000000000000000000000000..b7ef7d3c54a9cf15a31bd3974696e29553ba357e --- /dev/null +++ b/arch/arm/mach-s3c2410/mach-smdk2413.c @@ -0,0 +1,126 @@ +/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the + * loans of SMDK2413 to work with. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//#include +#include +#include +#include + +#include +#include + +#include "s3c2410.h" +#include "s3c2412.h" +#include "clock.h" +#include "devs.h" +#include "cpu.h" + +#include "common-smdk.h" + +static struct map_desc smdk2413_iodesc[] __initdata = { +}; + +static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + /* IR port */ + [2] = { + .hwport = 2, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x43, + .ufcon = 0x51, + } +}; + +static struct platform_device *smdk2413_devices[] __initdata = { + &s3c_device_usb, + //&s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, +}; + +static struct s3c24xx_board smdk2413_board __initdata = { + .devices = smdk2413_devices, + .devices_count = ARRAY_SIZE(smdk2413_devices) +}; + +static void __init smdk2413_fixup(struct machine_desc *desc, + struct tag *tags, char **cmdline, + struct meminfo *mi) +{ + if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) { + mi->nr_banks=1; + mi->bank[0].start = 0x30000000; + mi->bank[0].size = SZ_64M; + mi->bank[0].node = 0; + } +} + +static void __init smdk2413_map_io(void) +{ + s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc)); + s3c24xx_init_clocks(12000000); + s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs)); + s3c24xx_set_board(&smdk2413_board); +} + +static void __init smdk2413_machine_init(void) +{ + smdk_machine_init(); +} + +MACHINE_START(S3C2413, "SMDK2413") + /* Maintainer: Ben Dooks */ + .phys_io = S3C2410_PA_UART, + .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, + .boot_params = S3C2410_SDRAM_PA + 0x100, + + .fixup = smdk2413_fixup, + .init_irq = s3c24xx_init_irq, + .map_io = smdk2413_map_io, + .init_machine = smdk2413_machine_init, + .timer = &s3c24xx_timer, +MACHINE_END diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c index 4c7ccef6c207d0d2ba67349445324c1b87c2974a..7b244566a436891d6f2b9f32cf848f1f222a0627 100644 --- a/arch/arm/mach-s3c2410/pm-simtec.c +++ b/arch/arm/mach-s3c2410/pm-simtec.c @@ -48,7 +48,8 @@ static __init int pm_simtec_init(void) /* check which machine we are running on */ - if (!machine_is_bast() && !machine_is_vr1000() && !machine_is_anubis()) + if (!machine_is_bast() && !machine_is_vr1000() && + !machine_is_anubis() && !machine_is_osiris()) return 0; printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n"); diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c index fd17c60e11324d03094d9e1599bbdbf4a2cddfc2..99718663318e74dc2f9eca1bb5ae066f500853e3 100644 --- a/arch/arm/mach-s3c2410/s3c2410-clock.c +++ b/arch/arm/mach-s3c2410/s3c2410-clock.c @@ -182,7 +182,15 @@ static struct clk init_clocks[] = { .id = -1, .parent = &clk_p, .ctrlbit = 0, - } + }, { + .name = "usb-bus-host", + .id = -1, + .parent = &clk_usb_bus, + }, { + .name = "usb-bus-gadget", + .id = -1, + .parent = &clk_usb_bus, + }, }; /* s3c2410_baseclk_add() diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c index d5e1caea1d231614b42c773668d54aff592579f8..471a714900103c55c034d6c396f5c6cb9ad2b082 100644 --- a/arch/arm/mach-s3c2410/s3c2410-gpio.c +++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c @@ -18,9 +18,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Changelog - * 15-Jan-2006 LCVR Splitted from gpio.c */ #include @@ -38,7 +35,7 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, unsigned int config) { - void __iomem *reg = S3C2410_EINFLT0; + void __iomem *reg = S3C24XX_EINFLT0; unsigned long flags; unsigned long val; @@ -47,7 +44,7 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, config &= 0xff; - pin -= S3C2410_GPG8_EINT16; + pin -= S3C2410_GPG8; reg += pin & ~3; local_irq_save(flags); @@ -61,10 +58,10 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, /* update filter enable */ - val = __raw_readl(S3C2410_EXTINT2); + val = __raw_readl(S3C24XX_EXTINT2); val &= ~(1 << ((pin * 4) + 3)); val |= on << ((pin * 4) + 3); - __raw_writel(val, S3C2410_EXTINT2); + __raw_writel(val, S3C24XX_EXTINT2); local_irq_restore(flags); @@ -75,7 +72,7 @@ EXPORT_SYMBOL(s3c2410_gpio_irqfilter); int s3c2410_gpio_getirq(unsigned int pin) { - if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23) + if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15) return -1; /* not valid interrupts */ if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2410/s3c2412-clock.c new file mode 100644 index 0000000000000000000000000000000000000000..c95ed3e18580a9a1db711a95f73063f433b1eebd --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2412-clock.c @@ -0,0 +1,711 @@ +/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * S3C2412,S3C2413 Clock control support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "clock.h" +#include "cpu.h" + +/* We currently have to assume that the system is running + * from the XTPll input, and that all ***REFCLKs are being + * fed from it, as we cannot read the state of OM[4] from + * software. + * + * It would be possible for each board initialisation to + * set the correct muxing at initialisation +*/ + +int s3c2412_clkcon_enable(struct clk *clk, int enable) +{ + unsigned int clocks = clk->ctrlbit; + unsigned long clkcon; + + clkcon = __raw_readl(S3C2410_CLKCON); + + if (enable) + clkcon |= clocks; + else + clkcon &= ~clocks; + + __raw_writel(clkcon, S3C2410_CLKCON); + + return 0; +} + +static int s3c2412_upll_enable(struct clk *clk, int enable) +{ + unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); + unsigned long orig = upllcon; + + if (!enable) + upllcon |= S3C2412_PLLCON_OFF; + else + upllcon &= ~S3C2412_PLLCON_OFF; + + __raw_writel(upllcon, S3C2410_UPLLCON); + + /* allow ~150uS for the PLL to settle and lock */ + + if (enable && (orig & S3C2412_PLLCON_OFF)) + udelay(150); + + return 0; +} + +/* clock selections */ + +/* CPU EXTCLK input */ +static struct clk clk_ext = { + .name = "extclk", + .id = -1, +}; + +static struct clk clk_erefclk = { + .name = "erefclk", + .id = -1, +}; + +static struct clk clk_urefclk = { + .name = "urefclk", + .id = -1, +}; + +static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_urefclk) + clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL; + else if (parent == &clk_upll) + clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static struct clk clk_usysclk = { + .name = "usysclk", + .id = -1, + .parent = &clk_xtal, + .set_parent = s3c2412_setparent_usysclk, +}; + +static struct clk clk_mrefclk = { + .name = "mrefclk", + .parent = &clk_xtal, + .id = -1, +}; + +static struct clk clk_mdivclk = { + .name = "mdivclk", + .parent = &clk_xtal, + .id = -1, +}; + +static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_usysclk) + clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK; + else if (parent == &clk_h) + clksrc |= S3C2412_CLKSRC_USBCLK_HCLK; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk, + unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + int div; + + if (rate > parent_rate) + return parent_rate; + + div = parent_rate / rate; + if (div > 2) + div = 2; + + return parent_rate / div; +} + +static unsigned long s3c2412_getrate_usbsrc(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1); +} + +static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_usbsrc(clk, rate); + + if ((parent_rate / rate) == 2) + clkdivn |= S3C2412_CLKDIVN_USB48DIV; + else + clkdivn &= ~S3C2412_CLKDIVN_USB48DIV; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_usbsrc = { + .name = "usbsrc", + .id = -1, + .get_rate = s3c2412_getrate_usbsrc, + .set_rate = s3c2412_setrate_usbsrc, + .round_rate = s3c2412_roundrate_usbsrc, + .set_parent = s3c2412_setparent_usbsrc, +}; + +static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_mdivclk) + clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL; + else if (parent == &clk_upll) + clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static struct clk clk_msysclk = { + .name = "msysclk", + .id = -1, + .set_parent = s3c2412_setparent_msysclk, +}; + +/* these next clocks have an divider immediately after them, + * so we can register them with their divider and leave out the + * intermediate clock stage +*/ +static unsigned long s3c2412_roundrate_clksrc(struct clk *clk, + unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + int div; + + if (rate > parent_rate) + return parent_rate; + + /* note, we remove the +/- 1 calculations as they cancel out */ + + div = (rate / parent_rate); + + if (div < 1) + div = 1; + else if (div > 16) + div = 16; + + return parent_rate / div; +} + +static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_erefclk) + clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL; + else if (parent == &clk_mpll) + clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static unsigned long s3c2412_getrate_uart(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + div &= S3C2412_CLKDIVN_UARTDIV_MASK; + div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_clksrc(clk, rate); + + clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK; + clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_uart = { + .name = "uartclk", + .id = -1, + .get_rate = s3c2412_getrate_uart, + .set_rate = s3c2412_setrate_uart, + .set_parent = s3c2412_setparent_uart, + .round_rate = s3c2412_roundrate_clksrc, +}; + +static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_erefclk) + clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL; + else if (parent == &clk_mpll) + clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static unsigned long s3c2412_getrate_i2s(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + div &= S3C2412_CLKDIVN_I2SDIV_MASK; + div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_clksrc(clk, rate); + + clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK; + clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_i2s = { + .name = "i2sclk", + .id = -1, + .get_rate = s3c2412_getrate_i2s, + .set_rate = s3c2412_setrate_i2s, + .set_parent = s3c2412_setparent_i2s, + .round_rate = s3c2412_roundrate_clksrc, +}; + +static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_usysclk) + clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK; + else if (parent == &clk_h) + clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} +static unsigned long s3c2412_getrate_cam(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + div &= S3C2412_CLKDIVN_CAMDIV_MASK; + div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_clksrc(clk, rate); + + clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK; + clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_cam = { + .name = "camif-upll", /* same as 2440 name */ + .id = -1, + .get_rate = s3c2412_getrate_cam, + .set_rate = s3c2412_setrate_cam, + .set_parent = s3c2412_setparent_cam, + .round_rate = s3c2412_roundrate_clksrc, +}; + +/* standard clock definitions */ + +static struct clk init_clocks_disable[] = { + { + .name = "nand", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_NAND, + }, { + .name = "sdi", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_SDI, + }, { + .name = "adc", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_ADC, + }, { + .name = "i2c", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_IIC, + }, { + .name = "iis", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_IIS, + }, { + .name = "spi", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_SPI, + } +}; + +static struct clk init_clocks[] = { + { + .name = "dma", + .id = 0, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA0, + }, { + .name = "dma", + .id = 1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA1, + }, { + .name = "dma", + .id = 2, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA2, + }, { + .name = "dma", + .id = 3, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA3, + }, { + .name = "lcd", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_LCDC, + }, { + .name = "gpio", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_GPIO, + }, { + .name = "usb-host", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USBH, + }, { + .name = "usb-device", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USBD, + }, { + .name = "timers", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_PWMT, + }, { + .name = "uart", + .id = 0, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_UART0, + }, { + .name = "uart", + .id = 1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_UART1, + }, { + .name = "uart", + .id = 2, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_UART2, + }, { + .name = "rtc", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_RTC, + }, { + .name = "watchdog", + .id = -1, + .parent = &clk_p, + .ctrlbit = 0, + }, { + .name = "usb-bus-gadget", + .id = -1, + .parent = &clk_usb_bus, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USB_DEV48, + }, { + .name = "usb-bus-host", + .id = -1, + .parent = &clk_usb_bus, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USB_HOST48, + } +}; + +/* clocks to add where we need to check their parentage */ + +struct clk_init { + struct clk *clk; + unsigned int bit; + struct clk *src_0; + struct clk *src_1; +}; + +struct clk_init clks_src[] __initdata = { + { + .clk = &clk_usysclk, + .bit = S3C2412_CLKSRC_USBCLK_HCLK, + .src_0 = &clk_urefclk, + .src_1 = &clk_upll, + }, { + .clk = &clk_i2s, + .bit = S3C2412_CLKSRC_I2SCLK_MPLL, + .src_0 = &clk_erefclk, + .src_1 = &clk_mpll, + }, { + .clk = &clk_cam, + .bit = S3C2412_CLKSRC_CAMCLK_HCLK, + .src_0 = &clk_usysclk, + .src_1 = &clk_h, + }, { + .clk = &clk_msysclk, + .bit = S3C2412_CLKSRC_MSYSCLK_MPLL, + .src_0 = &clk_mdivclk, + .src_1 = &clk_mpll, + }, { + .clk = &clk_uart, + .bit = S3C2412_CLKSRC_UARTCLK_MPLL, + .src_0 = &clk_erefclk, + .src_1 = &clk_mpll, + }, { + .clk = &clk_usbsrc, + .bit = S3C2412_CLKSRC_USBCLK_HCLK, + .src_0 = &clk_usysclk, + .src_1 = &clk_h, + }, +}; + +/* s3c2412_clk_initparents + * + * Initialise the parents for the clocks that we get at start-time +*/ + +static void __init s3c2412_clk_initparents(void) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + struct clk_init *cip = clks_src; + struct clk *src; + int ptr; + int ret; + + for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) { + ret = s3c24xx_register_clock(cip->clk); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + cip->clk->name, ret); + } + + src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0; + + printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name); + clk_set_parent(cip->clk, src); + } +} + +/* clocks to add straight away */ + +struct clk *clks[] __initdata = { + &clk_ext, + &clk_usb_bus, + &clk_erefclk, + &clk_urefclk, + &clk_mrefclk, +}; + +int __init s3c2412_baseclk_add(void) +{ + unsigned long clkcon = __raw_readl(S3C2410_CLKCON); + struct clk *clkp; + int ret; + int ptr; + + clk_upll.enable = s3c2412_upll_enable; + clk_usb_bus.parent = &clk_usbsrc; + clk_usb_bus.rate = 0x0; + + s3c2412_clk_initparents(); + + for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { + clkp = clks[ptr]; + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + /* ensure usb bus clock is within correct rate of 48MHz */ + + if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) { + printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n"); + + /* for the moment, let's use the UPLL, and see if we can + * get 48MHz */ + + clk_set_parent(&clk_usysclk, &clk_upll); + clk_set_parent(&clk_usbsrc, &clk_usysclk); + clk_set_rate(&clk_usbsrc, 48*1000*1000); + } + + printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", + (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on", + print_mhz(clk_get_rate(&clk_upll)), + print_mhz(clk_get_rate(&clk_usb_bus))); + + /* register clocks from clock array */ + + clkp = init_clocks; + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { + /* ensure that we note the clock state */ + + clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + /* We must be careful disabling the clocks we are not intending to + * be using at boot time, as subsytems such as the LCD which do + * their own DMA requests to the bus can cause the system to lockup + * if they where in the middle of requesting bus access. + * + * Disabling the LCD clock if the LCD is active is very dangerous, + * and therefore the bootloader should be careful to not enable + * the LCD clock if it is not needed. + */ + + /* install (and disable) the clocks we do not need immediately */ + + 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); + } + + s3c2412_clkcon_enable(clkp, 0); + } + + return 0; +} diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2410/s3c2412.c new file mode 100644 index 0000000000000000000000000000000000000000..e24ffd5e478bc08dcd50ab49a4f3712cbf0094a6 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2412.c @@ -0,0 +1,195 @@ +/* linux/arch/arm/mach-s3c2410/s3c2412.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * http://armlinux.simtec.co.uk/. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 16-May-2003 BJD Created initial version + * 16-Aug-2003 BJD Fixed header files and copyright, added URL + * 05-Sep-2003 BJD Moved to kernel v2.6 + * 18-Jan-2004 BJD Added serial port configuration + * 21-Aug-2004 BJD Added new struct s3c2410_board handler + * 28-Sep-2004 BJD Updates for new serial port bits + * 04-Nov-2004 BJD Updated UART configuration process + * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate + * 13-Aug-2005 DA Removed UART from initial I/O mappings +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "s3c2412.h" +#include "cpu.h" +#include "devs.h" +#include "clock.h" +#include "pm.h" + +#ifndef CONFIG_CPU_S3C2412_ONLY +void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; +#endif + +/* Initial IO mappings */ + +static struct map_desc s3c2412_iodesc[] __initdata = { + IODESC_ENT(CLKPWR), + IODESC_ENT(LCD), + IODESC_ENT(TIMER), + IODESC_ENT(ADC), + IODESC_ENT(WATCHDOG), +}; + +/* uart registration process */ + +void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no); + + /* rename devices that are s3c2412/s3c2413 specific */ + s3c_device_sdi.name = "s3c2412-sdi"; + s3c_device_nand.name = "s3c2412-nand"; +} + +/* s3c2412_map_io + * + * register the standard cpu IO areas, and any passed in from the + * machine specific initialisation. +*/ + +void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size) +{ + /* move base of IO */ + + s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10; + + /* register our io-tables */ + + iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc)); + iotable_init(mach_desc, mach_size); +} + +void __init s3c2412_init_clocks(int xtal) +{ + unsigned long tmp; + unsigned long fclk; + unsigned long hclk; + unsigned long pclk; + + /* now we've got our machine bits initialised, work out what + * clocks we've got */ + + fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2); + + tmp = __raw_readl(S3C2410_CLKDIVN); + + /* work out clock scalings */ + + hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1); + hclk /= ((tmp & S3C2421_CLKDIVN_ARMDIVN) ? 2 : 1); + pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1); + + /* print brieft summary of clocks, etc */ + + printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", + print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); + + /* initialise the clocks here, to allow other things like the + * console to use them + */ + + s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); + s3c2412_baseclk_add(); +} + +/* need to register class before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2412 based system) + * as a driver which may support both 2410 and 2440 may try and use it. +*/ + +#ifdef CONFIG_PM +static struct sleep_save s3c2412_sleep[] = { + SAVE_ITEM(S3C2412_DSC0), + SAVE_ITEM(S3C2412_DSC1), + SAVE_ITEM(S3C2413_GPJDAT), + SAVE_ITEM(S3C2413_GPJCON), + SAVE_ITEM(S3C2413_GPJUP), + + /* save the sleep configuration anyway, just in case these + * get damaged during wakeup */ + + SAVE_ITEM(S3C2412_GPBSLPCON), + SAVE_ITEM(S3C2412_GPCSLPCON), + SAVE_ITEM(S3C2412_GPDSLPCON), + SAVE_ITEM(S3C2412_GPESLPCON), + SAVE_ITEM(S3C2412_GPFSLPCON), + SAVE_ITEM(S3C2412_GPGSLPCON), + SAVE_ITEM(S3C2412_GPHSLPCON), + SAVE_ITEM(S3C2413_GPJSLPCON), +}; + +static int s3c2412_suspend(struct sys_device *dev, pm_message_t state) +{ + s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); + return 0; +} + +static int s3c2412_resume(struct sys_device *dev) +{ + s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); + return 0; +} + +#else +#define s3c2412_suspend NULL +#define s3c2412_resume NULL +#endif + +struct sysdev_class s3c2412_sysclass = { + set_kset_name("s3c2412-core"), + .suspend = s3c2412_suspend, + .resume = s3c2412_resume +}; + +static int __init s3c2412_core_init(void) +{ + return sysdev_class_register(&s3c2412_sysclass); +} + +core_initcall(s3c2412_core_init); + +static struct sys_device s3c2412_sysdev = { + .cls = &s3c2412_sysclass, +}; + +int __init s3c2412_init(void) +{ + printk("S3C2412: Initialising architecture\n"); + + return sysdev_register(&s3c2412_sysdev); +} diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/arch/arm/mach-s3c2410/s3c2412.h new file mode 100644 index 0000000000000000000000000000000000000000..c6e56032a6e7177336ce06de58cce2d71b0967e3 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2412.h @@ -0,0 +1,29 @@ +/* arch/arm/mach-s3c2410/s3c2412.h + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2412 cpu support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifdef CONFIG_CPU_S3C2412 + +extern int s3c2412_init(void); + +extern void s3c2412_map_io(struct map_desc *mach_desc, int size); + +extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); + +extern void s3c2412_init_clocks(int xtal); + +extern int s3c2412_baseclk_add(void); +#else +#define s3c2412_init_clocks NULL +#define s3c2412_init_uarts NULL +#define s3c2412_map_io NULL +#define s3c2412_init NULL +#endif diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 4221d054a1e9434ee510e5241b7151b22edcca90..ecf5e232a6fc2a3e0d6c419ca918933bdacd2fd3 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -61,9 +61,9 @@ config CPU_ARM720T # ARM920T config CPU_ARM920T - bool "Support ARM920T processor" if !ARCH_S3C2410 - depends on ARCH_EP93XX || ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200 - default y if ARCH_S3C2410 || ARCH_AT91RM9200 + bool "Support ARM920T processor" + depends on ARCH_EP93XX || ARCH_INTEGRATOR || CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200 + default y if CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_AT91RM9200 select CPU_32v4 select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -121,8 +121,8 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T bool "Support ARM926T processor" - depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX - default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 + default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_CACHE_VIVT diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bef4a9622ed7850c16fb5f35ba84be8af1d36971..5b48ac22c9c5964b62b93500831f1656a1b84e1a 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -354,21 +354,24 @@ config SERIAL_CLPS711X_CONSOLE kernel at boot time.) config SERIAL_S3C2410 - tristate "Samsung S3C2410 Serial port support" + tristate "Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support" depends on ARM && ARCH_S3C2410 select SERIAL_CORE help - Support for the on-chip UARTs on the Samsung S3C2410X CPU, + Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, providing /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of these ports, depending on how the serial port pins are configured. + Currently this driver supports the UARTS on the S3C2410, S3C2440, + S3C2442, S3C2412 and S3C2413 CPUs. + config SERIAL_S3C2410_CONSOLE bool "Support for console on S3C2410 serial port" depends on SERIAL_S3C2410=y select SERIAL_CORE_CONSOLE help - Allow selection of the S3C2410 on-board serial ports for use as + Allow selection of the S3C24XX on-board serial ports for use as an virtual console. Even if you say Y here, the currently visible virtual console diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 53c2465bad2d37117e121ee78e5967f2c5cfc67a..837b6da520b3aeb0f9bbd0897ead81f123233b55 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -872,6 +872,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port) return "S3C2410"; case PORT_S3C2440: return "S3C2440"; + case PORT_S3C2412: + return "S3C2412"; default: return NULL; } @@ -1528,6 +1530,141 @@ static inline void s3c2440_serial_exit(void) #define s3c2440_uart_inf_at NULL #endif /* CONFIG_CPU_S3C2440 */ +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + +static int s3c2412_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + ucon &= ~S3C2412_UCON_CLKMASK; + + if (strcmp(clk->name, "uclk") == 0) + ucon |= S3C2440_UCON_UCLK; + else if (strcmp(clk->name, "pclk") == 0) + ucon |= S3C2440_UCON_PCLK; + else if (strcmp(clk->name, "usysclk") == 0) + ucon |= S3C2412_UCON_USYSCLK; + else { + printk(KERN_ERR "unknown clock source %s\n", clk->name); + return -EINVAL; + } + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + + +static int s3c2412_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + switch (ucon & S3C2412_UCON_CLKMASK) { + case S3C2412_UCON_UCLK: + clk->divisor = 1; + clk->name = "uclk"; + break; + + case S3C2412_UCON_PCLK: + case S3C2412_UCON_PCLK2: + clk->divisor = 1; + clk->name = "pclk"; + break; + + case S3C2412_UCON_USYSCLK: + clk->divisor = 1; + clk->name = "usysclk"; + break; + } + + return 0; +} + +static int s3c2412_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + dbg("%s: port=%p (%08lx), cfg=%p\n", + __FUNCTION__, port, port->mapbase, cfg); + + /* ensure we don't change the clock settings... */ + + ucon &= S3C2412_UCON_CLKMASK; + + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c2412_uart_inf = { + .name = "Samsung S3C2412 UART", + .type = PORT_S3C2412, + .fifosize = 64, + .rx_fifomask = S3C2440_UFSTAT_RXMASK, + .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2440_UFSTAT_RXFULL, + .tx_fifofull = S3C2440_UFSTAT_TXFULL, + .tx_fifomask = S3C2440_UFSTAT_TXMASK, + .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, + .get_clksrc = s3c2412_serial_getsource, + .set_clksrc = s3c2412_serial_setsource, + .reset_port = s3c2412_serial_resetport, +}; + +/* device management */ + +static int s3c2412_serial_probe(struct platform_device *dev) +{ + dbg("s3c2440_serial_probe: dev=%p\n", dev); + return s3c24xx_serial_probe(dev, &s3c2440_uart_inf); +} + +static struct platform_driver s3c2412_serial_drv = { + .probe = s3c2412_serial_probe, + .remove = s3c24xx_serial_remove, + .suspend = s3c24xx_serial_suspend, + .resume = s3c24xx_serial_resume, + .driver = { + .name = "s3c2412-uart", + .owner = THIS_MODULE, + }, +}; + + +static inline int s3c2412_serial_init(void) +{ + return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf); +} + +static inline void s3c2412_serial_exit(void) +{ + platform_driver_unregister(&s3c2412_serial_drv); +} + +#define s3c2412_uart_inf_at &s3c2412_uart_inf +#else + +static inline int s3c2412_serial_init(void) +{ + return 0; +} + +static inline void s3c2412_serial_exit(void) +{ +} + +#define s3c2412_uart_inf_at NULL +#endif /* CONFIG_CPU_S3C2440 */ + + /* module initialisation code */ static int __init s3c24xx_serial_modinit(void) @@ -1542,6 +1679,7 @@ static int __init s3c24xx_serial_modinit(void) s3c2400_serial_init(); s3c2410_serial_init(); + s3c2412_serial_init(); s3c2440_serial_init(); return 0; @@ -1551,6 +1689,7 @@ static void __exit s3c24xx_serial_modexit(void) { s3c2400_serial_exit(); s3c2410_serial_exit(); + s3c2412_serial_exit(); s3c2440_serial_exit(); uart_unregister_driver(&s3c24xx_uart_drv); @@ -1773,6 +1912,8 @@ static int s3c24xx_serial_initconsole(void) info = s3c2410_uart_inf_at; } else if (strcmp(dev->name, "s3c2440-uart") == 0) { info = s3c2440_uart_inf_at; + } else if (strcmp(dev->name, "s3c2412-uart") == 0) { + info = s3c2412_uart_inf_at; } else { printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name); return 0; @@ -1796,4 +1937,4 @@ console_initcall(s3c24xx_serial_initconsole); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Dooks "); -MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver"); +MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver"); diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S index 5f8223e700d353f22a75c94c3e173f14ad609b78..b7d15d125458ad3fff6bd79e62df67821d9ac761 100644 --- a/include/asm-arm/arch-s3c2410/debug-macro.S +++ b/include/asm-arm/arch-s3c2410/debug-macro.S @@ -33,7 +33,7 @@ .endm .macro senduart,rd,rx - str \rd, [\rx, # S3C2410_UTXH ] + strb \rd, [\rx, # S3C2410_UTXH ] .endm .macro busyuart, rd, rx @@ -42,6 +42,12 @@ beq 1001f @ @ FIFO enabled... 1003: + @ check for arm920 vs arm926. currently assume all arm926 + @ devices have an 64 byte FIFO identical to the s3c2440 + mrc p15, 0, \rd, c0, c0 + and \rd, \rd, #0xff0 + teq \rd, #0x260 + beq 1004f mrc p15, 0, \rd, c1, c0 tst \rd, #1 addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART) @@ -50,7 +56,7 @@ ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ] and \rd, \rd, #0x00ff0000 teq \rd, #0x00440000 @ is it 2440? - +1004: ldr \rd, [ \rx, # S3C2410_UFSTAT ] moveq \rd, \rd, lsr #SHIFT_2440TXF tst \rd, #S3C2410_UFSTAT_TXFULL diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S index 894c35cf3b1e25ffbec91a5edd1644955f8f00c2..e09a6b8ec1535fc8929cd6a0ec4d1a82bc3528f8 100644 --- a/include/asm-arm/arch-s3c2410/entry-macro.S +++ b/include/asm-arm/arch-s3c2410/entry-macro.S @@ -18,8 +18,6 @@ #define INTPND (0x10) #define INTOFFSET (0x14) -#define EXTINTPEND (0xa8) -#define EXTINTMASK (0xa4) #include #include @@ -28,37 +26,23 @@ mov \base, #S3C24XX_VA_IRQ - ldr \irqstat, [ \base, #INTPND] - bics \irqnr, \irqstat, #3<<4 @@ only an GPIO IRQ - beq 2000f - @@ try the interrupt offset register, since it is there + ldr \irqstat, [ \base, #INTPND ] + teq \irqstat, #0 + beq 1002f ldr \irqnr, [ \base, #INTOFFSET ] mov \tmp, #1 tst \irqstat, \tmp, lsl \irqnr - addne \irqnr, \irqnr, #IRQ_EINT0 bne 1001f @@ the number specified is not a valid irq, so try @@ and work it out for ourselves - mov \irqnr, #IRQ_EINT0 @@ start here - b 3000f - -2000: - @@ load the GPIO interrupt register, and check it - - add \tmp, \base, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ - ldr \irqstat, [ \tmp, # EXTINTPEND ] - ldr \irqnr, [ \tmp, # EXTINTMASK ] - bics \irqstat, \irqstat, \irqnr - beq 1001f - - mov \irqnr, #(IRQ_EINT4 - 4) + mov \irqnr, #0 @@ start here @@ work out which irq (if any) we got -3000: + movs \tmp, \irqstat, lsl#16 addeq \irqnr, \irqnr, #16 moveq \irqstat, \irqstat, lsr#16 @@ -75,9 +59,9 @@ addeq \irqnr, \irqnr, #1 @@ we have the value - movs \irqnr, \irqnr - 1001: + adds \irqnr, \irqnr, #IRQ_EINT0 +1002: @@ exit here, Z flag unset if IRQ .endm diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h index 5e4c8c37bc66d86fe33980604c5fd6dec254cea2..fae2766ff32b2760d76dfd4fd35038224e2ef922 100644 --- a/include/asm-arm/arch-s3c2410/map.h +++ b/include/asm-arm/arch-s3c2410/map.h @@ -236,4 +236,20 @@ #define S3C24XX_PA_SPI S3C2410_PA_SPI #endif +/* deal with the registers that move under the 2412/2413 */ + +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +#ifndef __ASSEMBLY__ +extern void __iomem *s3c24xx_va_gpio2; +#endif +#ifdef CONFIG_CPU_S3C2412_ONLY +#define S3C24XX_VA_GPIO2 (S3C24XX_VA_GPIO + 0x10) +#else +#define S3C24XX_VA_GPIO2 s3c24xx_va_gpio2 +#endif +#else +#define s3c24xx_va_gpio2 S3C24XX_VA_GPIO +#define S3C24XX_VA_GPIO2 S3C24XX_VA_GPIO +#endif + #endif /* __ASM_ARCH_MAP_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h index 6c92faffe98562266e22fc80a04f2c2f009be042..a7c61feb84331227e2bb66003b41430b8653053c 100644 --- a/include/asm-arm/arch-s3c2410/regs-clock.h +++ b/include/asm-arm/arch-s3c2410/regs-clock.h @@ -1,6 +1,6 @@ /* linux/include/asm/arch-s3c2410/regs-clock.h * - * Copyright (c) 2003,2004,2005 Simtec Electronics + * Copyright (c) 2003,2004,2005,2006 Simtec Electronics * http://armlinux.simtec.co.uk/ * * This program is free software; you can redistribute it and/or modify @@ -140,5 +140,66 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk) #endif /* CONFIG_CPU_S3C2440 or CONFIG_CPU_S3C2442 */ +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + +#define S3C2412_OSCSET S3C2410_CLKREG(0x18) +#define S3C2412_CLKSRC S3C2410_CLKREG(0x1C) + +#define S3C2412_PLLCON_OFF (1<<20) + +#define S3C2412_CLKDIVN_PDIVN (1<<2) +#define S3C2412_CLKDIVN_HDIVN_MASK (3<<0) +#define S3C2421_CLKDIVN_ARMDIVN (1<<3) +#define S3C2412_CLKDIVN_USB48DIV (1<<6) +#define S3C2412_CLKDIVN_UARTDIV_MASK (15<<8) +#define S3C2412_CLKDIVN_UARTDIV_SHIFT (8) +#define S3C2412_CLKDIVN_I2SDIV_MASK (15<<12) +#define S3C2412_CLKDIVN_I2SDIV_SHIFT (12) +#define S3C2412_CLKDIVN_CAMDIV_MASK (15<<16) +#define S3C2412_CLKDIVN_CAMDIV_SHIFT (16) + +#define S3C2412_CLKCON_WDT (1<<28) +#define S3C2412_CLKCON_SPI (1<<27) +#define S3C2412_CLKCON_IIS (1<<26) +#define S3C2412_CLKCON_IIC (1<<25) +#define S3C2412_CLKCON_ADC (1<<24) +#define S3C2412_CLKCON_RTC (1<<23) +#define S3C2412_CLKCON_GPIO (1<<22) +#define S3C2412_CLKCON_UART2 (1<<21) +#define S3C2412_CLKCON_UART1 (1<<20) +#define S3C2412_CLKCON_UART0 (1<<19) +#define S3C2412_CLKCON_SDI (1<<18) +#define S3C2412_CLKCON_PWMT (1<<17) +#define S3C2412_CLKCON_USBD (1<<16) +#define S3C2412_CLKCON_CAMCLK (1<<15) +#define S3C2412_CLKCON_UARTCLK (1<<14) +/* missing 13 */ +#define S3C2412_CLKCON_USB_HOST48 (1<<12) +#define S3C2412_CLKCON_USB_DEV48 (1<<11) +#define S3C2412_CLKCON_HCLKdiv2 (1<<10) +#define S3C2412_CLKCON_HCLKx2 (1<<9) +#define S3C2412_CLKCON_SDRAM (1<<8) +/* missing 7 */ +#define S3C2412_CLKCON_USBH S3C2410_CLKCON_USBH +#define S3C2412_CLKCON_LCDC S3C2410_CLKCON_LCDC +#define S3C2412_CLKCON_NAND S3C2410_CLKCON_NAND +#define S3C2412_CLKCON_DMA3 (1<<3) +#define S3C2412_CLKCON_DMA2 (1<<2) +#define S3C2412_CLKCON_DMA1 (1<<1) +#define S3C2412_CLKCON_DMA0 (1<<0) + +/* clock sourec controls */ + +#define S3C2412_CLKSRC_EXTCLKDIV_MASK (7 << 0) +#define S3C2412_CLKSRC_EXTCLKDIV_SHIFT (0) +#define S3C2412_CLKSRC_MDIVCLK_EXTCLKDIV (1<<3) +#define S3C2412_CLKSRC_MSYSCLK_MPLL (1<<4) +#define S3C2412_CLKSRC_USYSCLK_UPLL (1<<5) +#define S3C2412_CLKSRC_UARTCLK_MPLL (1<<8) +#define S3C2412_CLKSRC_I2SCLK_MPLL (1<<9) +#define S3C2412_CLKSRC_USBCLK_HCLK (1<<10) +#define S3C2412_CLKSRC_CAMCLK_HCLK (1<<11) + +#endif /* CONFIG_CPU_S3C2412 | CONFIG_CPU_S3C2413 */ #endif /* __ASM_ARM_REGS_CLOCK */ diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h index ba13a2c9e5470e138fe1da9ad3f773dd246c0993..84aca61cbaa3d70c2edc629dc257be5593c753b9 100644 --- a/include/asm-arm/arch-s3c2410/regs-dsc.h +++ b/include/asm-arm/arch-s3c2410/regs-dsc.h @@ -23,6 +23,9 @@ #define S3C2440_DSC0 S3C2410_GPIOREG(0xc4) #define S3C2440_DSC1 S3C2410_GPIOREG(0xc8) +#define S3C2412_DSC0 S3C2410_GPIOREG(0xdc) +#define S3C2412_DSC1 S3C2410_GPIOREG(0xe0) + #define S3C2440_SELECT_DSC0 (0) #define S3C2440_SELECT_DSC1 (1<<31) diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h index 5f10334f06bf2861e9463aac9c2c8ed9906a0bd5..6dd17f0f84e0ac04f36fd4fcbc507149b7ce5656 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpio.h +++ b/include/asm-arm/arch-s3c2410/regs-gpio.h @@ -45,7 +45,7 @@ #define S3C24XX_MISCCR S3C2400_MISCCR #else #define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x) -#define S3C24XX_MISCCR S3C2410_MISCCR +#define S3C24XX_MISCCR S3C24XX_GPIOREG2(0x80) #endif /* CONFIG_CPU_S3C2400 */ @@ -73,9 +73,15 @@ #define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* not available on A */ #define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */ -/* configure GPIO ports A..G */ +/* register address for the GPIO registers. + * S3C24XX_GPIOREG2 is for the second set of registers in the + * GPIO which move between s3c2410 and s3c2412 type systems */ #define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO) +#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2) + + +/* configure GPIO ports A..G */ /* port A - S3C2410: 22bits, zero in bit X makes pin X output * S3C2400: 18bits, zero in bit X makes pin X output @@ -953,11 +959,18 @@ #define S3C2410_GPH10_OUTP (0x01 << 20) #define S3C2410_GPH10_CLKOUT1 (0x02 << 20) +/* The S3C2412 and S3C2413 move the GPJ register set to after + * GPH, which means all registers after 0x80 are now offset by 0x10 + * for the 2412/2413 from the 2410/2440/2442 +*/ + /* miscellaneous control */ #define S3C2400_MISCCR S3C2410_GPIOREG(0x54) #define S3C2410_MISCCR S3C2410_GPIOREG(0x80) #define S3C2410_DCLKCON S3C2410_GPIOREG(0x84) +#define S3C24XX_DCLKCON S3C24XX_GPIOREG2(0x84) + /* see clock.h for dclk definitions */ /* pullup control on databus */ @@ -985,6 +998,8 @@ #define S3C2410_MISCCR_CLK0_DCLK0 (5<<4) #define S3C2410_MISCCR_CLK0_MASK (7<<4) +#define S3C2412_MISCCR_CLK0_RTC (2<<4) + #define S3C2410_MISCCR_CLK1_MPLL (0<<8) #define S3C2410_MISCCR_CLK1_UPLL (1<<8) #define S3C2410_MISCCR_CLK1_FCLK (2<<8) @@ -993,6 +1008,8 @@ #define S3C2410_MISCCR_CLK1_DCLK1 (5<<8) #define S3C2410_MISCCR_CLK1_MASK (7<<8) +#define S3C2412_MISCCR_CLK1_CLKsrc (0<<8) + #define S3C2410_MISCCR_USBSUSPND0 (1<<12) #define S3C2410_MISCCR_USBSUSPND1 (1<<13) @@ -1000,7 +1017,7 @@ #define S3C2410_MISCCR_nEN_SCLK0 (1<<17) #define S3C2410_MISCCR_nEN_SCLK1 (1<<18) -#define S3C2410_MISCCR_nEN_SCLKE (1<<19) +#define S3C2410_MISCCR_nEN_SCLKE (1<<19) /* not 2412 */ #define S3C2410_MISCCR_SDSLEEP (7<<17) /* external interrupt control... */ @@ -1017,6 +1034,10 @@ #define S3C2410_EXTINT1 S3C2410_GPIOREG(0x8C) #define S3C2410_EXTINT2 S3C2410_GPIOREG(0x90) +#define S3C24XX_EXTINT0 S3C24XX_GPIOREG2(0x88) +#define S3C24XX_EXTINT1 S3C24XX_GPIOREG2(0x8C) +#define S3C24XX_EXTINT2 S3C24XX_GPIOREG2(0x90) + /* values for S3C2410_EXTINT0/1/2 */ #define S3C2410_EXTINT_LOWLEV (0x00) #define S3C2410_EXTINT_HILEV (0x01) @@ -1030,6 +1051,11 @@ #define S3C2410_EINFLT2 S3C2410_GPIOREG(0x9C) #define S3C2410_EINFLT3 S3C2410_GPIOREG(0xA0) +#define S3C24XX_EINFLT0 S3C24XX_GPIOREG2(0x94) +#define S3C24XX_EINFLT1 S3C24XX_GPIOREG2(0x98) +#define S3C24XX_EINFLT2 S3C24XX_GPIOREG2(0x9C) +#define S3C24XX_EINFLT3 S3C24XX_GPIOREG2(0xA0) + /* values for interrupt filtering */ #define S3C2410_EINTFLT_PCLK (0x00) #define S3C2410_EINTFLT_EXTCLK (1<<7) @@ -1039,6 +1065,7 @@ /* GSTATUS have miscellaneous information in them * + * These move between s3c2410 and s3c2412 style systems. */ #define S3C2410_GSTATUS0 S3C2410_GPIOREG(0x0AC) @@ -1047,6 +1074,18 @@ #define S3C2410_GSTATUS3 S3C2410_GPIOREG(0x0B8) #define S3C2410_GSTATUS4 S3C2410_GPIOREG(0x0BC) +#define S3C2412_GSTATUS0 S3C2410_GPIOREG(0x0BC) +#define S3C2412_GSTATUS1 S3C2410_GPIOREG(0x0C0) +#define S3C2412_GSTATUS2 S3C2410_GPIOREG(0x0C4) +#define S3C2412_GSTATUS3 S3C2410_GPIOREG(0x0C8) +#define S3C2412_GSTATUS4 S3C2410_GPIOREG(0x0CC) + +#define S3C24XX_GSTATUS0 S3C24XX_GPIOREG2(0x0AC) +#define S3C24XX_GSTATUS1 S3C24XX_GPIOREG2(0x0B0) +#define S3C24XX_GSTATUS2 S3C24XX_GPIOREG2(0x0B4) +#define S3C24XX_GSTATUS3 S3C24XX_GPIOREG2(0x0B8) +#define S3C24XX_GSTATUS4 S3C24XX_GPIOREG2(0x0BC) + #define S3C2410_GSTATUS0_nWAIT (1<<3) #define S3C2410_GSTATUS0_NCON (1<<2) #define S3C2410_GSTATUS0_RnB (1<<1) @@ -1054,6 +1093,7 @@ #define S3C2410_GSTATUS1_IDMASK (0xffff0000) #define S3C2410_GSTATUS1_2410 (0x32410000) +#define S3C2410_GSTATUS1_2412 (0x32412001) #define S3C2410_GSTATUS1_2440 (0x32440000) #define S3C2410_GSTATUS1_2442 (0x32440aaa) @@ -1077,5 +1117,22 @@ #define S3C2400_OPENCR_OPC_MOSIDIS (0<<5) #define S3C2400_OPENCR_OPC_MOSIEN (1<<5) +/* 2412/2413 sleep configuration registers */ + +#define S3C2412_GPBSLPCON S3C2410_GPIOREG(0x1C) +#define S3C2412_GPCSLPCON S3C2410_GPIOREG(0x2C) +#define S3C2412_GPDSLPCON S3C2410_GPIOREG(0x3C) +#define S3C2412_GPESLPCON S3C2410_GPIOREG(0x4C) +#define S3C2412_GPFSLPCON S3C2410_GPIOREG(0x5C) +#define S3C2412_GPGSLPCON S3C2410_GPIOREG(0x6C) +#define S3C2412_GPHSLPCON S3C2410_GPIOREG(0x7C) + +/* definitions for each pin bit */ +#define S3C2412_SLPCON_LOW(x) ( 0x00 << ((x) * 2)) +#define S3C2412_SLPCON_HI(x) ( 0x01 << ((x) * 2)) +#define S3C2412_SLPCON_IN(x) ( 0x02 << ((x) * 2)) +#define S3C2412_SLPCON_PDWN(x) ( 0x03 << ((x) * 2)) +#define S3C2412_SLPCON_MASK(x) ( 0x03 << ((x) * 2)) + #endif /* __ASM_ARCH_REGS_GPIO_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-gpioj.h b/include/asm-arm/arch-s3c2410/regs-gpioj.h index 3ad2324acc397698701b2bd1a1e7ecc450916657..18edae50d0b82c9897842bd038a98b054041ba14 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpioj.h +++ b/include/asm-arm/arch-s3c2410/regs-gpioj.h @@ -32,6 +32,11 @@ #define S3C2440_GPJDAT S3C2410_GPIOREG(0xd4) #define S3C2440_GPJUP S3C2410_GPIOREG(0xd8) +#define S3C2413_GPJCON S3C2410_GPIOREG(0x80) +#define S3C2413_GPJDAT S3C2410_GPIOREG(0x84) +#define S3C2413_GPJUP S3C2410_GPIOREG(0x88) +#define S3C2413_GPJSLPCON S3C2410_GPIOREG(0x8C) + #define S3C2440_GPJ0 S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 0) #define S3C2440_GPJ0_INP (0x00 << 0) #define S3C2440_GPJ0_OUTP (0x01 << 0) diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h index 24b7292df79e26802cdcc0b883ea2cfbf9251a9c..572fca5d9acfb37451cc1d13f5e86f4073c4245a 100644 --- a/include/asm-arm/arch-s3c2410/regs-irq.h +++ b/include/asm-arm/arch-s3c2410/regs-irq.h @@ -23,6 +23,7 @@ #define S3C2410_IRQREG(x) ((x) + S3C24XX_VA_IRQ) #define S3C2410_EINTREG(x) ((x) + S3C24XX_VA_GPIO) +#define S3C24XX_EINTREG(x) ((x) + S3C24XX_VA_GPIO2) #define S3C2410_SRCPND S3C2410_IRQREG(0x000) #define S3C2410_INTMOD S3C2410_IRQREG(0x004) @@ -40,5 +41,10 @@ #define S3C2410_EINTMASK S3C2410_EINTREG(0x0A4) #define S3C2410_EINTPEND S3C2410_EINTREG(0X0A8) +#define S3C2412_EINTMASK S3C2410_EINTREG(0x0B4) +#define S3C2412_EINTPEND S3C2410_EINTREG(0X0B8) + +#define S3C24XX_EINTMASK S3C24XX_EINTREG(0x0A4) +#define S3C24XX_EINTPEND S3C24XX_EINTREG(0X0A8) #endif /* ___ASM_ARCH_REGS_IRQ_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/arch-s3c2410/regs-serial.h index 83b01254c4ac7374421cbad670debe9424ef42cc..93f651ae29677908a996a9c9524824d9508a0c8d 100644 --- a/include/asm-arm/arch-s3c2410/regs-serial.h +++ b/include/asm-arm/arch-s3c2410/regs-serial.h @@ -82,6 +82,12 @@ #define S3C2440_UCON2_DIVMASK (7 << 12) #define S3C2440_UCON_DIVSHIFT (12) +#define S3C2412_UCON_CLKMASK (3<<10) +#define S3C2412_UCON_UCLK (1<<10) +#define S3C2412_UCON_USYSCLK (3<<10) +#define S3C2412_UCON_PCLK (0<<10) +#define S3C2412_UCON_PCLK2 (2<<10) + #define S3C2410_UCON_UCLK (1<<10) #define S3C2410_UCON_SBREAK (1<<4) @@ -124,6 +130,15 @@ #define S3C2410_UMCOM_AFC (1<<4) #define S3C2410_UMCOM_RTS_LOW (1<<0) +#define S3C2412_UMCON_AFC_63 (0<<5) +#define S3C2412_UMCON_AFC_56 (1<<5) +#define S3C2412_UMCON_AFC_48 (2<<5) +#define S3C2412_UMCON_AFC_40 (3<<5) +#define S3C2412_UMCON_AFC_32 (4<<5) +#define S3C2412_UMCON_AFC_24 (5<<5) +#define S3C2412_UMCON_AFC_16 (6<<5) +#define S3C2412_UMCON_AFC_8 (7<<5) + #define S3C2410_UFSTAT_TXFULL (1<<9) #define S3C2410_UFSTAT_RXFULL (1<<8) #define S3C2410_UFSTAT_TXMASK (15<<4) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 0ef50baa7da6d09b782e662ddbde7b218899a81d..951c4e858274618ba3295dbce522954088ea9379 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -130,6 +130,9 @@ /* SUN4V Hypervisor Console */ #define PORT_SUNHV 72 +#define PORT_S3C2412 73 + + #ifdef __KERNEL__ #include