diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-02 23:40:15 +0000 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-02 23:40:15 +0000 |
commit | 882d01f96bc1909455696aae6eb7ce4df3e908c8 (patch) | |
tree | 06e5789cb33d0547c2497fd4d0327dc9e8614d37 /arch/arm/plat-samsung | |
parent | 64ed28a87a0c075e91c1c5b0fe7d225a6cc6ae39 (diff) | |
parent | d608c738bb8fb37e5fbfcdef9c566764f2fea086 (diff) | |
download | lwn-882d01f96bc1909455696aae6eb7ce4df3e908c8.tar.gz lwn-882d01f96bc1909455696aae6eb7ce4df3e908c8.zip |
Merge branch 'for-rmk/samsung5' of git://git.fluff.org/bjdooks/linux into devel-stable
Conflicts:
arch/arm/Kconfig
arch/arm/Makefile
Diffstat (limited to 'arch/arm/plat-samsung')
27 files changed, 3099 insertions, 31 deletions
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index 1c2fe91c23e9..d552c65fa1b0 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -7,12 +7,50 @@ config PLAT_SAMSUNG bool depends on ARCH_S3C2410 || ARCH_S3C24A0 || ARCH_S3C64XX || ARCH_S5PC1XX + select NO_IOPORT default y help Base platform code for all Samsung SoC based systems if PLAT_SAMSUNG +# boot configurations + +comment "Boot options" + +config S3C_BOOT_WATCHDOG + bool "S3C Initialisation watchdog" + depends on S3C2410_WATCHDOG + help + Say y to enable the watchdog during the kernel decompression + stage. If the kernel fails to uncompress, then the watchdog + will trigger a reset and the system should restart. + +config S3C_BOOT_ERROR_RESET + bool "S3C Reboot on decompression error" + help + Say y here to use the watchdog to reset the system if the + kernel decompressor detects an error during decompression. + +config S3C_BOOT_UART_FORCE_FIFO + bool "Force UART FIFO on during boot process" + default y + help + Say Y here to force the UART FIFOs on during the kernel + uncompressor + + +config S3C_LOWLEVEL_UART_PORT + int "S3C UART to use for low-level messages" + default 0 + help + Choice of which UART port to use for the low-level messages, + such as the `Uncompressing...` at start time. The value of + this configuration should be between zero and two. The port + must have been initialised by the boot-loader before use. + +# clock options + config SAMSUNG_CLKSRC bool help @@ -81,6 +119,21 @@ config SAMSUNG_GPIO_EXTRA provides. This allows expanding the GPIO space for use with GPIO expanders. +config S3C_GPIO_SPACE + int "Space between gpio banks" + default 0 + help + Add a number of spare GPIO entries between each bank for debugging + purposes. This allows any problems where an counter overflows from + one bank to another to be caught, at the expense of using a little + more memory. + +config S3C_GPIO_TRACK + bool + help + Internal configuration option to enable the s3c specific gpio + chip tracking if the platform requires it. + # ADC driver config S3C_ADC @@ -132,6 +185,19 @@ config S3C_DEV_NAND help Compile in platform device definition for NAND controller +config S3C64XX_DEV_SPI + bool + help + Compile in platform device definitions for S3C64XX's type + SPI controllers. + +# DMA + +config S3C_DMA + bool + help + Internal configuration for S3C DMA core + comment "Power management" config SAMSUNG_PM_DEBUG diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index c8c8caec8cde..22c89d08f6e5 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -11,6 +11,8 @@ obj- := # Objects we always build independent of SoC choice +obj-y += init.o +obj-y += time.o obj-y += clock.o obj-y += pwm-clock.o obj-y += gpio.o @@ -39,8 +41,13 @@ obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o obj-$(CONFIG_S3C_DEV_NAND) += dev-nand.o +# DMA support + +obj-$(CONFIG_S3C_DMA) += dma.o + # PM support +obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_PM) += pm-gpio.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c index c7659b7378b1..0b5833b9ac5b 100644 --- a/arch/arm/plat-samsung/adc.c +++ b/arch/arm/plat-samsung/adc.c @@ -262,6 +262,7 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw) { struct adc_device *adc = pw; struct s3c_adc_client *client = adc->cur; + enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data; unsigned long flags; unsigned data0, data1; @@ -276,9 +277,17 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw) client->nr_samples--; + if (cpu == TYPE_S3C64XX) { + /* S3C64XX ADC resolution is 12-bit */ + data0 &= 0xfff; + data1 &= 0xfff; + } else { + data0 &= 0x3ff; + data1 &= 0x3ff; + } + if (client->convert_cb) - (client->convert_cb)(client, data0 & 0x3ff, data1 & 0x3ff, - &client->nr_samples); + (client->convert_cb)(client, data0, data1, &client->nr_samples); if (client->nr_samples > 0) { /* fire another conversion for this */ @@ -295,7 +304,7 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw) } exit: - if (platform_get_device_id(adc->pdev)->driver_data == TYPE_S3C64XX) { + if (cpu == TYPE_S3C64XX) { /* Clear ADC interrupt */ writel(0, adc->regs + S3C64XX_ADCCLRINT); } @@ -308,6 +317,7 @@ static int s3c_adc_probe(struct platform_device *pdev) struct adc_device *adc; struct resource *regs; int ret; + unsigned tmp; adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL); if (adc == NULL) { @@ -354,8 +364,12 @@ static int s3c_adc_probe(struct platform_device *pdev) clk_enable(adc->clk); - writel(adc->prescale | S3C2410_ADCCON_PRSCEN, - adc->regs + S3C2410_ADCCON); + tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; + if (platform_get_device_id(pdev)->driver_data == TYPE_S3C64XX) { + /* Enable 12-bit ADC resolution */ + tmp |= S3C64XX_ADCCON_RESSEL; + } + writel(tmp, adc->regs + S3C2410_ADCCON); dev_info(dev, "attached adc driver\n"); @@ -398,6 +412,7 @@ static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state) con |= S3C2410_ADCCON_STDBM; writel(con, adc->regs + S3C2410_ADCCON); + disable_irq(adc->irq); clk_disable(adc->clk); return 0; @@ -408,6 +423,7 @@ static int s3c_adc_resume(struct platform_device *pdev) struct adc_device *adc = platform_get_drvdata(pdev); clk_enable(adc->clk); + enable_irq(adc->irq); writel(adc->prescale | S3C2410_ADCCON_PRSCEN, adc->regs + S3C2410_ADCCON); diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c index e9cdbe47beb6..1b25c9d8c403 100644 --- a/arch/arm/plat-samsung/clock.c +++ b/arch/arm/plat-samsung/clock.c @@ -307,6 +307,12 @@ struct clk s3c24xx_uclk = { /* initialise the clock system */ +/** + * s3c24xx_register_clock() - register a clock + * @clk: The clock to register + * + * Add the specified clock to the list of clocks known by the system. + */ int s3c24xx_register_clock(struct clk *clk) { if (clk->enable == NULL) @@ -324,13 +330,25 @@ int s3c24xx_register_clock(struct clk *clk) return 0; } +/** + * s3c24xx_register_clocks() - register an array of clock pointers + * @clks: Pointer to an array of struct clk pointers + * @nr_clks: The number of clocks in the @clks array. + * + * Call s3c24xx_register_clock() for all the clock pointers contained + * in the @clks list. Returns the number of failures. + */ 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) + 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; diff --git a/arch/arm/plat-samsung/dev-usb-hsotg.c b/arch/arm/plat-samsung/dev-usb-hsotg.c index e2f604b51c86..33a844ab6917 100644 --- a/arch/arm/plat-samsung/dev-usb-hsotg.c +++ b/arch/arm/plat-samsung/dev-usb-hsotg.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <mach/irqs.h> #include <mach/map.h> @@ -33,9 +34,15 @@ static struct resource s3c_usb_hsotg_resources[] = { }, }; +static u64 s3c_hsotg_dmamask = DMA_BIT_MASK(32); + struct platform_device s3c_device_usb_hsotg = { .name = "s3c-hsotg", .id = -1, .num_resources = ARRAY_SIZE(s3c_usb_hsotg_resources), .resource = s3c_usb_hsotg_resources, + .dev = { + .dma_mask = &s3c_hsotg_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, }; diff --git a/arch/arm/plat-samsung/dma.c b/arch/arm/plat-samsung/dma.c new file mode 100644 index 000000000000..cb459dd95459 --- /dev/null +++ b/arch/arm/plat-samsung/dma.c @@ -0,0 +1,84 @@ +/* linux/arch/arm/plat-samsung/dma.c + * + * Copyright (c) 2003-2009 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C DMA core + * + * 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. +*/ + +struct s3c2410_dma_buf; + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> + +#include <mach/dma.h> +#include <mach/irqs.h> + +/* dma channel state information */ +struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS]; +struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX]; + +/* s3c_dma_lookup_channel + * + * change the dma channel number given into a real dma channel id +*/ + +struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel) +{ + if (channel & DMACH_LOW_LEVEL) + return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; + else + return s3c_dma_chan_map[channel]; +} + +/* do we need to protect the settings of the fields from + * irq? +*/ + +int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn); + + chan->op_fn = rtn; + + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_set_opfn); + +int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn); + + chan->callback_fn = rtn; + + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); + +int s3c2410_dma_setflags(unsigned int channel, unsigned int flags) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + chan->flags = flags; + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_setflags); diff --git a/arch/arm/plat-samsung/include/plat/audio.h b/arch/arm/plat-samsung/include/plat/audio.h new file mode 100644 index 000000000000..e32f9edfd4b7 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/audio.h @@ -0,0 +1,25 @@ +/* arch/arm/plat-samsung/include/plat/audio.h + * + * Copyright (c) 2009 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh <jassi.brar@samsung.com> + * + * 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. + */ + +/* The machine init code calls s3c*_ac97_setup_gpio with + * one of these defines in order to select appropriate bank + * of GPIO for AC97 pins + */ +#define S3C64XX_AC97_GPD 0 +#define S3C64XX_AC97_GPE 1 +extern void s3c64xx_ac97_setup_gpio(int); + +/** + * struct s3c_audio_pdata - common platform data for audio device drivers + * @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode + */ +struct s3c_audio_pdata { + int (*cfg_gpio)(struct platform_device *); +}; diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h index ba9a1cdd3a28..60b62692ac7a 100644 --- a/arch/arm/plat-samsung/include/plat/clock.h +++ b/arch/arm/plat-samsung/include/plat/clock.h @@ -94,7 +94,6 @@ extern void s3c_register_clocks(struct clk *clk, int nr_clks); extern int s3c24xx_register_baseclocks(unsigned long xtal); -extern void s3c64xx_register_clocks(void); extern void s5p_register_clocks(unsigned long xtal_freq); extern void s3c24xx_setup_clocks(unsigned long fclk, diff --git a/arch/arm/plat-samsung/include/plat/cpu-freq.h b/arch/arm/plat-samsung/include/plat/cpu-freq.h new file mode 100644 index 000000000000..80c4a809c721 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/cpu-freq.h @@ -0,0 +1,145 @@ +/* arch/arm/plat-samsung/include/plat/cpu-freq.h + * + * Copyright (c) 2006-2007 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C CPU frequency scaling support - driver and board + * + * 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 <linux/cpufreq.h> + +struct s3c_cpufreq_info; +struct s3c_cpufreq_board; +struct s3c_iotimings; + +/** + * struct s3c_freq - frequency information (mainly for core drivers) + * @fclk: The FCLK frequency in Hz. + * @armclk: The ARMCLK frequency in Hz. + * @hclk_tns: HCLK cycle time in 10ths of nano-seconds. + * @hclk: The HCLK frequency in Hz. + * @pclk: The PCLK frequency in Hz. + * + * This contains the frequency information about the current configuration + * mainly for the core drivers to ensure we do not end up passing about + * a large number of parameters. + * + * The @hclk_tns field is a useful cache for the parts of the drivers that + * need to calculate IO timings and suchlike. + */ +struct s3c_freq { + unsigned long fclk; + unsigned long armclk; + unsigned long hclk_tns; /* in 10ths of ns */ + unsigned long hclk; + unsigned long pclk; +}; + +/** + * struct s3c_cpufreq_freqs - s3c cpufreq notification information. + * @freqs: The cpufreq setting information. + * @old: The old clock settings. + * @new: The new clock settings. + * @pll_changing: Set if the PLL is changing. + * + * Wrapper 'struct cpufreq_freqs' so that any drivers receiving the + * notification can use this information that is not provided by just + * having the core frequency alone. + * + * The pll_changing flag is used to indicate if the PLL itself is + * being set during this change. This is important as the clocks + * will temporarily be set to the XTAL clock during this time, so + * drivers may want to close down their output during this time. + * + * Note, this is not being used by any current drivers and therefore + * may be removed in the future. + */ +struct s3c_cpufreq_freqs { + struct cpufreq_freqs freqs; + struct s3c_freq old; + struct s3c_freq new; + + unsigned int pll_changing:1; +}; + +#define to_s3c_cpufreq(_cf) container_of(_cf, struct s3c_cpufreq_freqs, freqs) + +/** + * struct s3c_clkdivs - clock divisor information + * @p_divisor: Divisor from FCLK to PCLK. + * @h_divisor: Divisor from FCLK to HCLK. + * @arm_divisor: Divisor from FCLK to ARMCLK (not all CPUs). + * @dvs: Non-zero if using DVS mode for ARMCLK. + * + * Divisor settings for the core clocks. + */ +struct s3c_clkdivs { + int p_divisor; + int h_divisor; + int arm_divisor; + unsigned char dvs; +}; + +#define PLLVAL(_m, _p, _s) (((_m) << 12) | ((_p) << 4) | (_s)) + +/** + * struct s3c_pllval - PLL value entry. + * @freq: The frequency for this entry in Hz. + * @pll_reg: The PLL register setting for this PLL value. + */ +struct s3c_pllval { + unsigned long freq; + unsigned long pll_reg; +}; + +/** + * struct s3c_cpufreq_board - per-board cpu frequency informatin + * @refresh: The SDRAM refresh period in nanoseconds. + * @auto_io: Set if the IO timing settings should be generated from the + * initialisation time hardware registers. + * @need_io: Set if the board has external IO on any of the chipselect + * lines that will require the hardware timing registers to be + * updated on a clock change. + * @max: The maxium frequency limits for the system. Any field that + * is left at zero will use the CPU's settings. + * + * This contains the board specific settings that affect how the CPU + * drivers chose settings. These include the memory refresh and IO + * timing information. + * + * Registration depends on the driver being used, the ARMCLK only + * implementation does not currently need this but the older style + * driver requires this to be available. + */ +struct s3c_cpufreq_board { + unsigned int refresh; + unsigned int auto_io:1; /* automatically init io timings. */ + unsigned int need_io:1; /* set if needs io timing support. */ + + /* any non-zero field in here is taken as an upper limit. */ + struct s3c_freq max; /* frequency limits */ +}; + +/* Things depending on frequency scaling. */ +#ifdef CONFIG_CPU_FREQ_S3C +#define __init_or_cpufreq +#else +#define __init_or_cpufreq __init +#endif + +/* Board functions */ + +#ifdef CONFIG_CPU_FREQ_S3C +extern int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board); +#else + +static inline int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) +{ + return 0; +} +#endif /* CONFIG_CPU_FREQ_S3C */ diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h new file mode 100644 index 000000000000..d316b4a579f4 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -0,0 +1,84 @@ +/* linux/arch/arm/plat-samsung/include/plat/cpu.h + * + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for S3C24XX 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. +*/ + +/* todo - fix when rmk changes iodescs to use `void __iomem *` */ + +#ifndef __SAMSUNG_PLAT_CPU_H +#define __SAMSUNG_PLAT_CPU_H + +#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE } + +#ifndef MHZ +#define MHZ (1000*1000) +#endif + +#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000) + +/* forward declaration */ +struct s3c24xx_uart_resources; +struct platform_device; +struct s3c2410_uartcfg; +struct map_desc; + +/* per-cpu initialisation function table. */ + +struct cpu_table { + unsigned long idcode; + unsigned long idmask; + void (*map_io)(void); + void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no); + void (*init_clocks)(int xtal); + int (*init)(void); + const char *name; +}; + +extern void s3c_init_cpu(unsigned long idcode, + struct cpu_table *cpus, unsigned int cputab_size); + +/* core initialisation functions */ + +extern void s3c24xx_init_irq(void); +extern void s3c64xx_init_irq(u32 vic0, u32 vic1); +extern void s5p_init_irq(u32 *vic, u32 num_vic); + +extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); +extern void s3c64xx_init_io(struct map_desc *mach_desc, int size); +extern void s5p_init_io(struct map_desc *mach_desc, + int size, void __iomem *cpuid_addr); + +extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no); + +extern void s3c24xx_init_clocks(int xtal); + +extern void s3c24xx_init_uartdevs(char *name, + struct s3c24xx_uart_resources *res, + struct s3c2410_uartcfg *cfg, int no); + +/* timer for 2410/2440 */ + +struct sys_timer; +extern struct sys_timer s3c24xx_timer; + +/* system device classes */ + +extern struct sysdev_class s3c2410_sysclass; +extern struct sysdev_class s3c2410a_sysclass; +extern struct sysdev_class s3c2412_sysclass; +extern struct sysdev_class s3c2440_sysclass; +extern struct sysdev_class s3c2442_sysclass; +extern struct sysdev_class s3c2443_sysclass; +extern struct sysdev_class s3c6410_sysclass; +extern struct sysdev_class s3c64xx_sysclass; + +extern void (*s5pc1xx_idle)(void); + +#endif diff --git a/arch/arm/plat-samsung/include/plat/debug-macro.S b/arch/arm/plat-samsung/include/plat/debug-macro.S new file mode 100644 index 000000000000..dc6efd90e8ff --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/debug-macro.S @@ -0,0 +1,87 @@ +/* arch/arm/plat-samsung/include/plat/debug-macro.S + * + * Copyright 2005, 2007 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@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. +*/ + +#include <plat/regs-serial.h> + +/* The S5PV210/S5PC110 and S5P6442 implementations are as belows. */ + + .macro fifo_level_s5pv210 rd, rx + ldr \rd, [ \rx, # S3C2410_UFSTAT ] + and \rd, \rd, #S5PV210_UFSTAT_TXMASK + .endm + + .macro fifo_full_s5pv210 rd, rx + ldr \rd, [ \rx, # S3C2410_UFSTAT ] + tst \rd, #S5PV210_UFSTAT_TXFULL + .endm + +/* The S3C2440 implementations are used by default as they are the + * most widely re-used */ + + .macro fifo_level_s3c2440 rd, rx + ldr \rd, [ \rx, # S3C2410_UFSTAT ] + and \rd, \rd, #S3C2440_UFSTAT_TXMASK + .endm + +#ifndef fifo_level +#define fifo_level fifo_level_s3c2440 +#endif + + .macro fifo_full_s3c2440 rd, rx + ldr \rd, [ \rx, # S3C2410_UFSTAT ] + tst \rd, #S3C2440_UFSTAT_TXFULL + .endm + +#ifndef fifo_full +#define fifo_full fifo_full_s3c2440 +#endif + + .macro senduart,rd,rx + strb \rd, [\rx, # S3C2410_UTXH ] + .endm + + .macro busyuart, rd, rx + ldr \rd, [ \rx, # S3C2410_UFCON ] + tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled? + beq 1001f @ + @ FIFO enabled... +1003: + fifo_full \rd, \rx + bne 1003b + b 1002f + +1001: + @ busy waiting for non fifo + ldr \rd, [ \rx, # S3C2410_UTRSTAT ] + tst \rd, #S3C2410_UTRSTAT_TXFE + beq 1001b + +1002: @ exit busyuart + .endm + + .macro waituart,rd,rx + ldr \rd, [ \rx, # S3C2410_UFCON ] + tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled? + beq 1001f @ + @ FIFO enabled... +1003: + fifo_level \rd, \rx + teq \rd, #0 + bne 1003b + b 1002f +1001: + @ idle waiting for non fifo + ldr \rd, [ \rx, # S3C2410_UTRSTAT ] + tst \rd, #S3C2410_UTRSTAT_TXFE + beq 1001b + +1002: @ exit busyuart + .endm diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h new file mode 100644 index 000000000000..796d24258313 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -0,0 +1,74 @@ +/* arch/arm/plat-samsung/include/plat/devs.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for s3c2410 standard platform devices + * + * 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 <linux/platform_device.h> + +struct s3c24xx_uart_resources { + struct resource *resources; + unsigned long nr_resources; +}; + +extern struct s3c24xx_uart_resources s3c2410_uart_resources[]; +extern struct s3c24xx_uart_resources s3c64xx_uart_resources[]; +extern struct s3c24xx_uart_resources s5p_uart_resources[]; + +extern struct platform_device *s3c24xx_uart_devs[]; +extern struct platform_device *s3c24xx_uart_src[]; + +extern struct platform_device s3c_device_timer[]; + +extern struct platform_device s3c64xx_device_iis0; +extern struct platform_device s3c64xx_device_iis1; +extern struct platform_device s3c64xx_device_iisv4; + +extern struct platform_device s3c64xx_device_spi0; +extern struct platform_device s3c64xx_device_spi1; + +extern struct platform_device s3c64xx_device_pcm0; +extern struct platform_device s3c64xx_device_pcm1; + +extern struct platform_device s3c64xx_device_ac97; + +extern struct platform_device s3c_device_ts; + +extern struct platform_device s3c_device_fb; +extern struct platform_device s3c_device_ohci; +extern struct platform_device s3c_device_lcd; +extern struct platform_device s3c_device_wdt; +extern struct platform_device s3c_device_i2c0; +extern struct platform_device s3c_device_i2c1; +extern struct platform_device s3c_device_rtc; +extern struct platform_device s3c_device_adc; +extern struct platform_device s3c_device_sdi; +extern struct platform_device s3c_device_iis; +extern struct platform_device s3c_device_hwmon; +extern struct platform_device s3c_device_hsmmc0; +extern struct platform_device s3c_device_hsmmc1; +extern struct platform_device s3c_device_hsmmc2; + +extern struct platform_device s3c_device_spi0; +extern struct platform_device s3c_device_spi1; + +extern struct platform_device s3c_device_hwmon; + +extern struct platform_device s3c_device_nand; + +extern struct platform_device s3c_device_usbgadget; +extern struct platform_device s3c_device_usb_hsotg; + +/* s3c2440 specific devices */ + +#ifdef CONFIG_CPU_S3C2440 + +extern struct platform_device s3c_device_camif; +extern struct platform_device s3c_device_ac97; + +#endif diff --git a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h new file mode 100644 index 000000000000..336d5ac02035 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h @@ -0,0 +1,84 @@ +/* linux/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h + * + * Copyright (C) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C24XX DMA support - per SoC functions + * + * 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 <plat/dma-core.h> + +extern struct sysdev_class dma_sysclass; +extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS]; + +#define DMA_CH_VALID (1<<31) +#define DMA_CH_NEVER (1<<30) + +struct s3c24xx_dma_addr { + unsigned long from; + unsigned long to; +}; + +/* struct s3c24xx_dma_map + * + * this holds the mapping information for the channel selected + * to be connected to the specified device +*/ + +struct s3c24xx_dma_map { + const char *name; + struct s3c24xx_dma_addr hw_addr; + + unsigned long channels[S3C_DMA_CHANNELS]; + unsigned long channels_rx[S3C_DMA_CHANNELS]; +}; + +struct s3c24xx_dma_selection { + struct s3c24xx_dma_map *map; + unsigned long map_size; + unsigned long dcon_mask; + + void (*select)(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map); + + void (*direction)(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map, + enum s3c2410_dmasrc dir); +}; + +extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); + +/* struct s3c24xx_dma_order_ch + * + * channel map for one of the `enum dma_ch` dma channels. the list + * entry contains a set of low-level channel numbers, orred with + * DMA_CH_VALID, which are checked in the order in the array. +*/ + +struct s3c24xx_dma_order_ch { + unsigned int list[S3C_DMA_CHANNELS]; /* list of channels */ + unsigned int flags; /* flags */ +}; + +/* struct s3c24xx_dma_order + * + * information provided by either the core or the board to give the + * dma system a hint on how to allocate channels +*/ + +struct s3c24xx_dma_order { + struct s3c24xx_dma_order_ch channels[DMACH_MAX]; +}; + +extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map); + +/* DMA init code, called from the cpu support code */ + +extern int s3c2410_dma_init(void); + +extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq, + unsigned int stride); diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h new file mode 100644 index 000000000000..7584d751ed51 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma.h @@ -0,0 +1,127 @@ +/* arch/arm/plat-samsung/include/plat/dma.h + * + * Copyright (C) 2003-2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C DMA 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. +*/ + +enum s3c2410_dma_buffresult { + S3C2410_RES_OK, + S3C2410_RES_ERR, + S3C2410_RES_ABORT +}; + +enum s3c2410_dmasrc { + S3C2410_DMASRC_HW, /* source is memory */ + S3C2410_DMASRC_MEM /* source is hardware */ +}; + +/* enum s3c2410_chan_op + * + * operation codes passed to the DMA code by the user, and also used + * to inform the current channel owner of any changes to the system state +*/ + +enum s3c2410_chan_op { + S3C2410_DMAOP_START, + S3C2410_DMAOP_STOP, + S3C2410_DMAOP_PAUSE, + S3C2410_DMAOP_RESUME, + S3C2410_DMAOP_FLUSH, + S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */ + S3C2410_DMAOP_STARTED, /* indicate channel started */ +}; + +struct s3c2410_dma_client { + char *name; +}; + +struct s3c2410_dma_chan; + +/* s3c2410_dma_cbfn_t + * + * buffer callback routine type +*/ + +typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *, + void *buf, int size, + enum s3c2410_dma_buffresult result); + +typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *, + enum s3c2410_chan_op ); + + + +/* s3c2410_dma_request + * + * request a dma channel exclusivley +*/ + +extern int s3c2410_dma_request(unsigned int channel, + struct s3c2410_dma_client *, void *dev); + + +/* s3c2410_dma_ctrl + * + * change the state of the dma channel +*/ + +extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op); + +/* s3c2410_dma_setflags + * + * set the channel's flags to a given state +*/ + +extern int s3c2410_dma_setflags(unsigned int channel, + unsigned int flags); + +/* s3c2410_dma_free + * + * free the dma channel (will also abort any outstanding operations) +*/ + +extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *); + +/* s3c2410_dma_enqueue + * + * place the given buffer onto the queue of operations for the channel. + * The buffer must be allocated from dma coherent memory, or the Dcache/WB + * drained before the buffer is given to the DMA system. +*/ + +extern int s3c2410_dma_enqueue(unsigned int channel, void *id, + dma_addr_t data, int size); + +/* s3c2410_dma_config + * + * configure the dma channel +*/ + +extern int s3c2410_dma_config(unsigned int channel, int xferunit); + +/* s3c2410_dma_devconfig + * + * configure the device we're talking to +*/ + +extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source, + unsigned long devaddr); + +/* s3c2410_dma_getposition + * + * get the position that the dma transfer is currently at +*/ + +extern int s3c2410_dma_getposition(unsigned int channel, + dma_addr_t *src, dma_addr_t *dest); + +extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn); +extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn); + + diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h new file mode 100644 index 000000000000..ffc01a76b7ce --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/fb.h @@ -0,0 +1,80 @@ +/* arch/arm/plat-samsung/include/plat/fb.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - FB platform data definitions + * + * 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. +*/ + +#ifndef __PLAT_S3C_FB_H +#define __PLAT_S3C_FB_H __FILE__ + +/** + * struct s3c_fb_pd_win - per window setup data + * @win_mode: The display parameters to initialise (not for window 0) + * @virtual_x: The virtual X size. + * @virtual_y: The virtual Y size. + */ +struct s3c_fb_pd_win { + struct fb_videomode win_mode; + + unsigned short default_bpp; + unsigned short max_bpp; + unsigned short virtual_x; + unsigned short virtual_y; +}; + +/** + * struct s3c_fb_platdata - S3C driver platform specific information + * @setup_gpio: Setup the external GPIO pins to the right state to transfer + * the data from the display system to the connected display + * device. + * @vidcon0: The base vidcon0 values to control the panel data format. + * @vidcon1: The base vidcon1 values to control the panel data output. + * @win: The setup data for each hardware window, or NULL for unused. + * @display_mode: The LCD output display mode. + * + * The platform data supplies the video driver with all the information + * it requires to work with the display(s) attached to the machine. It + * controls the initial mode, the number of display windows (0 is always + * the base framebuffer) that are initialised etc. + * + */ +struct s3c_fb_platdata { + void (*setup_gpio)(void); + + struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN]; + + u32 vidcon0; + u32 vidcon1; +}; + +/** + * s3c_fb_set_platdata() - Setup the FB device with platform data. + * @pd: The platform data to set. The data is copied from the passed structure + * so the machine data can mark the data __initdata so that any unused + * machines will end up dumping their data at runtime. + */ +extern void s3c_fb_set_platdata(struct s3c_fb_platdata *pd); + +/** + * s3c64xx_fb_gpio_setup_24bpp() - S3C64XX setup function for 24bpp LCD + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface. + */ +extern void s3c64xx_fb_gpio_setup_24bpp(void); + +/** + * s5pc100_fb_gpio_setup_24bpp() - S5PC100 setup function for 24bpp LCD + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface. + */ +extern void s5pc100_fb_gpio_setup_24bpp(void); + +#endif /* __PLAT_S3C_FB_H */ diff --git a/arch/arm/plat-samsung/include/plat/map-base.h b/arch/arm/plat-samsung/include/plat/map-base.h new file mode 100644 index 000000000000..250be311c85b --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/map-base.h @@ -0,0 +1,46 @@ +/* linux/include/asm-arm/plat-s3c/map.h + * + * Copyright 2003, 2007 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - Memory map definitions (virtual addresses) + * + * 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. +*/ + +#ifndef __ASM_PLAT_MAP_H +#define __ASM_PLAT_MAP_H __FILE__ + +/* Fit all our registers in at 0xF4000000 upwards, trying to use as + * little of the VA space as possible so vmalloc and friends have a + * better chance of getting memory. + * + * we try to ensure stuff like the IRQ registers are available for + * an single MOVS instruction (ie, only 8 bits of set data) + */ + +#define S3C_ADDR_BASE (0xF4000000) + +#ifndef __ASSEMBLY__ +#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x)) +#else +#define S3C_ADDR(x) (S3C_ADDR_BASE + (x)) +#endif + +#define S3C_VA_IRQ S3C_ADDR(0x00000000) /* irq controller(s) */ +#define S3C_VA_SYS S3C_ADDR(0x00100000) /* system control */ +#define S3C_VA_MEM S3C_ADDR(0x00200000) /* memory control */ +#define S3C_VA_TIMER S3C_ADDR(0x00300000) /* timer block */ +#define S3C_VA_WATCHDOG S3C_ADDR(0x00400000) /* watchdog */ +#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */ + +/* This is used for the CPU specific mappings that may be needed, so that + * they do not need to directly used S3C_ADDR() and thus make it easier to + * modify the space for mapping. + */ +#define S3C_ADDR_CPU(x) S3C_ADDR(0x00500000 + (x)) + +#endif /* __ASM_PLAT_MAP_H */ diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h new file mode 100644 index 000000000000..245836d91931 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -0,0 +1,189 @@ +/* arch/arm/plat-samsung/include/plat/pm.h + * + * Copyright (c) 2004 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Written by Ben Dooks, <ben@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. +*/ + +/* s3c_pm_init + * + * called from board at initialisation time to setup the power + * management +*/ + +#ifdef CONFIG_PM + +extern __init int s3c_pm_init(void); + +#else + +static inline int s3c_pm_init(void) +{ + return 0; +} +#endif + +/* configuration for the IRQ mask over sleep */ +extern unsigned long s3c_irqwake_intmask; +extern unsigned long s3c_irqwake_eintmask; + +/* IRQ masks for IRQs allowed to go to sleep (see irq.c) */ +extern unsigned long s3c_irqwake_intallow; +extern unsigned long s3c_irqwake_eintallow; + +/* per-cpu sleep functions */ + +extern void (*pm_cpu_prep)(void); +extern void (*pm_cpu_sleep)(void); + +/* Flags for PM Control */ + +extern unsigned long s3c_pm_flags; + +extern unsigned char pm_uart_udivslot; /* true to save UART UDIVSLOT */ + +/* from sleep.S */ + +extern int s3c_cpu_save(unsigned long *saveblk); +extern void s3c_cpu_resume(void); + +extern void s3c2410_cpu_suspend(void); + +extern unsigned long s3c_sleep_save_phys; + +/* sleep save info */ + +/** + * struct sleep_save - save information for shared peripherals. + * @reg: Pointer to the register to save. + * @val: Holder for the value saved from reg. + * + * This describes a list of registers which is used by the pm core and + * other subsystem to save and restore register values over suspend. + */ +struct sleep_save { + void __iomem *reg; + unsigned long val; +}; + +#define SAVE_ITEM(x) \ + { .reg = (x) } + +/** + * struct pm_uart_save - save block for core UART + * @ulcon: Save value for S3C2410_ULCON + * @ucon: Save value for S3C2410_UCON + * @ufcon: Save value for S3C2410_UFCON + * @umcon: Save value for S3C2410_UMCON + * @ubrdiv: Save value for S3C2410_UBRDIV + * + * Save block for UART registers to be held over sleep and restored if they + * are needed (say by debug). +*/ +struct pm_uart_save { + u32 ulcon; + u32 ucon; + u32 ufcon; + u32 umcon; + u32 ubrdiv; + u32 udivslot; +}; + +/* helper functions to save/restore lists of registers. */ + +extern void s3c_pm_do_save(struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore(struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count); + +#ifdef CONFIG_PM +extern int s3c_irqext_wake(unsigned int irqno, unsigned int state); +extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state); +extern int s3c24xx_irq_resume(struct sys_device *dev); +#else +#define s3c_irqext_wake NULL +#define s3c24xx_irq_suspend NULL +#define s3c24xx_irq_resume NULL +#endif + +/* PM debug functions */ + +#ifdef CONFIG_SAMSUNG_PM_DEBUG +/** + * s3c_pm_dbg() - low level debug function for use in suspend/resume. + * @msg: The message to print. + * + * This function is used mainly to debug the resume process before the system + * can rely on printk/console output. It uses the low-level debugging output + * routine printascii() to do its work. + */ +extern void s3c_pm_dbg(const char *msg, ...); + +#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt) +#else +#define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt) +#endif + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK +/** + * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs + * @set: set bits for the state of the LEDs + * @clear: clear bits for the state of the LEDs. + */ +extern void s3c_pm_debug_smdkled(u32 set, u32 clear); + +#else +static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { } +#endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */ + +/* suspend memory checking */ + +#ifdef CONFIG_SAMSUNG_PM_CHECK +extern void s3c_pm_check_prepare(void); +extern void s3c_pm_check_restore(void); +extern void s3c_pm_check_cleanup(void); +extern void s3c_pm_check_store(void); +#else +#define s3c_pm_check_prepare() do { } while(0) +#define s3c_pm_check_restore() do { } while(0) +#define s3c_pm_check_cleanup() do { } while(0) +#define s3c_pm_check_store() do { } while(0) +#endif + +/** + * s3c_pm_configure_extint() - ensure pins are correctly set for IRQ + * + * Setup all the necessary GPIO pins for waking the system on external + * interrupt. + */ +extern void s3c_pm_configure_extint(void); + +/** + * s3c_pm_restore_gpios() - restore the state of the gpios after sleep. + * + * Restore the state of the GPIO pins after sleep, which may involve ensuring + * that we do not glitch the state of the pins from that the bootloader's + * resume code has done. +*/ +extern void s3c_pm_restore_gpios(void); + +/** + * s3c_pm_save_gpios() - save the state of the GPIOs for restoring after sleep. + * + * Save the GPIO states for resotration on resume. See s3c_pm_restore_gpios(). + */ +extern void s3c_pm_save_gpios(void); + +/** + * s3c_pm_cb_flushcache - callback for assembly code + * + * Callback to issue flush_cache_all() as this call is + * not a directly callable object. + */ +extern void s3c_pm_cb_flushcache(void); + +extern void s3c_pm_save_core(void); +extern void s3c_pm_restore_core(void); diff --git a/arch/arm/plat-samsung/include/plat/regs-adc.h b/arch/arm/plat-samsung/include/plat/regs-adc.h index f43c8dab39e4..7554c4fcddb9 100644 --- a/arch/arm/plat-samsung/include/plat/regs-adc.h +++ b/arch/arm/plat-samsung/include/plat/regs-adc.h @@ -25,6 +25,7 @@ /* ADCCON Register Bits */ +#define S3C64XX_ADCCON_RESSEL (1<<16) #define S3C2410_ADCCON_ECFLG (1<<15) #define S3C2410_ADCCON_PRSCEN (1<<14) #define S3C2410_ADCCON_PRSCVL(x) (((x)&0xFF)<<6) diff --git a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h b/arch/arm/plat-samsung/include/plat/regs-fb-v4.h new file mode 100644 index 000000000000..0f43599248ad --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-fb-v4.h @@ -0,0 +1,235 @@ +/* arch/arm/plat-samsung/include/plat/regs-fb-v4.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C64XX - new-style framebuffer register definitions + * + * This is the register set for the new style framebuffer interface + * found from the S3C2443 onwards and specifically the S3C64XX series + * S3C6400 and S3C6410. + * + * The file contains the cpu specific items which change between whichever + * architecture is selected. See <plat/regs-fb.h> for the core definitions + * that are the same. + * + * 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 the core definitions here, in case we really do need to + * override them at a later date. +*/ + +#include <plat/regs-fb.h> + +#define S3C_FB_MAX_WIN (5) /* number of hardware windows available. */ +#define VIDCON1_FSTATUS_EVEN (1 << 15) + +/* Video timing controls */ +#define VIDTCON0 (0x10) +#define VIDTCON1 (0x14) +#define VIDTCON2 (0x18) + +/* Window position controls */ + +#define WINCON(_win) (0x20 + ((_win) * 4)) + +/* OSD1 and OSD4 do not have register D */ + +#define VIDOSD_A(_win) (0x40 + ((_win) * 16)) +#define VIDOSD_B(_win) (0x44 + ((_win) * 16)) +#define VIDOSD_C(_win) (0x48 + ((_win) * 16)) +#define VIDOSD_D(_win) (0x4C + ((_win) * 16)) + + +#define VIDINTCON0 (0x130) + +#define WxKEYCONy(_win, _con) ((0x140 + ((_win) * 8)) + ((_con) * 4)) + +/* WINCONx */ + +#define WINCONx_CSCWIDTH_MASK (0x3 << 26) +#define WINCONx_CSCWIDTH_SHIFT (26) +#define WINCONx_CSCWIDTH_WIDE (0x0 << 26) +#define WINCONx_CSCWIDTH_NARROW (0x3 << 26) + +#define WINCONx_ENLOCAL (1 << 22) +#define WINCONx_BUFSTATUS (1 << 21) +#define WINCONx_BUFSEL (1 << 20) +#define WINCONx_BUFAUTOEN (1 << 19) +#define WINCONx_YCbCr (1 << 13) + +#define WINCON1_LOCALSEL_CAMIF (1 << 23) + +#define WINCON2_LOCALSEL_CAMIF (1 << 23) +#define WINCON2_BLD_PIX (1 << 6) + +#define WINCON2_ALPHA_SEL (1 << 1) +#define WINCON2_BPPMODE_MASK (0xf << 2) +#define WINCON2_BPPMODE_SHIFT (2) +#define WINCON2_BPPMODE_1BPP (0x0 << 2) +#define WINCON2_BPPMODE_2BPP (0x1 << 2) +#define WINCON2_BPPMODE_4BPP (0x2 << 2) +#define WINCON2_BPPMODE_8BPP_1232 (0x4 << 2) +#define WINCON2_BPPMODE_16BPP_565 (0x5 << 2) +#define WINCON2_BPPMODE_16BPP_A1555 (0x6 << 2) +#define WINCON2_BPPMODE_16BPP_I1555 (0x7 << 2) +#define WINCON2_BPPMODE_18BPP_666 (0x8 << 2) +#define WINCON2_BPPMODE_18BPP_A1665 (0x9 << 2) +#define WINCON2_BPPMODE_19BPP_A1666 (0xa << 2) +#define WINCON2_BPPMODE_24BPP_888 (0xb << 2) +#define WINCON2_BPPMODE_24BPP_A1887 (0xc << 2) +#define WINCON2_BPPMODE_25BPP_A1888 (0xd << 2) +#define WINCON2_BPPMODE_28BPP_A4888 (0xd << 2) + +#define WINCON3_BLD_PIX (1 << 6) + +#define WINCON3_ALPHA_SEL (1 << 1) +#define WINCON3_BPPMODE_MASK (0xf << 2) +#define WINCON3_BPPMODE_SHIFT (2) +#define WINCON3_BPPMODE_1BPP (0x0 << 2) +#define WINCON3_BPPMODE_2BPP (0x1 << 2) +#define WINCON3_BPPMODE_4BPP (0x2 << 2) +#define WINCON3_BPPMODE_16BPP_565 (0x5 << 2) +#define WINCON3_BPPMODE_16BPP_A1555 (0x6 << 2) +#define WINCON3_BPPMODE_16BPP_I1555 (0x7 << 2) +#define WINCON3_BPPMODE_18BPP_666 (0x8 << 2) +#define WINCON3_BPPMODE_18BPP_A1665 (0x9 << 2) +#define WINCON3_BPPMODE_19BPP_A1666 (0xa << 2) +#define WINCON3_BPPMODE_24BPP_888 (0xb << 2) +#define WINCON3_BPPMODE_24BPP_A1887 (0xc << 2) +#define WINCON3_BPPMODE_25BPP_A1888 (0xd << 2) +#define WINCON3_BPPMODE_28BPP_A4888 (0xd << 2) + +#define VIDINTCON0_FIFIOSEL_WINDOW2 (0x10 << 5) +#define VIDINTCON0_FIFIOSEL_WINDOW3 (0x20 << 5) +#define VIDINTCON0_FIFIOSEL_WINDOW4 (0x40 << 5) + +#define DITHMODE (0x170) +#define WINxMAP(_win) (0x180 + ((_win) * 4)) + + +#define DITHMODE_R_POS_MASK (0x3 << 5) +#define DITHMODE_R_POS_SHIFT (5) +#define DITHMODE_R_POS_8BIT (0x0 << 5) +#define DITHMODE_R_POS_6BIT (0x1 << 5) +#define DITHMODE_R_POS_5BIT (0x2 << 5) + +#define DITHMODE_G_POS_MASK (0x3 << 3) +#define DITHMODE_G_POS_SHIFT (3) +#define DITHMODE_G_POS_8BIT (0x0 << 3) +#define DITHMODE_G_POS_6BIT (0x1 << 3) +#define DITHMODE_G_POS_5BIT (0x2 << 3) + +#define DITHMODE_B_POS_MASK (0x3 << 1) +#define DITHMODE_B_POS_SHIFT (1) +#define DITHMODE_B_POS_8BIT (0x0 << 1) +#define DITHMODE_B_POS_6BIT (0x1 << 1) +#define DITHMODE_B_POS_5BIT (0x2 << 1) + +#define DITHMODE_DITH_EN (1 << 0) + +#define WPALCON (0x1A0) + +/* Palette control */ +/* Note for S5PC100: you can still use those macros on WPALCON (aka WPALCON_L), + * but make sure that WPALCON_H W2PAL-W4PAL entries are zeroed out */ +#define WPALCON_W4PAL_16BPP_A555 (1 << 8) +#define WPALCON_W3PAL_16BPP_A555 (1 << 7) +#define WPALCON_W2PAL_16BPP_A555 (1 << 6) + + +/* system specific implementation code for palette sizes, and other + * information that changes depending on which architecture is being + * compiled. +*/ + +/* return true if window _win has OSD register D */ +#define s3c_fb_has_osd_d(_win) ((_win) != 4 && (_win) != 0) + +static inline unsigned int s3c_fb_win_pal_size(unsigned int win) +{ + if (win < 2) + return 256; + if (win < 4) + return 16; + if (win == 4) + return 4; + + BUG(); /* shouldn't get here */ +} + +static inline int s3c_fb_validate_win_bpp(unsigned int win, unsigned int bpp) +{ + /* all windows can do 1/2 bpp */ + + if ((bpp == 25 || bpp == 19) && win == 0) + return 0; /* win 0 does not have 19 or 25bpp modes */ + + if (bpp == 4 && win == 4) + return 0; + + if (bpp == 8 && (win >= 3)) + return 0; /* win 3/4 cannot do 8bpp in any mode */ + + return 1; +} + +static inline int s3c_fb_pal_is16(unsigned int window) +{ + return window > 1; +} + +struct s3c_fb_palette { + struct fb_bitfield r; + struct fb_bitfield g; + struct fb_bitfield b; + struct fb_bitfield a; +}; + +static inline void s3c_fb_init_palette(unsigned int window, + struct s3c_fb_palette *palette) +{ + if (window < 2) { + /* Windows 0/1 are 8/8/8 or A/8/8/8 */ + palette->r.offset = 16; + palette->r.length = 8; + palette->g.offset = 8; + palette->g.length = 8; + palette->b.offset = 0; + palette->b.length = 8; + } else { + /* currently we assume RGB 5/6/5 */ + palette->r.offset = 11; + palette->r.length = 5; + palette->g.offset = 5; + palette->g.length = 6; + palette->b.offset = 0; + palette->b.length = 5; + } +} + +/* Notes on per-window bpp settings + * + * Value Win0 Win1 Win2 Win3 Win 4 + * 0000 1(P) 1(P) 1(P) 1(P) 1(P) + * 0001 2(P) 2(P) 2(P) 2(P) 2(P) + * 0010 4(P) 4(P) 4(P) 4(P) -none- + * 0011 8(P) 8(P) -none- -none- -none- + * 0100 -none- 8(A232) 8(A232) -none- -none- + * 0101 16(565) 16(565) 16(565) 16(565) 16(565) + * 0110 -none- 16(A555) 16(A555) 16(A555) 16(A555) + * 0111 16(I555) 16(I565) 16(I555) 16(I555) 16(I555) + * 1000 18(666) 18(666) 18(666) 18(666) 18(666) + * 1001 -none- 18(A665) 18(A665) 18(A665) 16(A665) + * 1010 -none- 19(A666) 19(A666) 19(A666) 19(A666) + * 1011 24(888) 24(888) 24(888) 24(888) 24(888) + * 1100 -none- 24(A887) 24(A887) 24(A887) 24(A887) + * 1101 -none- 25(A888) 25(A888) 25(A888) 25(A888) + * 1110 -none- -none- -none- -none- -none- + * 1111 -none- -none- -none- -none- -none- +*/ diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/arch/arm/plat-samsung/include/plat/regs-fb.h new file mode 100644 index 000000000000..0ef806e50344 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-fb.h @@ -0,0 +1,366 @@ +/* arch/arm/plat-samsung/include/plat/regs-fb.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Platform - new-style framebuffer register definitions + * + * This is the register set for the new style framebuffer interface + * found from the S3C2443 onwards into the S3C2416, S3C2450 and the + * S3C64XX series such as the S3C6400 and S3C6410. + * + * The file does not contain the cpu specific items which are based on + * whichever architecture is selected, it only contains the core of the + * register set. See <mach/regs-fb.h> to get the specifics. + * + * Note, we changed to using regs-fb.h as it avoids any clashes with + * the original regs-lcd.h so out of the way of regs-lcd.h as well as + * indicating the newer block is much more than just an LCD interface. + * + * 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. +*/ + +/* Please do not include this file directly, use <mach/regs-fb.h> to + * ensure all the localised SoC support is included as necessary. +*/ + +/* VIDCON0 */ + +#define VIDCON0 (0x00) +#define VIDCON0_INTERLACE (1 << 29) +#define VIDCON0_VIDOUT_MASK (0x3 << 26) +#define VIDCON0_VIDOUT_SHIFT (26) +#define VIDCON0_VIDOUT_RGB (0x0 << 26) +#define VIDCON0_VIDOUT_TV (0x1 << 26) +#define VIDCON0_VIDOUT_I80_LDI0 (0x2 << 26) +#define VIDCON0_VIDOUT_I80_LDI1 (0x3 << 26) + +#define VIDCON0_L1_DATA_MASK (0x7 << 23) +#define VIDCON0_L1_DATA_SHIFT (23) +#define VIDCON0_L1_DATA_16BPP (0x0 << 23) +#define VIDCON0_L1_DATA_18BPP16 (0x1 << 23) +#define VIDCON0_L1_DATA_18BPP9 (0x2 << 23) +#define VIDCON0_L1_DATA_24BPP (0x3 << 23) +#define VIDCON0_L1_DATA_18BPP (0x4 << 23) +#define VIDCON0_L1_DATA_16BPP8 (0x5 << 23) + +#define VIDCON0_L0_DATA_MASK (0x7 << 20) +#define VIDCON0_L0_DATA_SHIFT (20) +#define VIDCON0_L0_DATA_16BPP (0x0 << 20) +#define VIDCON0_L0_DATA_18BPP16 (0x1 << 20) +#define VIDCON0_L0_DATA_18BPP9 (0x2 << 20) +#define VIDCON0_L0_DATA_24BPP (0x3 << 20) +#define VIDCON0_L0_DATA_18BPP (0x4 << 20) +#define VIDCON0_L0_DATA_16BPP8 (0x5 << 20) + +#define VIDCON0_PNRMODE_MASK (0x3 << 17) +#define VIDCON0_PNRMODE_SHIFT (17) +#define VIDCON0_PNRMODE_RGB (0x0 << 17) +#define VIDCON0_PNRMODE_BGR (0x1 << 17) +#define VIDCON0_PNRMODE_SERIAL_RGB (0x2 << 17) +#define VIDCON0_PNRMODE_SERIAL_BGR (0x3 << 17) + +#define VIDCON0_CLKVALUP (1 << 16) +#define VIDCON0_CLKVAL_F_MASK (0xff << 6) +#define VIDCON0_CLKVAL_F_SHIFT (6) +#define VIDCON0_CLKVAL_F_LIMIT (0xff) +#define VIDCON0_CLKVAL_F(_x) ((_x) << 6) +#define VIDCON0_VLCKFREE (1 << 5) +#define VIDCON0_CLKDIR (1 << 4) + +#define VIDCON0_CLKSEL_MASK (0x3 << 2) +#define VIDCON0_CLKSEL_SHIFT (2) +#define VIDCON0_CLKSEL_HCLK (0x0 << 2) +#define VIDCON0_CLKSEL_LCD (0x1 << 2) +#define VIDCON0_CLKSEL_27M (0x3 << 2) + +#define VIDCON0_ENVID (1 << 1) +#define VIDCON0_ENVID_F (1 << 0) + +#define VIDCON1 (0x04) +#define VIDCON1_LINECNT_MASK (0x7ff << 16) +#define VIDCON1_LINECNT_SHIFT (16) +#define VIDCON1_LINECNT_GET(_v) (((_v) >> 16) & 0x7ff) +#define VIDCON1_VSTATUS_MASK (0x3 << 13) +#define VIDCON1_VSTATUS_SHIFT (13) +#define VIDCON1_VSTATUS_VSYNC (0x0 << 13) +#define VIDCON1_VSTATUS_BACKPORCH (0x1 << 13) +#define VIDCON1_VSTATUS_ACTIVE (0x2 << 13) +#define VIDCON1_VSTATUS_FRONTPORCH (0x0 << 13) + +#define VIDCON1_INV_VCLK (1 << 7) +#define VIDCON1_INV_HSYNC (1 << 6) +#define VIDCON1_INV_VSYNC (1 << 5) +#define VIDCON1_INV_VDEN (1 << 4) + +/* VIDCON2 */ + +#define VIDCON2 (0x08) +#define VIDCON2_EN601 (1 << 23) +#define VIDCON2_TVFMTSEL_SW (1 << 14) + +#define VIDCON2_TVFMTSEL1_MASK (0x3 << 12) +#define VIDCON2_TVFMTSEL1_SHIFT (12) +#define VIDCON2_TVFMTSEL1_RGB (0x0 << 12) +#define VIDCON2_TVFMTSEL1_YUV422 (0x1 << 12) +#define VIDCON2_TVFMTSEL1_YUV444 (0x2 << 12) + +#define VIDCON2_ORGYCbCr (1 << 8) +#define VIDCON2_YUVORDCrCb (1 << 7) + +/* VIDTCON0 */ + +#define VIDTCON0_VBPDE_MASK (0xff << 24) +#define VIDTCON0_VBPDE_SHIFT (24) +#define VIDTCON0_VBPDE_LIMIT (0xff) +#define VIDTCON0_VBPDE(_x) ((_x) << 24) + +#define VIDTCON0_VBPD_MASK (0xff << 16) +#define VIDTCON0_VBPD_SHIFT (16) +#define VIDTCON0_VBPD_LIMIT (0xff) +#define VIDTCON0_VBPD(_x) ((_x) << 16) + +#define VIDTCON0_VFPD_MASK (0xff << 8) +#define VIDTCON0_VFPD_SHIFT (8) +#define VIDTCON0_VFPD_LIMIT (0xff) +#define VIDTCON0_VFPD(_x) ((_x) << 8) + +#define VIDTCON0_VSPW_MASK (0xff << 0) +#define VIDTCON0_VSPW_SHIFT (0) +#define VIDTCON0_VSPW_LIMIT (0xff) +#define VIDTCON0_VSPW(_x) ((_x) << 0) + +/* VIDTCON1 */ + +#define VIDTCON1_VFPDE_MASK (0xff << 24) +#define VIDTCON1_VFPDE_SHIFT (24) +#define VIDTCON1_VFPDE_LIMIT (0xff) +#define VIDTCON1_VFPDE(_x) ((_x) << 24) + +#define VIDTCON1_HBPD_MASK (0xff << 16) +#define VIDTCON1_HBPD_SHIFT (16) +#define VIDTCON1_HBPD_LIMIT (0xff) +#define VIDTCON1_HBPD(_x) ((_x) << 16) + +#define VIDTCON1_HFPD_MASK (0xff << 8) +#define VIDTCON1_HFPD_SHIFT (8) +#define VIDTCON1_HFPD_LIMIT (0xff) +#define VIDTCON1_HFPD(_x) ((_x) << 8) + +#define VIDTCON1_HSPW_MASK (0xff << 0) +#define VIDTCON1_HSPW_SHIFT (0) +#define VIDTCON1_HSPW_LIMIT (0xff) +#define VIDTCON1_HSPW(_x) ((_x) << 0) + +#define VIDTCON2 (0x18) +#define VIDTCON2_LINEVAL_MASK (0x7ff << 11) +#define VIDTCON2_LINEVAL_SHIFT (11) +#define VIDTCON2_LINEVAL_LIMIT (0x7ff) +#define VIDTCON2_LINEVAL(_x) ((_x) << 11) + +#define VIDTCON2_HOZVAL_MASK (0x7ff << 0) +#define VIDTCON2_HOZVAL_SHIFT (0) +#define VIDTCON2_HOZVAL_LIMIT (0x7ff) +#define VIDTCON2_HOZVAL(_x) ((_x) << 0) + +/* WINCONx */ + + +#define WINCONx_BITSWP (1 << 18) +#define WINCONx_BYTSWP (1 << 17) +#define WINCONx_HAWSWP (1 << 16) +#define WINCONx_BURSTLEN_MASK (0x3 << 9) +#define WINCONx_BURSTLEN_SHIFT (9) +#define WINCONx_BURSTLEN_16WORD (0x0 << 9) +#define WINCONx_BURSTLEN_8WORD (0x1 << 9) +#define WINCONx_BURSTLEN_4WORD (0x2 << 9) + +#define WINCONx_ENWIN (1 << 0) +#define WINCON0_BPPMODE_MASK (0xf << 2) +#define WINCON0_BPPMODE_SHIFT (2) +#define WINCON0_BPPMODE_1BPP (0x0 << 2) +#define WINCON0_BPPMODE_2BPP (0x1 << 2) +#define WINCON0_BPPMODE_4BPP (0x2 << 2) +#define WINCON0_BPPMODE_8BPP_PALETTE (0x3 << 2) +#define WINCON0_BPPMODE_16BPP_565 (0x5 << 2) +#define WINCON0_BPPMODE_16BPP_1555 (0x7 << 2) +#define WINCON0_BPPMODE_18BPP_666 (0x8 << 2) +#define WINCON0_BPPMODE_24BPP_888 (0xb << 2) + +#define WINCON1_BLD_PIX (1 << 6) + +#define WINCON1_ALPHA_SEL (1 << 1) +#define WINCON1_BPPMODE_MASK (0xf << 2) +#define WINCON1_BPPMODE_SHIFT (2) +#define WINCON1_BPPMODE_1BPP (0x0 << 2) +#define WINCON1_BPPMODE_2BPP (0x1 << 2) +#define WINCON1_BPPMODE_4BPP (0x2 << 2) +#define WINCON1_BPPMODE_8BPP_PALETTE (0x3 << 2) +#define WINCON1_BPPMODE_8BPP_1232 (0x4 << 2) +#define WINCON1_BPPMODE_16BPP_565 (0x5 << 2) +#define WINCON1_BPPMODE_16BPP_A1555 (0x6 << 2) +#define WINCON1_BPPMODE_16BPP_I1555 (0x7 << 2) +#define WINCON1_BPPMODE_18BPP_666 (0x8 << 2) +#define WINCON1_BPPMODE_18BPP_A1665 (0x9 << 2) +#define WINCON1_BPPMODE_19BPP_A1666 (0xa << 2) +#define WINCON1_BPPMODE_24BPP_888 (0xb << 2) +#define WINCON1_BPPMODE_24BPP_A1887 (0xc << 2) +#define WINCON1_BPPMODE_25BPP_A1888 (0xd << 2) +#define WINCON1_BPPMODE_28BPP_A4888 (0xd << 2) + + +#define VIDOSDxA_TOPLEFT_X_MASK (0x7ff << 11) +#define VIDOSDxA_TOPLEFT_X_SHIFT (11) +#define VIDOSDxA_TOPLEFT_X_LIMIT (0x7ff) +#define VIDOSDxA_TOPLEFT_X(_x) ((_x) << 11) + +#define VIDOSDxA_TOPLEFT_Y_MASK (0x7ff << 0) +#define VIDOSDxA_TOPLEFT_Y_SHIFT (0) +#define VIDOSDxA_TOPLEFT_Y_LIMIT (0x7ff) +#define VIDOSDxA_TOPLEFT_Y(_x) ((_x) << 0) + +#define VIDOSDxB_BOTRIGHT_X_MASK (0x7ff << 11) +#define VIDOSDxB_BOTRIGHT_X_SHIFT (11) +#define VIDOSDxB_BOTRIGHT_X_LIMIT (0x7ff) +#define VIDOSDxB_BOTRIGHT_X(_x) ((_x) << 11) + +#define VIDOSDxB_BOTRIGHT_Y_MASK (0x7ff << 0) +#define VIDOSDxB_BOTRIGHT_Y_SHIFT (0) +#define VIDOSDxB_BOTRIGHT_Y_LIMIT (0x7ff) +#define VIDOSDxB_BOTRIGHT_Y(_x) ((_x) << 0) + +/* For VIDOSD[1..4]C */ +#define VIDISD14C_ALPHA0_R(_x) ((_x) << 20) +#define VIDISD14C_ALPHA0_G_MASK (0xf << 16) +#define VIDISD14C_ALPHA0_G_SHIFT (16) +#define VIDISD14C_ALPHA0_G_LIMIT (0xf) +#define VIDISD14C_ALPHA0_G(_x) ((_x) << 16) +#define VIDISD14C_ALPHA0_B_MASK (0xf << 12) +#define VIDISD14C_ALPHA0_B_SHIFT (12) +#define VIDISD14C_ALPHA0_B_LIMIT (0xf) +#define VIDISD14C_ALPHA0_B(_x) ((_x) << 12) +#define VIDISD14C_ALPHA1_R_MASK (0xf << 8) +#define VIDISD14C_ALPHA1_R_SHIFT (8) +#define VIDISD14C_ALPHA1_R_LIMIT (0xf) +#define VIDISD14C_ALPHA1_R(_x) ((_x) << 8) +#define VIDISD14C_ALPHA1_G_MASK (0xf << 4) +#define VIDISD14C_ALPHA1_G_SHIFT (4) +#define VIDISD14C_ALPHA1_G_LIMIT (0xf) +#define VIDISD14C_ALPHA1_G(_x) ((_x) << 4) +#define VIDISD14C_ALPHA1_B_MASK (0xf << 0) +#define VIDISD14C_ALPHA1_B_SHIFT (0) +#define VIDISD14C_ALPHA1_B_LIMIT (0xf) +#define VIDISD14C_ALPHA1_B(_x) ((_x) << 0) + +/* Video buffer addresses */ +#define VIDW_BUF_START(_buff) (0xA0 + ((_buff) * 8)) +#define VIDW_BUF_START1(_buff) (0xA4 + ((_buff) * 8)) +#define VIDW_BUF_END(_buff) (0xD0 + ((_buff) * 8)) +#define VIDW_BUF_END1(_buff) (0xD4 + ((_buff) * 8)) +#define VIDW_BUF_SIZE(_buff) (0x100 + ((_buff) * 4)) + +#define VIDW_BUF_SIZE_OFFSET_MASK (0x1fff << 13) +#define VIDW_BUF_SIZE_OFFSET_SHIFT (13) +#define VIDW_BUF_SIZE_OFFSET_LIMIT (0x1fff) +#define VIDW_BUF_SIZE_OFFSET(_x) ((_x) << 13) + +#define VIDW_BUF_SIZE_PAGEWIDTH_MASK (0x1fff << 0) +#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT (0) +#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT (0x1fff) +#define VIDW_BUF_SIZE_PAGEWIDTH(_x) ((_x) << 0) + +/* Interrupt controls and status */ + +#define VIDINTCON0_FIFOINTERVAL_MASK (0x3f << 20) +#define VIDINTCON0_FIFOINTERVAL_SHIFT (20) +#define VIDINTCON0_FIFOINTERVAL_LIMIT (0x3f) +#define VIDINTCON0_FIFOINTERVAL(_x) ((_x) << 20) + +#define VIDINTCON0_INT_SYSMAINCON (1 << 19) +#define VIDINTCON0_INT_SYSSUBCON (1 << 18) +#define VIDINTCON0_INT_I80IFDONE (1 << 17) + +#define VIDINTCON0_FRAMESEL0_MASK (0x3 << 15) +#define VIDINTCON0_FRAMESEL0_SHIFT (15) +#define VIDINTCON0_FRAMESEL0_BACKPORCH (0x0 << 15) +#define VIDINTCON0_FRAMESEL0_VSYNC (0x1 << 15) +#define VIDINTCON0_FRAMESEL0_ACTIVE (0x2 << 15) +#define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15) + +#define VIDINTCON0_FRAMESEL1 (1 << 14) +#define VIDINTCON0_FRAMESEL1_NONE (0x0 << 14) +#define VIDINTCON0_FRAMESEL1_BACKPORCH (0x1 << 14) +#define VIDINTCON0_FRAMESEL1_VSYNC (0x2 << 14) +#define VIDINTCON0_FRAMESEL1_FRONTPORCH (0x3 << 14) + +#define VIDINTCON0_INT_FRAME (1 << 12) +#define VIDINTCON0_FIFIOSEL_MASK (0x7f << 5) +#define VIDINTCON0_FIFIOSEL_SHIFT (5) +#define VIDINTCON0_FIFIOSEL_WINDOW0 (0x1 << 5) +#define VIDINTCON0_FIFIOSEL_WINDOW1 (0x2 << 5) + +#define VIDINTCON0_FIFOLEVEL_MASK (0x7 << 2) +#define VIDINTCON0_FIFOLEVEL_SHIFT (2) +#define VIDINTCON0_FIFOLEVEL_TO25PC (0x0 << 2) +#define VIDINTCON0_FIFOLEVEL_TO50PC (0x1 << 2) +#define VIDINTCON0_FIFOLEVEL_TO75PC (0x2 << 2) +#define VIDINTCON0_FIFOLEVEL_EMPTY (0x3 << 2) +#define VIDINTCON0_FIFOLEVEL_FULL (0x4 << 2) + +#define VIDINTCON0_INT_FIFO_MASK (0x3 << 0) +#define VIDINTCON0_INT_FIFO_SHIFT (0) +#define VIDINTCON0_INT_ENABLE (1 << 0) + +#define VIDINTCON1 (0x134) +#define VIDINTCON1_INT_I180 (1 << 2) +#define VIDINTCON1_INT_FRAME (1 << 1) +#define VIDINTCON1_INT_FIFO (1 << 0) + +/* Window colour-key control registers */ + +#define WxKEYCON0_KEYBL_EN (1 << 26) +#define WxKEYCON0_KEYEN_F (1 << 25) +#define WxKEYCON0_DIRCON (1 << 24) +#define WxKEYCON0_COMPKEY_MASK (0xffffff << 0) +#define WxKEYCON0_COMPKEY_SHIFT (0) +#define WxKEYCON0_COMPKEY_LIMIT (0xffffff) +#define WxKEYCON0_COMPKEY(_x) ((_x) << 0) +#define WxKEYCON1_COLVAL_MASK (0xffffff << 0) +#define WxKEYCON1_COLVAL_SHIFT (0) +#define WxKEYCON1_COLVAL_LIMIT (0xffffff) +#define WxKEYCON1_COLVAL(_x) ((_x) << 0) + + +/* Window blanking (MAP) */ + +#define WINxMAP_MAP (1 << 24) +#define WINxMAP_MAP_COLOUR_MASK (0xffffff << 0) +#define WINxMAP_MAP_COLOUR_SHIFT (0) +#define WINxMAP_MAP_COLOUR_LIMIT (0xffffff) +#define WINxMAP_MAP_COLOUR(_x) ((_x) << 0) + +#define WPALCON_PAL_UPDATE (1 << 9) +#define WPALCON_W1PAL_MASK (0x7 << 3) +#define WPALCON_W1PAL_SHIFT (3) +#define WPALCON_W1PAL_25BPP_A888 (0x0 << 3) +#define WPALCON_W1PAL_24BPP (0x1 << 3) +#define WPALCON_W1PAL_19BPP_A666 (0x2 << 3) +#define WPALCON_W1PAL_18BPP_A665 (0x3 << 3) +#define WPALCON_W1PAL_18BPP (0x4 << 3) +#define WPALCON_W1PAL_16BPP_A555 (0x5 << 3) +#define WPALCON_W1PAL_16BPP_565 (0x6 << 3) + +#define WPALCON_W0PAL_MASK (0x7 << 0) +#define WPALCON_W0PAL_SHIFT (0) +#define WPALCON_W0PAL_25BPP_A888 (0x0 << 0) +#define WPALCON_W0PAL_24BPP (0x1 << 0) +#define WPALCON_W0PAL_19BPP_A666 (0x2 << 0) +#define WPALCON_W0PAL_18BPP_A665 (0x3 << 0) +#define WPALCON_W0PAL_18BPP (0x4 << 0) +#define WPALCON_W0PAL_16BPP_A555 (0x5 << 0) +#define WPALCON_W0PAL_16BPP_565 (0x6 << 0) + diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h new file mode 100644 index 000000000000..a6eba8496b24 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/regs-serial.h @@ -0,0 +1,281 @@ +/* arch/arm/plat-samsung/include/plat/regs-serial.h + * + * From linux/include/asm-arm/hardware/serial_s3c2410.h + * + * Internal header file for Samsung S3C2410 serial ports (UART0-2) + * + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * + * Additional defines, Copyright 2003 Simtec Electronics (linux@simtec.co.uk) + * + * Adapted from: + * + * Internal header file for MX1ADS serial ports (UART1 & 2) + * + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * + * 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 +*/ + +#ifndef __ASM_ARM_REGS_SERIAL_H +#define __ASM_ARM_REGS_SERIAL_H + +#define S3C24XX_VA_UART0 (S3C_VA_UART) +#define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 ) +#define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 ) +#define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 ) + +#define S3C2410_PA_UART0 (S3C24XX_PA_UART) +#define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 ) +#define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 ) +#define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 ) + +#define S3C2410_URXH (0x24) +#define S3C2410_UTXH (0x20) +#define S3C2410_ULCON (0x00) +#define S3C2410_UCON (0x04) +#define S3C2410_UFCON (0x08) +#define S3C2410_UMCON (0x0C) +#define S3C2410_UBRDIV (0x28) +#define S3C2410_UTRSTAT (0x10) +#define S3C2410_UERSTAT (0x14) +#define S3C2410_UFSTAT (0x18) +#define S3C2410_UMSTAT (0x1C) + +#define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3)) + +#define S3C2410_LCON_CS5 (0x0) +#define S3C2410_LCON_CS6 (0x1) +#define S3C2410_LCON_CS7 (0x2) +#define S3C2410_LCON_CS8 (0x3) +#define S3C2410_LCON_CSMASK (0x3) + +#define S3C2410_LCON_PNONE (0x0) +#define S3C2410_LCON_PEVEN (0x5 << 3) +#define S3C2410_LCON_PODD (0x4 << 3) +#define S3C2410_LCON_PMASK (0x7 << 3) + +#define S3C2410_LCON_STOPB (1<<2) +#define S3C2410_LCON_IRM (1<<6) + +#define S3C2440_UCON_CLKMASK (3<<10) +#define S3C2440_UCON_PCLK (0<<10) +#define S3C2440_UCON_UCLK (1<<10) +#define S3C2440_UCON_PCLK2 (2<<10) +#define S3C2440_UCON_FCLK (3<<10) +#define S3C2443_UCON_EPLL (3<<10) + +#define S3C6400_UCON_CLKMASK (3<<10) +#define S3C6400_UCON_PCLK (0<<10) +#define S3C6400_UCON_PCLK2 (2<<10) +#define S3C6400_UCON_UCLK0 (1<<10) +#define S3C6400_UCON_UCLK1 (3<<10) + +#define S3C2440_UCON2_FCLK_EN (1<<15) +#define S3C2440_UCON0_DIVMASK (15 << 12) +#define S3C2440_UCON1_DIVMASK (15 << 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) + +#define S3C2410_UCON_TXILEVEL (1<<9) +#define S3C2410_UCON_RXILEVEL (1<<8) +#define S3C2410_UCON_TXIRQMODE (1<<2) +#define S3C2410_UCON_RXIRQMODE (1<<0) +#define S3C2410_UCON_RXFIFO_TOI (1<<7) +#define S3C2443_UCON_RXERR_IRQEN (1<<6) +#define S3C2443_UCON_LOOPBACK (1<<5) + +#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ + S3C2410_UCON_RXILEVEL | \ + S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI) + +#define S3C2410_UFCON_FIFOMODE (1<<0) +#define S3C2410_UFCON_TXTRIG0 (0<<6) +#define S3C2410_UFCON_RXTRIG8 (1<<4) +#define S3C2410_UFCON_RXTRIG12 (2<<4) + +/* S3C2440 FIFO trigger levels */ +#define S3C2440_UFCON_RXTRIG1 (0<<4) +#define S3C2440_UFCON_RXTRIG8 (1<<4) +#define S3C2440_UFCON_RXTRIG16 (2<<4) +#define S3C2440_UFCON_RXTRIG32 (3<<4) + +#define S3C2440_UFCON_TXTRIG0 (0<<6) +#define S3C2440_UFCON_TXTRIG16 (1<<6) +#define S3C2440_UFCON_TXTRIG32 (2<<6) +#define S3C2440_UFCON_TXTRIG48 (3<<6) + +#define S3C2410_UFCON_RESETBOTH (3<<1) +#define S3C2410_UFCON_RESETTX (1<<2) +#define S3C2410_UFCON_RESETRX (1<<1) + +#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ + S3C2410_UFCON_TXTRIG0 | \ + S3C2410_UFCON_RXTRIG8 ) + +#define S3C2410_UMCOM_AFC (1<<4) +#define S3C2410_UMCOM_RTS_LOW (1<<0) + +#define S3C2412_UMCON_AFC_63 (0<<5) /* same as s3c2443 */ +#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) +#define S3C2410_UFSTAT_TXSHIFT (4) +#define S3C2410_UFSTAT_RXMASK (15<<0) +#define S3C2410_UFSTAT_RXSHIFT (0) + +/* UFSTAT S3C24A0 */ +#define S3C24A0_UFSTAT_TXFULL (1 << 14) +#define S3C24A0_UFSTAT_RXFULL (1 << 6) +#define S3C24A0_UFSTAT_TXMASK (63 << 8) +#define S3C24A0_UFSTAT_TXSHIFT (8) +#define S3C24A0_UFSTAT_RXMASK (63) +#define S3C24A0_UFSTAT_RXSHIFT (0) + +/* UFSTAT S3C2443 same as S3C2440 */ +#define S3C2440_UFSTAT_TXFULL (1<<14) +#define S3C2440_UFSTAT_RXFULL (1<<6) +#define S3C2440_UFSTAT_TXSHIFT (8) +#define S3C2440_UFSTAT_RXSHIFT (0) +#define S3C2440_UFSTAT_TXMASK (63<<8) +#define S3C2440_UFSTAT_RXMASK (63) + +#define S3C2410_UTRSTAT_TXE (1<<2) +#define S3C2410_UTRSTAT_TXFE (1<<1) +#define S3C2410_UTRSTAT_RXDR (1<<0) + +#define S3C2410_UERSTAT_OVERRUN (1<<0) +#define S3C2410_UERSTAT_FRAME (1<<2) +#define S3C2410_UERSTAT_BREAK (1<<3) +#define S3C2443_UERSTAT_PARITY (1<<1) + +#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \ + S3C2410_UERSTAT_FRAME | \ + S3C2410_UERSTAT_BREAK) + +#define S3C2410_UMSTAT_CTS (1<<0) +#define S3C2410_UMSTAT_DeltaCTS (1<<2) + +#define S3C2443_DIVSLOT (0x2C) + +/* S3C64XX interrupt registers. */ +#define S3C64XX_UINTP 0x30 +#define S3C64XX_UINTSP 0x34 +#define S3C64XX_UINTM 0x38 + +/* Following are specific to S5PV210 and S5P6442 */ +#define S5PV210_UCON_CLKMASK (1<<10) +#define S5PV210_UCON_PCLK (0<<10) +#define S5PV210_UCON_UCLK (1<<10) + +#define S5PV210_UFCON_TXTRIG0 (0<<8) +#define S5PV210_UFCON_TXTRIG4 (1<<8) +#define S5PV210_UFCON_TXTRIG8 (2<<8) +#define S5PV210_UFCON_TXTRIG16 (3<<8) +#define S5PV210_UFCON_TXTRIG32 (4<<8) +#define S5PV210_UFCON_TXTRIG64 (5<<8) +#define S5PV210_UFCON_TXTRIG128 (6<<8) +#define S5PV210_UFCON_TXTRIG256 (7<<8) + +#define S5PV210_UFCON_RXTRIG1 (0<<4) +#define S5PV210_UFCON_RXTRIG4 (1<<4) +#define S5PV210_UFCON_RXTRIG8 (2<<4) +#define S5PV210_UFCON_RXTRIG16 (3<<4) +#define S5PV210_UFCON_RXTRIG32 (4<<4) +#define S5PV210_UFCON_RXTRIG64 (5<<4) +#define S5PV210_UFCON_RXTRIG128 (6<<4) +#define S5PV210_UFCON_RXTRIG256 (7<<4) + +#define S5PV210_UFSTAT_TXFULL (1<<24) +#define S5PV210_UFSTAT_RXFULL (1<<8) +#define S5PV210_UFSTAT_TXMASK (255<<16) +#define S5PV210_UFSTAT_TXSHIFT (16) +#define S5PV210_UFSTAT_RXMASK (255<<0) +#define S5PV210_UFSTAT_RXSHIFT (0) + +#ifndef __ASSEMBLY__ + +/* struct s3c24xx_uart_clksrc + * + * this structure defines a named clock source that can be used for the + * uart, so that the best clock can be selected for the requested baud + * rate. + * + * min_baud and max_baud define the range of baud-rates this clock is + * acceptable for, if they are both zero, it is assumed any baud rate that + * can be generated from this clock will be used. + * + * divisor gives the divisor from the clock to the one seen by the uart +*/ + +struct s3c24xx_uart_clksrc { + const char *name; + unsigned int divisor; + unsigned int min_baud; + unsigned int max_baud; +}; + +/* configuration structure for per-machine configurations for the + * serial port + * + * the pointer is setup by the machine specific initialisation from the + * arch/arm/mach-s3c2410/ directory. +*/ + +struct s3c2410_uartcfg { + unsigned char hwport; /* hardware port number */ + unsigned char unused; + unsigned short flags; + upf_t uart_flags; /* default uart flags */ + + unsigned long ucon; /* value of ucon for port */ + unsigned long ulcon; /* value of ulcon for port */ + unsigned long ufcon; /* value of ufcon for port */ + + struct s3c24xx_uart_clksrc *clocks; + unsigned int clocks_size; +}; + +/* s3c24xx_uart_devs + * + * this is exported from the core as we cannot use driver_register(), + * or platform_add_device() before the console_initcall() +*/ + +extern struct platform_device *s3c24xx_uart_devs[4]; + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_ARM_REGS_SERIAL_H */ + diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h index 53198673b6bd..7d07cd7aa4f2 100644 --- a/arch/arm/plat-samsung/include/plat/sdhci.h +++ b/arch/arm/plat-samsung/include/plat/sdhci.h @@ -78,8 +78,8 @@ extern void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *, int w); /* S3C6400 SDHCI setup */ -#ifdef CONFIG_S3C6400_SETUP_SDHCI -extern char *s3c6400_hsmmc_clksrcs[4]; +#ifdef CONFIG_S3C64XX_SETUP_SDHCI +extern char *s3c64xx_hsmmc_clksrcs[4]; #ifdef CONFIG_S3C_DEV_HSMMC extern void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev, @@ -89,7 +89,7 @@ extern void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev, static inline void s3c6400_default_sdhci0(void) { - s3c_hsmmc0_def_platdata.clocks = s3c6400_hsmmc_clksrcs; + s3c_hsmmc0_def_platdata.clocks = s3c64xx_hsmmc_clksrcs; s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; s3c_hsmmc0_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card; } @@ -101,7 +101,7 @@ static inline void s3c6400_default_sdhci0(void) { } #ifdef CONFIG_S3C_DEV_HSMMC1 static inline void s3c6400_default_sdhci1(void) { - s3c_hsmmc1_def_platdata.clocks = s3c6400_hsmmc_clksrcs; + s3c_hsmmc1_def_platdata.clocks = s3c64xx_hsmmc_clksrcs; s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; s3c_hsmmc1_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card; } @@ -112,7 +112,7 @@ static inline void s3c6400_default_sdhci1(void) { } #ifdef CONFIG_S3C_DEV_HSMMC2 static inline void s3c6400_default_sdhci2(void) { - s3c_hsmmc2_def_platdata.clocks = s3c6400_hsmmc_clksrcs; + s3c_hsmmc2_def_platdata.clocks = s3c64xx_hsmmc_clksrcs; s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio; s3c_hsmmc2_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card; } @@ -120,27 +120,19 @@ static inline void s3c6400_default_sdhci2(void) static inline void s3c6400_default_sdhci2(void) { } #endif /* CONFIG_S3C_DEV_HSMMC2 */ -#else -static inline void s3c6400_default_sdhci0(void) { } -static inline void s3c6400_default_sdhci1(void) { } -#endif /* CONFIG_S3C6400_SETUP_SDHCI */ - /* S3C6410 SDHCI setup */ -#ifdef CONFIG_S3C6410_SETUP_SDHCI -extern char *s3c6410_hsmmc_clksrcs[4]; - -extern void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev, - void __iomem *r, - struct mmc_ios *ios, - struct mmc_card *card); +extern void s3c6410_setup_sdhci_cfg_card(struct platform_device *dev, + void __iomem *r, + struct mmc_ios *ios, + struct mmc_card *card); #ifdef CONFIG_S3C_DEV_HSMMC static inline void s3c6410_default_sdhci0(void) { - s3c_hsmmc0_def_platdata.clocks = s3c6410_hsmmc_clksrcs; + s3c_hsmmc0_def_platdata.clocks = s3c64xx_hsmmc_clksrcs; s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; - s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card; + s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci_cfg_card; } #else static inline void s3c6410_default_sdhci0(void) { } @@ -149,9 +141,9 @@ static inline void s3c6410_default_sdhci0(void) { } #ifdef CONFIG_S3C_DEV_HSMMC1 static inline void s3c6410_default_sdhci1(void) { - s3c_hsmmc1_def_platdata.clocks = s3c6410_hsmmc_clksrcs; + s3c_hsmmc1_def_platdata.clocks = s3c64xx_hsmmc_clksrcs; s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; - s3c_hsmmc1_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card; + s3c_hsmmc1_def_platdata.cfg_card = s3c6410_setup_sdhci_cfg_card; } #else static inline void s3c6410_default_sdhci1(void) { } @@ -160,9 +152,9 @@ static inline void s3c6410_default_sdhci1(void) { } #ifdef CONFIG_S3C_DEV_HSMMC2 static inline void s3c6410_default_sdhci2(void) { - s3c_hsmmc2_def_platdata.clocks = s3c6410_hsmmc_clksrcs; + s3c_hsmmc2_def_platdata.clocks = s3c64xx_hsmmc_clksrcs; s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio; - s3c_hsmmc2_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card; + s3c_hsmmc2_def_platdata.cfg_card = s3c6410_setup_sdhci_cfg_card; } #else static inline void s3c6410_default_sdhci2(void) { } @@ -171,7 +163,10 @@ static inline void s3c6410_default_sdhci2(void) { } #else static inline void s3c6410_default_sdhci0(void) { } static inline void s3c6410_default_sdhci1(void) { } -#endif /* CONFIG_S3C6410_SETUP_SDHCI */ +static inline void s3c6400_default_sdhci0(void) { } +static inline void s3c6400_default_sdhci1(void) { } + +#endif /* CONFIG_S3C64XX_SETUP_SDHCI */ /* S5PC100 SDHCI setup */ diff --git a/arch/arm/plat-samsung/include/plat/uncompress.h b/arch/arm/plat-samsung/include/plat/uncompress.h new file mode 100644 index 000000000000..e87ce8ffbbcd --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/uncompress.h @@ -0,0 +1,186 @@ +/* arch/arm/plat-samsung/include/plat/uncompress.h + * + * Copyright 2003, 2007 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - uncompress code + * + * 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. +*/ + +#ifndef __ASM_PLAT_UNCOMPRESS_H +#define __ASM_PLAT_UNCOMPRESS_H + +typedef unsigned int upf_t; /* cannot include linux/serial_core.h */ + +/* uart setup */ + +static unsigned int fifo_mask; +static unsigned int fifo_max; + +/* forward declerations */ + +static void arch_detect_cpu(void); + +/* defines for UART registers */ + +#include <plat/regs-serial.h> +#include <plat/regs-watchdog.h> + +/* working in physical space... */ +#undef S3C2410_WDOGREG +#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x))) + +/* how many bytes we allow into the FIFO at a time in FIFO mode */ +#define FIFO_MAX (14) + +#define uart_base S3C_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT) + +static __inline__ void +uart_wr(unsigned int reg, unsigned int val) +{ + volatile unsigned int *ptr; + + ptr = (volatile unsigned int *)(reg + uart_base); + *ptr = val; +} + +static __inline__ unsigned int +uart_rd(unsigned int reg) +{ + volatile unsigned int *ptr; + + ptr = (volatile unsigned int *)(reg + uart_base); + return *ptr; +} + +/* we can deal with the case the UARTs are being run + * in FIFO mode, so that we don't hold up our execution + * waiting for tx to happen... +*/ + +static void putc(int ch) +{ + if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) { + int level; + + while (1) { + level = uart_rd(S3C2410_UFSTAT); + level &= fifo_mask; + + if (level < fifo_max) + break; + } + + } else { + /* not using fifos */ + + while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE) + barrier(); + } + + /* write byte to transmission register */ + uart_wr(S3C2410_UTXH, ch); +} + +static inline void flush(void) +{ +} + +#define __raw_writel(d, ad) \ + do { \ + *((volatile unsigned int __force *)(ad)) = (d); \ + } while (0) + +/* CONFIG_S3C_BOOT_WATCHDOG + * + * Simple boot-time watchdog setup, to reboot the system if there is + * any problem with the boot process +*/ + +#ifdef CONFIG_S3C_BOOT_WATCHDOG + +#define WDOG_COUNT (0xff00) + +static inline void arch_decomp_wdog(void) +{ + __raw_writel(WDOG_COUNT, S3C2410_WTCNT); +} + +static void arch_decomp_wdog_start(void) +{ + __raw_writel(WDOG_COUNT, S3C2410_WTDAT); + __raw_writel(WDOG_COUNT, S3C2410_WTCNT); + __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON); +} + +#else +#define arch_decomp_wdog_start() +#define arch_decomp_wdog() +#endif + +#ifdef CONFIG_S3C_BOOT_ERROR_RESET + +static void arch_decomp_error(const char *x) +{ + putstr("\n\n"); + putstr(x); + putstr("\n\n -- System resetting\n"); + + __raw_writel(0x4000, S3C2410_WTDAT); + __raw_writel(0x4000, S3C2410_WTCNT); + __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON); + + while(1); +} + +#define arch_error arch_decomp_error +#endif + +static void error(char *err); + +#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO +static inline void arch_enable_uart_fifo(void) +{ + u32 fifocon = uart_rd(S3C2410_UFCON); + + if (!(fifocon & S3C2410_UFCON_FIFOMODE)) { + fifocon |= S3C2410_UFCON_RESETBOTH; + uart_wr(S3C2410_UFCON, fifocon); + + /* wait for fifo reset to complete */ + while (1) { + fifocon = uart_rd(S3C2410_UFCON); + if (!(fifocon & S3C2410_UFCON_RESETBOTH)) + break; + } + } +} +#else +#define arch_enable_uart_fifo() do { } while(0) +#endif + + +static void +arch_decomp_setup(void) +{ + /* we may need to setup the uart(s) here if we are not running + * on an BAST... the BAST will have left the uarts configured + * after calling linux. + */ + + arch_detect_cpu(); + arch_decomp_wdog_start(); + + /* Enable the UART FIFOs if they where not enabled and our + * configuration says we should turn them on. + */ + + arch_enable_uart_fifo(); +} + + +#endif /* __ASM_PLAT_UNCOMPRESS_H */ diff --git a/arch/arm/plat-samsung/include/plat/usb-control.h b/arch/arm/plat-samsung/include/plat/usb-control.h new file mode 100644 index 000000000000..7fa1fbefc3f2 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/usb-control.h @@ -0,0 +1,43 @@ +/* arch/arm/plat-samsung/include/plat/usb-control.h + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - USB host port information + * + * 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. +*/ + +#ifndef __ASM_ARCH_USBCONTROL_H +#define __ASM_ARCH_USBCONTROL_H + +#define S3C_HCDFLG_USED (1) + +struct s3c2410_hcd_port { + unsigned char flags; + unsigned char power; + unsigned char oc_status; + unsigned char oc_changed; +}; + +struct s3c2410_hcd_info { + struct usb_hcd *hcd; + struct s3c2410_hcd_port port[2]; + + void (*power_control)(int port, int to); + void (*enable_oc)(struct s3c2410_hcd_info *, int on); + void (*report_oc)(struct s3c2410_hcd_info *, int ports); +}; + +static void inline s3c2410_usb_report_oc(struct s3c2410_hcd_info *info, int ports) +{ + if (info->report_oc != NULL) { + (info->report_oc)(info, ports); + } +} + +extern void s3c_ohci_set_platdata(struct s3c2410_hcd_info *info); + +#endif /*__ASM_ARCH_USBCONTROL_H */ diff --git a/arch/arm/plat-samsung/init.c b/arch/arm/plat-samsung/init.c new file mode 100644 index 000000000000..6790edfaca6f --- /dev/null +++ b/arch/arm/plat-samsung/init.c @@ -0,0 +1,160 @@ +/* linux/arch/arm/plat-s3c/init.c + * + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C series CPU initialisation + * + * 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 <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/serial_core.h> +#include <linux/platform_device.h> + +#include <mach/hardware.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/clock.h> + +#include <plat/regs-serial.h> + +static struct cpu_table *cpu; + +static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode, + struct cpu_table *tab, + unsigned int count) +{ + for (; count != 0; count--, tab++) { + if ((idcode & tab->idmask) == tab->idcode) + return tab; + } + + return NULL; +} + +void __init s3c_init_cpu(unsigned long idcode, + struct cpu_table *cputab, unsigned int cputab_size) +{ + cpu = s3c_lookup_cpu(idcode, cputab, cputab_size); + + 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(); +} + +/* s3c24xx_init_clocks + * + * Initialise the clock subsystem and associated information from the + * given master crystal value. + * + * xtal = 0 -> use default PLL crystal value (normally 12MHz) + * != 0 -> PLL crystal value in Hz +*/ + +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); +} + +/* uart management */ + +static int nr_uarts __initdata = 0; + +static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS]; + +/* s3c24xx_init_uartdevs + * + * copy the specified platform data and configuration into our central + * set of devices, before the data is thrown away after the init process. + * + * This also fills in the array passed to the serial driver for the + * early initialisation of the console. +*/ + +void __init s3c24xx_init_uartdevs(char *name, + struct s3c24xx_uart_resources *res, + struct s3c2410_uartcfg *cfg, int no) +{ + struct platform_device *platdev; + struct s3c2410_uartcfg *cfgptr = uart_cfgs; + struct s3c24xx_uart_resources *resp; + int uart; + + memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no); + + for (uart = 0; uart < no; uart++, cfg++, cfgptr++) { + platdev = s3c24xx_uart_src[cfgptr->hwport]; + + resp = res + cfgptr->hwport; + + s3c24xx_uart_devs[uart] = platdev; + + platdev->name = name; + platdev->resource = resp->resources; + platdev->num_resources = resp->nr_resources; + + platdev->dev.platform_data = cfgptr; + } + + nr_uarts = no; +} + +void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + if (cpu == NULL) + return; + + if (cpu->init_uarts == NULL) { + printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n"); + } else + (cpu->init_uarts)(cfg, no); +} + +static int __init s3c_arch_init(void) +{ + int ret; + + // do the correct init for cpu + + if (cpu == NULL) + panic("s3c_arch_init: NULL cpu\n"); + + ret = (cpu->init)(); + if (ret != 0) + return ret; + + ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); + return ret; +} + +arch_initcall(s3c_arch_init); diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c new file mode 100644 index 000000000000..27cfca597699 --- /dev/null +++ b/arch/arm/plat-samsung/pm.c @@ -0,0 +1,378 @@ +/* linux/arch/arm/plat-s3c/pm.c + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2004-2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C common power management (suspend to ram) 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. +*/ + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/serial_core.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <mach/hardware.h> +#include <mach/map.h> + +#include <plat/regs-serial.h> +#include <mach/regs-clock.h> +#include <mach/regs-irq.h> +#include <asm/irq.h> + +#include <plat/pm.h> +#include <mach/pm-core.h> + +/* for external use */ + +unsigned long s3c_pm_flags; + +/* Debug code: + * + * This code supports debug output to the low level UARTs for use on + * resume before the console layer is available. +*/ + +#ifdef CONFIG_SAMSUNG_PM_DEBUG +extern void printascii(const char *); + +void s3c_pm_dbg(const char *fmt, ...) +{ + va_list va; + char buff[256]; + + va_start(va, fmt); + vsprintf(buff, fmt, va); + va_end(va); + + printascii(buff); +} + +static inline void s3c_pm_debug_init(void) +{ + /* restart uart clocks so we can use them to output */ + s3c_pm_debug_init_uart(); +} + +#else +#define s3c_pm_debug_init() do { } while(0) + +#endif /* CONFIG_SAMSUNG_PM_DEBUG */ + +/* Save the UART configurations if we are configured for debug. */ + +unsigned char pm_uart_udivslot; + +#ifdef CONFIG_SAMSUNG_PM_DEBUG + +struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS]; + +static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) +{ + void __iomem *regs = S3C_VA_UARTx(uart); + + save->ulcon = __raw_readl(regs + S3C2410_ULCON); + save->ucon = __raw_readl(regs + S3C2410_UCON); + save->ufcon = __raw_readl(regs + S3C2410_UFCON); + save->umcon = __raw_readl(regs + S3C2410_UMCON); + save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); + + if (pm_uart_udivslot) + save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); + + S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", + uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); +} + +static void s3c_pm_save_uarts(void) +{ + struct pm_uart_save *save = uart_save; + unsigned int uart; + + for (uart = 0; uart < CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++) + s3c_pm_save_uart(uart, save); +} + +static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) +{ + void __iomem *regs = S3C_VA_UARTx(uart); + + s3c_pm_arch_update_uart(regs, save); + + __raw_writel(save->ulcon, regs + S3C2410_ULCON); + __raw_writel(save->ucon, regs + S3C2410_UCON); + __raw_writel(save->ufcon, regs + S3C2410_UFCON); + __raw_writel(save->umcon, regs + S3C2410_UMCON); + __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); + + if (pm_uart_udivslot) + __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); +} + +static void s3c_pm_restore_uarts(void) +{ + struct pm_uart_save *save = uart_save; + unsigned int uart; + + for (uart = 0; uart < CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++) + s3c_pm_restore_uart(uart, save); +} +#else +static void s3c_pm_save_uarts(void) { } +static void s3c_pm_restore_uarts(void) { } +#endif + +/* The IRQ ext-int code goes here, it is too small to currently bother + * with its own file. */ + +unsigned long s3c_irqwake_intmask = 0xffffffffL; +unsigned long s3c_irqwake_eintmask = 0xffffffffL; + +int s3c_irqext_wake(unsigned int irqno, unsigned int state) +{ + unsigned long bit = 1L << IRQ_EINT_BIT(irqno); + + if (!(s3c_irqwake_eintallow & bit)) + return -ENOENT; + + printk(KERN_INFO "wake %s for irq %d\n", + state ? "enabled" : "disabled", irqno); + + if (!state) + s3c_irqwake_eintmask |= bit; + else + s3c_irqwake_eintmask &= ~bit; + + return 0; +} + +/* helper functions to save and restore register state */ + +/** + * s3c_pm_do_save() - save a set of registers for restoration on resume. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Run through the list of registers given, saving their contents in the + * array for later restoration when we wakeup. + */ +void s3c_pm_do_save(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + ptr->val = __raw_readl(ptr->reg); + S3C_PMDBG("saved %p value %08lx\n", ptr->reg, ptr->val); + } +} + +/** + * s3c_pm_do_restore() - restore register values from the save list. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Restore the register values saved from s3c_pm_do_save(). + * + * Note, we do not use S3C_PMDBG() in here, as the system may not have + * restore the UARTs state yet +*/ + +void s3c_pm_do_restore(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", + ptr->reg, ptr->val, __raw_readl(ptr->reg)); + + __raw_writel(ptr->val, ptr->reg); + } +} + +/** + * s3c_pm_do_restore_core() - early restore register values from save list. + * + * This is similar to s3c_pm_do_restore() except we try and minimise the + * side effects of the function in case registers that hardware might need + * to work has been restored. + * + * WARNING: Do not put any debug in here that may effect memory or use + * peripherals, as things may be changing! +*/ + +void s3c_pm_do_restore_core(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) + __raw_writel(ptr->val, ptr->reg); +} + +/* s3c2410_pm_show_resume_irqs + * + * print any IRQs asserted at resume time (ie, we woke from) +*/ +static void s3c_pm_show_resume_irqs(int start, unsigned long which, + unsigned long mask) +{ + int i; + + which &= ~mask; + + for (i = 0; i <= 31; i++) { + if (which & (1L<<i)) { + S3C_PMDBG("IRQ %d asserted at resume\n", start+i); + } + } +} + + +void (*pm_cpu_prep)(void); +void (*pm_cpu_sleep)(void); + +#define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) + +/* s3c_pm_enter + * + * central control for sleep/resume process +*/ + +static int s3c_pm_enter(suspend_state_t state) +{ + static unsigned long regs_save[16]; + + /* ensure the debug is initialised (if enabled) */ + + s3c_pm_debug_init(); + + S3C_PMDBG("%s(%d)\n", __func__, state); + + if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { + printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__); + return -EINVAL; + } + + /* check if we have anything to wake-up with... bad things seem + * to happen if you suspend with no wakeup (system will often + * require a full power-cycle) + */ + + if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && + !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { + printk(KERN_ERR "%s: No wake-up sources!\n", __func__); + printk(KERN_ERR "%s: Aborting sleep\n", __func__); + return -EINVAL; + } + + /* store the physical address of the register recovery block */ + + s3c_sleep_save_phys = virt_to_phys(regs_save); + + S3C_PMDBG("s3c_sleep_save_phys=0x%08lx\n", s3c_sleep_save_phys); + + /* save all necessary core registers not covered by the drivers */ + + s3c_pm_save_gpios(); + s3c_pm_save_uarts(); + s3c_pm_save_core(); + + /* set the irq configuration for wake */ + + s3c_pm_configure_extint(); + + S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", + s3c_irqwake_intmask, s3c_irqwake_eintmask); + + s3c_pm_arch_prepare_irqs(); + + /* call cpu specific preparation */ + + pm_cpu_prep(); + + /* flush cache back to ram */ + + flush_cache_all(); + + s3c_pm_check_store(); + + /* send the cpu to sleep... */ + + s3c_pm_arch_stop_clocks(); + + /* s3c_cpu_save will also act as our return point from when + * we resume as it saves its own register state and restores it + * during the resume. */ + + s3c_cpu_save(regs_save); + + /* restore the cpu state using the kernel's cpu init code. */ + + cpu_init(); + + /* restore the system state */ + + s3c_pm_restore_core(); + s3c_pm_restore_uarts(); + s3c_pm_restore_gpios(); + + s3c_pm_debug_init(); + + /* check what irq (if any) restored the system */ + + s3c_pm_arch_show_resume_irqs(); + + S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); + + /* LEDs should now be 1110 */ + s3c_pm_debug_smdkled(1 << 1, 0); + + s3c_pm_check_restore(); + + /* ok, let's return from sleep */ + + S3C_PMDBG("S3C PM Resume (post-restore)\n"); + return 0; +} + +/* callback from assembly code */ +void s3c_pm_cb_flushcache(void) +{ + flush_cache_all(); +} + +static int s3c_pm_prepare(void) +{ + /* prepare check area if configured */ + + s3c_pm_check_prepare(); + return 0; +} + +static void s3c_pm_finish(void) +{ + s3c_pm_check_cleanup(); +} + +static struct platform_suspend_ops s3c_pm_ops = { + .enter = s3c_pm_enter, + .prepare = s3c_pm_prepare, + .finish = s3c_pm_finish, + .valid = suspend_valid_only_mem, +}; + +/* s3c_pm_init + * + * Attach the power management functions. This should be called + * from the board specific initialisation if the board supports + * it. +*/ + +int __init s3c_pm_init(void) +{ + printk("S3C Power Management, Copyright 2004 Simtec Electronics\n"); + + suspend_set_ops(&s3c_pm_ops); + return 0; +} diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c new file mode 100644 index 000000000000..2231d80ad817 --- /dev/null +++ b/arch/arm/plat-samsung/time.c @@ -0,0 +1,285 @@ +/* linux/arch/arm/plat-samsung/time.c + * + * Copyright (C) 2003-2005 Simtec Electronics + * Ben Dooks, <ben@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 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 <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <asm/system.h> +#include <asm/leds.h> +#include <asm/mach-types.h> + +#include <asm/irq.h> +#include <mach/map.h> +#include <plat/regs-timer.h> +#include <mach/regs-irq.h> +#include <asm/mach/time.h> +#include <mach/tick.h> + +#include <plat/clock.h> +#include <plat/cpu.h> + +static unsigned long timer_startval; +static unsigned long timer_usec_ticks; + +#ifndef TICK_MAX +#define TICK_MAX (0xffff) +#endif + +#define TIMER_USEC_SHIFT 16 + +/* we use the shifted arithmetic to work out the ratio of timer ticks + * to usecs, as often the peripheral clock is not a nice even multiple + * of 1MHz. + * + * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok + * for the current HZ value of 200 without producing overflows. + * + * Original patch by Dimitry Andric, updated by Ben Dooks +*/ + + +/* timer_mask_usec_ticks + * + * given a clock and divisor, make the value to pass into timer_ticks_to_usec + * to scale the ticks into usecs +*/ + +static inline unsigned long +timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk) +{ + unsigned long den = pclk / 1000; + + return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den; +} + +/* timer_ticks_to_usec + * + * convert timer ticks to usec. +*/ + +static inline unsigned long timer_ticks_to_usec(unsigned long ticks) +{ + unsigned long res; + + res = ticks * timer_usec_ticks; + res += 1 << (TIMER_USEC_SHIFT - 4); /* round up slightly */ + + return res >> TIMER_USEC_SHIFT; +} + +/*** + * Returns microsecond since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + * IRQs are disabled before entering here from do_gettimeofday() + */ + +static unsigned long s3c2410_gettimeoffset (void) +{ + unsigned long tdone; + unsigned long tval; + + /* work out how many ticks have gone since last timer interrupt */ + + tval = __raw_readl(S3C2410_TCNTO(4)); + tdone = timer_startval - tval; + + /* check to see if there is an interrupt pending */ + + if (s3c24xx_ostimer_pending()) { + /* re-read the timer, and try and fix up for the missed + * interrupt. Note, the interrupt may go off before the + * timer has re-loaded from wrapping. + */ + + tval = __raw_readl(S3C2410_TCNTO(4)); + tdone = timer_startval - tval; + + if (tval != 0) + tdone += timer_startval; + } + + return timer_ticks_to_usec(tdone); +} + + +/* + * IRQ handler for the timer + */ +static irqreturn_t +s3c2410_timer_interrupt(int irq, void *dev_id) +{ + timer_tick(); + return IRQ_HANDLED; +} + +static struct irqaction s3c2410_timer_irq = { + .name = "S3C2410 Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = s3c2410_timer_interrupt, +}; + +#define use_tclk1_12() ( \ + machine_is_bast() || \ + machine_is_vr1000() || \ + machine_is_anubis() || \ + machine_is_osiris()) + +static struct clk *tin; +static struct clk *tdiv; +static struct clk *timerclk; + +/* + * Set up timer interrupt, and return the current time in seconds. + * + * Currently we only use timer4, as it is the only timer which has no + * other function that can be exploited externally + */ +static void s3c2410_timer_setup (void) +{ + unsigned long tcon; + unsigned long tcnt; + unsigned long tcfg1; + unsigned long tcfg0; + + tcnt = TICK_MAX; /* default value for tcnt */ + + /* configure the system for whichever machine is in use */ + + if (use_tclk1_12()) { + /* timer is at 12MHz, scaler is 1 */ + timer_usec_ticks = timer_mask_usec_ticks(1, 12000000); + tcnt = 12000000 / HZ; + + tcfg1 = __raw_readl(S3C2410_TCFG1); + tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; + tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; + __raw_writel(tcfg1, S3C2410_TCFG1); + } else { + unsigned long pclk; + struct clk *tscaler; + + /* for the h1940 (and others), we use the pclk from the core + * to generate the timer values. since values around 50 to + * 70MHz are not values we can directly generate the timer + * value from, we need to pre-scale and divide before using it. + * + * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz + * (8.45 ticks per usec) + */ + + pclk = clk_get_rate(timerclk); + + /* configure clock tick */ + + timer_usec_ticks = timer_mask_usec_ticks(6, pclk); + + tscaler = clk_get_parent(tdiv); + + clk_set_rate(tscaler, pclk / 3); + clk_set_rate(tdiv, pclk / 6); + clk_set_parent(tin, tdiv); + + tcnt = clk_get_rate(tin) / HZ; + } + + tcon = __raw_readl(S3C2410_TCON); + tcfg0 = __raw_readl(S3C2410_TCFG0); + tcfg1 = __raw_readl(S3C2410_TCFG1); + + /* timers reload after counting zero, so reduce the count by 1 */ + + tcnt--; + + printk(KERN_DEBUG "timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n", + tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks); + + /* check to see if timer is within 16bit range... */ + if (tcnt > TICK_MAX) { + panic("setup_timer: HZ is too small, cannot configure timer!"); + return; + } + + __raw_writel(tcfg1, S3C2410_TCFG1); + __raw_writel(tcfg0, S3C2410_TCFG0); + + timer_startval = tcnt; + __raw_writel(tcnt, S3C2410_TCNTB(4)); + + /* ensure timer is stopped... */ + + tcon &= ~(7<<20); + tcon |= S3C2410_TCON_T4RELOAD; + tcon |= S3C2410_TCON_T4MANUALUPD; + + __raw_writel(tcon, S3C2410_TCON); + __raw_writel(tcnt, S3C2410_TCNTB(4)); + __raw_writel(tcnt, S3C2410_TCMPB(4)); + + /* start the timer running */ + tcon |= S3C2410_TCON_T4START; + tcon &= ~S3C2410_TCON_T4MANUALUPD; + __raw_writel(tcon, S3C2410_TCON); +} + +static void __init s3c2410_timer_resources(void) +{ + struct platform_device tmpdev; + + tmpdev.dev.bus = &platform_bus_type; + tmpdev.id = 4; + + timerclk = clk_get(NULL, "timers"); + if (IS_ERR(timerclk)) + panic("failed to get clock for system timer"); + + clk_enable(timerclk); + + if (!use_tclk1_12()) { + tin = clk_get(&tmpdev.dev, "pwm-tin"); + if (IS_ERR(tin)) + panic("failed to get pwm-tin clock for system timer"); + + tdiv = clk_get(&tmpdev.dev, "pwm-tdiv"); + if (IS_ERR(tdiv)) + panic("failed to get pwm-tdiv clock for system timer"); + } + + clk_enable(tin); +} + +static void __init s3c2410_timer_init(void) +{ + s3c2410_timer_resources(); + s3c2410_timer_setup(); + setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); +} + +struct sys_timer s3c24xx_timer = { + .init = s3c2410_timer_init, + .offset = s3c2410_gettimeoffset, + .resume = s3c2410_timer_setup +}; |