diff options
Diffstat (limited to 'arch/arm/plat-s5p')
-rw-r--r-- | arch/arm/plat-s5p/Kconfig | 23 | ||||
-rw-r--r-- | arch/arm/plat-s5p/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/plat-s5p/cpu.c | 25 | ||||
-rw-r--r-- | arch/arm/plat-s5p/dev-csis0.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-s5p/dev-csis1.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-s5p/dev-fimc3.c | 43 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/camport.h | 28 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/csis.h | 28 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/exynos4.h | 34 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/mipi_csis.h | 43 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/s5p-time.h | 40 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/s5pv310.h | 34 | ||||
-rw-r--r-- | arch/arm/plat-s5p/include/plat/sysmmu.h | 95 | ||||
-rw-r--r-- | arch/arm/plat-s5p/irq-gpioint.c | 170 | ||||
-rw-r--r-- | arch/arm/plat-s5p/s5p-time.c | 448 | ||||
-rw-r--r-- | arch/arm/plat-s5p/setup-mipiphy.c | 63 | ||||
-rw-r--r-- | arch/arm/plat-s5p/sysmmu.c | 370 |
17 files changed, 1112 insertions, 339 deletions
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 557f8c507f6..84922971658 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -7,10 +7,10 @@ config PLAT_S5P bool - depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310) + depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS4) default y - select ARM_VIC if !ARCH_S5PV310 - select ARM_GIC if ARCH_S5PV310 + select ARM_VIC if !ARCH_EXYNOS4 + select ARM_GIC if ARCH_EXYNOS4 select NO_IOPORT select ARCH_REQUIRE_GPIOLIB select S3C_GPIO_TRACK @@ -37,11 +37,16 @@ config S5P_GPIO_INT help Common code for the GPIO interrupts (other than external interrupts.) +config S5P_HRT + bool + help + Use the High Resolution timer support + comment "System MMU" config S5P_SYSTEM_MMU bool "S5P SYSTEM MMU" - depends on ARCH_S5PV310 + depends on ARCH_EXYNOS4 help Say Y here if you want to enable System MMU @@ -60,6 +65,11 @@ config S5P_DEV_FIMC2 help Compile in platform device definitions for FIMC controller 2 +config S5P_DEV_FIMC3 + bool + help + Compile in platform device definitions for FIMC controller 3 + config S5P_DEV_ONENAND bool help @@ -74,3 +84,8 @@ config S5P_DEV_CSIS1 bool help Compile in platform device definitions for MIPI-CSIS channel 1 + +config S5P_SETUP_MIPIPHY + bool + help + Compile in common setup code for MIPI-CSIS and MIPI-DSIM devices diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile index 4bd5cf90897..42afff7f60b 100644 --- a/arch/arm/plat-s5p/Makefile +++ b/arch/arm/plat-s5p/Makefile @@ -22,12 +22,15 @@ obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_PM) += irq-pm.o +obj-$(CONFIG_S5P_HRT) += s5p-time.o # devices obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o +obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o +obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c index 047d31c1bbd..c3bfe9b13ac 100644 --- a/arch/arm/plat-s5p/cpu.c +++ b/arch/arm/plat-s5p/cpu.c @@ -1,7 +1,7 @@ /* linux/arch/arm/plat-s5p/cpu.c * - * Copyright (c) 2009 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com * * S5P CPU Support * @@ -12,17 +12,20 @@ #include <linux/init.h> #include <linux/module.h> -#include <mach/map.h> + #include <asm/mach/arch.h> #include <asm/mach/map.h> + +#include <mach/map.h> #include <mach/regs-clock.h> + #include <plat/cpu.h> #include <plat/s5p6440.h> #include <plat/s5p6442.h> #include <plat/s5p6450.h> #include <plat/s5pc100.h> #include <plat/s5pv210.h> -#include <plat/s5pv310.h> +#include <plat/exynos4.h> /* table of supported CPUs */ @@ -31,7 +34,7 @@ static const char name_s5p6442[] = "S5P6442"; static const char name_s5p6450[] = "S5P6450"; static const char name_s5pc100[] = "S5PC100"; static const char name_s5pv210[] = "S5PV210/S5PC110"; -static const char name_s5pv310[] = "S5PV310"; +static const char name_exynos4210[] = "EXYNOS4210"; static struct cpu_table cpu_ids[] __initdata = { { @@ -75,13 +78,13 @@ static struct cpu_table cpu_ids[] __initdata = { .init = s5pv210_init, .name = name_s5pv210, }, { - .idcode = 0x43200000, + .idcode = 0x43210000, .idmask = 0xfffff000, - .map_io = s5pv310_map_io, - .init_clocks = s5pv310_init_clocks, - .init_uarts = s5pv310_init_uarts, - .init = s5pv310_init, - .name = name_s5pv310, + .map_io = exynos4_map_io, + .init_clocks = exynos4_init_clocks, + .init_uarts = exynos4_init_uarts, + .init = exynos4_init, + .name = name_exynos4210, }, }; diff --git a/arch/arm/plat-s5p/dev-csis0.c b/arch/arm/plat-s5p/dev-csis0.c index dfab1c85f54..e3aabef5e34 100644 --- a/arch/arm/plat-s5p/dev-csis0.c +++ b/arch/arm/plat-s5p/dev-csis0.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Samsung Electronics + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. * * S5P series device definition for MIPI-CSIS channel 0 * diff --git a/arch/arm/plat-s5p/dev-csis1.c b/arch/arm/plat-s5p/dev-csis1.c index e3053f27fbb..08b91b58020 100644 --- a/arch/arm/plat-s5p/dev-csis1.c +++ b/arch/arm/plat-s5p/dev-csis1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Samsung Electronics + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. * * S5P series device definition for MIPI-CSIS channel 1 * diff --git a/arch/arm/plat-s5p/dev-fimc3.c b/arch/arm/plat-s5p/dev-fimc3.c new file mode 100644 index 00000000000..ef31beca386 --- /dev/null +++ b/arch/arm/plat-s5p/dev-fimc3.c @@ -0,0 +1,43 @@ +/* linux/arch/arm/plat-s5p/dev-fimc3.c + * + * Copyright (c) 2010 Samsung Electronics + * + * Base S5P FIMC3 resource and device 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. + */ + +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <mach/map.h> + +static struct resource s5p_fimc3_resource[] = { + [0] = { + .start = S5P_PA_FIMC3, + .end = S5P_PA_FIMC3 + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_FIMC3, + .end = IRQ_FIMC3, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 s5p_fimc3_dma_mask = DMA_BIT_MASK(32); + +struct platform_device s5p_device_fimc3 = { + .name = "s5p-fimc", + .id = 3, + .num_resources = ARRAY_SIZE(s5p_fimc3_resource), + .resource = s5p_fimc3_resource, + .dev = { + .dma_mask = &s5p_fimc3_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; diff --git a/arch/arm/plat-s5p/include/plat/camport.h b/arch/arm/plat-s5p/include/plat/camport.h new file mode 100644 index 00000000000..71688c8ba28 --- /dev/null +++ b/arch/arm/plat-s5p/include/plat/camport.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * S5P series camera interface helper 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. + */ + +#ifndef PLAT_S5P_CAMPORT_H_ +#define PLAT_S5P_CAMPORT_H_ __FILE__ + +enum s5p_camport_id { + S5P_CAMPORT_A, + S5P_CAMPORT_B, +}; + +/* + * The helper functions to configure GPIO for the camera parallel bus. + * The camera port can be multiplexed with any FIMC entity, even multiple + * FIMC entities are allowed to be attached to a single port simultaneously. + * These functions are to be used in the board setup code. + */ +int s5pv210_fimc_setup_gpio(enum s5p_camport_id id); +int exynos4_fimc_setup_gpio(enum s5p_camport_id id); + +#endif diff --git a/arch/arm/plat-s5p/include/plat/csis.h b/arch/arm/plat-s5p/include/plat/csis.h deleted file mode 100644 index 51e308c7981..00000000000 --- a/arch/arm/plat-s5p/include/plat/csis.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2010 Samsung Electronics - * - * S5P series MIPI CSI slave device 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. - */ - -#ifndef PLAT_S5P_CSIS_H_ -#define PLAT_S5P_CSIS_H_ __FILE__ - -/** - * struct s5p_platform_mipi_csis - platform data for MIPI-CSIS - * @clk_rate: bus clock frequency - * @lanes: number of data lanes used - * @alignment: data alignment in bits - * @hs_settle: HS-RX settle time - */ -struct s5p_platform_mipi_csis { - unsigned long clk_rate; - u8 lanes; - u8 alignment; - u8 hs_settle; -}; - -#endif /* PLAT_S5P_CSIS_H_ */ diff --git a/arch/arm/plat-s5p/include/plat/exynos4.h b/arch/arm/plat-s5p/include/plat/exynos4.h new file mode 100644 index 00000000000..907caab53dc --- /dev/null +++ b/arch/arm/plat-s5p/include/plat/exynos4.h @@ -0,0 +1,34 @@ +/* linux/arch/arm/plat-s5p/include/plat/exynos4.h + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Header file for exynos4 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. +*/ + +/* Common init code for EXYNOS4 related SoCs */ + +extern void exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void exynos4_register_clocks(void); +extern void exynos4_setup_clocks(void); + +#ifdef CONFIG_CPU_EXYNOS4210 + +extern int exynos4_init(void); +extern void exynos4_init_irq(void); +extern void exynos4_map_io(void); +extern void exynos4_init_clocks(int xtal); +extern struct sys_timer exynos4_timer; + +#define exynos4_init_uarts exynos4_common_init_uarts + +#else +#define exynos4_init_clocks NULL +#define exynos4_init_uarts NULL +#define exynos4_map_io NULL +#define exynos4_init NULL +#endif diff --git a/arch/arm/plat-s5p/include/plat/mipi_csis.h b/arch/arm/plat-s5p/include/plat/mipi_csis.h new file mode 100644 index 00000000000..9bd254c5ed2 --- /dev/null +++ b/arch/arm/plat-s5p/include/plat/mipi_csis.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * + * S5P series MIPI CSI slave device 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. + */ + +#ifndef PLAT_S5P_MIPI_CSIS_H_ +#define PLAT_S5P_MIPI_CSIS_H_ __FILE__ + +struct platform_device; + +/** + * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver + * @clk_rate: bus clock frequency + * @lanes: number of data lanes used + * @alignment: data alignment in bits + * @hs_settle: HS-RX settle time + * @fixed_phy_vdd: false to enable external D-PHY regulator management in the + * driver or true in case this regulator has no enable function + * @phy_enable: pointer to a callback controlling D-PHY enable/reset + */ +struct s5p_platform_mipi_csis { + unsigned long clk_rate; + u8 lanes; + u8 alignment; + u8 hs_settle; + bool fixed_phy_vdd; + int (*phy_enable)(struct platform_device *pdev, bool on); +}; + +/** + * s5p_csis_phy_enable - global MIPI-CSI receiver D-PHY control + * @pdev: MIPI-CSIS platform device + * @on: true to enable D-PHY and deassert its reset + * false to disable D-PHY + */ +int s5p_csis_phy_enable(struct platform_device *pdev, bool on); + +#endif /* PLAT_S5P_MIPI_CSIS_H_ */ diff --git a/arch/arm/plat-s5p/include/plat/s5p-time.h b/arch/arm/plat-s5p/include/plat/s5p-time.h new file mode 100644 index 00000000000..575e88109db --- /dev/null +++ b/arch/arm/plat-s5p/include/plat/s5p-time.h @@ -0,0 +1,40 @@ +/* linux/arch/arm/plat-s5p/include/plat/s5p-time.h + * + * Copyright 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Header file for s5p time 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. +*/ + +#ifndef __ASM_PLAT_S5P_TIME_H +#define __ASM_PLAT_S5P_TIME_H __FILE__ + +/* S5P HR-Timer Clock mode */ +enum s5p_timer_mode { + S5P_PWM0, + S5P_PWM1, + S5P_PWM2, + S5P_PWM3, + S5P_PWM4, +}; + +struct s5p_timer_source { + unsigned int event_id; + unsigned int source_id; +}; + +/* Be able to sleep for atleast 4 seconds (usually more) */ +#define S5PTIMER_MIN_RANGE 4 + +#define TCNT_MAX 0xffffffff +#define NON_PERIODIC 0 +#define PERIODIC 1 + +extern void __init s5p_set_timer_source(enum s5p_timer_mode event, + enum s5p_timer_mode source); +extern struct sys_timer s5p_timer; +#endif /* __ASM_PLAT_S5P_TIME_H */ diff --git a/arch/arm/plat-s5p/include/plat/s5pv310.h b/arch/arm/plat-s5p/include/plat/s5pv310.h deleted file mode 100644 index 769c991ceb3..00000000000 --- a/arch/arm/plat-s5p/include/plat/s5pv310.h +++ /dev/null @@ -1,34 +0,0 @@ -/* linux/arch/arm/plat-s5p/include/plat/s5pv310.h - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * Header file for s5pv310 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. -*/ - -/* Common init code for S5PV310 related SoCs */ - -extern void s5pv310_common_init_uarts(struct s3c2410_uartcfg *cfg, int no); -extern void s5pv310_register_clocks(void); -extern void s5pv310_setup_clocks(void); - -#ifdef CONFIG_CPU_S5PV310 - -extern int s5pv310_init(void); -extern void s5pv310_init_irq(void); -extern void s5pv310_map_io(void); -extern void s5pv310_init_clocks(int xtal); -extern struct sys_timer s5pv310_timer; - -#define s5pv310_init_uarts s5pv310_common_init_uarts - -#else -#define s5pv310_init_clocks NULL -#define s5pv310_init_uarts NULL -#define s5pv310_map_io NULL -#define s5pv310_init NULL -#endif diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h new file mode 100644 index 00000000000..bf5283c2a19 --- /dev/null +++ b/arch/arm/plat-s5p/include/plat/sysmmu.h @@ -0,0 +1,95 @@ +/* linux/arch/arm/plat-s5p/include/plat/sysmmu.h + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung System MMU driver for S5P platform + * + * 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_SYSMMU_H +#define __ASM__PLAT_SYSMMU_H __FILE__ + +enum S5P_SYSMMU_INTERRUPT_TYPE { + SYSMMU_PAGEFAULT, + SYSMMU_AR_MULTIHIT, + SYSMMU_AW_MULTIHIT, + SYSMMU_BUSERROR, + SYSMMU_AR_SECURITY, + SYSMMU_AR_ACCESS, + SYSMMU_AW_SECURITY, + SYSMMU_AW_PROTECTION, /* 7 */ + SYSMMU_FAULTS_NUM +}; + +#ifdef CONFIG_S5P_SYSTEM_MMU + +#include <mach/sysmmu.h> + +/** + * s5p_sysmmu_enable() - enable system mmu of ip + * @ips: The ip connected system mmu. + * #pgd: Base physical address of the 1st level page table + * + * This function enable system mmu to transfer address + * from virtual address to physical address + */ +void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd); + +/** + * s5p_sysmmu_disable() - disable sysmmu mmu of ip + * @ips: The ip connected system mmu. + * + * This function disable system mmu to transfer address + * from virtual address to physical address + */ +void s5p_sysmmu_disable(sysmmu_ips ips); + +/** + * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table + * @ips: The ip connected system mmu. + * @pgd: The page table base address. + * + * This function set page table base address + * When system mmu transfer address from virtaul address to physical address, + * system mmu refer address information from page table + */ +void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd); + +/** + * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu + * @ips: The ip connected system mmu. + * + * This function flush all TLB entry in system mmu + */ +void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips); + +/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs + * @itype: type of fault. + * @pgtable_base: the physical address of page table base. This is 0 if @ips is + * SYSMMU_BUSERROR. + * @fault_addr: the device (virtual) address that the System MMU tried to + * translated. This is 0 if @ips is SYSMMU_BUSERROR. + * Called when interrupt occurred by the System MMUs + * The device drivers of peripheral devices that has a System MMU can implement + * a fault handler to resolve address translation fault by System MMU. + * The meanings of return value and parameters are described below. + + * return value: non-zero if the fault is correctly resolved. + * zero if the fault is not handled. + */ +void s5p_sysmmu_set_fault_handler(sysmmu_ips ips, + int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype, + unsigned long pgtable_base, + unsigned long fault_addr)); +#else +#define s5p_sysmmu_enable(ips, pgd) do { } while (0) +#define s5p_sysmmu_disable(ips) do { } while (0) +#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0) +#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0) +#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0) +#endif +#endif /* __ASM_PLAT_SYSMMU_H */ diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c index 3b6bf89d173..cd87d3256e0 100644 --- a/arch/arm/plat-s5p/irq-gpioint.c +++ b/arch/arm/plat-s5p/irq-gpioint.c @@ -17,82 +17,79 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/slab.h> #include <mach/map.h> #include <plat/gpio-core.h> #include <plat/gpio-cfg.h> -#define S5P_GPIOREG(x) (S5P_VA_GPIO + (x)) +#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u) -#define GPIOINT_CON_OFFSET 0x700 -#define GPIOINT_MASK_OFFSET 0x900 -#define GPIOINT_PEND_OFFSET 0xA00 +#define CON_OFFSET 0x700 +#define MASK_OFFSET 0x900 +#define PEND_OFFSET 0xA00 +#define REG_OFFSET(x) ((x) << 2) -static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR]; - -static int s5p_gpioint_get_group(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_data(data); - struct s3c_gpio_chip *s3c_chip = container_of(chip, - struct s3c_gpio_chip, chip); - int group; - - for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) - if (s3c_chip == irq_chips[group]) - break; +struct s5p_gpioint_bank { + struct list_head list; + int start; + int nr_groups; + int irq; + struct s3c_gpio_chip **chips; + void (*handler)(unsigned int, struct irq_desc *); +}; - return group; -} +LIST_HEAD(banks); static int s5p_gpioint_get_offset(struct irq_data *data) { - struct gpio_chip *chip = irq_data_get_irq_data(data); - struct s3c_gpio_chip *s3c_chip = container_of(chip, - struct s3c_gpio_chip, chip); - - return data->irq - s3c_chip->irq_base; + struct s3c_gpio_chip *chip = irq_data_get_irq_data(data); + return data->irq - chip->irq_base; } static void s5p_gpioint_ack(struct irq_data *data) { + struct s3c_gpio_chip *chip = irq_data_get_irq_data(data); int group, offset, pend_offset; unsigned int value; - group = s5p_gpioint_get_group(data); + group = chip->group; offset = s5p_gpioint_get_offset(data); - pend_offset = group << 2; + pend_offset = REG_OFFSET(group); - value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); - value |= 1 << offset; - __raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); + value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset); + value |= BIT(offset); + __raw_writel(value, GPIO_BASE(chip) + PEND_OFFSET + pend_offset); } static void s5p_gpioint_mask(struct irq_data *data) { + struct s3c_gpio_chip *chip = irq_data_get_irq_data(data); int group, offset, mask_offset; unsigned int value; - group = s5p_gpioint_get_group(data); + group = chip->group; offset = s5p_gpioint_get_offset(data); - mask_offset = group << 2; + mask_offset = REG_OFFSET(group); - value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); - value |= 1 << offset; - __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); + value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset); + value |= BIT(offset); + __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset); } static void s5p_gpioint_unmask(struct irq_data *data) { + struct s3c_gpio_chip *chip = irq_data_get_irq_data(data); int group, offset, mask_offset; unsigned int value; - group = s5p_gpioint_get_group(data); + group = chip->group; offset = s5p_gpioint_get_offset(data); - mask_offset = group << 2; + mask_offset = REG_OFFSET(group); - value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); - value &= ~(1 << offset); - __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); + value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset); + value &= ~BIT(offset); + __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset); } static void s5p_gpioint_mask_ack(struct irq_data *data) @@ -103,12 +100,13 @@ static void s5p_gpioint_mask_ack(struct irq_data *data) static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type) { + struct s3c_gpio_chip *chip = irq_data_get_irq_data(data); int group, offset, con_offset; unsigned int value; - group = s5p_gpioint_get_group(data); + group = chip->group; offset = s5p_gpioint_get_offset(data); - con_offset = group << 2; + con_offset = REG_OFFSET(group); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -132,15 +130,15 @@ static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type) return -EINVAL; } - value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); + value = __raw_readl(GPIO_BASE(chip) + CON_OFFSET + con_offset); value &= ~(0x7 << (offset * 0x4)); value |= (type << (offset * 0x4)); - __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); + __raw_writel(value, GPIO_BASE(chip) + CON_OFFSET + con_offset); return 0; } -struct irq_chip s5p_gpioint = { +static struct irq_chip s5p_gpioint = { .name = "s5p_gpioint", .irq_ack = s5p_gpioint_ack, .irq_mask = s5p_gpioint_mask, @@ -151,30 +149,29 @@ struct irq_chip s5p_gpioint = { static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) { - int group, offset, pend_offset, mask_offset; - int real_irq; + struct s5p_gpioint_bank *bank = get_irq_data(irq); + int group, pend_offset, mask_offset; unsigned int pend, mask; - for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) { - pend_offset = group << 2; - pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + - pend_offset); + for (group = 0; group < bank->nr_groups; group++) { + struct s3c_gpio_chip *chip = bank->chips[group]; + if (!chip) + continue; + + pend_offset = REG_OFFSET(group); + pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset); if (!pend) continue; - mask_offset = group << 2; - mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + - mask_offset); + mask_offset = REG_OFFSET(group); + mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset); pend &= ~mask; - for (offset = 0; offset < 8; offset++) { - if (pend & (1 << offset)) { - struct s3c_gpio_chip *chip = irq_chips[group]; - if (chip) { - real_irq = chip->irq_base + offset; - generic_handle_irq(real_irq); - } - } + while (pend) { + int offset = fls(pend) - 1; + int real_irq = chip->irq_base + offset; + generic_handle_irq(real_irq); + pend &= ~BIT(offset); } } } @@ -182,27 +179,48 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) { static int used_gpioint_groups = 0; - static bool handler_registered = 0; int irq, group = chip->group; int i; + struct s5p_gpioint_bank *bank = NULL; if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) return -ENOMEM; + list_for_each_entry(bank, &banks, list) { + if (group >= bank->start && + group < bank->start + bank->nr_groups) + break; + } + if (!bank) + return -EINVAL; + + if (!bank->handler) { + bank->chips = kzalloc(sizeof(struct s3c_gpio_chip *) * + bank->nr_groups, GFP_KERNEL); + if (!bank->chips) + return -ENOMEM; + + set_irq_chained_handler(bank->irq, s5p_gpioint_handler); + set_irq_data(bank->irq, bank); + bank->handler = s5p_gpioint_handler; + printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n", + bank->irq); + } + + /* + * chained GPIO irq has been sucessfully registered, allocate new gpio + * int group and assign irq nubmers + */ + chip->irq_base = S5P_GPIOINT_BASE + used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; used_gpioint_groups++; - if (!handler_registered) { - set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler); - handler_registered = 1; - } - - irq_chips[group] = chip; + bank->chips[group - bank->start] = chip; for (i = 0; i < chip->chip.ngpio; i++) { irq = chip->irq_base + i; set_irq_chip(irq, &s5p_gpioint); - set_irq_data(irq, &chip->chip); + set_irq_data(irq, chip); set_irq_handler(irq, handle_level_irq); set_irq_flags(irq, IRQF_VALID); } @@ -235,3 +253,19 @@ int __init s5p_register_gpio_interrupt(int pin) } return ret; } + +int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups) +{ + struct s5p_gpioint_bank *bank; + + bank = kzalloc(sizeof(*bank), GFP_KERNEL); + if (!bank) + return -ENOMEM; + + bank->start = start; + bank->nr_groups = nr_groups; + bank->irq = chain_irq; + + list_add_tail(&bank->list, &banks); + return 0; +} diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c new file mode 100644 index 00000000000..8090403eec0 --- /dev/null +++ b/arch/arm/plat-s5p/s5p-time.c @@ -0,0 +1,448 @@ +/* linux/arch/arm/plat-s5p/s5p-time.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5P - Common hr-timer 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/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/platform_device.h> + +#include <asm/smp_twd.h> +#include <asm/mach/time.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/sched_clock.h> + +#include <mach/map.h> +#include <plat/devs.h> +#include <plat/regs-timer.h> +#include <plat/s5p-time.h> + +static struct clk *tin_event; +static struct clk *tin_source; +static struct clk *tdiv_event; +static struct clk *tdiv_source; +static struct clk *timerclk; +static struct s5p_timer_source timer_source; +static unsigned long clock_count_per_tick; +static void s5p_timer_resume(void); + +static void s5p_time_stop(enum s5p_timer_mode mode) +{ + unsigned long tcon; + + tcon = __raw_readl(S3C2410_TCON); + + switch (mode) { + case S5P_PWM0: + tcon &= ~S3C2410_TCON_T0START; + break; + + case S5P_PWM1: + tcon &= ~S3C2410_TCON_T1START; + break; + + case S5P_PWM2: + tcon &= ~S3C2410_TCON_T2START; + break; + + case S5P_PWM3: + tcon &= ~S3C2410_TCON_T3START; + break; + + case S5P_PWM4: + tcon &= ~S3C2410_TCON_T4START; + break; + + default: + printk(KERN_ERR "Invalid Timer %d\n", mode); + break; + } + __raw_writel(tcon, S3C2410_TCON); +} + +static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt) +{ + unsigned long tcon; + + tcon = __raw_readl(S3C2410_TCON); + + tcnt--; + + switch (mode) { + case S5P_PWM0: + tcon &= ~(0x0f << 0); + tcon |= S3C2410_TCON_T0MANUALUPD; + break; + + case S5P_PWM1: + tcon &= ~(0x0f << 8); + tcon |= S3C2410_TCON_T1MANUALUPD; + break; + + case S5P_PWM2: + tcon &= ~(0x0f << 12); + tcon |= S3C2410_TCON_T2MANUALUPD; + break; + + case S5P_PWM3: + tcon &= ~(0x0f << 16); + tcon |= S3C2410_TCON_T3MANUALUPD; + break; + + case S5P_PWM4: + tcon &= ~(0x07 << 20); + tcon |= S3C2410_TCON_T4MANUALUPD; + break; + + default: + printk(KERN_ERR "Invalid Timer %d\n", mode); + break; + } + + __raw_writel(tcnt, S3C2410_TCNTB(mode)); + __raw_writel(tcnt, S3C2410_TCMPB(mode)); + __raw_writel(tcon, S3C2410_TCON); +} + +static void s5p_time_start(enum s5p_timer_mode mode, bool periodic) +{ + unsigned long tcon; + + tcon = __raw_readl(S3C2410_TCON); + + switch (mode) { + case S5P_PWM0: + tcon |= S3C2410_TCON_T0START; + tcon &= ~S3C2410_TCON_T0MANUALUPD; + + if (periodic) + tcon |= S3C2410_TCON_T0RELOAD; + else + tcon &= ~S3C2410_TCON_T0RELOAD; + break; + + case S5P_PWM1: + tcon |= S3C2410_TCON_T1START; + tcon &= ~S3C2410_TCON_T1MANUALUPD; + + if (periodic) + tcon |= S3C2410_TCON_T1RELOAD; + else + tcon &= ~S3C2410_TCON_T1RELOAD; + break; + + case S5P_PWM2: + tcon |= S3C2410_TCON_T2START; + tcon &= ~S3C2410_TCON_T2MANUALUPD; + + if (periodic) + tcon |= S3C2410_TCON_T2RELOAD; + else + tcon &= ~S3C2410_TCON_T2RELOAD; + break; + + case S5P_PWM3: + tcon |= S3C2410_TCON_T3START; + tcon &= ~S3C2410_TCON_T3MANUALUPD; + + if (periodic) + tcon |= S3C2410_TCON_T3RELOAD; + else + tcon &= ~S3C2410_TCON_T3RELOAD; + break; + + case S5P_PWM4: + tcon |= S3C2410_TCON_T4START; |