aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-s5p
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-s5p')
-rw-r--r--arch/arm/plat-s5p/Kconfig23
-rw-r--r--arch/arm/plat-s5p/Makefile3
-rw-r--r--arch/arm/plat-s5p/cpu.c25
-rw-r--r--arch/arm/plat-s5p/dev-csis0.c2
-rw-r--r--arch/arm/plat-s5p/dev-csis1.c2
-rw-r--r--arch/arm/plat-s5p/dev-fimc3.c43
-rw-r--r--arch/arm/plat-s5p/include/plat/camport.h28
-rw-r--r--arch/arm/plat-s5p/include/plat/csis.h28
-rw-r--r--arch/arm/plat-s5p/include/plat/exynos4.h34
-rw-r--r--arch/arm/plat-s5p/include/plat/mipi_csis.h43
-rw-r--r--arch/arm/plat-s5p/include/plat/s5p-time.h40
-rw-r--r--arch/arm/plat-s5p/include/plat/s5pv310.h34
-rw-r--r--arch/arm/plat-s5p/include/plat/sysmmu.h95
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c170
-rw-r--r--arch/arm/plat-s5p/s5p-time.c448
-rw-r--r--arch/arm/plat-s5p/setup-mipiphy.c63
-rw-r--r--arch/arm/plat-s5p/sysmmu.c370
17 files changed, 1112 insertions, 339 deletions
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 557f8c507f6d..849229716586 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -7,10 +7,10 @@
7 7
8config PLAT_S5P 8config PLAT_S5P
9 bool 9 bool
10 depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310) 10 depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS4)
11 default y 11 default y
12 select ARM_VIC if !ARCH_S5PV310 12 select ARM_VIC if !ARCH_EXYNOS4
13 select ARM_GIC if ARCH_S5PV310 13 select ARM_GIC if ARCH_EXYNOS4
14 select NO_IOPORT 14 select NO_IOPORT
15 select ARCH_REQUIRE_GPIOLIB 15 select ARCH_REQUIRE_GPIOLIB
16 select S3C_GPIO_TRACK 16 select S3C_GPIO_TRACK
@@ -37,11 +37,16 @@ config S5P_GPIO_INT
37 help 37 help
38 Common code for the GPIO interrupts (other than external interrupts.) 38 Common code for the GPIO interrupts (other than external interrupts.)
39 39
40config S5P_HRT
41 bool
42 help
43 Use the High Resolution timer support
44
40comment "System MMU" 45comment "System MMU"
41 46
42config S5P_SYSTEM_MMU 47config S5P_SYSTEM_MMU
43 bool "S5P SYSTEM MMU" 48 bool "S5P SYSTEM MMU"
44 depends on ARCH_S5PV310 49 depends on ARCH_EXYNOS4
45 help 50 help
46 Say Y here if you want to enable System MMU 51 Say Y here if you want to enable System MMU
47 52
@@ -60,6 +65,11 @@ config S5P_DEV_FIMC2
60 help 65 help
61 Compile in platform device definitions for FIMC controller 2 66 Compile in platform device definitions for FIMC controller 2
62 67
68config S5P_DEV_FIMC3
69 bool
70 help
71 Compile in platform device definitions for FIMC controller 3
72
63config S5P_DEV_ONENAND 73config S5P_DEV_ONENAND
64 bool 74 bool
65 help 75 help
@@ -74,3 +84,8 @@ config S5P_DEV_CSIS1
74 bool 84 bool
75 help 85 help
76 Compile in platform device definitions for MIPI-CSIS channel 1 86 Compile in platform device definitions for MIPI-CSIS channel 1
87
88config S5P_SETUP_MIPIPHY
89 bool
90 help
91 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 4bd5cf908977..42afff7f60be 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
22obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o 22obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o
23obj-$(CONFIG_PM) += pm.o 23obj-$(CONFIG_PM) += pm.o
24obj-$(CONFIG_PM) += irq-pm.o 24obj-$(CONFIG_PM) += irq-pm.o
25obj-$(CONFIG_S5P_HRT) += s5p-time.o
25 26
26# devices 27# devices
27 28
28obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o 29obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o
29obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o 30obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o
30obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o 31obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o
32obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o
31obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o 33obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
32obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o 34obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
33obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o 35obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
36obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o
diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c
index 047d31c1bbd8..c3bfe9b13acf 100644
--- a/arch/arm/plat-s5p/cpu.c
+++ b/arch/arm/plat-s5p/cpu.c
@@ -1,7 +1,7 @@
1/* linux/arch/arm/plat-s5p/cpu.c 1/* linux/arch/arm/plat-s5p/cpu.c
2 * 2 *
3 * Copyright (c) 2009 Samsung Electronics Co., Ltd. 3 * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/ 4 * http://www.samsung.com
5 * 5 *
6 * S5P CPU Support 6 * S5P CPU Support
7 * 7 *
@@ -12,17 +12,20 @@
12 12
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <mach/map.h> 15
16#include <asm/mach/arch.h> 16#include <asm/mach/arch.h>
17#include <asm/mach/map.h> 17#include <asm/mach/map.h>
18
19#include <mach/map.h>
18#include <mach/regs-clock.h> 20#include <mach/regs-clock.h>
21
19#include <plat/cpu.h> 22#include <plat/cpu.h>
20#include <plat/s5p6440.h> 23#include <plat/s5p6440.h>
21#include <plat/s5p6442.h> 24#include <plat/s5p6442.h>
22#include <plat/s5p6450.h> 25#include <plat/s5p6450.h>
23#include <plat/s5pc100.h> 26#include <plat/s5pc100.h>
24#include <plat/s5pv210.h> 27#include <plat/s5pv210.h>
25#include <plat/s5pv310.h> 28#include <plat/exynos4.h>
26 29
27/* table of supported CPUs */ 30/* table of supported CPUs */
28 31
@@ -31,7 +34,7 @@ static const char name_s5p6442[] = "S5P6442";
31static const char name_s5p6450[] = "S5P6450"; 34static const char name_s5p6450[] = "S5P6450";
32static const char name_s5pc100[] = "S5PC100"; 35static const char name_s5pc100[] = "S5PC100";
33static const char name_s5pv210[] = "S5PV210/S5PC110"; 36static const char name_s5pv210[] = "S5PV210/S5PC110";
34static const char name_s5pv310[] = "S5PV310"; 37static const char name_exynos4210[] = "EXYNOS4210";
35 38
36static struct cpu_table cpu_ids[] __initdata = { 39static struct cpu_table cpu_ids[] __initdata = {
37 { 40 {
@@ -75,13 +78,13 @@ static struct cpu_table cpu_ids[] __initdata = {
75 .init = s5pv210_init, 78 .init = s5pv210_init,
76 .name = name_s5pv210, 79 .name = name_s5pv210,
77 }, { 80 }, {
78 .idcode = 0x43200000, 81 .idcode = 0x43210000,
79 .idmask = 0xfffff000, 82 .idmask = 0xfffff000,
80 .map_io = s5pv310_map_io, 83 .map_io = exynos4_map_io,
81 .init_clocks = s5pv310_init_clocks, 84 .init_clocks = exynos4_init_clocks,
82 .init_uarts = s5pv310_init_uarts, 85 .init_uarts = exynos4_init_uarts,
83 .init = s5pv310_init, 86 .init = exynos4_init,
84 .name = name_s5pv310, 87 .name = name_exynos4210,
85 }, 88 },
86}; 89};
87 90
diff --git a/arch/arm/plat-s5p/dev-csis0.c b/arch/arm/plat-s5p/dev-csis0.c
index dfab1c85f54f..e3aabef5e347 100644
--- a/arch/arm/plat-s5p/dev-csis0.c
+++ b/arch/arm/plat-s5p/dev-csis0.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2010 Samsung Electronics 2 * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
3 * 3 *
4 * S5P series device definition for MIPI-CSIS channel 0 4 * S5P series device definition for MIPI-CSIS channel 0
5 * 5 *
diff --git a/arch/arm/plat-s5p/dev-csis1.c b/arch/arm/plat-s5p/dev-csis1.c
index e3053f27fbbf..08b91b580207 100644
--- a/arch/arm/plat-s5p/dev-csis1.c
+++ b/arch/arm/plat-s5p/dev-csis1.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2010 Samsung Electronics 2 * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
3 * 3 *
4 * S5P series device definition for MIPI-CSIS channel 1 4 * S5P series device definition for MIPI-CSIS channel 1
5 * 5 *
diff --git a/arch/arm/plat-s5p/dev-fimc3.c b/arch/arm/plat-s5p/dev-fimc3.c
new file mode 100644
index 000000000000..ef31beca386c
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-fimc3.c
@@ -0,0 +1,43 @@
1/* linux/arch/arm/plat-s5p/dev-fimc3.c
2 *
3 * Copyright (c) 2010 Samsung Electronics
4 *
5 * Base S5P FIMC3 resource and device definitions
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/dma-mapping.h>
14#include <linux/platform_device.h>
15#include <linux/interrupt.h>
16#include <linux/ioport.h>
17#include <mach/map.h>
18
19static struct resource s5p_fimc3_resource[] = {
20 [0] = {
21 .start = S5P_PA_FIMC3,
22 .end = S5P_PA_FIMC3 + SZ_4K - 1,
23 .flags = IORESOURCE_MEM,
24 },
25 [1] = {
26 .start = IRQ_FIMC3,
27 .end = IRQ_FIMC3,
28 .flags = IORESOURCE_IRQ,
29 },
30};
31
32static u64 s5p_fimc3_dma_mask = DMA_BIT_MASK(32);
33
34struct platform_device s5p_device_fimc3 = {
35 .name = "s5p-fimc",
36 .id = 3,
37 .num_resources = ARRAY_SIZE(s5p_fimc3_resource),
38 .resource = s5p_fimc3_resource,
39 .dev = {
40 .dma_mask = &s5p_fimc3_dma_mask,
41 .coherent_dma_mask = DMA_BIT_MASK(32),
42 },
43};
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 000000000000..71688c8ba288
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/camport.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
3 *
4 * S5P series camera interface helper functions
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef PLAT_S5P_CAMPORT_H_
12#define PLAT_S5P_CAMPORT_H_ __FILE__
13
14enum s5p_camport_id {
15 S5P_CAMPORT_A,
16 S5P_CAMPORT_B,
17};
18
19/*
20 * The helper functions to configure GPIO for the camera parallel bus.
21 * The camera port can be multiplexed with any FIMC entity, even multiple
22 * FIMC entities are allowed to be attached to a single port simultaneously.
23 * These functions are to be used in the board setup code.
24 */
25int s5pv210_fimc_setup_gpio(enum s5p_camport_id id);
26int exynos4_fimc_setup_gpio(enum s5p_camport_id id);
27
28#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 51e308c7981d..000000000000
--- a/arch/arm/plat-s5p/include/plat/csis.h
+++ /dev/null
@@ -1,28 +0,0 @@
1/*
2 * Copyright (C) 2010 Samsung Electronics
3 *
4 * S5P series MIPI CSI slave device support
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef PLAT_S5P_CSIS_H_
12#define PLAT_S5P_CSIS_H_ __FILE__
13
14/**
15 * struct s5p_platform_mipi_csis - platform data for MIPI-CSIS
16 * @clk_rate: bus clock frequency
17 * @lanes: number of data lanes used
18 * @alignment: data alignment in bits
19 * @hs_settle: HS-RX settle time
20 */
21struct s5p_platform_mipi_csis {
22 unsigned long clk_rate;
23 u8 lanes;
24 u8 alignment;
25 u8 hs_settle;
26};
27
28#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 000000000000..907caab53dcf
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/exynos4.h
@@ -0,0 +1,34 @@
1/* linux/arch/arm/plat-s5p/include/plat/exynos4.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Header file for exynos4 cpu support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13/* Common init code for EXYNOS4 related SoCs */
14
15extern void exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
16extern void exynos4_register_clocks(void);
17extern void exynos4_setup_clocks(void);
18
19#ifdef CONFIG_CPU_EXYNOS4210
20
21extern int exynos4_init(void);
22extern void exynos4_init_irq(void);
23extern void exynos4_map_io(void);
24extern void exynos4_init_clocks(int xtal);
25extern struct sys_timer exynos4_timer;
26
27#define exynos4_init_uarts exynos4_common_init_uarts
28
29#else
30#define exynos4_init_clocks NULL
31#define exynos4_init_uarts NULL
32#define exynos4_map_io NULL
33#define exynos4_init NULL
34#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 000000000000..9bd254c5ed22
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/mipi_csis.h
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
3 *
4 * S5P series MIPI CSI slave device support
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef PLAT_S5P_MIPI_CSIS_H_
12#define PLAT_S5P_MIPI_CSIS_H_ __FILE__
13
14struct platform_device;
15
16/**
17 * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver
18 * @clk_rate: bus clock frequency
19 * @lanes: number of data lanes used
20 * @alignment: data alignment in bits
21 * @hs_settle: HS-RX settle time
22 * @fixed_phy_vdd: false to enable external D-PHY regulator management in the
23 * driver or true in case this regulator has no enable function
24 * @phy_enable: pointer to a callback controlling D-PHY enable/reset
25 */
26struct s5p_platform_mipi_csis {
27 unsigned long clk_rate;
28 u8 lanes;
29 u8 alignment;
30 u8 hs_settle;
31 bool fixed_phy_vdd;
32 int (*phy_enable)(struct platform_device *pdev, bool on);
33};
34
35/**
36 * s5p_csis_phy_enable - global MIPI-CSI receiver D-PHY control
37 * @pdev: MIPI-CSIS platform device
38 * @on: true to enable D-PHY and deassert its reset
39 * false to disable D-PHY
40 */
41int s5p_csis_phy_enable(struct platform_device *pdev, bool on);
42
43#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 000000000000..575e88109db8
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/s5p-time.h
@@ -0,0 +1,40 @@
1/* linux/arch/arm/plat-s5p/include/plat/s5p-time.h
2 *
3 * Copyright 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * Header file for s5p time support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifndef __ASM_PLAT_S5P_TIME_H
14#define __ASM_PLAT_S5P_TIME_H __FILE__
15
16/* S5P HR-Timer Clock mode */
17enum s5p_timer_mode {
18 S5P_PWM0,
19 S5P_PWM1,
20 S5P_PWM2,
21 S5P_PWM3,
22 S5P_PWM4,
23};
24
25struct s5p_timer_source {
26 unsigned int event_id;
27 unsigned int source_id;
28};
29
30/* Be able to sleep for atleast 4 seconds (usually more) */
31#define S5PTIMER_MIN_RANGE 4
32
33#define TCNT_MAX 0xffffffff
34#define NON_PERIODIC 0
35#define PERIODIC 1
36
37extern void __init s5p_set_timer_source(enum s5p_timer_mode event,
38 enum s5p_timer_mode source);
39extern struct sys_timer s5p_timer;
40#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 769c991ceb37..000000000000
--- a/arch/arm/plat-s5p/include/plat/s5pv310.h
+++ /dev/null
@@ -1,34 +0,0 @@
1/* linux/arch/arm/plat-s5p/include/plat/s5pv310.h
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * Header file for s5pv310 cpu support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13/* Common init code for S5PV310 related SoCs */
14
15extern void s5pv310_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
16extern void s5pv310_register_clocks(void);
17extern void s5pv310_setup_clocks(void);
18
19#ifdef CONFIG_CPU_S5PV310
20
21extern int s5pv310_init(void);
22extern void s5pv310_init_irq(void);
23extern void s5pv310_map_io(void);
24extern void s5pv310_init_clocks(int xtal);
25extern struct sys_timer s5pv310_timer;
26
27#define s5pv310_init_uarts s5pv310_common_init_uarts
28
29#else
30#define s5pv310_init_clocks NULL
31#define s5pv310_init_uarts NULL
32#define s5pv310_map_io NULL
33#define s5pv310_init NULL
34#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 000000000000..bf5283c2a19d
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/sysmmu.h
@@ -0,0 +1,95 @@
1/* linux/arch/arm/plat-s5p/include/plat/sysmmu.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Samsung System MMU driver for S5P platform
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifndef __ASM__PLAT_SYSMMU_H
14#define __ASM__PLAT_SYSMMU_H __FILE__
15
16enum S5P_SYSMMU_INTERRUPT_TYPE {
17 SYSMMU_PAGEFAULT,
18 SYSMMU_AR_MULTIHIT,
19 SYSMMU_AW_MULTIHIT,
20 SYSMMU_BUSERROR,
21 SYSMMU_AR_SECURITY,
22 SYSMMU_AR_ACCESS,
23 SYSMMU_AW_SECURITY,
24 SYSMMU_AW_PROTECTION, /* 7 */
25 SYSMMU_FAULTS_NUM
26};
27
28#ifdef CONFIG_S5P_SYSTEM_MMU
29
30#include <mach/sysmmu.h>
31
32/**
33 * s5p_sysmmu_enable() - enable system mmu of ip
34 * @ips: The ip connected system mmu.
35 * #pgd: Base physical address of the 1st level page table
36 *
37 * This function enable system mmu to transfer address
38 * from virtual address to physical address
39 */
40void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd);
41
42/**
43 * s5p_sysmmu_disable() - disable sysmmu mmu of ip
44 * @ips: The ip connected system mmu.
45 *
46 * This function disable system mmu to transfer address
47 * from virtual address to physical address
48 */
49void s5p_sysmmu_disable(sysmmu_ips ips);
50
51/**
52 * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
53 * @ips: The ip connected system mmu.
54 * @pgd: The page table base address.
55 *
56 * This function set page table base address
57 * When system mmu transfer address from virtaul address to physical address,
58 * system mmu refer address information from page table
59 */
60void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
61
62/**
63 * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
64 * @ips: The ip connected system mmu.
65 *
66 * This function flush all TLB entry in system mmu
67 */
68void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
69
70/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs
71 * @itype: type of fault.
72 * @pgtable_base: the physical address of page table base. This is 0 if @ips is
73 * SYSMMU_BUSERROR.
74 * @fault_addr: the device (virtual) address that the System MMU tried to
75 * translated. This is 0 if @ips is SYSMMU_BUSERROR.
76 * Called when interrupt occurred by the System MMUs
77 * The device drivers of peripheral devices that has a System MMU can implement
78 * a fault handler to resolve address translation fault by System MMU.
79 * The meanings of return value and parameters are described below.
80
81 * return value: non-zero if the fault is correctly resolved.
82 * zero if the fault is not handled.
83 */
84void s5p_sysmmu_set_fault_handler(sysmmu_ips ips,
85 int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
86 unsigned long pgtable_base,
87 unsigned long fault_addr));
88#else
89#define s5p_sysmmu_enable(ips, pgd) do { } while (0)
90#define s5p_sysmmu_disable(ips) do { } while (0)
91#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0)
92#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0)
93#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0)
94#endif
95#endif /* __ASM_PLAT_SYSMMU_H */
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 3b6bf89d1739..cd87d3256e03 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -17,82 +17,79 @@
17#include <linux/irq.h> 17#include <linux/irq.h>
18#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/gpio.h> 19#include <linux/gpio.h>
20#include <linux/slab.h>
20 21
21#include <mach/map.h> 22#include <mach/map.h>
22#include <plat/gpio-core.h> 23#include <plat/gpio-core.h>
23#include <plat/gpio-cfg.h> 24#include <plat/gpio-cfg.h>
24 25
25#define S5P_GPIOREG(x) (S5P_VA_GPIO + (x)) 26#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
26 27
27#define GPIOINT_CON_OFFSET 0x700 28#define CON_OFFSET 0x700
28#define GPIOINT_MASK_OFFSET 0x900 29#define MASK_OFFSET 0x900
29#define GPIOINT_PEND_OFFSET 0xA00 30#define PEND_OFFSET 0xA00
31#define REG_OFFSET(x) ((x) << 2)
30 32
31static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR]; 33struct s5p_gpioint_bank {
32 34 struct list_head list;
33static int s5p_gpioint_get_group(struct irq_data *data) 35 int start;
34{ 36 int nr_groups;
35 struct gpio_chip *chip = irq_data_get_irq_data(data); 37 int irq;
36 struct s3c_gpio_chip *s3c_chip = container_of(chip, 38 struct s3c_gpio_chip **chips;
37 struct s3c_gpio_chip, chip); 39 void (*handler)(unsigned int, struct irq_desc *);
38 int group; 40};
39
40 for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++)
41 if (s3c_chip == irq_chips[group])
42 break;
43 41
44 return group; 42LIST_HEAD(banks);
45}
46 43
47static int s5p_gpioint_get_offset(struct irq_data *data) 44static int s5p_gpioint_get_offset(struct irq_data *data)
48{ 45{
49 struct gpio_chip *chip = irq_data_get_irq_data(data); 46 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
50 struct s3c_gpio_chip *s3c_chip = container_of(chip, 47 return data->irq - chip->irq_base;
51 struct s3c_gpio_chip, chip);
52
53 return data->irq - s3c_chip->irq_base;
54} 48}
55 49
56static void s5p_gpioint_ack(struct irq_data *data) 50static void s5p_gpioint_ack(struct irq_data *data)
57{ 51{
52 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
58 int group, offset, pend_offset; 53 int group, offset, pend_offset;
59 unsigned int value; 54 unsigned int value;
60 55
61 group = s5p_gpioint_get_group(data); 56 group = chip->group;
62 offset = s5p_gpioint_get_offset(data); 57 offset = s5p_gpioint_get_offset(data);
63 pend_offset = group << 2; 58 pend_offset = REG_OFFSET(group);
64 59
65 value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); 60 value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
66 value |= 1 << offset; 61 value |= BIT(offset);
67 __raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); 62 __raw_writel(value, GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
68} 63}
69 64
70static void s5p_gpioint_mask(struct irq_data *data) 65static void s5p_gpioint_mask(struct irq_data *data)
71{ 66{
67 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
72 int group, offset, mask_offset; 68 int group, offset, mask_offset;
73 unsigned int value; 69 unsigned int value;
74 70
75 group = s5p_gpioint_get_group(data); 71 group = chip->group;
76 offset = s5p_gpioint_get_offset(data); 72 offset = s5p_gpioint_get_offset(data);
77 mask_offset = group << 2; 73 mask_offset = REG_OFFSET(group);
78 74
79 value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 75 value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
80 value |= 1 << offset; 76 value |= BIT(offset);
81 __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 77 __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
82} 78}
83 79
84static void s5p_gpioint_unmask(struct irq_data *data) 80static void s5p_gpioint_unmask(struct irq_data *data)
85{ 81{
82 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
86 int group, offset, mask_offset; 83 int group, offset, mask_offset;
87 unsigned int value; 84 unsigned int value;
88 85
89 group = s5p_gpioint_get_group(data); 86 group = chip->group;
90 offset = s5p_gpioint_get_offset(data); 87 offset = s5p_gpioint_get_offset(data);
91 mask_offset = group << 2; 88 mask_offset = REG_OFFSET(group);
92 89
93 value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 90 value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
94 value &= ~(1 << offset); 91 value &= ~BIT(offset);
95 __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 92 __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
96} 93}
97 94
98static void s5p_gpioint_mask_ack(struct irq_data *data) 95static void s5p_gpioint_mask_ack(struct irq_data *data)
@@ -103,12 +100,13 @@ static void s5p_gpioint_mask_ack(struct irq_data *data)
103 100
104static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type) 101static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
105{ 102{
103 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
106 int group, offset, con_offset; 104 int group, offset, con_offset;
107 unsigned int value; 105 unsigned int value;
108 106
109 group = s5p_gpioint_get_group(data); 107 group = chip->group;
110 offset = s5p_gpioint_get_offset(data); 108 offset = s5p_gpioint_get_offset(data);
111 con_offset = group << 2; 109 con_offset = REG_OFFSET(group);
112 110
113 switch (type) { 111 switch (type) {
114 case IRQ_TYPE_EDGE_RISING: 112 case IRQ_TYPE_EDGE_RISING:
@@ -132,15 +130,15 @@ static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
132 return -EINVAL; 130 return -EINVAL;
133 } 131 }
134 132
135 value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); 133 value = __raw_readl(GPIO_BASE(chip) + CON_OFFSET + con_offset);
136 value &= ~(0x7 << (offset * 0x4)); 134 value &= ~(0x7 << (offset * 0x4));
137 value |= (type << (offset * 0x4)); 135 value |= (type << (offset * 0x4));
138 __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); 136 __raw_writel(value, GPIO_BASE(chip) + CON_OFFSET + con_offset);
139 137
140 return 0; 138 return 0;
141} 139}
142 140
143struct irq_chip s5p_gpioint = { 141static struct irq_chip s5p_gpioint = {
144 .name = "s5p_gpioint", 142 .name = "s5p_gpioint",
145 .irq_ack = s5p_gpioint_ack, 143 .irq_ack = s5p_gpioint_ack,
146 .irq_mask = s5p_gpioint_mask, 144 .irq_mask = s5p_gpioint_mask,
@@ -151,30 +149,29 @@ struct irq_chip s5p_gpioint = {
151 149
152static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) 150static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
153{ 151{
154 int group, offset, pend_offset, mask_offset; 152 struct s5p_gpioint_bank *bank = get_irq_data(irq);
155 int real_irq; 153 int group, pend_offset, mask_offset;
156 unsigned int pend, mask; 154 unsigned int pend, mask;
157 155
158 for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) { 156 for (group = 0; group < bank->nr_groups; group++) {
159 pend_offset = group << 2; 157 struct s3c_gpio_chip *chip = bank->chips[group];
160 pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + 158 if (!chip)
161 pend_offset); 159 continue;
160
161 pend_offset = REG_OFFSET(group);
162 pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
162 if (!pend) 163 if (!pend)
163 continue; 164 continue;
164 165
165 mask_offset = group << 2; 166 mask_offset = REG_OFFSET(group);
166 mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + 167 mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
167 mask_offset);
168 pend &= ~mask; 168 pend &= ~mask;
169 169
170 for (offset = 0; offset < 8; offset++) { 170 while (pend) {
171 if (pend & (1 << offset)) { 171 int offset = fls(pend) - 1;
172 struct s3c_gpio_chip *chip = irq_chips[group]; 172 int real_irq = chip->irq_base + offset;
173 if (chip) { 173 generic_handle_irq(real_irq);
174 real_irq = chip->irq_base + offset; 174 pend &= ~BIT(offset);
175 generic_handle_irq(real_irq);
176 }
177 }
178 } 175 }
179 } 176 }
180} 177}
@@ -182,27 +179,48 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
182static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) 179static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
183{ 180{
184 static int used_gpioint_groups = 0; 181 static int used_gpioint_groups = 0;
185 static bool handler_registered = 0;
186 int irq, group = chip->group; 182 int irq, group = chip->group;
187 int i; 183 int i;
184 struct s5p_gpioint_bank *bank = NULL;
188 185
189 if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) 186 if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
190 return -ENOMEM; 187 return -ENOMEM;
191 188
189 list_for_each_entry(bank, &banks, list) {
190 if (group >= bank->start &&
191 group < bank->start + bank->nr_groups)
192 break;
193 }
194 if (!bank)
195 return -EINVAL;
196
197 if (!bank->handler) {
198 bank->chips = kzalloc(sizeof(struct s3c_gpio_chip *) *
199 bank->nr_groups, GFP_KERNEL);
200 if (!bank->chips)
201 return -ENOMEM;
202
203 set_irq_chained_handler(bank->irq, s5p_gpioint_handler);
204 set_irq_data(bank->irq, bank);
205 bank->handler = s5p_gpioint_handler;
206 printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n",
207 bank->irq);
208 }
209
210 /*
211 * chained GPIO irq has been sucessfully registered, allocate new gpio
212 * int group and assign irq nubmers
213 */
214
192 chip->irq_base = S5P_GPIOINT_BASE + 215 chip->irq_base = S5P_GPIOINT_BASE +
193 used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; 216 used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
194 used_gpioint_groups++; 217 used_gpioint_groups++;
195 218
196 if (!handler_registered) { 219 bank->chips[group - bank->start] = chip;
197 set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler);
198 handler_registered = 1;
199 }
200
201 irq_chips[group] = chip;
202 for (i = 0; i < chip->chip.ngpio; i++) { 220 for (i = 0; i < chip->chip.ngpio; i++) {
203 irq = chip->irq_base + i; 221 irq = chip->irq_base + i;
204 set_irq_chip(irq, &s5p_gpioint); 222 set_irq_chip(irq, &s5p_gpioint);
205 set_irq_data(irq, &chip->chip); 223 set_irq_data(irq, chip);
206 set_irq_handler(irq, handle_level_irq); 224 set_irq_handler(irq, handle_level_irq);
207 set_irq_flags(irq, IRQF_VALID); 225 set_irq_flags(irq, IRQF_VALID);
208 } 226 }
@@ -235,3 +253,19 @@ int __init s5p_register_gpio_interrupt(int pin)
235 } 253 }
236 return ret; 254 return ret;
237} 255}
256
257int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
258{
259 struct s5p_gpioint_bank *bank;
260
261 bank = kzalloc(sizeof(*bank), GFP_KERNEL);
262 if (!bank)
263 return -ENOMEM;
264
265 bank->start = start;
266 bank->nr_groups = nr_groups;
267 bank->irq = chain_irq;
268
269 list_add_tail(&bank->list, &banks);
270 return 0;
271}
diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c
new file mode 100644
index 000000000000..8090403eec0f
--- /dev/null
+++ b/arch/arm/plat-s5p/s5p-time.c
@@ -0,0 +1,448 @@
1/* linux/arch/arm/plat-s5p/s5p-time.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5P - Common hr-timer support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#include <linux/sched.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16#include <linux/err.h>
17#include <linux/clk.h>
18#include <linux/clockchips.h>
19#include <linux/platform_device.h>
20
21#include <asm/smp_twd.h>
22#include <asm/mach/time.h>
23#include <asm/mach/arch.h>
24#include <asm/mach/map.h>
25#include <asm/sched_clock.h>
26
27#include <mach/map.h>
28#include <plat/devs.h>
29#include <plat/regs-timer.h>
30#include <plat/s5p-time.h>
31
32static struct clk *tin_event;
33static struct clk *tin_source;
34static struct clk *tdiv_event;
35static struct clk *tdiv_source;
36static struct clk *timerclk;
37static struct s5p_timer_source timer_source;
38static unsigned long clock_count_per_tick;
39static void s5p_timer_resume(void);
40
41static void s5p_time_stop(enum s5p_timer_mode mode)
42{
43 unsigned long tcon;
44
45 tcon = __raw_readl(S3C2410_TCON);
46
47 switch (mode) {
48 case S5P_PWM0:
49 tcon &= ~S3C2410_TCON_T0START;
50 break;
51
52 case S5P_PWM1:
53 tcon &= ~S3C2410_TCON_T1START;
54 break;
55
56 case S5P_PWM2:
57 tcon &= ~S3C2410_TCON_T2START;
58 break;
59
60 case S5P_PWM3:
61 tcon &= ~S3C2410_TCON_T3START;
62 break;
63
64 case S5P_PWM4:
65 tcon &= ~S3C2410_TCON_T4START;
66 break;
67
68 default:
69 printk(KERN_ERR "Invalid Timer %d\n", mode);
70 break;
71 }
72 __raw_writel(tcon, S3C2410_TCON);
73}
74
75static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt)
76{
77 unsigned long tcon;
78
79 tcon = __raw_readl(S3C2410_TCON);
80
81 tcnt--;
82
83 switch (mode) {
84 case S5P_PWM0:
85 tcon &= ~(0x0f << 0);
86 tcon |= S3C2410_TCON_T0MANUALUPD;
87 break;
88
89 case S5P_PWM1:
90 tcon &= ~(0x0f << 8);
91 tcon |= S3C2410_TCON_T1MANUALUPD;
92 break;
93
94 case S5P_PWM2:
95 tcon &= ~(0x0f << 12);
96 tcon |= S3C2410_TCON_T2MANUALUPD;
97 break;
98
99 case S5P_PWM3:
100 tcon &= ~(0x0f << 16);
101 tcon |= S3C2410_TCON_T3MANUALUPD;
102 break;
103
104 case S5P_PWM4:
105 tcon &= ~(0x07 << 20);
106 tcon |= S3C2410_TCON_T4MANUALUPD;
107 break;
108
109 default:
110 printk(KERN_ERR "Invalid Timer %d\n", mode);
111 break;
112 }
113
114 __raw_writel(tcnt, S3C2410_TCNTB(mode));
115 __raw_writel(tcnt, S3C2410_TCMPB(mode));
116 __raw_writel(tcon, S3C2410_TCON);
117}
118
119static void s5p_time_start(enum s5p_timer_mode mode, bool periodic)
120{
121 unsigned long tcon;
122
123 tcon = __raw_readl(S3C2410_TCON);
124
125 switch (mode) {
126 case S5P_PWM0:
127 tcon |= S3C2410_TCON_T0START;
128 tcon &= ~S3C2410_TCON_T0MANUALUPD;
129
130 if (periodic)
131 tcon |= S3C2410_TCON_T0RELOAD;
132 else
133 tcon &= ~S3C2410_TCON_T0RELOAD;
134 break;
135
136 case S5P_PWM1:
137 tcon |= S3C2410_TCON_T1START;
138 tcon &= ~S3C2410_TCON_T1MANUALUPD;
139
140 if (periodic)
141 tcon |= S3C2410_TCON_T1RELOAD;
142 else
143 tcon &= ~S3C2410_TCON_T1RELOAD;
144 break;
145
146 case S5P_PWM2:
147 tcon |= S3C2410_TCON_T2START;
148 tcon &= ~S3C2410_TCON_T2MANUALUPD;
149
150 if (periodic)
151 tcon |= S3C2410_TCON_T2RELOAD;
152 else
153 tcon &= ~S3C2410_TCON_T2RELOAD;
154 break;
155
156 case S5P_PWM3:
157 tcon |= S3C2410_TCON_T3START;
158 tcon &= ~S3C2410_TCON_T3MANUALUPD;
159
160 if (periodic)
161 tcon |= S3C2410_TCON_T3RELOAD;
162 else
163 tcon &= ~S3C2410_TCON_T3RELOAD;
164 break;
165
166 case S5P_PWM4:
167 tcon |= S3C2410_TCON_T4START;
168 tcon &= ~S3C2410_TCON_T4MANUALUPD;
169
170 if (periodic)
171 tcon |= S3C2410_TCON_T4RELOAD;
172 else
173 tcon &= ~S3C2410_TCON_T4RELOAD;
174 break;
175
176 default:
177 printk(KERN_ERR "Invalid Timer %d\n", mode);
178 break;
179 }
180 __raw_writel(tcon, S3C2410_TCON);
181}
182
183static int s5p_set_next_event(unsigned long cycles,
184 struct clock_event_device *evt)
185{
186 s5p_time_setup(timer_source.event_id, cycles);
187 s5p_time_start(timer_source.event_id, NON_PERIODIC);
188
189 return 0;
190}
191
192static void s5p_set_mode(enum clock_event_mode mode,
193 struct clock_event_device *evt)
194{
195 s5p_time_stop(timer_source.event_id);
196
197 switch (mode) {
198 case CLOCK_EVT_MODE_PERIODIC:
199 s5p_time_setup(timer_source.event_id, clock_count_per_tick);
200 s5p_time_start(timer_source.event_id, PERIODIC);
201 break;
202
203 case CLOCK_EVT_MODE_ONESHOT:
204 break;
205
206 case CLOCK_EVT_MODE_UNUSED:
207 case CLOCK_EVT_MODE_SHUTDOWN:
208 break;
209
210 case CLOCK_EVT_MODE_RESUME:
211 s5p_timer_resume();
212 break;
213 }
214}
215
216static void s5p_timer_resume(void)
217{
218 /* event timer restart */
219 s5p_time_setup(timer_source.event_id, clock_count_per_tick);
220 s5p_time_start(timer_source.event_id, PERIODIC);
221
222 /* source timer restart */
223 s5p_time_setup(timer_source.source_id, TCNT_MAX);
224 s5p_time_start(timer_source.source_id, PERIODIC);
225}
226
227void __init s5p_set_timer_source(enum s5p_timer_mode event,
228 enum s5p_timer_mode source)
229{
230 s3c_device_timer[event].dev.bus = &platform_bus_type;
231 s3c_device_timer[source].dev.bus = &platform_bus_type;
232
233 timer_source.event_id = event;
234 timer_source.source_id = source;
235}
236
237static struct clock_event_device time_event_device = {
238 .name = "s5p_event_timer",
239 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
240 .rating = 200,
241 .set_next_event = s5p_set_next_event,
242 .set_mode = s5p_set_mode,
243};
244
245static irqreturn_t s5p_clock_event_isr(int irq, void *dev_id)
246{
247 struct clock_event_device *evt = dev_id;
248
249 evt->event_handler(evt);
250
251 return IRQ_HANDLED;
252}
253
254static struct irqaction s5p_clock_event_irq = {
255 .name = "s5p_time_irq",
256 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
257 .handler = s5p_clock_event_isr,
258 .dev_id = &time_event_device,
259};
260
261static void __init s5p_clockevent_init(void)
262{
263 unsigned long pclk;
264 unsigned long clock_rate;
265 unsigned int irq_number;
266 struct clk *tscaler;
267
268 pclk = clk_get_rate(timerclk);
269
270 tscaler = clk_get_parent(tdiv_event);
271
272 clk_set_rate(tscaler, pclk / 2);
273 clk_set_rate(tdiv_event, pclk / 2);
274 clk_set_parent(tin_event, tdiv_event);
275
276 clock_rate = clk_get_rate(tin_event);
277 clock_count_per_tick = clock_rate / HZ;
278
279 clockevents_calc_mult_shift(&time_event_device,
280 clock_rate, S5PTIMER_MIN_RANGE);
281 time_event_device.max_delta_ns =
282 clockevent_delta2ns(-1, &time_event_device);
283 time_event_device.min_delta_ns =
284 clockevent_delta2ns(1, &time_event_device);
285
286 time_event_device.cpumask = cpumask_of(0);
287 clockevents_register_device(&time_event_device);
288
289 irq_number = timer_source.event_id + IRQ_TIMER0;
290 setup_irq(irq_number, &s5p_clock_event_irq);
291}
292
293static cycle_t s5p_timer_read(struct clocksource *cs)
294{
295 unsigned long offset = 0;
296
297 switch (timer_source.source_id) {
298 case S5P_PWM0:
299 case S5P_PWM1:
300 case S5P_PWM2:
301 case S5P_PWM3:
302 offset = (timer_source.source_id * 0x0c) + 0x14;
303 break;
304
305 case S5P_PWM4:
306 offset = 0x40;
307 break;
308
309 default:
310 printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
311 return 0;
312 }
313
314 return (cycle_t) ~__raw_readl(S3C_TIMERREG(offset));
315}
316
317/*
318 * Override the global weak sched_clock symbol with this
319 * local implementation which uses the clocksource to get some
320 * better resolution when scheduling the kernel. We accept that
321 * this wraps around for now, since it is just a relative time
322 * stamp. (Inspired by U300 implementation.)
323 */
324static DEFINE_CLOCK_DATA(cd);
325
326unsigned long long notrace sched_clock(void)
327{
328 u32 cyc;
329 unsigned long offset = 0;
330
331 switch (timer_source.source_id) {
332 case S5P_PWM0:
333 case S5P_PWM1:
334 case S5P_PWM2:
335 case S5P_PWM3:
336 offset = (timer_source.source_id * 0x0c) + 0x14;
337 break;
338
339 case S5P_PWM4:
340 offset = 0x40;
341 break;
342
343 default:
344 printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
345 return 0;
346 }
347
348 cyc = ~__raw_readl(S3C_TIMERREG(offset));
349 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
350}
351
352static void notrace s5p_update_sched_clock(void)
353{
354 u32 cyc;
355 unsigned long offset = 0;
356
357 switch (timer_source.source_id) {
358 case S5P_PWM0:
359 case S5P_PWM1:
360 case S5P_PWM2:
361 case S5P_PWM3:
362 offset = (timer_source.source_id * 0x0c) + 0x14;
363 break;
364
365 case S5P_PWM4:
366 offset = 0x40;
367 break;
368
369 default:
370 printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
371 }
372
373 cyc = ~__raw_readl(S3C_TIMERREG(offset));
374 update_sched_clock(&cd, cyc, (u32)~0);
375}
376
377struct clocksource time_clocksource = {
378 .name = "s5p_clocksource_timer",
379 .rating = 250,
380 .read = s5p_timer_read,
381 .mask = CLOCKSOURCE_MASK(32),
382 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
383};
384
385static void __init s5p_clocksource_init(void)
386{
387 unsigned long pclk;
388 unsigned long clock_rate;
389
390 pclk = clk_get_rate(timerclk);
391
392 clk_set_rate(tdiv_source, pclk / 2);
393 clk_set_parent(tin_source, tdiv_source);
394
395 clock_rate = clk_get_rate(tin_source);
396
397 init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate);
398
399 s5p_time_setup(timer_source.source_id, TCNT_MAX);
400 s5p_time_start(timer_source.source_id, PERIODIC);
401
402 if (clocksource_register_hz(&time_clocksource, clock_rate))
403 panic("%s: can't register clocksource\n", time_clocksource.name);
404}
405
406static void __init s5p_timer_resources(void)
407{
408
409 unsigned long event_id = timer_source.event_id;
410 unsigned long source_id = timer_source.source_id;
411
412 timerclk = clk_get(NULL, "timers");
413 if (IS_ERR(timerclk))
414 panic("failed to get timers clock for timer");
415
416 clk_enable(timerclk);
417
418 tin_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tin");
419 if (IS_ERR(tin_event))
420 panic("failed to get pwm-tin clock for event timer");
421
422 tdiv_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tdiv");
423 if (IS_ERR(tdiv_event))
424 panic("failed to get pwm-tdiv clock for event timer");
425
426 clk_enable(tin_event);
427
428 tin_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tin");
429 if (IS_ERR(tin_source))
430 panic("failed to get pwm-tin clock for source timer");
431
432 tdiv_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tdiv");
433 if (IS_ERR(tdiv_source))
434 panic("failed to get pwm-tdiv clock for source timer");
435
436 clk_enable(tin_source);
437}
438
439static void __init s5p_timer_init(void)
440{
441 s5p_timer_resources();
442 s5p_clockevent_init();
443 s5p_clocksource_init();
444}
445
446struct sys_timer s5p_timer = {
447 .init = s5p_timer_init,
448};
diff --git a/arch/arm/plat-s5p/setup-mipiphy.c b/arch/arm/plat-s5p/setup-mipiphy.c
new file mode 100644
index 000000000000..683c466c0e6a
--- /dev/null
+++ b/arch/arm/plat-s5p/setup-mipiphy.c
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
3 *
4 * S5P - Helper functions for MIPI-CSIS and MIPI-DSIM D-PHY control
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/platform_device.h>
13#include <linux/io.h>
14#include <linux/spinlock.h>
15#include <mach/regs-clock.h>
16
17static int __s5p_mipi_phy_control(struct platform_device *pdev,
18 bool on, u32 reset)
19{
20 static DEFINE_SPINLOCK(lock);
21 void __iomem *addr;
22 unsigned long flags;
23 int pid;
24 u32 cfg;
25
26 if (!pdev)
27 return -EINVAL;
28
29 pid = (pdev->id == -1) ? 0 : pdev->id;
30
31 if (pid != 0 && pid != 1)
32 return -EINVAL;
33
34 addr = S5P_MIPI_DPHY_CONTROL(pid);
35
36 spin_lock_irqsave(&lock, flags);
37
38 cfg = __raw_readl(addr);
39 cfg = on ? (cfg | reset) : (cfg & ~reset);
40 __raw_writel(cfg, addr);
41
42 if (on) {
43 cfg |= S5P_MIPI_DPHY_ENABLE;
44 } else if (!(cfg & (S5P_MIPI_DPHY_SRESETN |
45 S5P_MIPI_DPHY_MRESETN) & ~reset)) {
46 cfg &= ~S5P_MIPI_DPHY_ENABLE;
47 }
48
49 __raw_writel(cfg, addr);
50 spin_unlock_irqrestore(&lock, flags);
51
52 return 0;
53}
54
55int s5p_csis_phy_enable(struct platform_device *pdev, bool on)
56{
57 return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_SRESETN);
58}
59
60int s5p_dsim_phy_enable(struct platform_device *pdev, bool on)
61{
62 return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_MRESETN);
63}
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
index ffe8a48bc3c1..54f5eddc921d 100644
--- a/arch/arm/plat-s5p/sysmmu.c
+++ b/arch/arm/plat-s5p/sysmmu.c
@@ -12,280 +12,266 @@
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14 14
15#include <asm/pgtable.h>
16
15#include <mach/map.h> 17#include <mach/map.h>
16#include <mach/regs-sysmmu.h> 18#include <mach/regs-sysmmu.h>
17#include <mach/sysmmu.h> 19#include <plat/sysmmu.h>
20
21#define CTRL_ENABLE 0x5
22#define CTRL_BLOCK 0x7
23#define CTRL_DISABLE 0x0
24
25static struct device *dev;
26
27static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
28 S5P_PAGE_FAULT_ADDR,
29 S5P_AR_FAULT_ADDR,
30 S5P_AW_FAULT_ADDR,
31 S5P_DEFAULT_SLAVE_ADDR,
32 S5P_AR_FAULT_ADDR,
33 S5P_AR_FAULT_ADDR,
34 S5P_AW_FAULT_ADDR,
35 S5P_AW_FAULT_ADDR
36};
37
38static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
39 "PAGE FAULT",
40 "AR MULTI-HIT FAULT",
41 "AW MULTI-HIT FAULT",
42 "BUS ERROR",
43 "AR SECURITY PROTECTION FAULT",
44 "AR ACCESS PROTECTION FAULT",
45 "AW SECURITY PROTECTION FAULT",
46 "AW ACCESS PROTECTION FAULT"
47};
18 48
19struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM]; 49static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])(
50 enum S5P_SYSMMU_INTERRUPT_TYPE itype,
51 unsigned long pgtable_base,
52 unsigned long fault_addr);
20 53
21void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp) 54/*
55 * If adjacent 2 bits are true, the system MMU is enabled.
56 * The system MMU is disabled, otherwise.
57 */
58static unsigned long sysmmu_states;
59
60static inline void set_sysmmu_active(sysmmu_ips ips)
22{ 61{
23 unsigned int reg_mmu_ctrl; 62 sysmmu_states |= 3 << (ips * 2);
24 unsigned int reg_mmu_status;
25 unsigned int reg_pt_base_addr;
26 unsigned int reg_int_status;
27 unsigned int reg_page_ft_addr;
28
29 reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
30 reg_mmu_ctrl = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
31 reg_mmu_status = __raw_readl(sysmmuconp->regs + S5P_MMU_STATUS);
32 reg_pt_base_addr = __raw_readl(sysmmuconp->regs + S5P_PT_BASE_ADDR);
33 reg_page_ft_addr = __raw_readl(sysmmuconp->regs + S5P_PAGE_FAULT_ADDR);
34
35 printk(KERN_INFO "%s: ips:%s\n", __func__, sysmmuconp->name);
36 printk(KERN_INFO "%s: MMU_CTRL:0x%X, ", __func__, reg_mmu_ctrl);
37 printk(KERN_INFO "MMU_STATUS:0x%X, PT_BASE_ADDR:0x%X\n", reg_mmu_status, reg_pt_base_addr);
38 printk(KERN_INFO "%s: INT_STATUS:0x%X, PAGE_FAULT_ADDR:0x%X\n", __func__, reg_int_status, reg_page_ft_addr);
39
40 switch (reg_int_status & 0xFF) {
41 case 0x1:
42 printk(KERN_INFO "%s: Page fault\n", __func__);
43 printk(KERN_INFO "%s: Virtual address causing last page fault or bus error : 0x%x\n", __func__ , reg_page_ft_addr);
44 break;
45 case 0x2:
46 printk(KERN_INFO "%s: AR multi-hit fault\n", __func__);
47 break;
48 case 0x4:
49 printk(KERN_INFO "%s: AW multi-hit fault\n", __func__);
50 break;
51 case 0x8:
52 printk(KERN_INFO "%s: Bus error\n", __func__);
53 break;
54 case 0x10:
55 printk(KERN_INFO "%s: AR Security protection fault\n", __func__);
56 break;
57 case 0x20:
58 printk(KERN_INFO "%s: AR Access protection fault\n", __func__);
59 break;
60 case 0x40:
61 printk(KERN_INFO "%s: AW Security protection fault\n", __func__);
62 break;
63 case 0x80:
64 printk(KERN_INFO "%s: AW Access protection fault\n", __func__);
65 break;
66 }
67} 63}
68 64
69static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id) 65static inline void set_sysmmu_inactive(sysmmu_ips ips)
70{ 66{
71 unsigned int i; 67 sysmmu_states &= ~(3 << (ips * 2));
72 unsigned int reg_int_status;
73 struct sysmmu_controller *sysmmuconp;
74
75 for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
76 sysmmuconp = &s5p_sysmmu_cntlrs[i];
77
78 if (sysmmuconp->enable == true) {
79 reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
80
81 if (reg_int_status & 0xFF)
82 s5p_sysmmu_register(sysmmuconp);
83 }
84 }
85 return IRQ_HANDLED;
86} 68}
87 69
88int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd) 70static inline int is_sysmmu_active(sysmmu_ips ips)
89{ 71{
90 struct sysmmu_controller *sysmmuconp = NULL; 72 return sysmmu_states & (3 << (ips * 2));
91 73}
92 sysmmuconp = &s5p_sysmmu_cntlrs[ips];
93
94 if (sysmmuconp == NULL) {
95 printk(KERN_ERR "failed to get ip's sysmmu info\n");
96 return 1;
97 }
98
99 /* Set sysmmu page table base address */
100 __raw_writel(pgd, sysmmuconp->regs + S5P_PT_BASE_ADDR);
101 74
102 if (s5p_sysmmu_tlb_invalidate(ips) != 0) 75static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM];
103 printk(KERN_ERR "failed s5p_sysmmu_tlb_invalidate\n");
104 76
105 return 0; 77static inline void sysmmu_block(sysmmu_ips ips)
78{
79 __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL);
80 dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]);
106} 81}
107 82
108static int s5p_sysmmu_set_tablebase(sysmmu_ips ips) 83static inline void sysmmu_unblock(sysmmu_ips ips)
109{ 84{
110 unsigned int pg; 85 __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
111 struct sysmmu_controller *sysmmuconp; 86 dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]);
87}
112 88
113 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 89static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips)
90{
91 __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH);
92 dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]);
93}
114 94
115 if (sysmmuconp == NULL) { 95static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd)
116 printk(KERN_ERR "failed to get ip's sysmmu info\n"); 96{
117 return 1; 97 if (unlikely(pgd == 0)) {
98 pgd = (unsigned long)ZERO_PAGE(0);
99 __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB LV1 */
100 } else {
101 __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB LV1 */
118 } 102 }
119 103
120 __asm__("mrc p15, 0, %0, c2, c0, 0" \ 104 __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
121 : "=r" (pg) : : "cc"); \
122 pg &= ~0x3fff;
123 105
124 printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg); 106 dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n",
125 107 sysmmu_ips_name[ips], pgd);
126 /* Set sysmmu page table base address */ 108 __sysmmu_tlb_invalidate(ips);
127 __raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR); 109}
128 110
129 return 0; 111void sysmmu_set_fault_handler(sysmmu_ips ips,
112 int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
113 unsigned long pgtable_base,
114 unsigned long fault_addr))
115{
116 BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM)));
117 fault_handlers[ips] = handler;
130} 118}
131 119
132int s5p_sysmmu_enable(sysmmu_ips ips) 120static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
133{ 121{
134 unsigned int reg; 122 /* SYSMMU is in blocked when interrupt occurred. */
123 unsigned long base = 0;
124 sysmmu_ips ips = (sysmmu_ips)dev_id;
125 enum S5P_SYSMMU_INTERRUPT_TYPE itype;
135 126
136 struct sysmmu_controller *sysmmuconp; 127 itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
128 __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS));
137 129
138 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 130 BUG_ON(!((itype >= 0) && (itype < 8)));
139 131
140 if (sysmmuconp == NULL) { 132 dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype],
141 printk(KERN_ERR "failed to get ip's sysmmu info\n"); 133 sysmmu_ips_name[ips]);
142 return 1;
143 }
144 134
145 s5p_sysmmu_set_tablebase(ips); 135 if (fault_handlers[ips]) {
136 unsigned long addr;
146 137
147 /* replacement policy : LRU */ 138 base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
148 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG); 139 addr = __raw_readl(sysmmusfrs[ips] + fault_reg_offset[itype]);
149 reg |= 0x1;
150 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
151 140
152 /* Enable interrupt, Enable MMU */ 141 if (fault_handlers[ips](itype, base, addr)) {
153 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL); 142 __raw_writel(1 << itype,
154 reg |= (0x1 << 2) | (0x1 << 0); 143 sysmmusfrs[ips] + S5P_INT_CLEAR);
144 dev_notice(dev, "%s from %s is resolved."
145 " Retrying translation.\n",
146 sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
147 } else {
148 base = 0;
149 }
150 }
155 151
156 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL); 152 sysmmu_unblock(ips);
157 153
158 sysmmuconp->enable = true; 154 if (!base)
155 dev_notice(dev, "%s from %s is not handled.\n",
156 sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
159 157
160 return 0; 158 return IRQ_HANDLED;
161} 159}
162 160
163int s5p_sysmmu_disable(sysmmu_ips ips) 161void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
164{ 162{
165 unsigned int reg; 163 if (is_sysmmu_active(ips)) {
166 164 sysmmu_block(ips);
167 struct sysmmu_controller *sysmmuconp = NULL; 165 __sysmmu_set_ptbase(ips, pgd);
168 166 sysmmu_unblock(ips);
169 if (ips > S5P_SYSMMU_TOTAL_IPNUM) 167 } else {
170 printk(KERN_ERR "failed to get ips parameter\n"); 168 dev_dbg(dev, "%s is disabled. "
171 169 "Skipping initializing page table base.\n",
172 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 170 sysmmu_ips_name[ips]);
173
174 if (sysmmuconp == NULL) {
175 printk(KERN_ERR "failed to get ip's sysmmu info\n");
176 return 1;
177 } 171 }
172}
178 173
179 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG); 174void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd)
180 175{
181 /* replacement policy : LRU */ 176 if (!is_sysmmu_active(ips)) {
182 reg |= 0x1; 177 sysmmu_clk_enable(ips);
183 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
184
185 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
186 178
187 /* Disable MMU */ 179 __sysmmu_set_ptbase(ips, pgd);
188 reg &= ~0x1;
189 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
190 180
191 sysmmuconp->enable = false; 181 __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
192 182
193 return 0; 183 set_sysmmu_active(ips);
184 dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]);
185 } else {
186 dev_dbg(dev, "%s is already enabled.\n", sysmmu_ips_name[ips]);
187 }
194} 188}
195 189
196int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips) 190void s5p_sysmmu_disable(sysmmu_ips ips)
197{ 191{
198 unsigned int reg; 192 if (is_sysmmu_active(ips)) {
199 struct sysmmu_controller *sysmmuconp = NULL; 193 __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
200 194 set_sysmmu_inactive(ips);
201 sysmmuconp = &s5p_sysmmu_cntlrs[ips]; 195 sysmmu_clk_disable(ips);
202 196 dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]);
203 if (sysmmuconp == NULL) { 197 } else {
204 printk(KERN_ERR "failed to get ip's sysmmu info\n"); 198 dev_dbg(dev, "%s is already disabled.\n", sysmmu_ips_name[ips]);
205 return 1;
206 } 199 }
200}
207 201
208 /* set Block MMU for flush TLB */ 202void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
209 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL); 203{
210 reg |= 0x1 << 1; 204 if (is_sysmmu_active(ips)) {
211 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL); 205 sysmmu_block(ips);
212 206 __sysmmu_tlb_invalidate(ips);
213 /* flush all TLB entry */ 207 sysmmu_unblock(ips);
214 __raw_writel(0x1, sysmmuconp->regs + S5P_MMU_FLUSH); 208 } else {
215 209 dev_dbg(dev, "%s is disabled. "
216 /* set Un-block MMU after flush TLB */ 210 "Skipping invalidating TLB.\n", sysmmu_ips_name[ips]);
217 reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL); 211 }
218 reg &= ~(0x1 << 1);
219 __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
220
221 return 0;
222} 212}
223 213
224static int s5p_sysmmu_probe(struct platform_device *pdev) 214static int s5p_sysmmu_probe(struct platform_device *pdev)
225{ 215{
226 int i; 216 int i, ret;
227 int ret; 217 struct resource *res, *mem;
228 struct resource *res; 218
229 struct sysmmu_controller *sysmmuconp; 219 dev = &pdev->dev;
230 sysmmu_ips ips;
231 220
232 for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) { 221 for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
233 sysmmuconp = &s5p_sysmmu_cntlrs[i]; 222 int irq;
234 if (sysmmuconp == NULL) {
235 printk(KERN_ERR "failed to get ip's sysmmu info\n");
236 ret = -ENOENT;
237 goto err_res;
238 }
239 223
240 sysmmuconp->name = sysmmu_ips_name[i]; 224 sysmmu_clk_init(dev, i);
225 sysmmu_clk_disable(i);
241 226
242 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 227 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
243 if (!res) { 228 if (!res) {
244 printk(KERN_ERR "failed to get sysmmu resource\n"); 229 dev_err(dev, "Failed to get the resource of %s.\n",
230 sysmmu_ips_name[i]);
245 ret = -ENODEV; 231 ret = -ENODEV;
246 goto err_res; 232 goto err_res;
247 } 233 }
248 234
249 sysmmuconp->mem = request_mem_region(res->start, 235 mem = request_mem_region(res->start,
250 ((res->end) - (res->start)) + 1, pdev->name); 236 ((res->end) - (res->start)) + 1, pdev->name);
251 if (!sysmmuconp->mem) { 237 if (!mem) {
252 pr_err("failed to request sysmmu memory region\n"); 238 dev_err(dev, "Failed to request the memory region of %s.\n",
239 sysmmu_ips_name[i]);
253 ret = -EBUSY; 240 ret = -EBUSY;
254 goto err_res; 241 goto err_res;
255 } 242 }
256 243
257 sysmmuconp->regs = ioremap(res->start, res->end - res->start + 1); 244 sysmmusfrs[i] = ioremap(res->start, res->end - res->start + 1);
258 if (!sysmmuconp->regs) { 245 if (!sysmmusfrs[i]) {
259 pr_err("failed to sysmmu ioremap\n"); 246 dev_err(dev, "Failed to ioremap() for %s.\n",
247 sysmmu_ips_name[i]);
260 ret = -ENXIO; 248 ret = -ENXIO;
261 goto err_reg; 249 goto err_reg;
262 } 250 }
263 251
264 sysmmuconp->irq = platform_get_irq(pdev, i); 252 irq = platform_get_irq(pdev, i);
265 if (sysmmuconp->irq <= 0) { 253 if (irq <= 0) {
266 pr_err("failed to get sysmmu irq resource\n"); 254 dev_err(dev, "Failed to get the IRQ resource of %s.\n",
255 sysmmu_ips_name[i]);
267 ret = -ENOENT; 256 ret = -ENOENT;
268 goto err_map; 257 goto err_map;
269 } 258 }
270 259
271 ret = request_irq(sysmmuconp->irq, s5p_sysmmu_irq, IRQF_DISABLED, pdev->name, sysmmuconp); 260 if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED,
272 if (ret) { 261 pdev->name, (void *)i)) {
273 pr_err("failed to request irq\n"); 262 dev_err(dev, "Failed to request IRQ for %s.\n",
263 sysmmu_ips_name[i]);
274 ret = -ENOENT; 264 ret = -ENOENT;
275 goto err_map; 265 goto err_map;
276 } 266 }
277
278 ips = (sysmmu_ips)i;
279
280 sysmmuconp->ips = ips;
281 } 267 }
282 268
283 return 0; 269 return 0;
284 270
285err_reg:
286 release_mem_region((resource_size_t)sysmmuconp->mem, (resource_size_t)((res->end) - (res->start) + 1));
287err_map: 271err_map:
288 iounmap(sysmmuconp->regs); 272 iounmap(sysmmusfrs[i]);
273err_reg:
274 release_mem_region(mem->start, resource_size(mem));
289err_res: 275err_res:
290 return ret; 276 return ret;
291} 277}