diff options
357 files changed, 14962 insertions, 3907 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 53d7f619a1b9..8bf0fa652eb6 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
| @@ -42,6 +42,20 @@ config KPROBES | |||
| 42 | for kernel debugging, non-intrusive instrumentation and testing. | 42 | for kernel debugging, non-intrusive instrumentation and testing. |
| 43 | If in doubt, say "N". | 43 | If in doubt, say "N". |
| 44 | 44 | ||
| 45 | config JUMP_LABEL | ||
| 46 | bool "Optimize trace point call sites" | ||
| 47 | depends on HAVE_ARCH_JUMP_LABEL | ||
| 48 | help | ||
| 49 | If it is detected that the compiler has support for "asm goto", | ||
| 50 | the kernel will compile trace point locations with just a | ||
| 51 | nop instruction. When trace points are enabled, the nop will | ||
| 52 | be converted to a jump to the trace function. This technique | ||
| 53 | lowers overhead and stress on the branch prediction of the | ||
| 54 | processor. | ||
| 55 | |||
| 56 | On i386, options added to the compiler flags may increase | ||
| 57 | the size of the kernel slightly. | ||
| 58 | |||
| 45 | config OPTPROBES | 59 | config OPTPROBES |
| 46 | def_bool y | 60 | def_bool y |
| 47 | depends on KPROBES && HAVE_OPTPROBES | 61 | depends on KPROBES && HAVE_OPTPROBES |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b527bf5701c9..a19a5266d5fc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -720,9 +720,11 @@ config ARCH_S5PC100 | |||
| 720 | config ARCH_S5PV210 | 720 | config ARCH_S5PV210 |
| 721 | bool "Samsung S5PV210/S5PC110" | 721 | bool "Samsung S5PV210/S5PC110" |
| 722 | select CPU_V7 | 722 | select CPU_V7 |
| 723 | select ARCH_SPARSEMEM_ENABLE | ||
| 723 | select GENERIC_GPIO | 724 | select GENERIC_GPIO |
| 724 | select HAVE_CLK | 725 | select HAVE_CLK |
| 725 | select ARM_L1_CACHE_SHIFT_6 | 726 | select ARM_L1_CACHE_SHIFT_6 |
| 727 | select ARCH_HAS_CPUFREQ | ||
| 726 | select ARCH_USES_GETTIMEOFFSET | 728 | select ARCH_USES_GETTIMEOFFSET |
| 727 | select HAVE_S3C2410_I2C | 729 | select HAVE_S3C2410_I2C |
| 728 | select HAVE_S3C_RTC | 730 | select HAVE_S3C_RTC |
| @@ -733,9 +735,13 @@ config ARCH_S5PV210 | |||
| 733 | config ARCH_S5PV310 | 735 | config ARCH_S5PV310 |
| 734 | bool "Samsung S5PV310/S5PC210" | 736 | bool "Samsung S5PV310/S5PC210" |
| 735 | select CPU_V7 | 737 | select CPU_V7 |
| 738 | select ARCH_SPARSEMEM_ENABLE | ||
| 736 | select GENERIC_GPIO | 739 | select GENERIC_GPIO |
| 737 | select HAVE_CLK | 740 | select HAVE_CLK |
| 738 | select GENERIC_CLOCKEVENTS | 741 | select GENERIC_CLOCKEVENTS |
| 742 | select HAVE_S3C_RTC | ||
| 743 | select HAVE_S3C2410_I2C | ||
| 744 | select HAVE_S3C2410_WATCHDOG | ||
| 739 | help | 745 | help |
| 740 | Samsung S5PV310 series based systems | 746 | Samsung S5PV310 series based systems |
| 741 | 747 | ||
| @@ -1662,6 +1668,12 @@ if ARCH_HAS_CPUFREQ | |||
| 1662 | 1668 | ||
| 1663 | source "drivers/cpufreq/Kconfig" | 1669 | source "drivers/cpufreq/Kconfig" |
| 1664 | 1670 | ||
| 1671 | config CPU_FREQ_IMX | ||
| 1672 | tristate "CPUfreq driver for i.MX CPUs" | ||
| 1673 | depends on ARCH_MXC && CPU_FREQ | ||
| 1674 | help | ||
| 1675 | This enables the CPUfreq driver for i.MX CPUs. | ||
| 1676 | |||
| 1665 | config CPU_FREQ_SA1100 | 1677 | config CPU_FREQ_SA1100 |
| 1666 | bool | 1678 | bool |
| 1667 | 1679 | ||
diff --git a/arch/arm/configs/mx51_defconfig b/arch/arm/configs/mx51_defconfig index 163cfee7644c..5c7a87260fab 100644 --- a/arch/arm/configs/mx51_defconfig +++ b/arch/arm/configs/mx51_defconfig | |||
| @@ -82,6 +82,7 @@ CONFIG_FEC=y | |||
| 82 | CONFIG_INPUT_FF_MEMLESS=m | 82 | CONFIG_INPUT_FF_MEMLESS=m |
| 83 | # CONFIG_INPUT_MOUSEDEV_PSAUX is not set | 83 | # CONFIG_INPUT_MOUSEDEV_PSAUX is not set |
| 84 | CONFIG_INPUT_EVDEV=y | 84 | CONFIG_INPUT_EVDEV=y |
| 85 | CONFIG_KEYBOARD_GPIO=y | ||
| 85 | CONFIG_INPUT_EVBUG=m | 86 | CONFIG_INPUT_EVBUG=m |
| 86 | CONFIG_MOUSE_PS2=m | 87 | CONFIG_MOUSE_PS2=m |
| 87 | CONFIG_MOUSE_PS2_ELANTECH=y | 88 | CONFIG_MOUSE_PS2_ELANTECH=y |
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h index 6bcba48800fe..cc42d5fdee17 100644 --- a/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/arch/arm/include/asm/hardware/cache-l2x0.h | |||
| @@ -21,9 +21,6 @@ | |||
| 21 | #define __ASM_ARM_HARDWARE_L2X0_H | 21 | #define __ASM_ARM_HARDWARE_L2X0_H |
| 22 | 22 | ||
| 23 | #define L2X0_CACHE_ID 0x000 | 23 | #define L2X0_CACHE_ID 0x000 |
| 24 | #define L2X0_CACHE_ID_PART_MASK (0xf << 6) | ||
| 25 | #define L2X0_CACHE_ID_PART_L210 (1 << 6) | ||
| 26 | #define L2X0_CACHE_ID_PART_L310 (3 << 6) | ||
| 27 | #define L2X0_CACHE_TYPE 0x004 | 24 | #define L2X0_CACHE_TYPE 0x004 |
| 28 | #define L2X0_CTRL 0x100 | 25 | #define L2X0_CTRL 0x100 |
| 29 | #define L2X0_AUX_CTRL 0x104 | 26 | #define L2X0_AUX_CTRL 0x104 |
| @@ -53,6 +50,16 @@ | |||
| 53 | #define L2X0_LINE_DATA 0xF10 | 50 | #define L2X0_LINE_DATA 0xF10 |
| 54 | #define L2X0_LINE_TAG 0xF30 | 51 | #define L2X0_LINE_TAG 0xF30 |
| 55 | #define L2X0_DEBUG_CTRL 0xF40 | 52 | #define L2X0_DEBUG_CTRL 0xF40 |
| 53 | #define L2X0_PREFETCH_CTRL 0xF60 | ||
| 54 | #define L2X0_POWER_CTRL 0xF80 | ||
| 55 | #define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1) | ||
| 56 | #define L2X0_STNDBY_MODE_EN (1 << 0) | ||
| 57 | |||
| 58 | /* Registers shifts and masks */ | ||
| 59 | #define L2X0_CACHE_ID_PART_MASK (0xf << 6) | ||
| 60 | #define L2X0_CACHE_ID_PART_L210 (1 << 6) | ||
| 61 | #define L2X0_CACHE_ID_PART_L310 (3 << 6) | ||
| 62 | #define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17) | ||
| 56 | 63 | ||
| 57 | #ifndef __ASSEMBLY__ | 64 | #ifndef __ASSEMBLY__ |
| 58 | extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); | 65 | extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); |
diff --git a/arch/arm/include/asm/memblock.h b/arch/arm/include/asm/memblock.h index fdbc43b2e6c0..b8da2e415e4e 100644 --- a/arch/arm/include/asm/memblock.h +++ b/arch/arm/include/asm/memblock.h | |||
| @@ -1,13 +1,6 @@ | |||
| 1 | #ifndef _ASM_ARM_MEMBLOCK_H | 1 | #ifndef _ASM_ARM_MEMBLOCK_H |
| 2 | #define _ASM_ARM_MEMBLOCK_H | 2 | #define _ASM_ARM_MEMBLOCK_H |
| 3 | 3 | ||
| 4 | #ifdef CONFIG_MMU | ||
| 5 | extern phys_addr_t lowmem_end_addr; | ||
| 6 | #define MEMBLOCK_REAL_LIMIT lowmem_end_addr | ||
| 7 | #else | ||
| 8 | #define MEMBLOCK_REAL_LIMIT 0 | ||
| 9 | #endif | ||
| 10 | |||
| 11 | struct meminfo; | 4 | struct meminfo; |
| 12 | struct machine_desc; | 5 | struct machine_desc; |
| 13 | 6 | ||
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 25f76bae57ab..fc1900925275 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h | |||
| @@ -25,6 +25,9 @@ struct outer_cache_fns { | |||
| 25 | void (*inv_range)(unsigned long, unsigned long); | 25 | void (*inv_range)(unsigned long, unsigned long); |
| 26 | void (*clean_range)(unsigned long, unsigned long); | 26 | void (*clean_range)(unsigned long, unsigned long); |
| 27 | void (*flush_range)(unsigned long, unsigned long); | 27 | void (*flush_range)(unsigned long, unsigned long); |
| 28 | void (*flush_all)(void); | ||
| 29 | void (*inv_all)(void); | ||
| 30 | void (*disable)(void); | ||
| 28 | #ifdef CONFIG_OUTER_CACHE_SYNC | 31 | #ifdef CONFIG_OUTER_CACHE_SYNC |
| 29 | void (*sync)(void); | 32 | void (*sync)(void); |
| 30 | #endif | 33 | #endif |
| @@ -50,6 +53,24 @@ static inline void outer_flush_range(unsigned long start, unsigned long end) | |||
| 50 | outer_cache.flush_range(start, end); | 53 | outer_cache.flush_range(start, end); |
| 51 | } | 54 | } |
| 52 | 55 | ||
| 56 | static inline void outer_flush_all(void) | ||
| 57 | { | ||
| 58 | if (outer_cache.flush_all) | ||
| 59 | outer_cache.flush_all(); | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline void outer_inv_all(void) | ||
| 63 | { | ||
| 64 | if (outer_cache.inv_all) | ||
| 65 | outer_cache.inv_all(); | ||
| 66 | } | ||
| 67 | |||
| 68 | static inline void outer_disable(void) | ||
| 69 | { | ||
| 70 | if (outer_cache.disable) | ||
| 71 | outer_cache.disable(); | ||
| 72 | } | ||
| 73 | |||
| 53 | #else | 74 | #else |
| 54 | 75 | ||
| 55 | static inline void outer_inv_range(unsigned long start, unsigned long end) | 76 | static inline void outer_inv_range(unsigned long start, unsigned long end) |
| @@ -58,6 +79,9 @@ static inline void outer_clean_range(unsigned long start, unsigned long end) | |||
| 58 | { } | 79 | { } |
| 59 | static inline void outer_flush_range(unsigned long start, unsigned long end) | 80 | static inline void outer_flush_range(unsigned long start, unsigned long end) |
| 60 | { } | 81 | { } |
| 82 | static inline void outer_flush_all(void) { } | ||
| 83 | static inline void outer_inv_all(void) { } | ||
| 84 | static inline void outer_disable(void) { } | ||
| 61 | 85 | ||
| 62 | #endif | 86 | #endif |
| 63 | 87 | ||
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 1fc74cbd1a19..3a8fd5140d7a 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c | |||
| @@ -78,7 +78,10 @@ void machine_kexec(struct kimage *image) | |||
| 78 | local_fiq_disable(); | 78 | local_fiq_disable(); |
| 79 | setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ | 79 | setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ |
| 80 | flush_cache_all(); | 80 | flush_cache_all(); |
| 81 | outer_flush_all(); | ||
| 82 | outer_disable(); | ||
| 81 | cpu_proc_fin(); | 83 | cpu_proc_fin(); |
| 84 | outer_inv_all(); | ||
| 82 | flush_cache_all(); | 85 | flush_cache_all(); |
| 83 | cpu_reset(reboot_code_buffer_phys); | 86 | cpu_reset(reboot_code_buffer_phys); |
| 84 | } | 87 | } |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 1953e3d21abf..cead8893b46b 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
| @@ -113,6 +113,7 @@ SECTIONS | |||
| 113 | *(.rodata.*) | 113 | *(.rodata.*) |
| 114 | *(.glue_7) | 114 | *(.glue_7) |
| 115 | *(.glue_7t) | 115 | *(.glue_7t) |
| 116 | . = ALIGN(4); | ||
| 116 | *(.got) /* Global offset table */ | 117 | *(.got) /* Global offset table */ |
| 117 | ARM_CPU_KEEP(PROC_INFO) | 118 | ARM_CPU_KEEP(PROC_INFO) |
| 118 | } | 119 | } |
diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c index b8bbd31aa850..84a5ba03f1ba 100644 --- a/arch/arm/mach-imx/mach-mx27_3ds.c +++ b/arch/arm/mach-imx/mach-mx27_3ds.c | |||
| @@ -23,16 +23,20 @@ | |||
| 23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
| 24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
| 25 | #include <linux/input/matrix_keypad.h> | 25 | #include <linux/input/matrix_keypad.h> |
| 26 | #include <linux/irq.h> | ||
| 26 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
| 27 | #include <asm/mach/arch.h> | 28 | #include <asm/mach/arch.h> |
| 28 | #include <asm/mach/time.h> | 29 | #include <asm/mach/time.h> |
| 29 | #include <mach/hardware.h> | 30 | #include <mach/hardware.h> |
| 30 | #include <mach/common.h> | 31 | #include <mach/common.h> |
| 31 | #include <mach/iomux-mx27.h> | 32 | #include <mach/iomux-mx27.h> |
| 33 | #include <mach/mmc.h> | ||
| 32 | 34 | ||
| 33 | #include "devices-imx27.h" | 35 | #include "devices-imx27.h" |
| 34 | #include "devices.h" | 36 | #include "devices.h" |
| 35 | 37 | ||
| 38 | #define SD1_EN_GPIO (GPIO_PORTB + 25) | ||
| 39 | |||
| 36 | static const int mx27pdk_pins[] __initconst = { | 40 | static const int mx27pdk_pins[] __initconst = { |
| 37 | /* UART1 */ | 41 | /* UART1 */ |
| 38 | PE12_PF_UART1_TXD, | 42 | PE12_PF_UART1_TXD, |
| @@ -58,6 +62,14 @@ static const int mx27pdk_pins[] __initconst = { | |||
| 58 | PD15_AOUT_FEC_COL, | 62 | PD15_AOUT_FEC_COL, |
| 59 | PD16_AIN_FEC_TX_ER, | 63 | PD16_AIN_FEC_TX_ER, |
| 60 | PF23_AIN_FEC_TX_EN, | 64 | PF23_AIN_FEC_TX_EN, |
| 65 | /* SDHC1 */ | ||
| 66 | PE18_PF_SD1_D0, | ||
| 67 | PE19_PF_SD1_D1, | ||
| 68 | PE20_PF_SD1_D2, | ||
| 69 | PE21_PF_SD1_D3, | ||
| 70 | PE22_PF_SD1_CMD, | ||
| 71 | PE23_PF_SD1_CLK, | ||
| 72 | SD1_EN_GPIO | GPIO_GPIO | GPIO_OUT, | ||
| 61 | }; | 73 | }; |
| 62 | 74 | ||
| 63 | static const struct imxuart_platform_data uart_pdata __initconst = { | 75 | static const struct imxuart_platform_data uart_pdata __initconst = { |
| @@ -85,13 +97,39 @@ static struct matrix_keymap_data mx27_3ds_keymap_data = { | |||
| 85 | .keymap_size = ARRAY_SIZE(mx27_3ds_keymap), | 97 | .keymap_size = ARRAY_SIZE(mx27_3ds_keymap), |
| 86 | }; | 98 | }; |
| 87 | 99 | ||
| 100 | static int mx27_3ds_sdhc1_init(struct device *dev, irq_handler_t detect_irq, | ||
| 101 | void *data) | ||
| 102 | { | ||
| 103 | return request_irq(IRQ_GPIOB(26), detect_irq, IRQF_TRIGGER_FALLING | | ||
| 104 | IRQF_TRIGGER_RISING, "sdhc1-card-detect", data); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void mx27_3ds_sdhc1_exit(struct device *dev, void *data) | ||
| 108 | { | ||
| 109 | free_irq(IRQ_GPIOB(26), data); | ||
| 110 | } | ||
| 111 | |||
| 112 | static struct imxmmc_platform_data sdhc1_pdata = { | ||
| 113 | .init = mx27_3ds_sdhc1_init, | ||
| 114 | .exit = mx27_3ds_sdhc1_exit, | ||
| 115 | }; | ||
| 116 | |||
| 117 | static void mx27_3ds_sdhc1_enable_level_translator(void) | ||
| 118 | { | ||
| 119 | /* Turn on TXB0108 OE pin */ | ||
| 120 | gpio_request(SD1_EN_GPIO, "sd1_enable"); | ||
| 121 | gpio_direction_output(SD1_EN_GPIO, 1); | ||
| 122 | } | ||
| 123 | |||
| 88 | static void __init mx27pdk_init(void) | 124 | static void __init mx27pdk_init(void) |
| 89 | { | 125 | { |
| 90 | mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins), | 126 | mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins), |
| 91 | "mx27pdk"); | 127 | "mx27pdk"); |
| 128 | mx27_3ds_sdhc1_enable_level_translator(); | ||
| 92 | imx27_add_imx_uart0(&uart_pdata); | 129 | imx27_add_imx_uart0(&uart_pdata); |
| 93 | imx27_add_fec(NULL); | 130 | imx27_add_fec(NULL); |
| 94 | mxc_register_device(&imx_kpp_device, &mx27_3ds_keymap_data); | 131 | mxc_register_device(&imx_kpp_device, &mx27_3ds_keymap_data); |
| 132 | mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata); | ||
| 95 | } | 133 | } |
| 96 | 134 | ||
| 97 | static void __init mx27pdk_timer_init(void) | 135 | static void __init mx27pdk_timer_init(void) |
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index babb22597163..e24e3d05397f 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c | |||
| @@ -197,7 +197,7 @@ unsigned long ixp2000_gettimeoffset (void) | |||
| 197 | return offset / ticks_per_usec; | 197 | return offset / ticks_per_usec; |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | static int ixp2000_timer_interrupt(int irq, void *dev_id) | 200 | static irqreturn_t ixp2000_timer_interrupt(int irq, void *dev_id) |
| 201 | { | 201 | { |
| 202 | /* clear timer 1 */ | 202 | /* clear timer 1 */ |
| 203 | ixp2000_reg_wrb(IXP2000_T1_CLR, 1); | 203 | ixp2000_reg_wrb(IXP2000_T1_CLR, 1); |
diff --git a/arch/arm/mach-mx25/Kconfig b/arch/arm/mach-mx25/Kconfig index aa57e35ce3cd..38ca09a5df9d 100644 --- a/arch/arm/mach-mx25/Kconfig +++ b/arch/arm/mach-mx25/Kconfig | |||
| @@ -6,6 +6,7 @@ config MACH_MX25_3DS | |||
| 6 | bool "Support MX25PDK (3DS) Platform" | 6 | bool "Support MX25PDK (3DS) Platform" |
| 7 | select IMX_HAVE_PLATFORM_IMX_UART | 7 | select IMX_HAVE_PLATFORM_IMX_UART |
| 8 | select IMX_HAVE_PLATFORM_MXC_NAND | 8 | select IMX_HAVE_PLATFORM_MXC_NAND |
| 9 | select IMX_HAVE_PLATFORM_ESDHC | ||
| 9 | 10 | ||
| 10 | config MACH_EUKREA_CPUIMX25 | 11 | config MACH_EUKREA_CPUIMX25 |
| 11 | bool "Support Eukrea CPUIMX25 Platform" | 12 | bool "Support Eukrea CPUIMX25 Platform" |
diff --git a/arch/arm/mach-mx25/mach-mx25_3ds.c b/arch/arm/mach-mx25/mach-mx25_3ds.c index 80805107a73e..f8be1eb0c062 100644 --- a/arch/arm/mach-mx25/mach-mx25_3ds.c +++ b/arch/arm/mach-mx25/mach-mx25_3ds.c | |||
| @@ -96,6 +96,14 @@ static struct pad_desc mx25pdk_pads[] = { | |||
| 96 | MX25_PAD_KPP_COL1__KPP_COL1, | 96 | MX25_PAD_KPP_COL1__KPP_COL1, |
| 97 | MX25_PAD_KPP_COL2__KPP_COL2, | 97 | MX25_PAD_KPP_COL2__KPP_COL2, |
| 98 | MX25_PAD_KPP_COL3__KPP_COL3, | 98 | MX25_PAD_KPP_COL3__KPP_COL3, |
| 99 | |||
| 100 | /* SD1 */ | ||
| 101 | MX25_PAD_SD1_CMD__SD1_CMD, | ||
| 102 | MX25_PAD_SD1_CLK__SD1_CLK, | ||
| 103 | MX25_PAD_SD1_DATA0__SD1_DATA0, | ||
| 104 | MX25_PAD_SD1_DATA1__SD1_DATA1, | ||
| 105 | MX25_PAD_SD1_DATA2__SD1_DATA2, | ||
| 106 | MX25_PAD_SD1_DATA3__SD1_DATA3, | ||
| 99 | }; | 107 | }; |
| 100 | 108 | ||
| 101 | static const struct fec_platform_data mx25_fec_pdata __initconst = { | 109 | static const struct fec_platform_data mx25_fec_pdata __initconst = { |
| @@ -193,6 +201,8 @@ static void __init mx25pdk_init(void) | |||
| 193 | mx25pdk_fec_reset(); | 201 | mx25pdk_fec_reset(); |
| 194 | imx25_add_fec(&mx25_fec_pdata); | 202 | imx25_add_fec(&mx25_fec_pdata); |
| 195 | mxc_register_device(&mx25_kpp_device, &mx25pdk_keymap_data); | 203 | mxc_register_device(&mx25_kpp_device, &mx25pdk_keymap_data); |
| 204 | |||
| 205 | imx25_add_esdhc(0, NULL); | ||
| 196 | } | 206 | } |
| 197 | 207 | ||
| 198 | static void __init mx25pdk_timer_init(void) | 208 | static void __init mx25pdk_timer_init(void) |
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig index 096fd33f8ab9..5000ac1f93e3 100644 --- a/arch/arm/mach-mx3/Kconfig +++ b/arch/arm/mach-mx3/Kconfig | |||
| @@ -143,8 +143,10 @@ config MACH_ARMADILLO5X0 | |||
| 143 | config MACH_MX35_3DS | 143 | config MACH_MX35_3DS |
| 144 | bool "Support MX35PDK platform" | 144 | bool "Support MX35PDK platform" |
| 145 | select ARCH_MX35 | 145 | select ARCH_MX35 |
| 146 | select MXC_DEBUG_BOARD | ||
| 146 | select IMX_HAVE_PLATFORM_IMX_UART | 147 | select IMX_HAVE_PLATFORM_IMX_UART |
| 147 | select IMX_HAVE_PLATFORM_MXC_NAND | 148 | select IMX_HAVE_PLATFORM_MXC_NAND |
| 149 | select IMX_HAVE_PLATFORM_ESDHC | ||
| 148 | default n | 150 | default n |
| 149 | help | 151 | help |
| 150 | Include support for MX35PDK platform. This includes specific | 152 | Include support for MX35PDK platform. This includes specific |
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c index f4dff11aaee7..d4da9496089a 100644 --- a/arch/arm/mach-mx3/devices.c +++ b/arch/arm/mach-mx3/devices.c | |||
| @@ -72,24 +72,24 @@ struct platform_device mxc_w1_master_device = { | |||
| 72 | #ifdef CONFIG_ARCH_MX31 | 72 | #ifdef CONFIG_ARCH_MX31 |
| 73 | static struct resource mxcsdhc0_resources[] = { | 73 | static struct resource mxcsdhc0_resources[] = { |
| 74 | { | 74 | { |
| 75 | .start = MMC_SDHC1_BASE_ADDR, | 75 | .start = MX31_MMC_SDHC1_BASE_ADDR, |
| 76 | .end = MMC_SDHC1_BASE_ADDR + SZ_16K - 1, | 76 | .end = MX31_MMC_SDHC1_BASE_ADDR + SZ_16K - 1, |
| 77 | .flags = IORESOURCE_MEM, | 77 | .flags = IORESOURCE_MEM, |
| 78 | }, { | 78 | }, { |
| 79 | .start = MXC_INT_MMC_SDHC1, | 79 | .start = MX31_INT_MMC_SDHC1, |
| 80 | .end = MXC_INT_MMC_SDHC1, | 80 | .end = MX31_INT_MMC_SDHC1, |
| 81 | .flags = IORESOURCE_IRQ, | 81 | .flags = IORESOURCE_IRQ, |
| 82 | }, | 82 | }, |
| 83 | }; | 83 | }; |
| 84 | 84 | ||
| 85 | static struct resource mxcsdhc1_resources[] = { | 85 | static struct resource mxcsdhc1_resources[] = { |
| 86 | { | 86 | { |
| 87 | .start = MMC_SDHC2_BASE_ADDR, | 87 | .start = MX31_MMC_SDHC2_BASE_ADDR, |
| 88 | .end = MMC_SDHC2_BASE_ADDR + SZ_16K - 1, | 88 | .end = MX31_MMC_SDHC2_BASE_ADDR + SZ_16K - 1, |
| 89 | .flags = IORESOURCE_MEM, | 89 | .flags = IORESOURCE_MEM, |
| 90 | }, { | 90 | }, { |
| 91 | .start = MXC_INT_MMC_SDHC2, | 91 | .start = MX31_INT_MMC_SDHC2, |
| 92 | .end = MXC_INT_MMC_SDHC2, | 92 | .end = MX31_INT_MMC_SDHC2, |
| 93 | .flags = IORESOURCE_IRQ, | 93 | .flags = IORESOURCE_IRQ, |
| 94 | }, | 94 | }, |
| 95 | }; | 95 | }; |
diff --git a/arch/arm/mach-mx3/mach-mx31_3ds.c b/arch/arm/mach-mx3/mach-mx31_3ds.c index 5c1d0e86c91e..0ad9e7821082 100644 --- a/arch/arm/mach-mx3/mach-mx31_3ds.c +++ b/arch/arm/mach-mx3/mach-mx31_3ds.c | |||
| @@ -38,39 +38,9 @@ | |||
| 38 | #include "devices-imx31.h" | 38 | #include "devices-imx31.h" |
| 39 | #include "devices.h" | 39 | #include "devices.h" |
| 40 | 40 | ||
| 41 | /* Definitions for components on the Debug board */ | ||
| 42 | |||
| 43 | /* Base address of CPLD controller on the Debug board */ | ||
| 44 | #define DEBUG_BASE_ADDRESS CS5_IO_ADDRESS(MX3x_CS5_BASE_ADDR) | ||
| 45 | |||
| 46 | /* LAN9217 ethernet base address */ | ||
| 47 | #define LAN9217_BASE_ADDR MX3x_CS5_BASE_ADDR | ||
| 48 | |||
| 49 | /* CPLD config and interrupt base address */ | ||
| 50 | #define CPLD_ADDR (DEBUG_BASE_ADDRESS + 0x20000) | ||
| 51 | |||
| 52 | /* status, interrupt */ | ||
| 53 | #define CPLD_INT_STATUS_REG (CPLD_ADDR + 0x10) | ||
| 54 | #define CPLD_INT_MASK_REG (CPLD_ADDR + 0x38) | ||
| 55 | #define CPLD_INT_RESET_REG (CPLD_ADDR + 0x20) | ||
| 56 | /* magic word for debug CPLD */ | ||
| 57 | #define CPLD_MAGIC_NUMBER1_REG (CPLD_ADDR + 0x40) | ||
| 58 | #define CPLD_MAGIC_NUMBER2_REG (CPLD_ADDR + 0x48) | ||
| 59 | /* CPLD code version */ | ||
| 60 | #define CPLD_CODE_VER_REG (CPLD_ADDR + 0x50) | ||
| 61 | /* magic word for debug CPLD */ | ||
| 62 | #define CPLD_MAGIC_NUMBER3_REG (CPLD_ADDR + 0x58) | ||
| 63 | |||
| 64 | /* CPLD IRQ line for external uart, external ethernet etc */ | 41 | /* CPLD IRQ line for external uart, external ethernet etc */ |
| 65 | #define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_1) | 42 | #define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_1) |
| 66 | 43 | ||
| 67 | #define MXC_EXP_IO_BASE (MXC_BOARD_IRQ_START) | ||
| 68 | #define MXC_IRQ_TO_EXPIO(irq) ((irq) - MXC_EXP_IO_BASE) | ||
| 69 | |||
| 70 | #define EXPIO_INT_ENET (MXC_EXP_IO_BASE + 0) | ||
| 71 | |||
| 72 | #define MXC_MAX_EXP_IO_LINES 16 | ||
| 73 | |||
| 74 | /* | 44 | /* |
| 75 | * This file contains the board-specific initialization routines. | 45 | * This file contains the board-specific initialization routines. |
| 76 | */ | 46 | */ |
| @@ -272,7 +242,7 @@ static void __init mxc_board_init(void) | |||
| 272 | imx31_add_imx_uart0(&uart_pdata); | 242 | imx31_add_imx_uart0(&uart_pdata); |
| 273 | imx31_add_mxc_nand(&mx31_3ds_nand_board_info); | 243 | imx31_add_mxc_nand(&mx31_3ds_nand_board_info); |
| 274 | 244 | ||
| 275 | imx31_add_spi_imx0(&spi1_pdata); | 245 | imx31_add_spi_imx1(&spi1_pdata); |
| 276 | spi_register_board_info(mx31_3ds_spi_devs, | 246 | spi_register_board_info(mx31_3ds_spi_devs, |
| 277 | ARRAY_SIZE(mx31_3ds_spi_devs)); | 247 | ARRAY_SIZE(mx31_3ds_spi_devs)); |
| 278 | 248 | ||
| @@ -281,9 +251,9 @@ static void __init mxc_board_init(void) | |||
| 281 | mx31_3ds_usbotg_init(); | 251 | mx31_3ds_usbotg_init(); |
| 282 | mxc_register_device(&mxc_otg_udc_device, &usbotg_pdata); | 252 | mxc_register_device(&mxc_otg_udc_device, &usbotg_pdata); |
| 283 | 253 | ||
| 284 | if (!mxc_expio_init(CS5_BASE_ADDR, EXPIO_PARENT_INT)) | 254 | if (mxc_expio_init(MX31_CS5_BASE_ADDR, EXPIO_PARENT_INT)) |
| 285 | printk(KERN_WARNING "Init of the debugboard failed, all " | 255 | printk(KERN_WARNING "Init of the debug board failed, all " |
| 286 | "devices on the board are unusable.\n"); | 256 | "devices on the debug board are unusable.\n"); |
| 287 | } | 257 | } |
| 288 | 258 | ||
| 289 | static void __init mx31_3ds_timer_init(void) | 259 | static void __init mx31_3ds_timer_init(void) |
diff --git a/arch/arm/mach-mx3/mach-mx35_3ds.c b/arch/arm/mach-mx3/mach-mx35_3ds.c index 05f628d90725..b66a75aa2e88 100644 --- a/arch/arm/mach-mx3/mach-mx35_3ds.c +++ b/arch/arm/mach-mx3/mach-mx35_3ds.c | |||
| @@ -38,11 +38,15 @@ | |||
| 38 | #include <mach/hardware.h> | 38 | #include <mach/hardware.h> |
| 39 | #include <mach/common.h> | 39 | #include <mach/common.h> |
| 40 | #include <mach/iomux-mx35.h> | 40 | #include <mach/iomux-mx35.h> |
| 41 | #include <mach/irqs.h> | ||
| 42 | #include <mach/3ds_debugboard.h> | ||
| 41 | #include <mach/mxc_ehci.h> | 43 | #include <mach/mxc_ehci.h> |
| 42 | 44 | ||
| 43 | #include "devices-imx35.h" | 45 | #include "devices-imx35.h" |
| 44 | #include "devices.h" | 46 | #include "devices.h" |
| 45 | 47 | ||
| 48 | #define EXPIO_PARENT_INT (MXC_INTERNAL_IRQS + GPIO_PORTA + 1) | ||
| 49 | |||
| 46 | static const struct imxuart_platform_data uart_pdata __initconst = { | 50 | static const struct imxuart_platform_data uart_pdata __initconst = { |
| 47 | .flags = IMXUART_HAVE_RTSCTS, | 51 | .flags = IMXUART_HAVE_RTSCTS, |
| 48 | }; | 52 | }; |
| @@ -108,6 +112,13 @@ static struct pad_desc mx35pdk_pads[] = { | |||
| 108 | /* USBH1 */ | 112 | /* USBH1 */ |
| 109 | MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR, | 113 | MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR, |
| 110 | MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC, | 114 | MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC, |
| 115 | /* SDCARD */ | ||
| 116 | MX35_PAD_SD1_CMD__ESDHC1_CMD, | ||
| 117 | MX35_PAD_SD1_CLK__ESDHC1_CLK, | ||
| 118 | MX35_PAD_SD1_DATA0__ESDHC1_DAT0, | ||
| 119 | MX35_PAD_SD1_DATA1__ESDHC1_DAT1, | ||
| 120 | MX35_PAD_SD1_DATA2__ESDHC1_DAT2, | ||
| 121 | MX35_PAD_SD1_DATA3__ESDHC1_DAT3, | ||
| 111 | }; | 122 | }; |
| 112 | 123 | ||
| 113 | /* OTG config */ | 124 | /* OTG config */ |
| @@ -140,6 +151,11 @@ static void __init mxc_board_init(void) | |||
| 140 | mxc_register_device(&mxc_usbh1, &usb_host_pdata); | 151 | mxc_register_device(&mxc_usbh1, &usb_host_pdata); |
| 141 | 152 | ||
| 142 | imx35_add_mxc_nand(&mx35pdk_nand_board_info); | 153 | imx35_add_mxc_nand(&mx35pdk_nand_board_info); |
| 154 | imx35_add_esdhc(0, NULL); | ||
| 155 | |||
| 156 | if (mxc_expio_init(MX35_CS5_BASE_ADDR, EXPIO_PARENT_INT)) | ||
| 157 | pr_warn("Init of the debugboard failed, all " | ||
| 158 | "devices on the debugboard are unusable.\n"); | ||
| 143 | } | 159 | } |
| 144 | 160 | ||
| 145 | static void __init mx35pdk_timer_init(void) | 161 | static void __init mx35pdk_timer_init(void) |
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index a2df9ac37996..3ec910a7a182 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig | |||
| @@ -6,6 +6,7 @@ config ARCH_MX51 | |||
| 6 | select MXC_TZIC | 6 | select MXC_TZIC |
| 7 | select ARCH_MXC_IOMUX_V3 | 7 | select ARCH_MXC_IOMUX_V3 |
| 8 | select ARCH_MXC_AUDMUX_V2 | 8 | select ARCH_MXC_AUDMUX_V2 |
| 9 | select ARCH_HAS_CPUFREQ | ||
| 9 | 10 | ||
| 10 | comment "MX5 platforms:" | 11 | comment "MX5 platforms:" |
| 11 | 12 | ||
| @@ -13,6 +14,7 @@ config MACH_MX51_BABBAGE | |||
| 13 | bool "Support MX51 BABBAGE platforms" | 14 | bool "Support MX51 BABBAGE platforms" |
| 14 | select IMX_HAVE_PLATFORM_IMX_I2C | 15 | select IMX_HAVE_PLATFORM_IMX_I2C |
| 15 | select IMX_HAVE_PLATFORM_IMX_UART | 16 | select IMX_HAVE_PLATFORM_IMX_UART |
| 17 | select IMX_HAVE_PLATFORM_ESDHC | ||
| 16 | help | 18 | help |
| 17 | Include support for MX51 Babbage platform, also known as MX51EVK in | 19 | Include support for MX51 Babbage platform, also known as MX51EVK in |
| 18 | u-boot. This includes specific configurations for the board and its | 20 | u-boot. This includes specific configurations for the board and its |
diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile index 1769c161a60d..462f177eddfe 100644 --- a/arch/arm/mach-mx5/Makefile +++ b/arch/arm/mach-mx5/Makefile | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | # Object file lists. | 5 | # Object file lists. |
| 6 | obj-y := cpu.o mm.o clock-mx51.o devices.o | 6 | obj-y := cpu.o mm.o clock-mx51.o devices.o |
| 7 | 7 | ||
| 8 | obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o | ||
| 8 | obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o | 9 | obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o |
| 9 | obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o | 10 | obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o |
| 10 | obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o | 11 | obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o |
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index 0821fe9b3b27..acbe30df2e69 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. | 2 | * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. |
| 3 | * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> | 3 | * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> |
| 4 | * | 4 | * |
| 5 | * The code contained herein is licensed under the GNU General Public | 5 | * The code contained herein is licensed under the GNU General Public |
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
| 19 | #include <linux/fsl_devices.h> | 19 | #include <linux/fsl_devices.h> |
| 20 | #include <linux/fec.h> | 20 | #include <linux/fec.h> |
| 21 | #include <linux/gpio_keys.h> | ||
| 22 | #include <linux/input.h> | ||
| 21 | 23 | ||
| 22 | #include <mach/common.h> | 24 | #include <mach/common.h> |
| 23 | #include <mach/hardware.h> | 25 | #include <mach/hardware.h> |
| @@ -32,11 +34,13 @@ | |||
| 32 | 34 | ||
| 33 | #include "devices-imx51.h" | 35 | #include "devices-imx51.h" |
| 34 | #include "devices.h" | 36 | #include "devices.h" |
| 37 | #include "cpu_op-mx51.h" | ||
| 35 | 38 | ||
| 36 | #define BABBAGE_USB_HUB_RESET (0*32 + 7) /* GPIO_1_7 */ | 39 | #define BABBAGE_USB_HUB_RESET (0*32 + 7) /* GPIO_1_7 */ |
| 37 | #define BABBAGE_USBH1_STP (0*32 + 27) /* GPIO_1_27 */ | 40 | #define BABBAGE_USBH1_STP (0*32 + 27) /* GPIO_1_27 */ |
| 38 | #define BABBAGE_PHY_RESET (1*32 + 5) /* GPIO_2_5 */ | 41 | #define BABBAGE_PHY_RESET (1*32 + 5) /* GPIO_2_5 */ |
| 39 | #define BABBAGE_FEC_PHY_RESET (1*32 + 14) /* GPIO_2_14 */ | 42 | #define BABBAGE_FEC_PHY_RESET (1*32 + 14) /* GPIO_2_14 */ |
| 43 | #define BABBAGE_POWER_KEY (1*32 + 21) /* GPIO_2_21 */ | ||
| 40 | 44 | ||
| 41 | /* USB_CTRL_1 */ | 45 | /* USB_CTRL_1 */ |
| 42 | #define MX51_USB_CTRL_1_OFFSET 0x10 | 46 | #define MX51_USB_CTRL_1_OFFSET 0x10 |
| @@ -46,6 +50,21 @@ | |||
| 46 | #define MX51_USB_PLL_DIV_19_2_MHZ 0x01 | 50 | #define MX51_USB_PLL_DIV_19_2_MHZ 0x01 |
| 47 | #define MX51_USB_PLL_DIV_24_MHZ 0x02 | 51 | #define MX51_USB_PLL_DIV_24_MHZ 0x02 |
| 48 | 52 | ||
| 53 | static struct gpio_keys_button babbage_buttons[] = { | ||
| 54 | { | ||
| 55 | .gpio = BABBAGE_POWER_KEY, | ||
| 56 | .code = BTN_0, | ||
| 57 | .desc = "PWR", | ||
| 58 | .active_low = 1, | ||
| 59 | .wakeup = 1, | ||
| 60 | }, | ||
| 61 | }; | ||
| 62 | |||
| 63 | static const struct gpio_keys_platform_data imx_button_data __initconst = { | ||
| 64 | .buttons = babbage_buttons, | ||
| 65 | .nbuttons = ARRAY_SIZE(babbage_buttons), | ||
| 66 | }; | ||
| 67 | |||
| 49 | static struct pad_desc mx51babbage_pads[] = { | 68 | static struct pad_desc mx51babbage_pads[] = { |
| 50 | /* UART1 */ | 69 | /* UART1 */ |
| 51 | MX51_PAD_UART1_RXD__UART1_RXD, | 70 | MX51_PAD_UART1_RXD__UART1_RXD, |
| @@ -112,6 +131,22 @@ static struct pad_desc mx51babbage_pads[] = { | |||
| 112 | 131 | ||
| 113 | /* FEC PHY reset line */ | 132 | /* FEC PHY reset line */ |
| 114 | MX51_PAD_EIM_A20__GPIO_2_14, | 133 | MX51_PAD_EIM_A20__GPIO_2_14, |
| 134 | |||
| 135 | /* SD 1 */ | ||
| 136 | MX51_PAD_SD1_CMD__SD1_CMD, | ||
| 137 | MX51_PAD_SD1_CLK__SD1_CLK, | ||
| 138 | MX51_PAD_SD1_DATA0__SD1_DATA0, | ||
| 139 | MX51_PAD_SD1_DATA1__SD1_DATA1, | ||
| 140 | MX51_PAD_SD1_DATA2__SD1_DATA2, | ||
| 141 | MX51_PAD_SD1_DATA3__SD1_DATA3, | ||
| 142 | |||
| 143 | /* SD 2 */ | ||
| 144 | MX51_PAD_SD2_CMD__SD2_CMD, | ||
| 145 | MX51_PAD_SD2_CLK__SD2_CLK, | ||
| 146 | MX51_PAD_SD2_DATA0__SD2_DATA0, | ||
| 147 | MX51_PAD_SD2_DATA1__SD2_DATA1, | ||
| 148 | MX51_PAD_SD2_DATA2__SD2_DATA2, | ||
| 149 | MX51_PAD_SD2_DATA3__SD2_DATA3, | ||
| 115 | }; | 150 | }; |
| 116 | 151 | ||
| 117 | /* Serial ports */ | 152 | /* Serial ports */ |
| @@ -281,13 +316,22 @@ __setup("otg_mode=", babbage_otg_mode); | |||
| 281 | static void __init mxc_board_init(void) | 316 | static void __init mxc_board_init(void) |
| 282 | { | 317 | { |
| 283 | struct pad_desc usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP; | 318 | struct pad_desc usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP; |
| 319 | struct pad_desc power_key = MX51_PAD_EIM_A27__GPIO_2_21; | ||
| 284 | 320 | ||
| 321 | #if defined(CONFIG_CPU_FREQ_IMX) | ||
| 322 | get_cpu_op = mx51_get_cpu_op; | ||
| 323 | #endif | ||
| 285 | mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, | 324 | mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, |
| 286 | ARRAY_SIZE(mx51babbage_pads)); | 325 | ARRAY_SIZE(mx51babbage_pads)); |
| 287 | mxc_init_imx_uart(); | 326 | mxc_init_imx_uart(); |
| 288 | babbage_fec_reset(); | 327 | babbage_fec_reset(); |
| 289 | imx51_add_fec(NULL); | 328 | imx51_add_fec(NULL); |
| 290 | 329 | ||
| 330 | /* Set the PAD settings for the pwr key. */ | ||
| 331 | power_key.pad_ctrl = MX51_GPIO_PAD_CTRL_2; | ||
| 332 | mxc_iomux_v3_setup_pad(&power_key); | ||
| 333 | imx51_add_gpio_keys(&imx_button_data); | ||
| 334 | |||
| 291 | imx51_add_imx_i2c(0, &babbage_i2c_data); | 335 | imx51_add_imx_i2c(0, &babbage_i2c_data); |
| 292 | imx51_add_imx_i2c(1, &babbage_i2c_data); | 336 | imx51_add_imx_i2c(1, &babbage_i2c_data); |
| 293 | mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data); | 337 | mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data); |
| @@ -304,6 +348,9 @@ static void __init mxc_board_init(void) | |||
| 304 | /* setback USBH1_STP to be function */ | 348 | /* setback USBH1_STP to be function */ |
| 305 | mxc_iomux_v3_setup_pad(&usbh1stp); | 349 | mxc_iomux_v3_setup_pad(&usbh1stp); |
| 306 | babbage_usbhub_reset(); | 350 | babbage_usbhub_reset(); |
| 351 | |||
| 352 | imx51_add_esdhc(0, NULL); | ||
| 353 | imx51_add_esdhc(1, NULL); | ||
| 307 | } | 354 | } |
| 308 | 355 | ||
| 309 | static void __init mx51_babbage_timer_init(void) | 356 | static void __init mx51_babbage_timer_init(void) |
diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c index f2aae92cf0e2..8ac36d882927 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c | |||
| @@ -362,7 +362,7 @@ static int _clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) | |||
| 362 | return 0; | 362 | return 0; |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | static unsigned long clk_arm_get_rate(struct clk *clk) | 365 | static unsigned long clk_cpu_get_rate(struct clk *clk) |
| 366 | { | 366 | { |
| 367 | u32 cacrr, div; | 367 | u32 cacrr, div; |
| 368 | unsigned long parent_rate; | 368 | unsigned long parent_rate; |
| @@ -374,6 +374,22 @@ static unsigned long clk_arm_get_rate(struct clk *clk) | |||
| 374 | return parent_rate / div; | 374 | return parent_rate / div; |
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | static int clk_cpu_set_rate(struct clk *clk, unsigned long rate) | ||
| 378 | { | ||
| 379 | u32 reg, cpu_podf; | ||
| 380 | unsigned long parent_rate; | ||
| 381 | |||
| 382 | parent_rate = clk_get_rate(clk->parent); | ||
| 383 | cpu_podf = parent_rate / rate - 1; | ||
| 384 | /* use post divider to change freq */ | ||
| 385 | reg = __raw_readl(MXC_CCM_CACRR); | ||
| 386 | reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; | ||
| 387 | reg |= cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; | ||
| 388 | __raw_writel(reg, MXC_CCM_CACRR); | ||
| 389 | |||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 377 | static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) | 393 | static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) |
| 378 | { | 394 | { |
| 379 | u32 reg, mux; | 395 | u32 reg, mux; |
| @@ -736,7 +752,8 @@ static struct clk periph_apm_clk = { | |||
| 736 | 752 | ||
| 737 | static struct clk cpu_clk = { | 753 | static struct clk cpu_clk = { |
| 738 | .parent = &pll1_sw_clk, | 754 | .parent = &pll1_sw_clk, |
| 739 | .get_rate = clk_arm_get_rate, | 755 | .get_rate = clk_cpu_get_rate, |
| 756 | .set_rate = clk_cpu_set_rate, | ||
| 740 | }; | 757 | }; |
| 741 | 758 | ||
| 742 | static struct clk ahb_clk = { | 759 | static struct clk ahb_clk = { |
| @@ -1064,6 +1081,7 @@ static struct clk_lookup lookups[] = { | |||
| 1064 | _REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk) | 1081 | _REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk) |
| 1065 | _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) | 1082 | _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) |
| 1066 | _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk) | 1083 | _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk) |
| 1084 | _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk) | ||
| 1067 | }; | 1085 | }; |
| 1068 | 1086 | ||
| 1069 | static void clk_tree_init(void) | 1087 | static void clk_tree_init(void) |
diff --git a/arch/arm/mach-mx5/cpu_op-mx51.c b/arch/arm/mach-mx5/cpu_op-mx51.c new file mode 100644 index 000000000000..9d34c3d4c024 --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx51.c | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* | ||
| 6 | * The code contained herein is licensed under the GNU General Public | ||
| 7 | * License. You may obtain a copy of the GNU General Public License | ||
| 8 | * Version 2 or later at the following locations: | ||
| 9 | * | ||
| 10 | * http://www.opensource.org/licenses/gpl-license.html | ||
| 11 | * http://www.gnu.org/copyleft/gpl.html | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/types.h> | ||
| 15 | #include <mach/hardware.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | |||
| 18 | static struct cpu_op mx51_cpu_op[] = { | ||
| 19 | { | ||
| 20 | .cpu_rate = 160000000,}, | ||
| 21 | { | ||
| 22 | .cpu_rate = 800000000,}, | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct cpu_op *mx51_get_cpu_op(int *op) | ||
| 26 | { | ||
| 27 | *op = ARRAY_SIZE(mx51_cpu_op); | ||
| 28 | return mx51_cpu_op; | ||
| 29 | } | ||
diff --git a/arch/arm/mach-mx5/cpu_op-mx51.h b/arch/arm/mach-mx5/cpu_op-mx51.h new file mode 100644 index 000000000000..97477fecb469 --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx51.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* | ||
| 6 | * The code contained herein is licensed under the GNU General Public | ||
| 7 | * License. You may obtain a copy of the GNU General Public License | ||
| 8 | * Version 2 or later at the following locations: | ||
| 9 | * | ||
| 10 | * http://www.opensource.org/licenses/gpl-license.html | ||
| 11 | * http://www.gnu.org/copyleft/gpl.html | ||
| 12 | */ | ||
| 13 | |||
| 14 | extern struct cpu_op *mx51_get_cpu_op(int *op); | ||
diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h index 5cc910e60538..8c50cb5d05f5 100644 --- a/arch/arm/mach-mx5/devices-imx51.h +++ b/arch/arm/mach-mx5/devices-imx51.h | |||
| @@ -13,6 +13,8 @@ extern const struct imx_fec_data imx51_fec_data __initconst; | |||
| 13 | #define imx51_add_fec(pdata) \ | 13 | #define imx51_add_fec(pdata) \ |
| 14 | imx_add_fec(&imx51_fec_data, pdata) | 14 | imx_add_fec(&imx51_fec_data, pdata) |
| 15 | 15 | ||
| 16 | #define imx51_add_gpio_keys(pdata) imx_add_gpio_keys(pdata) | ||
| 17 | |||
| 16 | extern const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst; | 18 | extern const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst; |
| 17 | #define imx51_add_imx_i2c(id, pdata) \ | 19 | #define imx51_add_imx_i2c(id, pdata) \ |
| 18 | imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata) | 20 | imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata) |
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 923f9f5f91ce..2f895553e6a8 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c | |||
| @@ -44,6 +44,13 @@ void __init gic_init_irq(void) | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | #ifdef CONFIG_CACHE_L2X0 | 46 | #ifdef CONFIG_CACHE_L2X0 |
| 47 | |||
| 48 | static void omap4_l2x0_disable(void) | ||
| 49 | { | ||
| 50 | /* Disable PL310 L2 Cache controller */ | ||
| 51 | omap_smc1(0x102, 0x0); | ||
| 52 | } | ||
| 53 | |||
| 47 | static int __init omap_l2_cache_init(void) | 54 | static int __init omap_l2_cache_init(void) |
| 48 | { | 55 | { |
| 49 | /* | 56 | /* |
| @@ -70,6 +77,12 @@ static int __init omap_l2_cache_init(void) | |||
| 70 | else | 77 | else |
| 71 | l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff); | 78 | l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff); |
| 72 | 79 | ||
| 80 | /* | ||
| 81 | * Override default outer_cache.disable with a OMAP4 | ||
| 82 | * specific one | ||
| 83 | */ | ||
| 84 | outer_cache.disable = omap4_l2x0_disable; | ||
| 85 | |||
| 73 | return 0; | 86 | return 0; |
| 74 | } | 87 | } |
| 75 | early_initcall(omap_l2_cache_init); | 88 | early_initcall(omap_l2_cache_init); |
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio.h b/arch/arm/mach-s3c2410/include/mach/gpio.h index b649bf2ccd5c..f7f6b07df30e 100644 --- a/arch/arm/mach-s3c2410/include/mach/gpio.h +++ b/arch/arm/mach-s3c2410/include/mach/gpio.h | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | 22 | ||
| 23 | #ifdef CONFIG_CPU_S3C244X | 23 | #ifdef CONFIG_CPU_S3C244X |
| 24 | #define ARCH_NR_GPIOS (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA) | 24 | #define ARCH_NR_GPIOS (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA) |
| 25 | #elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) | ||
| 26 | #define ARCH_NR_GPIOS (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA) | ||
| 25 | #else | 27 | #else |
| 26 | #define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA) | 28 | #define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA) |
| 27 | #endif | 29 | #endif |
| @@ -30,8 +32,10 @@ | |||
| 30 | #include <mach/gpio-nrs.h> | 32 | #include <mach/gpio-nrs.h> |
| 31 | #include <mach/gpio-fns.h> | 33 | #include <mach/gpio-fns.h> |
| 32 | 34 | ||
| 33 | #ifdef CONFIG_CPU_S3C24XX | 35 | #ifdef CONFIG_CPU_S3C244X |
| 34 | #define S3C_GPIO_END (S3C2410_GPIO_BANKJ + 32) | 36 | #define S3C_GPIO_END (S3C2410_GPJ(0) + 32) |
| 37 | #elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) | ||
| 38 | #define S3C_GPIO_END (S3C2410_GPM(0) + 32) | ||
| 35 | #else | 39 | #else |
| 36 | #define S3C_GPIO_END (S3C2410_GPIO_BANKH + 32) | 40 | #define S3C_GPIO_END (S3C2410_GPH(0) + 32) |
| 37 | #endif | 41 | #endif |
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h index 08ab9dfb6ae6..101aeea22310 100644 --- a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h +++ b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h | |||
| @@ -118,6 +118,8 @@ | |||
| 118 | #define S3C2443_SCLKCON_UARTCLK (1<<8) | 118 | #define S3C2443_SCLKCON_UARTCLK (1<<8) |
| 119 | #define S3C2443_SCLKCON_USBHOST (1<<1) | 119 | #define S3C2443_SCLKCON_USBHOST (1<<1) |
| 120 | 120 | ||
| 121 | #define S3C2443_PWRCFG_SLEEP (1<<15) | ||
| 122 | |||
| 121 | #include <asm/div64.h> | 123 | #include <asm/div64.h> |
| 122 | 124 | ||
| 123 | static inline unsigned int | 125 | static inline unsigned int |
diff --git a/arch/arm/mach-s3c2410/include/mach/vmalloc.h b/arch/arm/mach-s3c2410/include/mach/vmalloc.h index 54297eb0bf5e..7a311e8dddba 100644 --- a/arch/arm/mach-s3c2410/include/mach/vmalloc.h +++ b/arch/arm/mach-s3c2410/include/mach/vmalloc.h | |||
| @@ -15,6 +15,6 @@ | |||
| 15 | #ifndef __ASM_ARCH_VMALLOC_H | 15 | #ifndef __ASM_ARCH_VMALLOC_H |
| 16 | #define __ASM_ARCH_VMALLOC_H | 16 | #define __ASM_ARCH_VMALLOC_H |
| 17 | 17 | ||
| 18 | #define VMALLOC_END 0xE0000000UL | 18 | #define VMALLOC_END 0xF6000000UL |
| 19 | 19 | ||
| 20 | #endif /* __ASM_ARCH_VMALLOC_H */ | 20 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index bef39f77729d..4c6df51ddf33 100644 --- a/arch/arm/mach-s3c2412/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | #include <plat/clock.h> | 51 | #include <plat/clock.h> |
| 52 | #include <plat/pm.h> | 52 | #include <plat/pm.h> |
| 53 | #include <plat/pll.h> | 53 | #include <plat/pll.h> |
| 54 | #include <plat/nand-core.h> | ||
| 54 | 55 | ||
| 55 | #ifndef CONFIG_CPU_S3C2412_ONLY | 56 | #ifndef CONFIG_CPU_S3C2412_ONLY |
| 56 | void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; | 57 | void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; |
| @@ -92,7 +93,7 @@ void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no) | |||
| 92 | /* rename devices that are s3c2412/s3c2413 specific */ | 93 | /* rename devices that are s3c2412/s3c2413 specific */ |
| 93 | s3c_device_sdi.name = "s3c2412-sdi"; | 94 | s3c_device_sdi.name = "s3c2412-sdi"; |
| 94 | s3c_device_lcd.name = "s3c2412-lcd"; | 95 | s3c_device_lcd.name = "s3c2412-lcd"; |
| 95 | s3c_device_nand.name = "s3c2412-nand"; | 96 | s3c_nand_setname("s3c2412-nand"); |
| 96 | 97 | ||
| 97 | /* alter IRQ of SDI controller */ | 98 | /* alter IRQ of SDI controller */ |
| 98 | 99 | ||
diff --git a/arch/arm/mach-s3c2416/Kconfig b/arch/arm/mach-s3c2416/Kconfig index 657e4fe17f39..87b9c9f003bd 100644 --- a/arch/arm/mach-s3c2416/Kconfig +++ b/arch/arm/mach-s3c2416/Kconfig | |||
| @@ -25,6 +25,11 @@ config S3C2416_DMA | |||
| 25 | help | 25 | help |
| 26 | Internal config node for S3C2416 DMA support | 26 | Internal config node for S3C2416 DMA support |
| 27 | 27 | ||
| 28 | config S3C2416_PM | ||
| 29 | bool | ||
| 30 | help | ||
| 31 | Internal config node to apply S3C2416 power management | ||
| 32 | |||
| 28 | menu "S3C2416 Machines" | 33 | menu "S3C2416 Machines" |
| 29 | 34 | ||
| 30 | config MACH_SMDK2416 | 35 | config MACH_SMDK2416 |
| @@ -33,6 +38,7 @@ config MACH_SMDK2416 | |||
| 33 | select S3C_DEV_FB | 38 | select S3C_DEV_FB |
| 34 | select S3C_DEV_HSMMC | 39 | select S3C_DEV_HSMMC |
| 35 | select S3C_DEV_HSMMC1 | 40 | select S3C_DEV_HSMMC1 |
| 41 | select S3C2416_PM if PM | ||
| 36 | help | 42 | help |
| 37 | Say Y here if you are using an SMDK2416 | 43 | Say Y here if you are using an SMDK2416 |
| 38 | 44 | ||
diff --git a/arch/arm/mach-s3c2416/Makefile b/arch/arm/mach-s3c2416/Makefile index 6c12c7bf40ad..ef038d62ffdb 100644 --- a/arch/arm/mach-s3c2416/Makefile +++ b/arch/arm/mach-s3c2416/Makefile | |||
| @@ -11,7 +11,7 @@ obj- := | |||
| 11 | 11 | ||
| 12 | obj-$(CONFIG_CPU_S3C2416) += s3c2416.o clock.o | 12 | obj-$(CONFIG_CPU_S3C2416) += s3c2416.o clock.o |
| 13 | obj-$(CONFIG_CPU_S3C2416) += irq.o | 13 | obj-$(CONFIG_CPU_S3C2416) += irq.o |
| 14 | 14 | obj-$(CONFIG_S3C2416_PM) += pm.o | |
| 15 | #obj-$(CONFIG_S3C2416_DMA) += dma.o | 15 | #obj-$(CONFIG_S3C2416_DMA) += dma.o |
| 16 | 16 | ||
| 17 | # Machine support | 17 | # Machine support |
diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c2416/irq.c index 89f521d59d06..084d121f368c 100644 --- a/arch/arm/mach-s3c2416/irq.c +++ b/arch/arm/mach-s3c2416/irq.c | |||
| @@ -243,6 +243,8 @@ static int __init s3c2416_irq_add(struct sys_device *sysdev) | |||
| 243 | 243 | ||
| 244 | static struct sysdev_driver s3c2416_irq_driver = { | 244 | static struct sysdev_driver s3c2416_irq_driver = { |
| 245 | .add = s3c2416_irq_add, | 245 | .add = s3c2416_irq_add, |
| 246 | .suspend = s3c24xx_irq_suspend, | ||
| 247 | .resume = s3c24xx_irq_resume, | ||
| 246 | }; | 248 | }; |
| 247 | 249 | ||
| 248 | static int __init s3c2416_irq_init(void) | 250 | static int __init s3c2416_irq_init(void) |
diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c2416/pm.c new file mode 100644 index 000000000000..4a04205b04d5 --- /dev/null +++ b/arch/arm/mach-s3c2416/pm.c | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | /* linux/arch/arm/mach-s3c2416/pm.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S3C2416 - PM support (Based on Ben Dooks' S3C2412 PM 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/sysdev.h> | ||
| 14 | #include <linux/io.h> | ||
| 15 | |||
| 16 | #include <asm/cacheflush.h> | ||
| 17 | |||
| 18 | #include <mach/regs-power.h> | ||
| 19 | #include <mach/regs-s3c2443-clock.h> | ||
| 20 | |||
| 21 | #include <plat/cpu.h> | ||
| 22 | #include <plat/pm.h> | ||
| 23 | |||
| 24 | extern void s3c2412_sleep_enter(void); | ||
| 25 | |||
| 26 | static void s3c2416_cpu_suspend(void) | ||
| 27 | { | ||
| 28 | flush_cache_all(); | ||
| 29 | |||
| 30 | /* enable wakeup sources regardless of battery state */ | ||
| 31 | __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG); | ||
| 32 | |||
| 33 | /* set the mode as sleep, 2BED represents "Go to BED" */ | ||
| 34 | __raw_writel(0x2BED, S3C2443_PWRMODE); | ||
| 35 | |||
| 36 | s3c2412_sleep_enter(); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void s3c2416_pm_prepare(void) | ||
| 40 | { | ||
| 41 | /* | ||
| 42 | * write the magic value u-boot uses to check for resume into | ||
| 43 | * the INFORM0 register, and ensure INFORM1 is set to the | ||
| 44 | * correct address to resume from. | ||
| 45 | */ | ||
| 46 | __raw_writel(0x2BED, S3C2412_INFORM0); | ||
| 47 | __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1); | ||
| 48 | } | ||
| 49 | |||
| 50 | static int s3c2416_pm_add(struct sys_device *sysdev) | ||
| 51 | { | ||
| 52 | pm_cpu_prep = s3c2416_pm_prepare; | ||
| 53 | pm_cpu_sleep = s3c2416_cpu_suspend; | ||
| 54 | |||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int s3c2416_pm_suspend(struct sys_device *dev, pm_message_t state) | ||
| 59 | { | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int s3c2416_pm_resume(struct sys_device *dev) | ||
| 64 | { | ||
| 65 | /* unset the return-from-sleep amd inform flags */ | ||
| 66 | __raw_writel(0x0, S3C2443_PWRMODE); | ||
| 67 | __raw_writel(0x0, S3C2412_INFORM0); | ||
| 68 | __raw_writel(0x0, S3C2412_INFORM1); | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static struct sysdev_driver s3c2416_pm_driver = { | ||
| 74 | .add = s3c2416_pm_add, | ||
| 75 | .suspend = s3c2416_pm_suspend, | ||
| 76 | .resume = s3c2416_pm_resume, | ||
| 77 | }; | ||
| 78 | |||
| 79 | static __init int s3c2416_pm_init(void) | ||
| 80 | { | ||
| 81 | return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver); | ||
| 82 | } | ||
| 83 | |||
| 84 | arch_initcall(s3c2416_pm_init); | ||
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c index bc30245e133b..63f39cdc0972 100644 --- a/arch/arm/mach-s3c2416/s3c2416.c +++ b/arch/arm/mach-s3c2416/s3c2416.c | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | 56 | ||
| 57 | #include <plat/iic-core.h> | 57 | #include <plat/iic-core.h> |
| 58 | #include <plat/fb-core.h> | 58 | #include <plat/fb-core.h> |
| 59 | #include <plat/nand-core.h> | ||
| 59 | 60 | ||
| 60 | static struct map_desc s3c2416_iodesc[] __initdata = { | 61 | static struct map_desc s3c2416_iodesc[] __initdata = { |
| 61 | IODESC_ENT(WATCHDOG), | 62 | IODESC_ENT(WATCHDOG), |
| @@ -100,7 +101,7 @@ void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no) | |||
| 100 | { | 101 | { |
| 101 | s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); | 102 | s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); |
| 102 | 103 | ||
| 103 | s3c_device_nand.name = "s3c2416-nand"; | 104 | s3c_nand_setname("s3c2412-nand"); |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | /* s3c2416_map_io | 107 | /* s3c2416_map_io |
diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c index 5e4a97e76533..90c1707b9c95 100644 --- a/arch/arm/mach-s3c2440/s3c244x.c +++ b/arch/arm/mach-s3c2440/s3c244x.c | |||
| @@ -44,6 +44,7 @@ | |||
| 44 | #include <plat/cpu.h> | 44 | #include <plat/cpu.h> |
| 45 | #include <plat/pm.h> | 45 | #include <plat/pm.h> |
| 46 | #include <plat/pll.h> | 46 | #include <plat/pll.h> |
| 47 | #include <plat/nand-core.h> | ||
| 47 | 48 | ||
| 48 | static struct map_desc s3c244x_iodesc[] __initdata = { | 49 | static struct map_desc s3c244x_iodesc[] __initdata = { |
| 49 | IODESC_ENT(CLKPWR), | 50 | IODESC_ENT(CLKPWR), |
| @@ -68,7 +69,7 @@ void __init s3c244x_map_io(void) | |||
| 68 | 69 | ||
| 69 | s3c_device_sdi.name = "s3c2440-sdi"; | 70 | s3c_device_sdi.name = "s3c2440-sdi"; |
| 70 | s3c_device_i2c0.name = "s3c2440-i2c"; | 71 | s3c_device_i2c0.name = "s3c2440-i2c"; |
| 71 | s3c_device_nand.name = "s3c2440-nand"; | 72 | s3c_nand_setname("s3c2440-nand"); |
| 72 | s3c_device_ts.name = "s3c2440-ts"; | 73 | s3c_device_ts.name = "s3c2440-ts"; |
| 73 | s3c_device_usbgadget.name = "s3c2440-usbgadget"; | 74 | s3c_device_usbgadget.name = "s3c2440-usbgadget"; |
| 74 | } | 75 | } |
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c index 839b6b2ced74..33d18dd1ebd5 100644 --- a/arch/arm/mach-s3c2443/s3c2443.c +++ b/arch/arm/mach-s3c2443/s3c2443.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <plat/devs.h> | 36 | #include <plat/devs.h> |
| 37 | #include <plat/cpu.h> | 37 | #include <plat/cpu.h> |
| 38 | #include <plat/fb-core.h> | 38 | #include <plat/fb-core.h> |
| 39 | #include <plat/nand-core.h> | ||
| 39 | 40 | ||
| 40 | static struct map_desc s3c2443_iodesc[] __initdata = { | 41 | static struct map_desc s3c2443_iodesc[] __initdata = { |
| 41 | IODESC_ENT(WATCHDOG), | 42 | IODESC_ENT(WATCHDOG), |
| @@ -62,7 +63,7 @@ int __init s3c2443_init(void) | |||
| 62 | 63 | ||
| 63 | s3c24xx_reset_hook = s3c2443_hard_reset; | 64 | s3c24xx_reset_hook = s3c2443_hard_reset; |
| 64 | 65 | ||
| 65 | s3c_device_nand.name = "s3c2412-nand"; | 66 | s3c_nand_setname("s3c2412-nand"); |
| 66 | s3c_fb_setname("s3c2443-fb"); | 67 | s3c_fb_setname("s3c2443-fb"); |
| 67 | 68 | ||
| 68 | /* change WDT IRQ number */ | 69 | /* change WDT IRQ number */ |
diff --git a/arch/arm/mach-s3c24a0/include/mach/vmalloc.h b/arch/arm/mach-s3c24a0/include/mach/vmalloc.h index 914656820794..6480b15277f3 100644 --- a/arch/arm/mach-s3c24a0/include/mach/vmalloc.h +++ b/arch/arm/mach-s3c24a0/include/mach/vmalloc.h | |||
| @@ -12,6 +12,6 @@ | |||
| 12 | #ifndef __ASM_ARCH_VMALLOC_H | 12 | #ifndef __ASM_ARCH_VMALLOC_H |
| 13 | #define __ASM_ARCH_VMALLOC_H | 13 | #define __ASM_ARCH_VMALLOC_H |
| 14 | 14 | ||
| 15 | #define VMALLOC_END (0xe0000000UL) | 15 | #define VMALLOC_END 0xF6000000UL |
| 16 | 16 | ||
| 17 | #endif /* __ASM_ARCH_VMALLOC_H */ | 17 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 546db5cb8929..1ca7bdc6485c 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig | |||
| @@ -98,12 +98,33 @@ config MACH_ANW6410 | |||
| 98 | help | 98 | help |
| 99 | Machine support for the A&W6410 | 99 | Machine support for the A&W6410 |
| 100 | 100 | ||
| 101 | config MACH_MINI6410 | ||
| 102 | bool "MINI6410" | ||
| 103 | select CPU_S3C6410 | ||
| 104 | select S3C_DEV_HSMMC | ||
| 105 | select S3C_DEV_HSMMC1 | ||
| 106 | select S3C64XX_SETUP_SDHCI | ||
| 107 | select S3C_DEV_USB_HOST | ||
| 108 | select S3C_DEV_NAND | ||
| 109 | select S3C_DEV_FB | ||
| 110 | select S3C64XX_SETUP_FB_24BPP | ||
| 111 | select SAMSUNG_DEV_ADC | ||
| 112 | select SAMSUNG_DEV_TS | ||
| 113 | help | ||
| 114 | Machine support for the FriendlyARM MINI6410 | ||
| 115 | |||
| 101 | config MACH_REAL6410 | 116 | config MACH_REAL6410 |
| 102 | bool "REAL6410" | 117 | bool "REAL6410" |
| 103 | select CPU_S3C6410 | 118 | select CPU_S3C6410 |
| 104 | select S3C_DEV_HSMMC | 119 | select S3C_DEV_HSMMC |
| 105 | select S3C_DEV_HSMMC1 | 120 | select S3C_DEV_HSMMC1 |
| 106 | select S3C64XX_SETUP_SDHCI | 121 | select S3C64XX_SETUP_SDHCI |
| 122 | select S3C_DEV_FB | ||
| 123 | select S3C64XX_SETUP_FB_24BPP | ||
| 124 | select S3C_DEV_NAND | ||
| 125 | select SAMSUNG_DEV_ADC | ||
| 126 | select SAMSUNG_DEV_TS | ||
| 127 | select S3C_DEV_USB_HOST | ||
| 107 | help | 128 | help |
| 108 | Machine support for the CoreWind REAL6410 | 129 | Machine support for the CoreWind REAL6410 |
| 109 | 130 | ||
diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 90221a2e0c55..4657363f0674 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile | |||
| @@ -53,6 +53,7 @@ obj-$(CONFIG_MACH_ANW6410) += mach-anw6410.o | |||
| 53 | obj-$(CONFIG_MACH_SMDK6400) += mach-smdk6400.o | 53 | obj-$(CONFIG_MACH_SMDK6400) += mach-smdk6400.o |
| 54 | obj-$(CONFIG_MACH_SMDK6410) += mach-smdk6410.o | 54 | obj-$(CONFIG_MACH_SMDK6410) += mach-smdk6410.o |
| 55 | obj-$(CONFIG_MACH_REAL6410) += mach-real6410.o | 55 | obj-$(CONFIG_MACH_REAL6410) += mach-real6410.o |
| 56 | obj-$(CONFIG_MACH_MINI6410) += mach-mini6410.o | ||
| 56 | obj-$(CONFIG_MACH_NCP) += mach-ncp.o | 57 | obj-$(CONFIG_MACH_NCP) += mach-ncp.o |
| 57 | obj-$(CONFIG_MACH_HMT) += mach-hmt.o | 58 | obj-$(CONFIG_MACH_HMT) += mach-hmt.o |
| 58 | obj-$(CONFIG_MACH_SMARTQ) += mach-smartq.o | 59 | obj-$(CONFIG_MACH_SMARTQ) += mach-smartq.o |
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c index 3838335f125b..76426a32c013 100644 --- a/arch/arm/mach-s3c64xx/dev-audio.c +++ b/arch/arm/mach-s3c64xx/dev-audio.c | |||
| @@ -22,27 +22,16 @@ | |||
| 22 | #include <plat/audio.h> | 22 | #include <plat/audio.h> |
| 23 | #include <plat/gpio-cfg.h> | 23 | #include <plat/gpio-cfg.h> |
| 24 | 24 | ||
| 25 | #include <mach/gpio-bank-c.h> | ||
| 26 | #include <mach/gpio-bank-d.h> | ||
| 27 | #include <mach/gpio-bank-e.h> | ||
| 28 | #include <mach/gpio-bank-h.h> | ||
| 29 | |||
| 30 | static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev) | 25 | static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev) |
| 31 | { | 26 | { |
| 27 | unsigned int base; | ||
| 28 | |||
| 32 | switch (pdev->id) { | 29 | switch (pdev->id) { |
| 33 | case 0: | 30 | case 0: |
| 34 | s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK); | 31 | base = S3C64XX_GPD(0); |
| 35 | s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK); | ||
| 36 | s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK); | ||
| 37 | s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI); | ||
| 38 | s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0); | ||
| 39 | break; | 32 | break; |
| 40 | case 1: | 33 | case 1: |
| 41 | s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK); | 34 | base = S3C64XX_GPE(0); |
| 42 | s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK); | ||
| 43 | s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK); | ||
| 44 | s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI); | ||
| 45 | s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0); | ||
| 46 | break; | 35 | break; |
| 47 | default: | 36 | default: |
| 48 | printk(KERN_DEBUG "Invalid I2S Controller number: %d\n", | 37 | printk(KERN_DEBUG "Invalid I2S Controller number: %d\n", |
| @@ -50,18 +39,17 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev) | |||
| 50 | return -EINVAL; | 39 | return -EINVAL; |
| 51 | } | 40 | } |
| 52 | 41 | ||
| 42 | s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(3)); | ||
| 43 | |||
| 53 | return 0; | 44 | return 0; |
| 54 | } | 45 | } |
| 55 | 46 | ||
| 56 | static int s3c64xx_i2sv4_cfg_gpio(struct platform_device *pdev) | 47 | static int s3c64xx_i2sv4_cfg_gpio(struct platform_device *pdev) |
| 57 | { | 48 | { |
| 58 | s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0); | 49 | s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5)); |
| 59 | s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1); | 50 | s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5)); |
| 60 | s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2); | 51 | s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5)); |
| 61 | s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK); | 52 | s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5)); |
| 62 | s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK); | ||
| 63 | s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK); | ||
| 64 | s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI); | ||
| 65 | 53 | ||
| 66 | return 0; | 54 | return 0; |
| 67 | } | 55 | } |
| @@ -170,20 +158,14 @@ EXPORT_SYMBOL(s3c64xx_device_iisv4); | |||
| 170 | 158 | ||
| 171 | static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev) | 159 | static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev) |
| 172 | { | 160 | { |
| 161 | unsigned int base; | ||
| 162 | |||
| 173 | switch (pdev->id) { | 163 | switch (pdev->id) { |
| 174 | case 0: | 164 | case 0: |
| 175 | s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK); | 165 | base = S3C64XX_GPD(0); |
| 176 | s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK); | ||
| 177 | s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC); | ||
| 178 | s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN); | ||
| 179 | s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT); | ||
| 180 | break; | 166 | break; |
| 181 | case 1: | 167 | case 1: |
| 182 | s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK); | 168 | base = S3C64XX_GPE(0); |
| 183 | s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK); | ||
| 184 | s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC); | ||
| 185 | s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN); | ||
| 186 | s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT); | ||
| 187 | break; | 169 | break; |
| 188 | default: | 170 | default: |
| 189 | printk(KERN_DEBUG "Invalid PCM Controller number: %d\n", | 171 | printk(KERN_DEBUG "Invalid PCM Controller number: %d\n", |
| @@ -191,6 +173,7 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev) | |||
| 191 | return -EINVAL; | 173 | return -EINVAL; |
| 192 | } | 174 | } |
| 193 | 175 | ||
| 176 | s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(2)); | ||
| 194 | return 0; | 177 | return 0; |
| 195 | } | 178 | } |
| 196 | 179 | ||
| @@ -264,24 +247,12 @@ EXPORT_SYMBOL(s3c64xx_device_pcm1); | |||
| 264 | 247 | ||
| 265 | static int s3c64xx_ac97_cfg_gpd(struct platform_device *pdev) | 248 | static int s3c64xx_ac97_cfg_gpd(struct platform_device *pdev) |
| 266 | { | 249 | { |
| 267 | s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_AC97_BITCLK); | 250 | return s3c_gpio_cfgpin_range(S3C64XX_GPD(0), 5, S3C_GPIO_SFN(4)); |
| 268 | s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_AC97_nRESET); | ||
| 269 | s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_AC97_SYNC); | ||
| 270 | s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_AC97_SDI); | ||
| 271 | s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_AC97_SDO); | ||
| 272 | |||
| 273 | return 0; | ||
| 274 | } | 251 | } |
| 275 | 252 | ||
| 276 | static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev) | 253 | static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev) |
| 277 | { | 254 | { |
| 278 | s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_AC97_BITCLK); | 255 | return s3c_gpio_cfgpin_range(S3C64XX_GPE(0), 5, S3C_GPIO_SFN(4)); |
| 279 | s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_AC97_nRESET); | ||
| 280 | s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_AC97_SYNC); | ||
| 281 | s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_AC97_SDI); | ||
| 282 | s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_AC97_SDO); | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | } | 256 | } |
| 286 | 257 | ||
| 287 | static struct resource s3c64xx_ac97_resource[] = { | 258 | static struct resource s3c64xx_ac97_resource[] = { |
diff --git a/arch/arm/mach-s3c64xx/gpiolib.c b/arch/arm/mach-s3c64xx/gpiolib.c index 300dee4a667b..fd99a82e82c4 100644 --- a/arch/arm/mach-s3c64xx/gpiolib.c +++ b/arch/arm/mach-s3c64xx/gpiolib.c | |||
| @@ -195,11 +195,6 @@ static struct s3c_gpio_cfg gpio_2bit_cfg_eint11 = { | |||
| 195 | .get_pull = s3c_gpio_getpull_updown, | 195 | .get_pull = s3c_gpio_getpull_updown, |
| 196 | }; | 196 | }; |
| 197 | 197 | ||
| 198 | int s3c64xx_gpio2int_gpn(struct gpio_chip *chip, unsigned pin) | ||
| 199 | { | ||
| 200 | return IRQ_EINT(0) + pin; | ||
| 201 | } | ||
| 202 | |||
| 203 | static struct s3c_gpio_chip gpio_2bit[] = { | 198 | static struct s3c_gpio_chip gpio_2bit[] = { |
| 204 | { | 199 | { |
| 205 | .base = S3C64XX_GPF_BASE, | 200 | .base = S3C64XX_GPF_BASE, |
| @@ -227,12 +222,13 @@ static struct s3c_gpio_chip gpio_2bit[] = { | |||
| 227 | }, | 222 | }, |
| 228 | }, { | 223 | }, { |
| 229 | .base = S3C64XX_GPN_BASE, | 224 | .base = S3C64XX_GPN_BASE, |
| 225 | .irq_base = IRQ_EINT(0), | ||
| 230 | .config = &gpio_2bit_cfg_eint10, | 226 | .config = &gpio_2bit_cfg_eint10, |
| 231 | .chip = { | 227 | .chip = { |
| 232 | .base = S3C64XX_GPN(0), | 228 | .base = S3C64XX_GPN(0), |
| 233 | .ngpio = S3C64XX_GPIO_N_NR, | 229 | .ngpio = S3C64XX_GPIO_N_NR, |
| 234 | .label = "GPN", | 230 | .label = "GPN", |
| 235 | .to_irq = s3c64xx_gpio2int_gpn, | 231 | .to_irq = samsung_gpiolib_to_irq, |
| 236 | }, | 232 | }, |
| 237 | }, { | 233 | }, { |
| 238 | .base = S3C64XX_GPO_BASE, | 234 | .base = S3C64XX_GPO_BASE, |
diff --git a/arch/arm/mach-s3c64xx/include/mach/vmalloc.h b/arch/arm/mach-s3c64xx/include/mach/vmalloc.h index bc0e91389864..23f75e556a30 100644 --- a/arch/arm/mach-s3c64xx/include/mach/vmalloc.h +++ b/arch/arm/mach-s3c64xx/include/mach/vmalloc.h | |||
| @@ -15,6 +15,6 @@ | |||
| 15 | #ifndef __ASM_ARCH_VMALLOC_H | 15 | #ifndef __ASM_ARCH_VMALLOC_H |
| 16 | #define __ASM_ARCH_VMALLOC_H | 16 | #define __ASM_ARCH_VMALLOC_H |
| 17 | 17 | ||
| 18 | #define VMALLOC_END 0xE0000000UL | 18 | #define VMALLOC_END 0xF6000000UL |
| 19 | 19 | ||
| 20 | #endif /* __ASM_ARCH_VMALLOC_H */ | 20 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c new file mode 100644 index 000000000000..249c62956471 --- /dev/null +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c | |||
| @@ -0,0 +1,357 @@ | |||
| 1 | /* linux/arch/arm/mach-s3c64xx/mach-mini6410.c | ||
| 2 | * | ||
| 3 | * Copyright 2010 Darius Augulis <augulis.darius@gmail.com> | ||
| 4 | * Copyright 2008 Openmoko, Inc. | ||
| 5 | * Copyright 2008 Simtec Electronics | ||
| 6 | * Ben Dooks <ben@simtec.co.uk> | ||
| 7 | * http://armlinux.simtec.co.uk/ | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/fb.h> | ||
| 18 | #include <linux/gpio.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/list.h> | ||
| 21 | #include <linux/dm9000.h> | ||
| 22 | #include <linux/mtd/mtd.h> | ||
| 23 | #include <linux/mtd/partitions.h> | ||
| 24 | #include <linux/serial_core.h> | ||
| 25 | #include <linux/types.h> | ||
| 26 | |||
| 27 | #include <asm/mach-types.h> | ||
| 28 | #include <asm/mach/arch.h> | ||
| 29 | #include <asm/mach/map.h> | ||
| 30 | |||
| 31 | #include <mach/map.h> | ||
| 32 | #include <mach/regs-fb.h> | ||
| 33 | #include <mach/regs-gpio.h> | ||
| 34 | #include <mach/regs-modem.h> | ||
| 35 | #include <mach/regs-srom.h> | ||
| 36 | #include <mach/s3c6410.h> | ||
| 37 | |||
| 38 | #include <plat/adc.h> | ||
| 39 | #include <plat/cpu.h> | ||
| 40 | #include <plat/devs.h> | ||
| 41 | #include <plat/fb.h> | ||
| 42 | #include <plat/nand.h> | ||
| 43 | #include <plat/regs-serial.h> | ||
| 44 | #include <plat/ts.h> | ||
| 45 | |||
| 46 | #include <video/platform_lcd.h> | ||
| 47 | |||
| 48 | #define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK) | ||
| 49 | #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) | ||
| 50 | #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) | ||
| 51 | |||
| 52 | static struct s3c2410_uartcfg mini6410_uartcfgs[] __initdata = { | ||
| 53 | [0] = { | ||
| 54 | .hwport = 0, | ||
| 55 | .flags = 0, | ||
| 56 | .ucon = UCON, | ||
| 57 | .ulcon = ULCON, | ||
| 58 | .ufcon = UFCON, | ||
| 59 | }, | ||
| 60 | [1] = { | ||
| 61 | .hwport = 1, | ||
| 62 | .flags = 0, | ||
| 63 | .ucon = UCON, | ||
| 64 | .ulcon = ULCON, | ||
| 65 | .ufcon = UFCON, | ||
| 66 | }, | ||
| 67 | [2] = { | ||
| 68 | .hwport = 2, | ||
| 69 | .flags = 0, | ||
| 70 | .ucon = UCON, | ||
| 71 | .ulcon = ULCON, | ||
| 72 | .ufcon = UFCON, | ||
| 73 | }, | ||
| 74 | [3] = { | ||
| 75 | .hwport = 3, | ||
| 76 | .flags = 0, | ||
| 77 | .ucon = UCON, | ||
| 78 | .ulcon = ULCON, | ||
| 79 | .ufcon = UFCON, | ||
| 80 | }, | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* DM9000AEP 10/100 ethernet controller */ | ||
| 84 | |||
| 85 | static struct resource mini6410_dm9k_resource[] = { | ||
| 86 | [0] = { | ||
| 87 | .start = S3C64XX_PA_XM0CSN1, | ||
| 88 | .end = S3C64XX_PA_XM0CSN1 + 1, | ||
| 89 | .flags = IORESOURCE_MEM | ||
| 90 | }, | ||
| 91 | [1] = { | ||
| 92 | .start = S3C64XX_PA_XM0CSN1 + 4, | ||
| 93 | .end = S3C64XX_PA_XM0CSN1 + 5, | ||
| 94 | .flags = IORESOURCE_MEM | ||
| 95 | }, | ||
| 96 | [2] = { | ||
| 97 | .start = S3C_EINT(7), | ||
| 98 | .end = S3C_EINT(7), | ||
| 99 | .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | ||
| 100 | } | ||
| 101 | }; | ||
| 102 | |||
| 103 | static struct dm9000_plat_data mini6410_dm9k_pdata = { | ||
| 104 | .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), | ||
| 105 | }; | ||
| 106 | |||
| 107 | static struct platform_device mini6410_device_eth = { | ||
| 108 | .name = "dm9000", | ||
| 109 | .id = -1, | ||
| 110 | .num_resources = ARRAY_SIZE(mini6410_dm9k_resource), | ||
| 111 | .resource = mini6410_dm9k_resource, | ||
| 112 | .dev = { | ||
| 113 | .platform_data = &mini6410_dm9k_pdata, | ||
| 114 | }, | ||
| 115 | }; | ||
| 116 | |||
| 117 | static struct mtd_partition mini6410_nand_part[] = { | ||
| 118 | [0] = { | ||
| 119 | .name = "uboot", | ||
| 120 | .size = SZ_1M, | ||
| 121 | .offset = 0, | ||
| 122 | }, | ||
| 123 | [1] = { | ||
| 124 | .name = "kernel", | ||
| 125 | .size = SZ_2M, | ||
| 126 | .offset = SZ_1M, | ||
| 127 | }, | ||
| 128 | [2] = { | ||
| 129 | .name = "rootfs", | ||
| 130 | .size = MTDPART_SIZ_FULL, | ||
| 131 | .offset = SZ_1M + SZ_2M, | ||
| 132 | }, | ||
| 133 | }; | ||
| 134 | |||
| 135 | static struct s3c2410_nand_set mini6410_nand_sets[] = { | ||
| 136 | [0] = { | ||
| 137 | .name = "nand", | ||
| 138 | .nr_chips = 1, | ||
| 139 | .nr_partitions = ARRAY_SIZE(mini6410_nand_part), | ||
| 140 | .partitions = mini6410_nand_part, | ||
| 141 | }, | ||
| 142 | }; | ||
| 143 | |||
| 144 | static struct s3c2410_platform_nand mini6410_nand_info = { | ||
| 145 | .tacls = 25, | ||
| 146 | .twrph0 = 55, | ||
| 147 | .twrph1 = 40, | ||
| 148 | .nr_sets = ARRAY_SIZE(mini6410_nand_sets), | ||
| 149 | .sets = mini6410_nand_sets, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static struct s3c_fb_pd_win mini6410_fb_win[] = { | ||
| 153 | { | ||
| 154 | .win_mode = { /* 4.3" 480x272 */ | ||
| 155 | .left_margin = 3, | ||
| 156 | .right_margin = 2, | ||
| 157 | .upper_margin = 1, | ||
| 158 | .lower_margin = 1, | ||
| 159 | .hsync_len = 40, | ||
| 160 | .vsync_len = 1, | ||
| 161 | .xres = 480, | ||
| 162 | .yres = 272, | ||
| 163 | }, | ||
| 164 | .max_bpp = 32, | ||
| 165 | .default_bpp = 16, | ||
| 166 | }, { | ||
| 167 | .win_mode = { /* 7.0" 800x480 */ | ||
| 168 | .left_margin = 8, | ||
| 169 | .right_margin = 13, | ||
| 170 | .upper_margin = 7, | ||
| 171 | .lower_margin = 5, | ||
| 172 | .hsync_len = 3, | ||
| 173 | .vsync_len = 1, | ||
| 174 | .xres = 800, | ||
| 175 | .yres = 480, | ||
| 176 | }, | ||
| 177 | .max_bpp = 32, | ||
| 178 | .default_bpp = 16, | ||
| 179 | }, | ||
| 180 | }; | ||
| 181 | |||
| 182 | static struct s3c_fb_platdata mini6410_lcd_pdata __initdata = { | ||
| 183 | .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, | ||
| 184 | .win[0] = &mini6410_fb_win[0], | ||
| 185 | .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, | ||
| 186 | .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, | ||
| 187 | }; | ||
| 188 | |||
| 189 | static void mini6410_lcd_power_set(struct plat_lcd_data *pd, | ||
| 190 | unsigned int power) | ||
| 191 | { | ||
| 192 | if (power) | ||
| 193 | gpio_direction_output(S3C64XX_GPE(0), 1); | ||
| 194 | else | ||
| 195 | gpio_direction_output(S3C64XX_GPE(0), 0); | ||
| 196 | } | ||
| 197 | |||
| 198 | static struct plat_lcd_data mini6410_lcd_power_data = { | ||
| 199 | .set_power = mini6410_lcd_power_set, | ||
| 200 | }; | ||
| 201 | |||
| 202 | static struct platform_device mini6410_lcd_powerdev = { | ||
| 203 | .name = "platform-lcd", | ||
| 204 | .dev.parent = &s3c_device_fb.dev, | ||
| 205 | .dev.platform_data = &mini6410_lcd_power_data, | ||
| 206 | }; | ||
| 207 | |||
| 208 | static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = { | ||
| 209 | .delay = 10000, | ||
| 210 | .presc = 49, | ||
| 211 | .oversampling_shift = 2, | ||
| 212 | }; | ||
| 213 | |||
| 214 | static struct platform_device *mini6410_devices[] __initdata = { | ||
| 215 | &mini6410_device_eth, | ||
| 216 | &s3c_device_hsmmc0, | ||
| 217 | &s3c_device_hsmmc1, | ||
| 218 | &s3c_device_ohci, | ||
| 219 | &s3c_device_nand, | ||
| 220 | &s3c_device_fb, | ||
| 221 | &mini6410_lcd_powerdev, | ||
| 222 | &s3c_device_adc, | ||
| 223 | &s3c_device_ts, | ||
| 224 | }; | ||
| 225 | |||
| 226 | static void __init mini6410_map_io(void) | ||
| 227 | { | ||
| 228 | u32 tmp; | ||
| 229 | |||
| 230 | s3c64xx_init_io(NULL, 0); | ||
| 231 | s3c24xx_init_clocks(12000000); | ||
| 232 | s3c24xx_init_uarts(mini6410_uartcfgs, ARRAY_SIZE(mini6410_uartcfgs)); | ||
| 233 | |||
| 234 | /* set the LCD type */ | ||
| 235 | tmp = __raw_readl(S3C64XX_SPCON); | ||
| 236 | tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; | ||
| 237 | tmp |= S3C64XX_SPCON_LCD_SEL_RGB; | ||
| 238 | __raw_writel(tmp, S3C64XX_SPCON); | ||
| 239 | |||
| 240 | /* remove the LCD bypass */ | ||
| 241 | tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); | ||
| 242 | tmp &= ~MIFPCON_LCD_BYPASS; | ||
| 243 | __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); | ||
| 244 | } | ||
| 245 | |||
| 246 | /* | ||
| 247 | * mini6410_features string | ||
| 248 | * | ||
| 249 | * 0-9 LCD configuration | ||
| 250 | * | ||
| 251 | */ | ||
| 252 | static char mini6410_features_str[12] __initdata = "0"; | ||
| 253 | |||
| 254 | static int __init mini6410_features_setup(char *str) | ||
| 255 | { | ||
| 256 | if (str) | ||
| 257 | strlcpy(mini6410_features_str, str, | ||
| 258 | sizeof(mini6410_features_str)); | ||
| 259 | return 1; | ||
| 260 | } | ||
| 261 | |||
| 262 | __setup("mini6410=", mini6410_features_setup); | ||
| 263 | |||
| 264 | #define FEATURE_SCREEN (1 << 0) | ||
| 265 | |||
| 266 | struct mini6410_features_t { | ||
| 267 | int done; | ||
| 268 | int lcd_index; | ||
| 269 | }; | ||
| 270 | |||
| 271 | static void mini6410_parse_features( | ||
| 272 | struct mini6410_features_t *features, | ||
| 273 | const char *features_str) | ||
| 274 | { | ||
| 275 | const char *fp = features_str; | ||
| 276 | |||
| 277 | features->done = 0; | ||
| 278 | features->lcd_index = 0; | ||
| 279 | |||
| 280 | while (*fp) { | ||
| 281 | char f = *fp++; | ||
| 282 | |||
| 283 | switch (f) { | ||
| 284 | case '0'...'9': /* tft screen */ | ||
| 285 | if (features->done & FEATURE_SCREEN) { | ||
| 286 | printk(KERN_INFO "MINI6410: '%c' ignored, " | ||
| 287 | "screen type already set\n", f); | ||
| 288 | } else { | ||
| 289 | int li = f - '0'; | ||
| 290 | if (li >= ARRAY_SIZE(mini6410_fb_win)) | ||
| 291 | printk(KERN_INFO "MINI6410: '%c' out " | ||
| 292 | "of range LCD mode\n", f); | ||
| 293 | else { | ||
| 294 | features->lcd_index = li; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | features->done |= FEATURE_SCREEN; | ||
| 298 | break; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | static void __init mini6410_machine_init(void) | ||
| 304 | { | ||
| 305 | u32 cs1; | ||
| 306 | struct mini6410_features_t features = { 0 }; | ||
| 307 | |||
| 308 | printk(KERN_INFO "MINI6410: Option string mini6410=%s\n", | ||
| 309 | mini6410_features_str); | ||
| 310 | |||
| 311 | /* Parse the feature string */ | ||
| 312 | mini6410_parse_features(&features, mini6410_features_str); | ||
| 313 | |||
| 314 | mini6410_lcd_pdata.win[0] = &mini6410_fb_win[features.lcd_index]; | ||
| 315 | |||
| 316 | printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n", | ||
| 317 | mini6410_lcd_pdata.win[0]->win_mode.xres, | ||
| 318 | mini6410_lcd_pdata.win[0]->win_mode.yres); | ||
| 319 | |||
| 320 | s3c_nand_set_platdata(&mini6410_nand_info); | ||
| 321 | s3c_fb_set_platdata(&mini6410_lcd_pdata); | ||
| 322 | s3c24xx_ts_set_platdata(&s3c_ts_platform); | ||
| 323 | |||
| 324 | /* configure nCS1 width to 16 bits */ | ||
| 325 | |||
| 326 | cs1 = __raw_readl(S3C64XX_SROM_BW) & | ||
| 327 | ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT); | ||
| 328 | cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) | | ||
| 329 | (1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) | | ||
| 330 | (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) << | ||
| 331 | S3C64XX_SROM_BW__NCS1__SHIFT; | ||
| 332 | __raw_writel(cs1, S3C64XX_SROM_BW); | ||
| 333 | |||
| 334 | /* set timing for nCS1 suitable for ethernet chip */ | ||
| 335 | |||
| 336 | __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) | | ||
| 337 | (6 << S3C64XX_SROM_BCX__TACP__SHIFT) | | ||
| 338 | (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) | | ||
| 339 | (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) | | ||
| 340 | (13 << S3C64XX_SROM_BCX__TACC__SHIFT) | | ||
| 341 | (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | | ||
| 342 | (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); | ||
| 343 | |||
| 344 | gpio_request(S3C64XX_GPF(15), "LCD power"); | ||
| 345 | gpio_request(S3C64XX_GPE(0), "LCD power"); | ||
| 346 | |||
| 347 | platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices)); | ||
| 348 | } | ||
| 349 | |||
| 350 | MACHINE_START(MINI6410, "MINI6410") | ||
| 351 | /* Maintainer: Darius Augulis <augulis.darius@gmail.com> */ | ||
| 352 | .boot_params = S3C64XX_PA_SDRAM + 0x100, | ||
| 353 | .init_irq = s3c6410_init_irq, | ||
| 354 | .map_io = mini6410_map_io, | ||
| 355 | .init_machine = mini6410_machine_init, | ||
| 356 | .timer = &s3c24xx_timer, | ||
| 357 | MACHINE_END | ||
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index 4b4475da8ec6..f9ef9b5c5f5a 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c | |||
| @@ -12,23 +12,39 @@ | |||
| 12 | * | 12 | * |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/types.h> | ||
| 17 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
| 17 | #include <linux/fb.h> | ||
| 18 | #include <linux/gpio.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 18 | #include <linux/list.h> | 20 | #include <linux/list.h> |
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/dm9000.h> | 21 | #include <linux/dm9000.h> |
| 21 | #include <linux/serial_core.h> | 22 | #include <linux/mtd/mtd.h> |
| 23 | #include <linux/mtd/partitions.h> | ||
| 22 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/serial_core.h> | ||
| 26 | #include <linux/types.h> | ||
| 27 | |||
| 23 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
| 24 | #include <asm/mach/arch.h> | 29 | #include <asm/mach/arch.h> |
| 25 | #include <asm/mach/map.h> | 30 | #include <asm/mach/map.h> |
| 31 | |||
| 26 | #include <mach/map.h> | 32 | #include <mach/map.h> |
| 27 | #include <mach/s3c6410.h> | 33 | #include <mach/regs-fb.h> |
| 34 | #include <mach/regs-gpio.h> | ||
| 35 | #include <mach/regs-modem.h> | ||
| 28 | #include <mach/regs-srom.h> | 36 | #include <mach/regs-srom.h> |
| 37 | #include <mach/s3c6410.h> | ||
| 38 | |||
| 39 | #include <plat/adc.h> | ||
| 29 | #include <plat/cpu.h> | 40 | #include <plat/cpu.h> |
| 30 | #include <plat/devs.h> | 41 | #include <plat/devs.h> |
| 42 | #include <plat/fb.h> | ||
| 43 | #include <plat/nand.h> | ||
| 31 | #include <plat/regs-serial.h> | 44 | #include <plat/regs-serial.h> |
| 45 | #include <plat/ts.h> | ||
| 46 | |||
| 47 | #include <video/platform_lcd.h> | ||
| 32 | 48 | ||
| 33 | #define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK) | 49 | #define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK) |
| 34 | #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) | 50 | #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) |
| @@ -99,22 +115,192 @@ static struct platform_device real6410_device_eth = { | |||
| 99 | }, | 115 | }, |
| 100 | }; | 116 | }; |
| 101 | 117 | ||
| 118 | static struct s3c_fb_pd_win real6410_fb_win[] = { | ||
| 119 | { | ||
| 120 | .win_mode = { /* 4.3" 480x272 */ | ||
| 121 | .left_margin = 3, | ||
| 122 | .right_margin = 2, | ||
| 123 | .upper_margin = 1, | ||
| 124 | .lower_margin = 1, | ||
| 125 | .hsync_len = 40, | ||
| 126 | .vsync_len = 1, | ||
| 127 | .xres = 480, | ||
| 128 | .yres = 272, | ||
| 129 | }, | ||
| 130 | .max_bpp = 32, | ||
| 131 | .default_bpp = 16, | ||
| 132 | }, { | ||
| 133 | .win_mode = { /* 7.0" 800x480 */ | ||
| 134 | .left_margin = 8, | ||
| 135 | .right_margin = 13, | ||
| 136 | .upper_margin = 7, | ||
| 137 | .lower_margin = 5, | ||
| 138 | .hsync_len = 3, | ||
| 139 | .vsync_len = 1, | ||
| 140 | .xres = 800, | ||
| 141 | .yres = 480, | ||
| 142 | }, | ||
| 143 | .max_bpp = 32, | ||
| 144 | .default_bpp = 16, | ||
| 145 | }, | ||
| 146 | }; | ||
| 147 | |||
| 148 | static struct s3c_fb_platdata real6410_lcd_pdata __initdata = { | ||
| 149 | .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, | ||
| 150 | .win[0] = &real6410_fb_win[0], | ||
| 151 | .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, | ||
| 152 | .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, | ||
| 153 | }; | ||
| 154 | |||
| 155 | static struct mtd_partition real6410_nand_part[] = { | ||
| 156 | [0] = { | ||
| 157 | .name = "uboot", | ||
| 158 | .size = SZ_1M, | ||
| 159 | .offset = 0, | ||
| 160 | }, | ||
| 161 | [1] = { | ||
| 162 | .name = "kernel", | ||
| 163 | .size = SZ_2M, | ||
| 164 | .offset = SZ_1M, | ||
| 165 | }, | ||
| 166 | [2] = { | ||
| 167 | .name = "rootfs", | ||
| 168 | .size = MTDPART_SIZ_FULL, | ||
| 169 | .offset = SZ_1M + SZ_2M, | ||
| 170 | }, | ||
| 171 | }; | ||
| 172 | |||
| 173 | static struct s3c2410_nand_set real6410_nand_sets[] = { | ||
| 174 | [0] = { | ||
| 175 | .name = "nand", | ||
| 176 | .nr_chips = 1, | ||
| 177 | .nr_partitions = ARRAY_SIZE(real6410_nand_part), | ||
| 178 | .partitions = real6410_nand_part, | ||
| 179 | }, | ||
| 180 | }; | ||
| 181 | |||
| 182 | static struct s3c2410_platform_nand real6410_nand_info = { | ||
| 183 | .tacls = 25, | ||
| 184 | .twrph0 = 55, | ||
| 185 | .twrph1 = 40, | ||
| 186 | .nr_sets = ARRAY_SIZE(real6410_nand_sets), | ||
| 187 | .sets = real6410_nand_sets, | ||
| 188 | }; | ||
| 189 | |||
| 102 | static struct platform_device *real6410_devices[] __initdata = { | 190 | static struct platform_device *real6410_devices[] __initdata = { |
| 103 | &real6410_device_eth, | 191 | &real6410_device_eth, |
| 104 | &s3c_device_hsmmc0, | 192 | &s3c_device_hsmmc0, |
| 105 | &s3c_device_hsmmc1, | 193 | &s3c_device_hsmmc1, |
| 194 | &s3c_device_fb, | ||
| 195 | &s3c_device_nand, | ||
| 196 | &s3c_device_adc, | ||
| 197 | &s3c_device_ts, | ||
| 198 | &s3c_device_ohci, | ||
| 199 | }; | ||
| 200 | |||
| 201 | static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = { | ||
| 202 | .delay = 10000, | ||
| 203 | .presc = 49, | ||
| 204 | .oversampling_shift = 2, | ||
| 106 | }; | 205 | }; |
| 107 | 206 | ||
| 108 | static void __init real6410_map_io(void) | 207 | static void __init real6410_map_io(void) |
| 109 | { | 208 | { |
| 209 | u32 tmp; | ||
| 210 | |||
| 110 | s3c64xx_init_io(NULL, 0); | 211 | s3c64xx_init_io(NULL, 0); |
| 111 | s3c24xx_init_clocks(12000000); | 212 | s3c24xx_init_clocks(12000000); |
| 112 | s3c24xx_init_uarts(real6410_uartcfgs, ARRAY_SIZE(real6410_uartcfgs)); | 213 | s3c24xx_init_uarts(real6410_uartcfgs, ARRAY_SIZE(real6410_uartcfgs)); |
| 214 | |||
| 215 | /* set the LCD type */ | ||
| 216 | tmp = __raw_readl(S3C64XX_SPCON); | ||
| 217 | tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; | ||
| 218 | tmp |= S3C64XX_SPCON_LCD_SEL_RGB; | ||
| 219 | __raw_writel(tmp, S3C64XX_SPCON); | ||
| 220 | |||
| 221 | /* remove the LCD bypass */ | ||
| 222 | tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); | ||
| 223 | tmp &= ~MIFPCON_LCD_BYPASS; | ||
| 224 | __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); | ||
| 225 | } | ||
| 226 | |||
| 227 | /* | ||
| 228 | * real6410_features string | ||
| 229 | * | ||
| 230 | * 0-9 LCD configuration | ||
| 231 | * | ||
| 232 | */ | ||
| 233 | static char real6410_features_str[12] __initdata = "0"; | ||
| 234 | |||
| 235 | static int __init real6410_features_setup(char *str) | ||
| 236 | { | ||
| 237 | if (str) | ||
| 238 | strlcpy(real6410_features_str, str, | ||
| 239 | sizeof(real6410_features_str)); | ||
| 240 | return 1; | ||
| 241 | } | ||
| 242 | |||
| 243 | __setup("real6410=", real6410_features_setup); | ||
| 244 | |||
| 245 | #define FEATURE_SCREEN (1 << 0) | ||
| 246 | |||
| 247 | struct real6410_features_t { | ||
| 248 | int done; | ||
| 249 | int lcd_index; | ||
| 250 | }; | ||
| 251 | |||
| 252 | static void real6410_parse_features( | ||
| 253 | struct real6410_features_t *features, | ||
| 254 | const char *features_str) | ||
| 255 | { | ||
| 256 | const char *fp = features_str; | ||
| 257 | |||
| 258 | features->done = 0; | ||
| 259 | features->lcd_index = 0; | ||
| 260 | |||
| 261 | while (*fp) { | ||
| 262 | char f = *fp++; | ||
| 263 | |||
| 264 | switch (f) { | ||
| 265 | case '0'...'9': /* tft screen */ | ||
| 266 | if (features->done & FEATURE_SCREEN) { | ||
| 267 | printk(KERN_INFO "REAL6410: '%c' ignored, " | ||
| 268 | "screen type already set\n", f); | ||
| 269 | } else { | ||
| 270 | int li = f - '0'; | ||
| 271 | if (li >= ARRAY_SIZE(real6410_fb_win)) | ||
| 272 | printk(KERN_INFO "REAL6410: '%c' out " | ||
| 273 | "of range LCD mode\n", f); | ||
| 274 | else { | ||
| 275 | features->lcd_index = li; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | features->done |= FEATURE_SCREEN; | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | } | ||
| 113 | } | 282 | } |
| 114 | 283 | ||
| 115 | static void __init real6410_machine_init(void) | 284 | static void __init real6410_machine_init(void) |
| 116 | { | 285 | { |
| 117 | u32 cs1; | 286 | u32 cs1; |
| 287 | struct real6410_features_t features = { 0 }; | ||
| 288 | |||
| 289 | printk(KERN_INFO "REAL6410: Option string real6410=%s\n", | ||
| 290 | real6410_features_str); | ||
| 291 | |||
| 292 | /* Parse the feature string */ | ||
| 293 | real6410_parse_features(&features, real6410_features_str); | ||
| 294 | |||
| 295 | real6410_lcd_pdata.win[0] = &real6410_fb_win[features.lcd_index]; | ||
| 296 | |||
| 297 | printk(KERN_INFO "REAL6410: selected LCD display is %dx%d\n", | ||
| 298 | real6410_lcd_pdata.win[0]->win_mode.xres, | ||
| 299 | real6410_lcd_pdata.win[0]->win_mode.yres); | ||
| 300 | |||
| 301 | s3c_fb_set_platdata(&real6410_lcd_pdata); | ||
| 302 | s3c_nand_set_platdata(&real6410_nand_info); | ||
| 303 | s3c24xx_ts_set_platdata(&s3c_ts_platform); | ||
| 118 | 304 | ||
| 119 | /* configure nCS1 width to 16 bits */ | 305 | /* configure nCS1 width to 16 bits */ |
| 120 | 306 | ||
| @@ -136,6 +322,8 @@ static void __init real6410_machine_init(void) | |||
| 136 | (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | | 322 | (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | |
| 137 | (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); | 323 | (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); |
| 138 | 324 | ||
| 325 | gpio_request(S3C64XX_GPF(15), "LCD power"); | ||
| 326 | |||
| 139 | platform_add_devices(real6410_devices, ARRAY_SIZE(real6410_devices)); | 327 | platform_add_devices(real6410_devices, ARRAY_SIZE(real6410_devices)); |
| 140 | } | 328 | } |
| 141 | 329 | ||
diff --git a/arch/arm/mach-s3c64xx/setup-fb-24bpp.c b/arch/arm/mach-s3c64xx/setup-fb-24bpp.c index 000736877df2..8f3091182f9c 100644 --- a/arch/arm/mach-s3c64xx/setup-fb-24bpp.c +++ b/arch/arm/mach-s3c64xx/setup-fb-24bpp.c | |||
| @@ -23,15 +23,6 @@ | |||
| 23 | 23 | ||
| 24 | extern void s3c64xx_fb_gpio_setup_24bpp(void) | 24 | extern void s3c64xx_fb_gpio_setup_24bpp(void) |
| 25 | { | 25 | { |
| 26 | unsigned int gpio; | 26 | s3c_gpio_cfgrange_nopull(S3C64XX_GPI(0), 16, S3C_GPIO_SFN(2)); |
| 27 | 27 | s3c_gpio_cfgrange_nopull(S3C64XX_GPJ(0), 12, S3C_GPIO_SFN(2)); | |
| 28 | for (gpio = S3C64XX_GPI(0); gpio <= S3C64XX_GPI(15); gpio++) { | ||
| 29 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 30 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 31 | } | ||
| 32 | |||
| 33 | for (gpio = S3C64XX_GPJ(0); gpio <= S3C64XX_GPJ(11); gpio++) { | ||
| 34 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 35 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 36 | } | ||
| 37 | } | 28 | } |
diff --git a/arch/arm/mach-s3c64xx/setup-ide.c b/arch/arm/mach-s3c64xx/setup-ide.c index c12c315f33bc..41b425602d88 100644 --- a/arch/arm/mach-s3c64xx/setup-ide.c +++ b/arch/arm/mach-s3c64xx/setup-ide.c | |||
| @@ -17,11 +17,11 @@ | |||
| 17 | #include <mach/map.h> | 17 | #include <mach/map.h> |
| 18 | #include <mach/regs-clock.h> | 18 | #include <mach/regs-clock.h> |
| 19 | #include <plat/gpio-cfg.h> | 19 | #include <plat/gpio-cfg.h> |
| 20 | #include <plat/ata.h> | ||
| 20 | 21 | ||
| 21 | void s3c64xx_ide_setup_gpio(void) | 22 | void s3c64xx_ide_setup_gpio(void) |
| 22 | { | 23 | { |
| 23 | u32 reg; | 24 | u32 reg; |
| 24 | u32 gpio = 0; | ||
| 25 | 25 | ||
| 26 | reg = readl(S3C_MEM_SYS_CFG) & (~0x3f); | 26 | reg = readl(S3C_MEM_SYS_CFG) & (~0x3f); |
| 27 | 27 | ||
| @@ -32,15 +32,12 @@ void s3c64xx_ide_setup_gpio(void) | |||
| 32 | s3c_gpio_cfgpin(S3C64XX_GPB(4), S3C_GPIO_SFN(4)); | 32 | s3c_gpio_cfgpin(S3C64XX_GPB(4), S3C_GPIO_SFN(4)); |
| 33 | 33 | ||
| 34 | /* Set XhiDATA[15:0] pins as CF Data[15:0] */ | 34 | /* Set XhiDATA[15:0] pins as CF Data[15:0] */ |
| 35 | for (gpio = S3C64XX_GPK(0); gpio <= S3C64XX_GPK(15); gpio++) | 35 | s3c_gpio_cfgpin_range(S3C64XX_GPK(0), 16, S3C_GPIO_SFN(5)); |
| 36 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(5)); | ||
| 37 | 36 | ||
| 38 | /* Set XhiADDR[2:0] pins as CF ADDR[2:0] */ | 37 | /* Set XhiADDR[2:0] pins as CF ADDR[2:0] */ |
| 39 | for (gpio = S3C64XX_GPL(0); gpio <= S3C64XX_GPL(2); gpio++) | 38 | s3c_gpio_cfgpin_range(S3C64XX_GPL(0), 3, S3C_GPIO_SFN(6)); |
| 40 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(6)); | ||
| 41 | 39 | ||
| 42 | /* Set Xhi ctrl pins as CF ctrl pins(IORDY, IOWR, IORD, CE[0:1]) */ | 40 | /* Set Xhi ctrl pins as CF ctrl pins(IORDY, IOWR, IORD, CE[0:1]) */ |
| 43 | s3c_gpio_cfgpin(S3C64XX_GPM(5), S3C_GPIO_SFN(1)); | 41 | s3c_gpio_cfgpin(S3C64XX_GPM(5), S3C_GPIO_SFN(1)); |
| 44 | for (gpio = S3C64XX_GPM(0); gpio <= S3C64XX_GPM(4); gpio++) | 42 | s3c_gpio_cfgpin_range(S3C64XX_GPM(0), 5, S3C_GPIO_SFN(6)); |
| 45 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(6)); | ||
| 46 | } | 43 | } |
diff --git a/arch/arm/mach-s3c64xx/setup-keypad.c b/arch/arm/mach-s3c64xx/setup-keypad.c index abc34e4e1a93..f8ed0d22db70 100644 --- a/arch/arm/mach-s3c64xx/setup-keypad.c +++ b/arch/arm/mach-s3c64xx/setup-keypad.c | |||
| @@ -12,23 +12,13 @@ | |||
| 12 | 12 | ||
| 13 | #include <linux/gpio.h> | 13 | #include <linux/gpio.h> |
| 14 | #include <plat/gpio-cfg.h> | 14 | #include <plat/gpio-cfg.h> |
| 15 | #include <plat/keypad.h> | ||
| 15 | 16 | ||
| 16 | void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) | 17 | void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) |
| 17 | { | 18 | { |
| 18 | unsigned int gpio; | ||
| 19 | unsigned int end; | ||
| 20 | |||
| 21 | /* Set all the necessary GPK pins to special-function 3: KP_ROW[x] */ | 19 | /* Set all the necessary GPK pins to special-function 3: KP_ROW[x] */ |
| 22 | end = S3C64XX_GPK(8 + rows); | 20 | s3c_gpio_cfgrange_nopull(S3C64XX_GPK(8), 8 + rows, S3C_GPIO_SFN(3)); |
| 23 | for (gpio = S3C64XX_GPK(8); gpio < end; gpio++) { | ||
| 24 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 25 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 26 | } | ||
| 27 | 21 | ||
| 28 | /* Set all the necessary GPL pins to special-function 3: KP_COL[x] */ | 22 | /* Set all the necessary GPL pins to special-function 3: KP_COL[x] */ |
| 29 | end = S3C64XX_GPL(0 + cols); | 23 | s3c_gpio_cfgrange_nopull(S3C64XX_GPL(0), cols, S3C_GPIO_SFN(3)); |
| 30 | for (gpio = S3C64XX_GPL(0); gpio < end; gpio++) { | ||
| 31 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 32 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 33 | } | ||
| 34 | } | 24 | } |
diff --git a/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c b/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c index 322359591374..6eac071afae2 100644 --- a/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c +++ b/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c | |||
| @@ -24,16 +24,9 @@ | |||
| 24 | void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | 24 | void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) |
| 25 | { | 25 | { |
| 26 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 26 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 27 | unsigned int gpio; | ||
| 28 | unsigned int end; | ||
| 29 | 27 | ||
| 30 | end = S3C64XX_GPG(2 + width); | 28 | /* Set all the necessary GPG pins to special-function 2 */ |
| 31 | 29 | s3c_gpio_cfgrange_nopull(S3C64XX_GPG(0), 2 + width, S3C_GPIO_SFN(2)); | |
| 32 | /* Set all the necessary GPG pins to special-function 0 */ | ||
| 33 | for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) { | ||
| 34 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 35 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 36 | } | ||
| 37 | 30 | ||
| 38 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | 31 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { |
| 39 | s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); | 32 | s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); |
| @@ -44,16 +37,9 @@ void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | |||
| 44 | void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) | 37 | void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) |
| 45 | { | 38 | { |
| 46 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 39 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 47 | unsigned int gpio; | ||
| 48 | unsigned int end; | ||
| 49 | 40 | ||
| 50 | end = S3C64XX_GPH(2 + width); | 41 | /* Set all the necessary GPH pins to special-function 2 */ |
| 51 | 42 | s3c_gpio_cfgrange_nopull(S3C64XX_GPH(0), 2 + width, S3C_GPIO_SFN(2)); | |
| 52 | /* Set all the necessary GPG pins to special-function 0 */ | ||
| 53 | for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) { | ||
| 54 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 55 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 56 | } | ||
| 57 | 43 | ||
| 58 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | 44 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { |
| 59 | s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); | 45 | s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); |
| @@ -63,20 +49,9 @@ void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) | |||
| 63 | 49 | ||
| 64 | void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) | 50 | void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) |
| 65 | { | 51 | { |
| 66 | unsigned int gpio; | 52 | /* Set all the necessary GPH pins to special-function 3 */ |
| 67 | unsigned int end; | 53 | s3c_gpio_cfgrange_nopull(S3C64XX_GPH(6), width, S3C_GPIO_SFN(3)); |
| 68 | 54 | ||
| 69 | end = S3C64XX_GPH(6 + width); | 55 | /* Set all the necessary GPC pins to special-function 3 */ |
| 70 | 56 | s3c_gpio_cfgrange_nopull(S3C64XX_GPC(4), 2, S3C_GPIO_SFN(3)); | |
| 71 | /* Set all the necessary GPH pins to special-function 1 */ | ||
| 72 | for (gpio = S3C64XX_GPH(6); gpio < end; gpio++) { | ||
| 73 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 74 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 75 | } | ||
| 76 | |||
| 77 | /* Set all the necessary GPC pins to special-function 1 */ | ||
| 78 | for (gpio = S3C64XX_GPC(4); gpio < S3C64XX_GPC(6); gpio++) { | ||
| 79 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 80 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 81 | } | ||
| 82 | } | 57 | } |
diff --git a/arch/arm/mach-s5p6442/Kconfig b/arch/arm/mach-s5p6442/Kconfig index 0fda0a5df968..33569e4007c4 100644 --- a/arch/arm/mach-s5p6442/Kconfig +++ b/arch/arm/mach-s5p6442/Kconfig | |||
| @@ -11,7 +11,6 @@ if ARCH_S5P6442 | |||
| 11 | 11 | ||
| 12 | config CPU_S5P6442 | 12 | config CPU_S5P6442 |
| 13 | bool | 13 | bool |
| 14 | select PLAT_S5P | ||
| 15 | select S3C_PL330_DMA | 14 | select S3C_PL330_DMA |
| 16 | help | 15 | help |
| 17 | Enable S5P6442 CPU support | 16 | Enable S5P6442 CPU support |
diff --git a/arch/arm/mach-s5p6442/clock.c b/arch/arm/mach-s5p6442/clock.c index dcd20f17212a..16d6e7e61b50 100644 --- a/arch/arm/mach-s5p6442/clock.c +++ b/arch/arm/mach-s5p6442/clock.c | |||
| @@ -192,6 +192,11 @@ static struct clk clk_pclkd1 = { | |||
| 192 | .parent = &clk_hclkd1, | 192 | .parent = &clk_hclkd1, |
| 193 | }; | 193 | }; |
| 194 | 194 | ||
| 195 | int s5p6442_clk_ip0_ctrl(struct clk *clk, int enable) | ||
| 196 | { | ||
| 197 | return s5p_gatectrl(S5P_CLKGATE_IP0, clk, enable); | ||
| 198 | } | ||
| 199 | |||
| 195 | int s5p6442_clk_ip3_ctrl(struct clk *clk, int enable) | 200 | int s5p6442_clk_ip3_ctrl(struct clk *clk, int enable) |
| 196 | { | 201 | { |
| 197 | return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable); | 202 | return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable); |
| @@ -335,6 +340,16 @@ void __init_or_cpufreq s5p6442_setup_clocks(void) | |||
| 335 | clk_pclkd1.rate = pclkd1; | 340 | clk_pclkd1.rate = pclkd1; |
| 336 | } | 341 | } |
| 337 | 342 | ||
| 343 | static struct clk init_clocks_disable[] = { | ||
| 344 | { | ||
| 345 | .name = "pdma", | ||
| 346 | .id = -1, | ||
| 347 | .parent = &clk_pclkd1, | ||
| 348 | .enable = s5p6442_clk_ip0_ctrl, | ||
| 349 | .ctrlbit = (1 << 3), | ||
| 350 | }, | ||
| 351 | }; | ||
| 352 | |||
| 338 | static struct clk init_clocks[] = { | 353 | static struct clk init_clocks[] = { |
| 339 | { | 354 | { |
| 340 | .name = "systimer", | 355 | .name = "systimer", |
| @@ -393,10 +408,23 @@ static struct clk *clks[] __initdata = { | |||
| 393 | 408 | ||
| 394 | void __init s5p6442_register_clocks(void) | 409 | void __init s5p6442_register_clocks(void) |
| 395 | { | 410 | { |
| 411 | struct clk *clkptr; | ||
| 412 | int i, ret; | ||
| 413 | |||
| 396 | s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); | 414 | s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); |
| 397 | 415 | ||
| 398 | s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); | 416 | s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); |
| 399 | s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); | 417 | s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); |
| 400 | 418 | ||
| 419 | clkptr = init_clocks_disable; | ||
| 420 | for (i = 0; i < ARRAY_SIZE(init_clocks_disable); i++, clkptr++) { | ||
| 421 | ret = s3c24xx_register_clock(clkptr); | ||
| 422 | if (ret < 0) { | ||
| 423 | printk(KERN_ERR "Fail to register clock %s (%d)\n", | ||
| 424 | clkptr->name, ret); | ||
| 425 | } else | ||
| 426 | (clkptr->enable)(clkptr, 0); | ||
| 427 | } | ||
| 428 | |||
| 401 | s3c_pwmclk_init(); | 429 | s3c_pwmclk_init(); |
| 402 | } | 430 | } |
diff --git a/arch/arm/mach-s5p6442/dev-audio.c b/arch/arm/mach-s5p6442/dev-audio.c index 7a4e34720b7b..3462197ff352 100644 --- a/arch/arm/mach-s5p6442/dev-audio.c +++ b/arch/arm/mach-s5p6442/dev-audio.c | |||
| @@ -21,22 +21,16 @@ | |||
| 21 | 21 | ||
| 22 | static int s5p6442_cfg_i2s(struct platform_device *pdev) | 22 | static int s5p6442_cfg_i2s(struct platform_device *pdev) |
| 23 | { | 23 | { |
| 24 | unsigned int base; | ||
| 25 | |||
| 24 | /* configure GPIO for i2s port */ | 26 | /* configure GPIO for i2s port */ |
| 25 | switch (pdev->id) { | 27 | switch (pdev->id) { |
| 26 | case 1: | 28 | case 1: |
| 27 | s3c_gpio_cfgpin(S5P6442_GPC1(0), S3C_GPIO_SFN(2)); | 29 | base = S5P6442_GPC1(0); |
| 28 | s3c_gpio_cfgpin(S5P6442_GPC1(1), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_cfgpin(S5P6442_GPC1(2), S3C_GPIO_SFN(2)); | ||
| 30 | s3c_gpio_cfgpin(S5P6442_GPC1(3), S3C_GPIO_SFN(2)); | ||
| 31 | s3c_gpio_cfgpin(S5P6442_GPC1(4), S3C_GPIO_SFN(2)); | ||
| 32 | break; | 30 | break; |
| 33 | 31 | ||
| 34 | case -1: | 32 | case -1: |
| 35 | s3c_gpio_cfgpin(S5P6442_GPC0(0), S3C_GPIO_SFN(2)); | 33 | base = S5P6442_GPC0(0); |
| 36 | s3c_gpio_cfgpin(S5P6442_GPC0(1), S3C_GPIO_SFN(2)); | ||
| 37 | s3c_gpio_cfgpin(S5P6442_GPC0(2), S3C_GPIO_SFN(2)); | ||
| 38 | s3c_gpio_cfgpin(S5P6442_GPC0(3), S3C_GPIO_SFN(2)); | ||
| 39 | s3c_gpio_cfgpin(S5P6442_GPC0(4), S3C_GPIO_SFN(2)); | ||
| 40 | break; | 34 | break; |
| 41 | 35 | ||
| 42 | default: | 36 | default: |
| @@ -44,6 +38,7 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev) | |||
| 44 | return -EINVAL; | 38 | return -EINVAL; |
| 45 | } | 39 | } |
| 46 | 40 | ||
| 41 | s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(2)); | ||
| 47 | return 0; | 42 | return 0; |
| 48 | } | 43 | } |
| 49 | 44 | ||
| @@ -111,21 +106,15 @@ struct platform_device s5p6442_device_iis1 = { | |||
| 111 | 106 | ||
| 112 | static int s5p6442_pcm_cfg_gpio(struct platform_device *pdev) | 107 | static int s5p6442_pcm_cfg_gpio(struct platform_device *pdev) |
| 113 | { | 108 | { |
| 109 | unsigned int base; | ||
| 110 | |||
| 114 | switch (pdev->id) { | 111 | switch (pdev->id) { |
| 115 | case 0: | 112 | case 0: |
| 116 | s3c_gpio_cfgpin(S5P6442_GPC0(0), S3C_GPIO_SFN(3)); | 113 | base = S5P6442_GPC0(0); |
| 117 | s3c_gpio_cfgpin(S5P6442_GPC0(1), S3C_GPIO_SFN(3)); | ||
| 118 | s3c_gpio_cfgpin(S5P6442_GPC0(2), S3C_GPIO_SFN(3)); | ||
| 119 | s3c_gpio_cfgpin(S5P6442_GPC0(3), S3C_GPIO_SFN(3)); | ||
| 120 | s3c_gpio_cfgpin(S5P6442_GPC0(4), S3C_GPIO_SFN(3)); | ||
| 121 | break; | 114 | break; |
| 122 | 115 | ||
| 123 | case 1: | 116 | case 1: |
| 124 | s3c_gpio_cfgpin(S5P6442_GPC1(0), S3C_GPIO_SFN(3)); | 117 | base = S5P6442_GPC1(0); |
| 125 | s3c_gpio_cfgpin(S5P6442_GPC1(1), S3C_GPIO_SFN(3)); | ||
| 126 | s3c_gpio_cfgpin(S5P6442_GPC1(2), S3C_GPIO_SFN(3)); | ||
| 127 | s3c_gpio_cfgpin(S5P6442_GPC1(3), S3C_GPIO_SFN(3)); | ||
| 128 | s3c_gpio_cfgpin(S5P6442_GPC1(4), S3C_GPIO_SFN(3)); | ||
| 129 | break; | 118 | break; |
| 130 | 119 | ||
| 131 | default: | 120 | default: |
| @@ -133,6 +122,7 @@ static int s5p6442_pcm_cfg_gpio(struct platform_device *pdev) | |||
| 133 | return -EINVAL; | 122 | return -EINVAL; |
| 134 | } | 123 | } |
| 135 | 124 | ||
| 125 | s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(3)); | ||
| 136 | return 0; | 126 | return 0; |
| 137 | } | 127 | } |
| 138 | 128 | ||
diff --git a/arch/arm/mach-s5p6442/dev-spi.c b/arch/arm/mach-s5p6442/dev-spi.c index e894651a88bd..cce8c2470709 100644 --- a/arch/arm/mach-s5p6442/dev-spi.c +++ b/arch/arm/mach-s5p6442/dev-spi.c | |||
| @@ -38,11 +38,9 @@ static int s5p6442_spi_cfg_gpio(struct platform_device *pdev) | |||
| 38 | switch (pdev->id) { | 38 | switch (pdev->id) { |
| 39 | case 0: | 39 | case 0: |
| 40 | s3c_gpio_cfgpin(S5P6442_GPB(0), S3C_GPIO_SFN(2)); | 40 | s3c_gpio_cfgpin(S5P6442_GPB(0), S3C_GPIO_SFN(2)); |
| 41 | s3c_gpio_cfgpin(S5P6442_GPB(2), S3C_GPIO_SFN(2)); | ||
| 42 | s3c_gpio_cfgpin(S5P6442_GPB(3), S3C_GPIO_SFN(2)); | ||
| 43 | s3c_gpio_setpull(S5P6442_GPB(0), S3C_GPIO_PULL_UP); | 41 | s3c_gpio_setpull(S5P6442_GPB(0), S3C_GPIO_PULL_UP); |
| 44 | s3c_gpio_setpull(S5P6442_GPB(2), S3C_GPIO_PULL_UP); | 42 | s3c_gpio_cfgall_range(S5P6442_GPB(2), 2, |
| 45 | s3c_gpio_setpull(S5P6442_GPB(3), S3C_GPIO_PULL_UP); | 43 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 46 | break; | 44 | break; |
| 47 | 45 | ||
| 48 | default: | 46 | default: |
diff --git a/arch/arm/mach-s5p6442/dma.c b/arch/arm/mach-s5p6442/dma.c index ad4f8704b93d..7dfb13654f8a 100644 --- a/arch/arm/mach-s5p6442/dma.c +++ b/arch/arm/mach-s5p6442/dma.c | |||
| @@ -82,7 +82,7 @@ static struct s3c_pl330_platdata s5p6442_pdma_pdata = { | |||
| 82 | 82 | ||
| 83 | static struct platform_device s5p6442_device_pdma = { | 83 | static struct platform_device s5p6442_device_pdma = { |
| 84 | .name = "s3c-pl330", | 84 | .name = "s3c-pl330", |
| 85 | .id = 1, | 85 | .id = -1, |
| 86 | .num_resources = ARRAY_SIZE(s5p6442_pdma_resource), | 86 | .num_resources = ARRAY_SIZE(s5p6442_pdma_resource), |
| 87 | .resource = s5p6442_pdma_resource, | 87 | .resource = s5p6442_pdma_resource, |
| 88 | .dev = { | 88 | .dev = { |
diff --git a/arch/arm/mach-s5p6442/include/mach/regs-clock.h b/arch/arm/mach-s5p6442/include/mach/regs-clock.h index d8360b5d4ece..00828a336991 100644 --- a/arch/arm/mach-s5p6442/include/mach/regs-clock.h +++ b/arch/arm/mach-s5p6442/include/mach/regs-clock.h | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #define S5P_CLK_DIV5 S5P_CLKREG(0x314) | 46 | #define S5P_CLK_DIV5 S5P_CLKREG(0x314) |
| 47 | #define S5P_CLK_DIV6 S5P_CLKREG(0x318) | 47 | #define S5P_CLK_DIV6 S5P_CLKREG(0x318) |
| 48 | 48 | ||
| 49 | #define S5P_CLKGATE_IP0 S5P_CLKREG(0x460) | ||
| 49 | #define S5P_CLKGATE_IP3 S5P_CLKREG(0x46C) | 50 | #define S5P_CLKGATE_IP3 S5P_CLKREG(0x46C) |
| 50 | 51 | ||
| 51 | /* CLK_OUT */ | 52 | /* CLK_OUT */ |
diff --git a/arch/arm/mach-s5p6442/include/mach/vmalloc.h b/arch/arm/mach-s5p6442/include/mach/vmalloc.h index f5c83f02c18e..4aa55e55ac47 100644 --- a/arch/arm/mach-s5p6442/include/mach/vmalloc.h +++ b/arch/arm/mach-s5p6442/include/mach/vmalloc.h | |||
| @@ -12,6 +12,6 @@ | |||
| 12 | #ifndef __ASM_ARCH_VMALLOC_H | 12 | #ifndef __ASM_ARCH_VMALLOC_H |
| 13 | #define __ASM_ARCH_VMALLOC_H | 13 | #define __ASM_ARCH_VMALLOC_H |
| 14 | 14 | ||
| 15 | #define VMALLOC_END 0xE0000000UL | 15 | #define VMALLOC_END 0xF6000000UL |
| 16 | 16 | ||
| 17 | #endif /* __ASM_ARCH_VMALLOC_H */ | 17 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig index fbcae9352022..164d2783d381 100644 --- a/arch/arm/mach-s5p64x0/Kconfig +++ b/arch/arm/mach-s5p64x0/Kconfig | |||
| @@ -9,14 +9,12 @@ if ARCH_S5P64X0 | |||
| 9 | 9 | ||
| 10 | config CPU_S5P6440 | 10 | config CPU_S5P6440 |
| 11 | bool | 11 | bool |
| 12 | select PLAT_S5P | ||
| 13 | select S3C_PL330_DMA | 12 | select S3C_PL330_DMA |
| 14 | help | 13 | help |
| 15 | Enable S5P6440 CPU support | 14 | Enable S5P6440 CPU support |
| 16 | 15 | ||
| 17 | config CPU_S5P6450 | 16 | config CPU_S5P6450 |
| 18 | bool | 17 | bool |
| 19 | select PLAT_S5P | ||
| 20 | select S3C_PL330_DMA | 18 | select S3C_PL330_DMA |
| 21 | help | 19 | help |
| 22 | Enable S5P6450 CPU support | 20 | Enable S5P6450 CPU support |
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c index f93dcd8b4d6a..e4883dc1c8d7 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6440.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c | |||
| @@ -79,13 +79,16 @@ static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate) | |||
| 79 | __raw_writel(epll_con, S5P64X0_EPLL_CON); | 79 | __raw_writel(epll_con, S5P64X0_EPLL_CON); |
| 80 | __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K); | 80 | __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K); |
| 81 | 81 | ||
| 82 | printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n", | ||
| 83 | clk->rate, rate); | ||
| 84 | |||
| 82 | clk->rate = rate; | 85 | clk->rate = rate; |
| 83 | 86 | ||
| 84 | return 0; | 87 | return 0; |
| 85 | } | 88 | } |
| 86 | 89 | ||
| 87 | static struct clk_ops s5p6440_epll_ops = { | 90 | static struct clk_ops s5p6440_epll_ops = { |
| 88 | .get_rate = s5p64x0_epll_get_rate, | 91 | .get_rate = s5p_epll_get_rate, |
| 89 | .set_rate = s5p6440_epll_set_rate, | 92 | .set_rate = s5p6440_epll_set_rate, |
| 90 | }; | 93 | }; |
| 91 | 94 | ||
| @@ -150,6 +153,12 @@ static struct clk init_clocks_disable[] = { | |||
| 150 | .enable = s5p64x0_hclk0_ctrl, | 153 | .enable = s5p64x0_hclk0_ctrl, |
| 151 | .ctrlbit = (1 << 8), | 154 | .ctrlbit = (1 << 8), |
| 152 | }, { | 155 | }, { |
| 156 | .name = "pdma", | ||
| 157 | .id = -1, | ||
| 158 | .parent = &clk_hclk_low.clk, | ||
| 159 | .enable = s5p64x0_hclk0_ctrl, | ||
| 160 | .ctrlbit = (1 << 12), | ||
| 161 | }, { | ||
| 153 | .name = "hsmmc", | 162 | .name = "hsmmc", |
| 154 | .id = 0, | 163 | .id = 0, |
| 155 | .parent = &clk_hclk_low.clk, | 164 | .parent = &clk_hclk_low.clk, |
| @@ -331,12 +340,6 @@ static struct clk init_clocks[] = { | |||
| 331 | .enable = s5p64x0_hclk0_ctrl, | 340 | .enable = s5p64x0_hclk0_ctrl, |
| 332 | .ctrlbit = (1 << 21), | 341 | .ctrlbit = (1 << 21), |
| 333 | }, { | 342 | }, { |
| 334 | .name = "dma", | ||
| 335 | .id = -1, | ||
| 336 | .parent = &clk_hclk_low.clk, | ||
| 337 | .enable = s5p64x0_hclk0_ctrl, | ||
| 338 | .ctrlbit = (1 << 12), | ||
| 339 | }, { | ||
| 340 | .name = "uart", | 343 | .name = "uart", |
| 341 | .id = 0, | 344 | .id = 0, |
| 342 | .parent = &clk_pclk_low.clk, | 345 | .parent = &clk_pclk_low.clk, |
| @@ -548,7 +551,7 @@ void __init_or_cpufreq s5p6440_setup_clocks(void) | |||
| 548 | 551 | ||
| 549 | /* Set S5P6440 functions for clk_fout_epll */ | 552 | /* Set S5P6440 functions for clk_fout_epll */ |
| 550 | 553 | ||
| 551 | clk_fout_epll.enable = s5p64x0_epll_enable; | 554 | clk_fout_epll.enable = s5p_epll_enable; |
| 552 | clk_fout_epll.ops = &s5p6440_epll_ops; | 555 | clk_fout_epll.ops = &s5p6440_epll_ops; |
| 553 | 556 | ||
| 554 | clk_48m.enable = s5p64x0_clk48m_ctrl; | 557 | clk_48m.enable = s5p64x0_clk48m_ctrl; |
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c index f9afb05b217c..7dbf3c968f53 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6450.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c | |||
| @@ -80,13 +80,16 @@ static int s5p6450_epll_set_rate(struct clk *clk, unsigned long rate) | |||
| 80 | __raw_writel(epll_con, S5P64X0_EPLL_CON); | 80 | __raw_writel(epll_con, S5P64X0_EPLL_CON); |
| 81 | __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K); | 81 | __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K); |
| 82 | 82 | ||
| 83 | printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n", | ||
| 84 | clk->rate, rate); | ||
| 85 | |||
| 83 | clk->rate = rate; | 86 | clk->rate = rate; |
| 84 | 87 | ||
| 85 | return 0; | 88 | return 0; |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | static struct clk_ops s5p6450_epll_ops = { | 91 | static struct clk_ops s5p6450_epll_ops = { |
| 89 | .get_rate = s5p64x0_epll_get_rate, | 92 | .get_rate = s5p_epll_get_rate, |
| 90 | .set_rate = s5p6450_epll_set_rate, | 93 | .set_rate = s5p6450_epll_set_rate, |
| 91 | }; | 94 | }; |
| 92 | 95 | ||
| @@ -186,6 +189,12 @@ static struct clk init_clocks_disable[] = { | |||
| 186 | .enable = s5p64x0_hclk0_ctrl, | 189 | .enable = s5p64x0_hclk0_ctrl, |
| 187 | .ctrlbit = (1 << 3), | 190 | .ctrlbit = (1 << 3), |
| 188 | }, { | 191 | }, { |
| 192 | .name = "pdma", | ||
| 193 | .id = -1, | ||
| 194 | .parent = &clk_hclk_low.clk, | ||
| 195 | .enable = s5p64x0_hclk0_ctrl, | ||
| 196 | .ctrlbit = (1 << 12), | ||
| 197 | }, { | ||
| 189 | .name = "hsmmc", | 198 | .name = "hsmmc", |
| 190 | .id = 0, | 199 | .id = 0, |
| 191 | .parent = &clk_hclk_low.clk, | 200 | .parent = &clk_hclk_low.clk, |
| @@ -283,12 +292,6 @@ static struct clk init_clocks[] = { | |||
| 283 | .enable = s5p64x0_hclk0_ctrl, | 292 | .enable = s5p64x0_hclk0_ctrl, |
| 284 | .ctrlbit = (1 << 21), | 293 | .ctrlbit = (1 << 21), |
| 285 | }, { | 294 | }, { |
| 286 | .name = "dma", | ||
| 287 | .id = -1, | ||
| 288 | .parent = &clk_hclk_low.clk, | ||
| 289 | .enable = s5p64x0_hclk0_ctrl, | ||
| 290 | .ctrlbit = (1 << 12), | ||
| 291 | }, { | ||
| 292 | .name = "uart", | 295 | .name = "uart", |
| 293 | .id = 0, | 296 | .id = 0, |
| 294 | .parent = &clk_pclk_low.clk, | 297 | .parent = &clk_pclk_low.clk, |
| @@ -581,7 +584,7 @@ void __init_or_cpufreq s5p6450_setup_clocks(void) | |||
| 581 | 584 | ||
| 582 | /* Set S5P6450 functions for clk_fout_epll */ | 585 | /* Set S5P6450 functions for clk_fout_epll */ |
| 583 | 586 | ||
| 584 | clk_fout_epll.enable = s5p64x0_epll_enable; | 587 | clk_fout_epll.enable = s5p_epll_enable; |
| 585 | clk_fout_epll.ops = &s5p6450_epll_ops; | 588 | clk_fout_epll.ops = &s5p6450_epll_ops; |
| 586 | 589 | ||
| 587 | clk_48m.enable = s5p64x0_clk48m_ctrl; | 590 | clk_48m.enable = s5p64x0_clk48m_ctrl; |
diff --git a/arch/arm/mach-s5p64x0/clock.c b/arch/arm/mach-s5p64x0/clock.c index 523ba8039ac2..b52c6e2f37a6 100644 --- a/arch/arm/mach-s5p64x0/clock.c +++ b/arch/arm/mach-s5p64x0/clock.c | |||
| @@ -73,24 +73,6 @@ static const u32 clock_table[][3] = { | |||
| 73 | {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)}, | 73 | {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)}, |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | int s5p64x0_epll_enable(struct clk *clk, int enable) | ||
| 77 | { | ||
| 78 | unsigned int ctrlbit = clk->ctrlbit; | ||
| 79 | unsigned int epll_con = __raw_readl(S5P64X0_EPLL_CON) & ~ctrlbit; | ||
| 80 | |||
| 81 | if (enable) | ||
| 82 | __raw_writel(epll_con | ctrlbit, S5P64X0_EPLL_CON); | ||
| 83 | else | ||
| 84 | __raw_writel(epll_con, S5P64X0_EPLL_CON); | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | unsigned long s5p64x0_epll_get_rate(struct clk *clk) | ||
| 90 | { | ||
| 91 | return clk->rate; | ||
| 92 | } | ||
| 93 | |||
| 94 | unsigned long s5p64x0_armclk_get_rate(struct clk *clk) | 76 | unsigned long s5p64x0_armclk_get_rate(struct clk *clk) |
| 95 | { | 77 | { |
| 96 | unsigned long rate = clk_get_rate(clk->parent); | 78 | unsigned long rate = clk_get_rate(clk->parent); |
diff --git a/arch/arm/mach-s5p64x0/dev-audio.c b/arch/arm/mach-s5p64x0/dev-audio.c index fa097bd68ca4..396bacc0a39a 100644 --- a/arch/arm/mach-s5p64x0/dev-audio.c +++ b/arch/arm/mach-s5p64x0/dev-audio.c | |||
| @@ -24,13 +24,8 @@ static int s5p6440_cfg_i2s(struct platform_device *pdev) | |||
| 24 | /* configure GPIO for i2s port */ | 24 | /* configure GPIO for i2s port */ |
| 25 | switch (pdev->id) { | 25 | switch (pdev->id) { |
| 26 | case -1: | 26 | case -1: |
| 27 | s3c_gpio_cfgpin(S5P6440_GPR(4), S3C_GPIO_SFN(5)); | 27 | s3c_gpio_cfgpin_range(S5P6440_GPR(4), 5, S3C_GPIO_SFN(5)); |
| 28 | s3c_gpio_cfgpin(S5P6440_GPR(5), S3C_GPIO_SFN(5)); | 28 | s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(5)); |
| 29 | s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(5)); | ||
| 30 | s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(5)); | ||
| 31 | s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(5)); | ||
| 32 | s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(5)); | ||
| 33 | s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(5)); | ||
| 34 | break; | 29 | break; |
| 35 | 30 | ||
| 36 | default: | 31 | default: |
| @@ -47,13 +42,9 @@ static int s5p6450_cfg_i2s(struct platform_device *pdev) | |||
| 47 | switch (pdev->id) { | 42 | switch (pdev->id) { |
| 48 | case -1: | 43 | case -1: |
| 49 | s3c_gpio_cfgpin(S5P6450_GPB(4), S3C_GPIO_SFN(5)); | 44 | s3c_gpio_cfgpin(S5P6450_GPB(4), S3C_GPIO_SFN(5)); |
| 50 | s3c_gpio_cfgpin(S5P6450_GPR(4), S3C_GPIO_SFN(5)); | 45 | s3c_gpio_cfgpin_range(S5P6450_GPR(4), 5, S3C_GPIO_SFN(5)); |
| 51 | s3c_gpio_cfgpin(S5P6450_GPR(5), S3C_GPIO_SFN(5)); | 46 | s3c_gpio_cfgpin_range(S5P6450_GPR(13), 2, S3C_GPIO_SFN(5)); |
| 52 | s3c_gpio_cfgpin(S5P6450_GPR(6), S3C_GPIO_SFN(5)); | 47 | |
| 53 | s3c_gpio_cfgpin(S5P6450_GPR(7), S3C_GPIO_SFN(5)); | ||
| 54 | s3c_gpio_cfgpin(S5P6450_GPR(8), S3C_GPIO_SFN(5)); | ||
| 55 | s3c_gpio_cfgpin(S5P6450_GPR(13), S3C_GPIO_SFN(5)); | ||
| 56 | s3c_gpio_cfgpin(S5P6450_GPR(14), S3C_GPIO_SFN(5)); | ||
| 57 | break; | 48 | break; |
| 58 | 49 | ||
| 59 | default: | 50 | default: |
| @@ -116,11 +107,8 @@ static int s5p6440_pcm_cfg_gpio(struct platform_device *pdev) | |||
| 116 | { | 107 | { |
| 117 | switch (pdev->id) { | 108 | switch (pdev->id) { |
| 118 | case 0: | 109 | case 0: |
| 119 | s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(2)); | 110 | s3c_gpio_cfgpin_range(S5P6440_GPR(6), 3, S3C_GPIO_SFN(2)); |
| 120 | s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(2)); | 111 | s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(2)); |
| 121 | s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(2)); | ||
| 122 | s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(2)); | ||
| 123 | s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(2)); | ||
| 124 | break; | 112 | break; |
| 125 | 113 | ||
| 126 | default: | 114 | default: |
diff --git a/arch/arm/mach-s5p64x0/dev-spi.c b/arch/arm/mach-s5p64x0/dev-spi.c index 5b69ec4c8af3..e78ee18c76e3 100644 --- a/arch/arm/mach-s5p64x0/dev-spi.c +++ b/arch/arm/mach-s5p64x0/dev-spi.c | |||
| @@ -39,23 +39,15 @@ static char *s5p64x0_spi_src_clks[] = { | |||
| 39 | */ | 39 | */ |
| 40 | static int s5p6440_spi_cfg_gpio(struct platform_device *pdev) | 40 | static int s5p6440_spi_cfg_gpio(struct platform_device *pdev) |
| 41 | { | 41 | { |
| 42 | unsigned int base; | ||
| 43 | |||
| 42 | switch (pdev->id) { | 44 | switch (pdev->id) { |
| 43 | case 0: | 45 | case 0: |
| 44 | s3c_gpio_cfgpin(S5P6440_GPC(0), S3C_GPIO_SFN(2)); | 46 | base = S5P6440_GPC(0); |
| 45 | s3c_gpio_cfgpin(S5P6440_GPC(1), S3C_GPIO_SFN(2)); | ||
| 46 | s3c_gpio_cfgpin(S5P6440_GPC(2), S3C_GPIO_SFN(2)); | ||
| 47 | s3c_gpio_setpull(S5P6440_GPC(0), S3C_GPIO_PULL_UP); | ||
| 48 | s3c_gpio_setpull(S5P6440_GPC(1), S3C_GPIO_PULL_UP); | ||
| 49 | s3c_gpio_setpull(S5P6440_GPC(2), S3C_GPIO_PULL_UP); | ||
| 50 | break; | 47 | break; |
| 51 | 48 | ||
| 52 | case 1: | 49 | case 1: |
| 53 | s3c_gpio_cfgpin(S5P6440_GPC(4), S3C_GPIO_SFN(2)); | 50 | base = S5P6440_GPC(4); |
| 54 | s3c_gpio_cfgpin(S5P6440_GPC(5), S3C_GPIO_SFN(2)); | ||
| 55 | s3c_gpio_cfgpin(S5P6440_GPC(6), S3C_GPIO_SFN(2)); | ||
| 56 | s3c_gpio_setpull(S5P6440_GPC(4), S3C_GPIO_PULL_UP); | ||
| 57 | s3c_gpio_setpull(S5P6440_GPC(5), S3C_GPIO_PULL_UP); | ||
| 58 | s3c_gpio_setpull(S5P6440_GPC(6), S3C_GPIO_PULL_UP); | ||
| 59 | break; | 51 | break; |
| 60 | 52 | ||
| 61 | default: | 53 | default: |
| @@ -63,28 +55,23 @@ static int s5p6440_spi_cfg_gpio(struct platform_device *pdev) | |||
| 63 | return -EINVAL; | 55 | return -EINVAL; |
| 64 | } | 56 | } |
| 65 | 57 | ||
| 58 | s3c_gpio_cfgall_range(base, 3, | ||
| 59 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); | ||
| 60 | |||
| 66 | return 0; | 61 | return 0; |
| 67 | } | 62 | } |
| 68 | 63 | ||
| 69 | static int s5p6450_spi_cfg_gpio(struct platform_device *pdev) | 64 | static int s5p6450_spi_cfg_gpio(struct platform_device *pdev) |
| 70 | { | 65 | { |
| 66 | unsigned int base; | ||
| 67 | |||
| 71 | switch (pdev->id) { | 68 | switch (pdev->id) { |
| 72 | case 0: | 69 | case 0: |
| 73 | s3c_gpio_cfgpin(S5P6450_GPC(0), S3C_GPIO_SFN(2)); | 70 | base = S5P6450_GPC(0); |
| 74 | s3c_gpio_cfgpin(S5P6450_GPC(1), S3C_GPIO_SFN(2)); | ||
| 75 | s3c_gpio_cfgpin(S5P6450_GPC(2), S3C_GPIO_SFN(2)); | ||
| 76 | s3c_gpio_setpull(S5P6450_GPC(0), S3C_GPIO_PULL_UP); | ||
| 77 | s3c_gpio_setpull(S5P6450_GPC(1), S3C_GPIO_PULL_UP); | ||
| 78 | s3c_gpio_setpull(S5P6450_GPC(2), S3C_GPIO_PULL_UP); | ||
| 79 | break; | 71 | break; |
| 80 | 72 | ||
| 81 | case 1: | 73 | case 1: |
| 82 | s3c_gpio_cfgpin(S5P6450_GPC(4), S3C_GPIO_SFN(2)); | 74 | base = S5P6450_GPC(4); |
| 83 | s3c_gpio_cfgpin(S5P6450_GPC(5), S3C_GPIO_SFN(2)); | ||
| 84 | s3c_gpio_cfgpin(S5P6450_GPC(6), S3C_GPIO_SFN(2)); | ||
| 85 | s3c_gpio_setpull(S5P6450_GPC(4), S3C_GPIO_PULL_UP); | ||
| 86 | s3c_gpio_setpull(S5P6450_GPC(5), S3C_GPIO_PULL_UP); | ||
| 87 | s3c_gpio_setpull(S5P6450_GPC(6), S3C_GPIO_PULL_UP); | ||
| 88 | break; | 75 | break; |
| 89 | 76 | ||
| 90 | default: | 77 | default: |
| @@ -92,6 +79,9 @@ static int s5p6450_spi_cfg_gpio(struct platform_device *pdev) | |||
| 92 | return -EINVAL; | 79 | return -EINVAL; |
| 93 | } | 80 | } |
| 94 | 81 | ||
| 82 | s3c_gpio_cfgall_range(base, 3, | ||
| 83 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); | ||
| 84 | |||
| 95 | return 0; | 85 | return 0; |
| 96 | } | 86 | } |
| 97 | 87 | ||
diff --git a/arch/arm/mach-s5p64x0/dma.c b/arch/arm/mach-s5p64x0/dma.c index 29a8c2410049..d7ad944b3475 100644 --- a/arch/arm/mach-s5p64x0/dma.c +++ b/arch/arm/mach-s5p64x0/dma.c | |||
| @@ -122,7 +122,7 @@ static struct s3c_pl330_platdata s5p6450_pdma_pdata = { | |||
| 122 | 122 | ||
| 123 | static struct platform_device s5p64x0_device_pdma = { | 123 | static struct platform_device s5p64x0_device_pdma = { |
| 124 | .name = "s3c-pl330", | 124 | .name = "s3c-pl330", |
| 125 | .id = 0, | 125 | .id = -1, |
| 126 | .num_resources = ARRAY_SIZE(s5p64x0_pdma_resource), | 126 | .num_resources = ARRAY_SIZE(s5p64x0_pdma_resource), |
| 127 | .resource = s5p64x0_pdma_resource, | 127 | .resource = s5p64x0_pdma_resource, |
| 128 | .dev = { | 128 | .dev = { |
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h index 58e1bc813804..a133f22fa155 100644 --- a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h +++ b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h | |||
| @@ -60,4 +60,6 @@ | |||
| 60 | #define ARM_DIV_RATIO_SHIFT 0 | 60 | #define ARM_DIV_RATIO_SHIFT 0 |
| 61 | #define ARM_DIV_MASK (0xF << ARM_DIV_RATIO_SHIFT) | 61 | #define ARM_DIV_MASK (0xF << ARM_DIV_RATIO_SHIFT) |
| 62 | 62 | ||
| 63 | #define S5P_EPLL_CON S5P64X0_EPLL_CON | ||
| 64 | |||
| 63 | #endif /* __ASM_ARCH_REGS_CLOCK_H */ | 65 | #endif /* __ASM_ARCH_REGS_CLOCK_H */ |
diff --git a/arch/arm/mach-s5p64x0/include/mach/vmalloc.h b/arch/arm/mach-s5p64x0/include/mach/vmalloc.h index 97a9df38f1cf..38dcc71a03cc 100644 --- a/arch/arm/mach-s5p64x0/include/mach/vmalloc.h +++ b/arch/arm/mach-s5p64x0/include/mach/vmalloc.h | |||
| @@ -15,6 +15,6 @@ | |||
| 15 | #ifndef __ASM_ARCH_VMALLOC_H | 15 | #ifndef __ASM_ARCH_VMALLOC_H |
| 16 | #define __ASM_ARCH_VMALLOC_H | 16 | #define __ASM_ARCH_VMALLOC_H |
| 17 | 17 | ||
| 18 | #define VMALLOC_END 0xE0000000UL | 18 | #define VMALLOC_END 0xF6000000UL |
| 19 | 19 | ||
| 20 | #endif /* __ASM_ARCH_VMALLOC_H */ | 20 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s5p64x0/setup-i2c0.c b/arch/arm/mach-s5p64x0/setup-i2c0.c index dc4cc65a5019..46b463917c54 100644 --- a/arch/arm/mach-s5p64x0/setup-i2c0.c +++ b/arch/arm/mach-s5p64x0/setup-i2c0.c | |||
| @@ -25,18 +25,14 @@ struct platform_device; /* don't need the contents */ | |||
| 25 | 25 | ||
| 26 | void s5p6440_i2c0_cfg_gpio(struct platform_device *dev) | 26 | void s5p6440_i2c0_cfg_gpio(struct platform_device *dev) |
| 27 | { | 27 | { |
| 28 | s3c_gpio_cfgpin(S5P6440_GPB(5), S3C_GPIO_SFN(2)); | 28 | s3c_gpio_cfgall_range(S5P6440_GPB(5), 2, |
| 29 | s3c_gpio_setpull(S5P6440_GPB(5), S3C_GPIO_PULL_UP); | 29 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 30 | s3c_gpio_cfgpin(S5P6440_GPB(6), S3C_GPIO_SFN(2)); | ||
| 31 | s3c_gpio_setpull(S5P6440_GPB(6), S3C_GPIO_PULL_UP); | ||
| 32 | } | 30 | } |
| 33 | 31 | ||
| 34 | void s5p6450_i2c0_cfg_gpio(struct platform_device *dev) | 32 | void s5p6450_i2c0_cfg_gpio(struct platform_device *dev) |
| 35 | { | 33 | { |
| 36 | s3c_gpio_cfgpin(S5P6450_GPB(5), S3C_GPIO_SFN(2)); | 34 | s3c_gpio_cfgall_range(S5P6450_GPB(5), 2, |
| 37 | s3c_gpio_setpull(S5P6450_GPB(5), S3C_GPIO_PULL_UP); | 35 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 38 | s3c_gpio_cfgpin(S5P6450_GPB(6), S3C_GPIO_SFN(2)); | ||
| 39 | s3c_gpio_setpull(S5P6450_GPB(6), S3C_GPIO_PULL_UP); | ||
| 40 | } | 36 | } |
| 41 | 37 | ||
| 42 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) { } | 38 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) { } |
diff --git a/arch/arm/mach-s5p64x0/setup-i2c1.c b/arch/arm/mach-s5p64x0/setup-i2c1.c index 2edd7912f8e4..6ad3b986021c 100644 --- a/arch/arm/mach-s5p64x0/setup-i2c1.c +++ b/arch/arm/mach-s5p64x0/setup-i2c1.c | |||
| @@ -25,18 +25,14 @@ struct platform_device; /* don't need the contents */ | |||
| 25 | 25 | ||
| 26 | void s5p6440_i2c1_cfg_gpio(struct platform_device *dev) | 26 | void s5p6440_i2c1_cfg_gpio(struct platform_device *dev) |
| 27 | { | 27 | { |
| 28 | s3c_gpio_cfgpin(S5P6440_GPR(9), S3C_GPIO_SFN(6)); | 28 | s3c_gpio_cfgall_range(S5P6440_GPR(9), 2, |
| 29 | s3c_gpio_setpull(S5P6440_GPR(9), S3C_GPIO_PULL_UP); | 29 | S3C_GPIO_SFN(6), S3C_GPIO_PULL_UP); |
| 30 | s3c_gpio_cfgpin(S5P6440_GPR(10), S3C_GPIO_SFN(6)); | ||
| 31 | s3c_gpio_setpull(S5P6440_GPR(10), S3C_GPIO_PULL_UP); | ||
| 32 | } | 30 | } |
| 33 | 31 | ||
| 34 | void s5p6450_i2c1_cfg_gpio(struct platform_device *dev) | 32 | void s5p6450_i2c1_cfg_gpio(struct platform_device *dev) |
| 35 | { | 33 | { |
| 36 | s3c_gpio_cfgpin(S5P6450_GPR(9), S3C_GPIO_SFN(6)); | 34 | s3c_gpio_cfgall_range(S5P6450_GPR(9), 2, |
| 37 | s3c_gpio_setpull(S5P6450_GPR(9), S3C_GPIO_PULL_UP); | 35 | S3C_GPIO_SFN(6), S3C_GPIO_PULL_UP); |
| 38 | s3c_gpio_cfgpin(S5P6450_GPR(10), S3C_GPIO_SFN(6)); | ||
| 39 | s3c_gpio_setpull(S5P6450_GPR(10), S3C_GPIO_PULL_UP); | ||
| 40 | } | 36 | } |
| 41 | 37 | ||
| 42 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) { } | 38 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) { } |
diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig index 77ae4bfb74ba..b8fbf2fcba6f 100644 --- a/arch/arm/mach-s5pc100/Kconfig +++ b/arch/arm/mach-s5pc100/Kconfig | |||
| @@ -9,7 +9,6 @@ if ARCH_S5PC100 | |||
| 9 | 9 | ||
| 10 | config CPU_S5PC100 | 10 | config CPU_S5PC100 |
| 11 | bool | 11 | bool |
| 12 | select PLAT_S5P | ||
| 13 | select S5P_EXT_INT | 12 | select S5P_EXT_INT |
| 14 | select S3C_PL330_DMA | 13 | select S3C_PL330_DMA |
| 15 | help | 14 | help |
diff --git a/arch/arm/mach-s5pc100/Makefile b/arch/arm/mach-s5pc100/Makefile index a021ed1fb4b6..eecab57d2e5d 100644 --- a/arch/arm/mach-s5pc100/Makefile +++ b/arch/arm/mach-s5pc100/Makefile | |||
| @@ -11,7 +11,7 @@ obj- := | |||
| 11 | 11 | ||
| 12 | # Core support for S5PC100 system | 12 | # Core support for S5PC100 system |
| 13 | 13 | ||
| 14 | obj-$(CONFIG_CPU_S5PC100) += cpu.o init.o clock.o gpiolib.o irq-gpio.o | 14 | obj-$(CONFIG_CPU_S5PC100) += cpu.o init.o clock.o gpiolib.o |
| 15 | obj-$(CONFIG_CPU_S5PC100) += setup-i2c0.o | 15 | obj-$(CONFIG_CPU_S5PC100) += setup-i2c0.o |
| 16 | obj-$(CONFIG_CPU_S5PC100) += dma.o | 16 | obj-$(CONFIG_CPU_S5PC100) += dma.o |
| 17 | 17 | ||
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c index 084abd13b0a5..2d4a761a5163 100644 --- a/arch/arm/mach-s5pc100/clock.c +++ b/arch/arm/mach-s5pc100/clock.c | |||
| @@ -273,24 +273,6 @@ static struct clksrc_clk clk_div_hdmi = { | |||
| 273 | .reg_div = { .reg = S5P_CLK_DIV3, .shift = 28, .size = 4 }, | 273 | .reg_div = { .reg = S5P_CLK_DIV3, .shift = 28, .size = 4 }, |
| 274 | }; | 274 | }; |
| 275 | 275 | ||
| 276 | static int s5pc100_epll_enable(struct clk *clk, int enable) | ||
| 277 | { | ||
| 278 | unsigned int ctrlbit = clk->ctrlbit; | ||
| 279 | unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit; | ||
| 280 | |||
| 281 | if (enable) | ||
| 282 | __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON); | ||
| 283 | else | ||
| 284 | __raw_writel(epll_con, S5P_EPLL_CON); | ||
| 285 | |||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static unsigned long s5pc100_epll_get_rate(struct clk *clk) | ||
| 290 | { | ||
| 291 | return clk->rate; | ||
| 292 | } | ||
| 293 | |||
| 294 | static u32 epll_div[][4] = { | 276 | static u32 epll_div[][4] = { |
| 295 | { 32750000, 131, 3, 4 }, | 277 | { 32750000, 131, 3, 4 }, |
| 296 | { 32768000, 131, 3, 4 }, | 278 | { 32768000, 131, 3, 4 }, |
| @@ -341,13 +323,16 @@ static int s5pc100_epll_set_rate(struct clk *clk, unsigned long rate) | |||
| 341 | 323 | ||
| 342 | __raw_writel(epll_con, S5P_EPLL_CON); | 324 | __raw_writel(epll_con, S5P_EPLL_CON); |
| 343 | 325 | ||
| 326 | printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n", | ||
| 327 | clk->rate, rate); | ||
| 328 | |||
| 344 | clk->rate = rate; | 329 | clk->rate = rate; |
| 345 | 330 | ||
| 346 | return 0; | 331 | return 0; |
| 347 | } | 332 | } |
| 348 | 333 | ||
| 349 | static struct clk_ops s5pc100_epll_ops = { | 334 | static struct clk_ops s5pc100_epll_ops = { |
| 350 | .get_rate = s5pc100_epll_get_rate, | 335 | .get_rate = s5p_epll_get_rate, |
| 351 | .set_rate = s5pc100_epll_set_rate, | 336 | .set_rate = s5pc100_epll_set_rate, |
| 352 | }; | 337 | }; |
| 353 | 338 | ||
| @@ -691,55 +676,55 @@ static struct clk init_clocks_disable[] = { | |||
| 691 | }, { | 676 | }, { |
| 692 | .name = "iis", | 677 | .name = "iis", |
| 693 | .id = 0, | 678 | .id = 0, |
| 694 | .parent = &clk_div_d1_bus.clk, | 679 | .parent = &clk_div_pclkd1.clk, |
| 695 | .enable = s5pc100_d1_5_ctrl, | 680 | .enable = s5pc100_d1_5_ctrl, |
| 696 | .ctrlbit = (1 << 0), | 681 | .ctrlbit = (1 << 0), |
| 697 | }, { | 682 | }, { |
| 698 | .name = "iis", | 683 | .name = "iis", |
| 699 | .id = 1, | 684 | .id = 1, |
| 700 | .parent = &clk_div_d1_bus.clk, | 685 | .parent = &clk_div_pclkd1.clk, |
| 701 | .enable = s5pc100_d1_5_ctrl, | 686 | .enable = s5pc100_d1_5_ctrl, |
| 702 | .ctrlbit = (1 << 1), | 687 | .ctrlbit = (1 << 1), |
| 703 | }, { | 688 | }, { |
| 704 | .name = "iis", | 689 | .name = "iis", |
| 705 | .id = 2, | 690 | .id = 2, |
| 706 | .parent = &clk_div_d1_bus.clk, | 691 | .parent = &clk_div_pclkd1.clk, |
| 707 | .enable = s5pc100_d1_5_ctrl, | 692 | .enable = s5pc100_d1_5_ctrl, |
| 708 | .ctrlbit = (1 << 2), | 693 | .ctrlbit = (1 << 2), |
| 709 | }, { | 694 | }, { |
| 710 | .name = "ac97", | 695 | .name = "ac97", |
| 711 | .id = -1, | 696 | .id = -1, |
| 712 | .parent = &clk_div_d1_bus.clk, | 697 | .parent = &clk_div_pclkd1.clk, |
| 713 | .enable = s5pc100_d1_5_ctrl, | 698 | .enable = s5pc100_d1_5_ctrl, |
| 714 | .ctrlbit = (1 << 3), | 699 | .ctrlbit = (1 << 3), |
| 715 | }, { | 700 | }, { |
| 716 | .name = "pcm", | 701 | .name = "pcm", |
| 717 | .id = 0, | 702 | .id = 0, |
| 718 | .parent = &clk_div_d1_bus.clk, | 703 | .parent = &clk_div_pclkd1.clk, |
| 719 | .enable = s5pc100_d1_5_ctrl, | 704 | .enable = s5pc100_d1_5_ctrl, |
| 720 | .ctrlbit = (1 << 4), | 705 | .ctrlbit = (1 << 4), |
| 721 | }, { | 706 | }, { |
| 722 | .name = "pcm", | 707 | .name = "pcm", |
| 723 | .id = 1, | 708 | .id = 1, |
| 724 | .parent = &clk_div_d1_bus.clk, | 709 | .parent = &clk_div_pclkd1.clk, |
| 725 | .enable = s5pc100_d1_5_ctrl, | 710 | .enable = s5pc100_d1_5_ctrl, |
| 726 | .ctrlbit = (1 << 5), | 711 | .ctrlbit = (1 << 5), |
| 727 | }, { | 712 | }, { |
| 728 | .name = "spdif", | 713 | .name = "spdif", |
| 729 | .id = -1, | 714 | .id = -1, |
| 730 | .parent = &clk_div_d1_bus.clk, | 715 | .parent = &clk_div_pclkd1.clk, |
| 731 | .enable = s5pc100_d1_5_ctrl, | 716 | .enable = s5pc100_d1_5_ctrl, |
| 732 | .ctrlbit = (1 << 6), | 717 | .ctrlbit = (1 << 6), |
| 733 | }, { | 718 | }, { |
| 734 | .name = "adc", | 719 | .name = "adc", |
| 735 | .id = -1, | 720 | .id = -1, |
| 736 | .parent = &clk_div_d1_bus.clk, | 721 | .parent = &clk_div_pclkd1.clk, |
| 737 | .enable = s5pc100_d1_5_ctrl, | 722 | .enable = s5pc100_d1_5_ctrl, |
| 738 | .ctrlbit = (1 << 7), | 723 | .ctrlbit = (1 << 7), |
| 739 | }, { | 724 | }, { |
| 740 | .name = "keypad", | 725 | .name = "keypad", |
| 741 | .id = -1, | 726 | .id = -1, |
| 742 | .parent = &clk_div_d1_bus.clk, | 727 | .parent = &clk_div_pclkd1.clk, |
| 743 | .enable = s5pc100_d1_5_ctrl, | 728 | .enable = s5pc100_d1_5_ctrl, |
| 744 | .ctrlbit = (1 << 8), | 729 | .ctrlbit = (1 << 8), |
| 745 | }, { | 730 | }, { |
| @@ -848,6 +833,18 @@ struct clksrc_sources clk_src_group3 = { | |||
| 848 | .nr_sources = ARRAY_SIZE(clk_src_group3_list), | 833 | .nr_sources = ARRAY_SIZE(clk_src_group3_list), |
| 849 | }; | 834 | }; |
| 850 | 835 | ||
| 836 | static struct clksrc_clk clk_sclk_audio0 = { | ||
| 837 | .clk = { | ||
| 838 | .name = "sclk_audio", | ||
| 839 | .id = 0, | ||
| 840 | .ctrlbit = (1 << 8), | ||
| 841 | .enable = s5pc100_sclk1_ctrl, | ||
| 842 | }, | ||
| 843 | .sources = &clk_src_group3, | ||
| 844 | .reg_src = { .reg = S5P_CLK_SRC3, .shift = 12, .size = 3 }, | ||
| 845 | .reg_div = { .reg = S5P_CLK_DIV4, .shift = 12, .size = 4 }, | ||
| 846 | }; | ||
| 847 | |||
| 851 | static struct clk *clk_src_group4_list[] = { | 848 | static struct clk *clk_src_group4_list[] = { |
| 852 | [0] = &clk_mout_epll.clk, | 849 | [0] = &clk_mout_epll.clk, |
| 853 | [1] = &clk_div_mpll.clk, | 850 | [1] = &clk_div_mpll.clk, |
| @@ -862,6 +859,18 @@ struct clksrc_sources clk_src_group4 = { | |||
| 862 | .nr_sources = ARRAY_SIZE(clk_src_group4_list), | 859 | .nr_sources = ARRAY_SIZE(clk_src_group4_list), |
| 863 | }; | 860 | }; |
| 864 | 861 | ||
| 862 | static struct clksrc_clk clk_sclk_audio1 = { | ||
| 863 | .clk = { | ||
| 864 | .name = "sclk_audio", | ||
| 865 | .id = 1, | ||
| 866 | .ctrlbit = (1 << 9), | ||
| 867 | .enable = s5pc100_sclk1_ctrl, | ||
| 868 | }, | ||
| 869 | .sources = &clk_src_group4, | ||
| 870 | .reg_src = { .reg = S5P_CLK_SRC3, .shift = 16, .size = 3 }, | ||
| 871 | .reg_div = { .reg = S5P_CLK_DIV4, .shift = 16, .size = 4 }, | ||
| 872 | }; | ||
| 873 | |||
| 865 | static struct clk *clk_src_group5_list[] = { | 874 | static struct clk *clk_src_group5_list[] = { |
| 866 | [0] = &clk_mout_epll.clk, | 875 | [0] = &clk_mout_epll.clk, |
| 867 | [1] = &clk_div_mpll.clk, | 876 | [1] = &clk_div_mpll.clk, |
| @@ -875,6 +884,18 @@ struct clksrc_sources clk_src_group5 = { | |||
| 875 | .nr_sources = ARRAY_SIZE(clk_src_group5_list), | 884 | .nr_sources = ARRAY_SIZE(clk_src_group5_list), |
| 876 | }; | 885 | }; |
| 877 | 886 | ||
| 887 | static struct clksrc_clk clk_sclk_audio2 = { | ||
| 888 | .clk = { | ||
| 889 | .name = "sclk_audio", | ||
| 890 | .id = 2, | ||
| 891 | .ctrlbit = (1 << 10), | ||
| 892 | .enable = s5pc100_sclk1_ctrl, | ||
| 893 | }, | ||
| 894 | .sources = &clk_src_group5, | ||
| 895 | .reg_src = { .reg = S5P_CLK_SRC3, .shift = 20, .size = 3 }, | ||
| 896 | .reg_div = { .reg = S5P_CLK_DIV4, .shift = 20, .size = 4 }, | ||
| 897 | }; | ||
| 898 | |||
| 878 | static struct clk *clk_src_group6_list[] = { | 899 | static struct clk *clk_src_group6_list[] = { |
| 879 | [0] = &s5p_clk_27m, | 900 | [0] = &s5p_clk_27m, |
| 880 | [1] = &clk_vclk54m, | 901 | [1] = &clk_vclk54m, |
| @@ -944,6 +965,64 @@ struct clksrc_sources clk_src_pwi = { | |||
| 944 | .nr_sources = ARRAY_SIZE(clk_src_pwi_list), | 965 | .nr_sources = ARRAY_SIZE(clk_src_pwi_list), |
| 945 | }; | 966 | }; |
| 946 | 967 | ||
| 968 | static struct clk *clk_sclk_spdif_list[] = { | ||
| 969 | [0] = &clk_sclk_audio0.clk, | ||
| 970 | [1] = &clk_sclk_audio1.clk, | ||
| 971 | [2] = &clk_sclk_audio2.clk, | ||
| 972 | }; | ||
| 973 | |||
| 974 | struct clksrc_sources clk_src_sclk_spdif = { | ||
| 975 | .sources = clk_sclk_spdif_list, | ||
| 976 | .nr_sources = ARRAY_SIZE(clk_sclk_spdif_list), | ||
| 977 | }; | ||
| 978 | |||
| 979 | static int s5pc100_spdif_set_rate(struct clk *clk, unsigned long rate) | ||
| 980 | { | ||
| 981 | struct clk *pclk; | ||
| 982 | int ret; | ||
| 983 | |||
| 984 | pclk = clk_get_parent(clk); | ||
| 985 | if (IS_ERR(pclk)) | ||
| 986 | return -EINVAL; | ||
| 987 | |||
| 988 | ret = pclk->ops->set_rate(pclk, rate); | ||
| 989 | clk_put(pclk); | ||
| 990 | |||
| 991 | return ret; | ||
| 992 | } | ||
| 993 | |||
| 994 | static unsigned long s5pc100_spdif_get_rate(struct clk *clk) | ||
| 995 | { | ||
| 996 | struct clk *pclk; | ||
| 997 | int rate; | ||
| 998 | |||
| 999 | pclk = clk_get_parent(clk); | ||
| 1000 | if (IS_ERR(pclk)) | ||
| 1001 | return -EINVAL; | ||
| 1002 | |||
| 1003 | rate = pclk->ops->get_rate(clk); | ||
| 1004 | clk_put(pclk); | ||
| 1005 | |||
| 1006 | return rate; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static struct clk_ops s5pc100_sclk_spdif_ops = { | ||
| 1010 | .set_rate = s5pc100_spdif_set_rate, | ||
| 1011 | .get_rate = s5pc100_spdif_get_rate, | ||
| 1012 | }; | ||
| 1013 | |||
| 1014 | static struct clksrc_clk clk_sclk_spdif = { | ||
| 1015 | .clk = { | ||
| 1016 | .name = "sclk_spdif", | ||
| 1017 | .id = -1, | ||
| 1018 | .ctrlbit = (1 << 11), | ||
| 1019 | .enable = s5pc100_sclk1_ctrl, | ||
| 1020 | .ops = &s5pc100_sclk_spdif_ops, | ||
| 1021 | }, | ||
| 1022 | .sources = &clk_src_sclk_spdif, | ||
| 1023 | .reg_src = { .reg = S5P_CLK_SRC3, .shift = 24, .size = 2 }, | ||
| 1024 | }; | ||
| 1025 | |||
| 947 | static struct clksrc_clk clksrcs[] = { | 1026 | static struct clksrc_clk clksrcs[] = { |
| 948 | { | 1027 | { |
| 949 | .clk = { | 1028 | .clk = { |
| @@ -1001,39 +1080,6 @@ static struct clksrc_clk clksrcs[] = { | |||
| 1001 | .reg_src = { .reg = S5P_CLK_SRC2, .shift = 28, .size = 2 }, | 1080 | .reg_src = { .reg = S5P_CLK_SRC2, .shift = 28, .size = 2 }, |
| 1002 | }, { | 1081 | }, { |
| 1003 | .clk = { | 1082 | .clk = { |
| 1004 | .name = "sclk_audio", | ||
| 1005 | .id = 0, | ||
| 1006 | .ctrlbit = (1 << 8), | ||
| 1007 | .enable = s5pc100_sclk1_ctrl, | ||
| 1008 | |||
| 1009 | }, | ||
| 1010 | .sources = &clk_src_group3, | ||
| 1011 | .reg_src = { .reg = S5P_CLK_SRC3, .shift = 12, .size = 3 }, | ||
| 1012 | .reg_div = { .reg = S5P_CLK_DIV4, .shift = 12, .size = 4 }, | ||
| 1013 | }, { | ||
| 1014 | .clk = { | ||
| 1015 | .name = "sclk_audio", | ||
| 1016 | .id = 1, | ||
| 1017 | .ctrlbit = (1 << 9), | ||
| 1018 | .enable = s5pc100_sclk1_ctrl, | ||
| 1019 | |||
| 1020 | }, | ||
| 1021 | .sources = &clk_src_group4, | ||
| 1022 | .reg_src = { .reg = S5P_CLK_SRC3, .shift = 16, .size = 3 }, | ||
| 1023 | .reg_div = { .reg = S5P_CLK_DIV4, .shift = 16, .size = 4 }, | ||
| 1024 | }, { | ||
| 1025 | .clk = { | ||
| 1026 | .name = "sclk_audio", | ||
| 1027 | .id = 2, | ||
| 1028 | .ctrlbit = (1 << 10), | ||
| 1029 | .enable = s5pc100_sclk1_ctrl, | ||
| 1030 | |||
| 1031 | }, | ||
| 1032 | .sources = &clk_src_group5, | ||
| 1033 | .reg_src = { .reg = S5P_CLK_SRC3, .shift = 20, .size = 3 }, | ||
| 1034 | .reg_div = { .reg = S5P_CLK_DIV4, .shift = 20, .size = 4 }, | ||
| 1035 | }, { | ||
| 1036 | .clk = { | ||
| 1037 | .name = "sclk_lcd", | 1083 | .name = "sclk_lcd", |
| 1038 | .id = -1, | 1084 | .id = -1, |
| 1039 | .ctrlbit = (1 << 0), | 1085 | .ctrlbit = (1 << 0), |
| @@ -1179,6 +1225,10 @@ static struct clksrc_clk *sysclks[] = { | |||
| 1179 | &clk_div_pclkd1, | 1225 | &clk_div_pclkd1, |
| 1180 | &clk_div_cam, | 1226 | &clk_div_cam, |
| 1181 | &clk_div_hdmi, | 1227 | &clk_div_hdmi, |
| 1228 | &clk_sclk_audio0, | ||
| 1229 | &clk_sclk_audio1, | ||
| 1230 | &clk_sclk_audio2, | ||
| 1231 | &clk_sclk_spdif, | ||
| 1182 | }; | 1232 | }; |
| 1183 | 1233 | ||
| 1184 | void __init_or_cpufreq s5pc100_setup_clocks(void) | 1234 | void __init_or_cpufreq s5pc100_setup_clocks(void) |
| @@ -1196,7 +1246,7 @@ void __init_or_cpufreq s5pc100_setup_clocks(void) | |||
| 1196 | unsigned int ptr; | 1246 | unsigned int ptr; |
| 1197 | 1247 | ||
| 1198 | /* Set S5PC100 functions for clk_fout_epll */ | 1248 | /* Set S5PC100 functions for clk_fout_epll */ |
| 1199 | clk_fout_epll.enable = s5pc100_epll_enable; | 1249 | clk_fout_epll.enable = s5p_epll_enable; |
| 1200 | clk_fout_epll.ops = &s5pc100_epll_ops; | 1250 | clk_fout_epll.ops = &s5pc100_epll_ops; |
| 1201 | 1251 | ||
| 1202 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); | 1252 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); |
diff --git a/arch/arm/mach-s5pc100/dev-audio.c b/arch/arm/mach-s5pc100/dev-audio.c index a699ed6acc23..564e195ec493 100644 --- a/arch/arm/mach-s5pc100/dev-audio.c +++ b/arch/arm/mach-s5pc100/dev-audio.c | |||
| @@ -24,19 +24,11 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev) | |||
| 24 | /* configure GPIO for i2s port */ | 24 | /* configure GPIO for i2s port */ |
| 25 | switch (pdev->id) { | 25 | switch (pdev->id) { |
| 26 | case 1: | 26 | case 1: |
| 27 | s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(2)); | 27 | s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(2)); |
| 28 | s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(2)); | ||
| 30 | s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(2)); | ||
| 31 | s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(2)); | ||
| 32 | break; | 28 | break; |
| 33 | 29 | ||
| 34 | case 2: | 30 | case 2: |
| 35 | s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(4)); | 31 | s3c_gpio_cfgpin_range(S5PC100_GPG3(0), 5, S3C_GPIO_SFN(4)); |
| 36 | s3c_gpio_cfgpin(S5PC100_GPG3(1), S3C_GPIO_SFN(4)); | ||
| 37 | s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(4)); | ||
| 38 | s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(4)); | ||
| 39 | s3c_gpio_cfgpin(S5PC100_GPG3(4), S3C_GPIO_SFN(4)); | ||
| 40 | break; | 32 | break; |
| 41 | 33 | ||
| 42 | case -1: /* Dedicated pins */ | 34 | case -1: /* Dedicated pins */ |
| @@ -144,19 +136,11 @@ static int s5pc100_pcm_cfg_gpio(struct platform_device *pdev) | |||
| 144 | { | 136 | { |
| 145 | switch (pdev->id) { | 137 | switch (pdev->id) { |
| 146 | case 0: | 138 | case 0: |
| 147 | s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(5)); | 139 | s3c_gpio_cfgpin_range(S5PC100_GPG3(0), 5, S3C_GPIO_SFN(5)); |
| 148 | s3c_gpio_cfgpin(S5PC100_GPG3(1), S3C_GPIO_SFN(5)); | ||
| 149 | s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(5)); | ||
| 150 | s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(5)); | ||
| 151 | s3c_gpio_cfgpin(S5PC100_GPG3(4), S3C_GPIO_SFN(5)); | ||
| 152 | break; | 140 | break; |
| 153 | 141 | ||
| 154 | case 1: | 142 | case 1: |
| 155 | s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(3)); | 143 | s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(3)); |
| 156 | s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(3)); | ||
| 157 | s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(3)); | ||
| 158 | s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(3)); | ||
| 159 | s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(3)); | ||
| 160 | break; | 144 | break; |
| 161 | 145 | ||
| 162 | default: | 146 | default: |
| @@ -231,13 +215,7 @@ struct platform_device s5pc100_device_pcm1 = { | |||
| 231 | 215 | ||
| 232 | static int s5pc100_ac97_cfg_gpio(struct platform_device *pdev) | 216 | static int s5pc100_ac97_cfg_gpio(struct platform_device *pdev) |
| 233 | { | 217 | { |
| 234 | s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(4)); | 218 | return s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(4)); |
| 235 | s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(4)); | ||
| 236 | s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(4)); | ||
| 237 | s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(4)); | ||
| 238 | s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(4)); | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | 219 | } |
| 242 | 220 | ||
| 243 | static struct resource s5pc100_ac97_resource[] = { | 221 | static struct resource s5pc100_ac97_resource[] = { |
| @@ -285,3 +263,57 @@ struct platform_device s5pc100_device_ac97 = { | |||
| 285 | .coherent_dma_mask = DMA_BIT_MASK(32), | 263 | .coherent_dma_mask = DMA_BIT_MASK(32), |
| 286 | }, | 264 | }, |
| 287 | }; | 265 | }; |
| 266 | |||
| 267 | /* S/PDIF Controller platform_device */ | ||
| 268 | static int s5pc100_spdif_cfg_gpd(struct platform_device *pdev) | ||
| 269 | { | ||
| 270 | s3c_gpio_cfgpin_range(S5PC100_GPD(5), 2, S3C_GPIO_SFN(3)); | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int s5pc100_spdif_cfg_gpg3(struct platform_device *pdev) | ||
| 276 | { | ||
| 277 | s3c_gpio_cfgpin_range(S5PC100_GPG3(5), 2, S3C_GPIO_SFN(3)); | ||
| 278 | |||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | static struct resource s5pc100_spdif_resource[] = { | ||
| 283 | [0] = { | ||
| 284 | .start = S5PC100_PA_SPDIF, | ||
| 285 | .end = S5PC100_PA_SPDIF + 0x100 - 1, | ||
| 286 | .flags = IORESOURCE_MEM, | ||
| 287 | }, | ||
| 288 | [1] = { | ||
| 289 | .start = DMACH_SPDIF, | ||
| 290 | .end = DMACH_SPDIF, | ||
| 291 | .flags = IORESOURCE_DMA, | ||
| 292 | }, | ||
| 293 | }; | ||
| 294 | |||
| 295 | static struct s3c_audio_pdata s5p_spdif_pdata = { | ||
| 296 | .cfg_gpio = s5pc100_spdif_cfg_gpd, | ||
| 297 | }; | ||
| 298 | |||
| 299 | static u64 s5pc100_spdif_dmamask = DMA_BIT_MASK(32); | ||
| 300 | |||
| 301 | struct platform_device s5pc100_device_spdif = { | ||
| 302 | .name = "samsung-spdif", | ||
| 303 | .id = -1, | ||
| 304 | .num_resources = ARRAY_SIZE(s5pc100_spdif_resource), | ||
| 305 | .resource = s5pc100_spdif_resource, | ||
| 306 | .dev = { | ||
| 307 | .platform_data = &s5p_spdif_pdata, | ||
| 308 | .dma_mask = &s5pc100_spdif_dmamask, | ||
| 309 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
| 310 | }, | ||
| 311 | }; | ||
| 312 | |||
| 313 | void __init s5pc100_spdif_setup_gpio(int gpio) | ||
| 314 | { | ||
| 315 | if (gpio == S5PC100_SPDIF_GPD) | ||
| 316 | s5p_spdif_pdata.cfg_gpio = s5pc100_spdif_cfg_gpd; | ||
| 317 | else | ||
| 318 | s5p_spdif_pdata.cfg_gpio = s5pc100_spdif_cfg_gpg3; | ||
| 319 | } | ||
diff --git a/arch/arm/mach-s5pc100/dev-spi.c b/arch/arm/mach-s5pc100/dev-spi.c index a0ef7c302c16..57b19794d9bb 100644 --- a/arch/arm/mach-s5pc100/dev-spi.c +++ b/arch/arm/mach-s5pc100/dev-spi.c | |||
| @@ -38,30 +38,20 @@ static int s5pc100_spi_cfg_gpio(struct platform_device *pdev) | |||
| 38 | { | 38 | { |
| 39 | switch (pdev->id) { | 39 | switch (pdev->id) { |
| 40 | case 0: | 40 | case 0: |
| 41 | s3c_gpio_cfgpin(S5PC100_GPB(0), S3C_GPIO_SFN(2)); | 41 | s3c_gpio_cfgall_range(S5PC100_GPB(0), 3, |
| 42 | s3c_gpio_cfgpin(S5PC100_GPB(1), S3C_GPIO_SFN(2)); | 42 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 43 | s3c_gpio_cfgpin(S5PC100_GPB(2), S3C_GPIO_SFN(2)); | ||
| 44 | s3c_gpio_setpull(S5PC100_GPB(0), S3C_GPIO_PULL_UP); | ||
| 45 | s3c_gpio_setpull(S5PC100_GPB(1), S3C_GPIO_PULL_UP); | ||
| 46 | s3c_gpio_setpull(S5PC100_GPB(2), S3C_GPIO_PULL_UP); | ||
| 47 | break; | 43 | break; |
| 48 | 44 | ||
| 49 | case 1: | 45 | case 1: |
| 50 | s3c_gpio_cfgpin(S5PC100_GPB(4), S3C_GPIO_SFN(2)); | 46 | s3c_gpio_cfgall_range(S5PC100_GPB(4), 3, |
| 51 | s3c_gpio_cfgpin(S5PC100_GPB(5), S3C_GPIO_SFN(2)); | 47 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 52 | s3c_gpio_cfgpin(S5PC100_GPB(6), S3C_GPIO_SFN(2)); | ||
| 53 | s3c_gpio_setpull(S5PC100_GPB(4), S3C_GPIO_PULL_UP); | ||
| 54 | s3c_gpio_setpull(S5PC100_GPB(5), S3C_GPIO_PULL_UP); | ||
| 55 | s3c_gpio_setpull(S5PC100_GPB(6), S3C_GPIO_PULL_UP); | ||
| 56 | break; | 48 | break; |
| 57 | 49 | ||
| 58 | case 2: | 50 | case 2: |
| 59 | s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(3)); | 51 | s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(3)); |
| 60 | s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(3)); | ||
| 61 | s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(3)); | ||
| 62 | s3c_gpio_setpull(S5PC100_GPG3(0), S3C_GPIO_PULL_UP); | 52 | s3c_gpio_setpull(S5PC100_GPG3(0), S3C_GPIO_PULL_UP); |
| 63 | s3c_gpio_setpull(S5PC100_GPG3(2), S3C_GPIO_PULL_UP); | 53 | s3c_gpio_cfgall_range(S5PC100_GPB(2), 2, |
| 64 | s3c_gpio_setpull(S5PC100_GPG3(3), S3C_GPIO_PULL_UP); | 54 | S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); |
| 65 | break; | 55 | break; |
| 66 | 56 | ||
| 67 | default: | 57 | default: |
diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c index 0f5517571e2c..bf4cd0fb97c6 100644 --- a/arch/arm/mach-s5pc100/dma.c +++ b/arch/arm/mach-s5pc100/dma.c | |||
| @@ -81,7 +81,7 @@ static struct s3c_pl330_platdata s5pc100_pdma0_pdata = { | |||
| 81 | 81 | ||
| 82 | static struct platform_device s5pc100_device_pdma0 = { | 82 | static struct platform_device s5pc100_device_pdma0 = { |
| 83 | .name = "s3c-pl330", | 83 | .name = "s3c-pl330", |
| 84 | .id = 1, | 84 | .id = 0, |
| 85 | .num_resources = ARRAY_SIZE(s5pc100_pdma0_resource), | 85 | .num_resources = ARRAY_SIZE(s5pc100_pdma0_resource), |
| 86 | .resource = s5pc100_pdma0_resource, | 86 | .resource = s5pc100_pdma0_resource, |
| 87 | .dev = { | 87 | .dev = { |
| @@ -143,7 +143,7 @@ static struct s3c_pl330_platdata s5pc100_pdma1_pdata = { | |||
| 143 | 143 | ||
| 144 | static struct platform_device s5pc100_device_pdma1 = { | 144 | static struct platform_device s5pc100_device_pdma1 = { |
| 145 | .name = "s3c-pl330", | 145 | .name = "s3c-pl330", |
| 146 | .id = 2, | 146 | .id = 1, |
| 147 | .num_resources = ARRAY_SIZE(s5pc100_pdma1_resource), | 147 | .num_resources = ARRAY_SIZE(s5pc100_pdma1_resource), |
| 148 | .resource = s5pc100_pdma1_resource, | 148 | .resource = s5pc100_pdma1_resource, |
| 149 | .dev = { | 149 | .dev = { |
diff --git a/arch/arm/mach-s5pc100/gpiolib.c b/arch/arm/mach-s5pc100/gpiolib.c index 0fab7f2cd8bf..20856eb7dd51 100644 --- a/arch/arm/mach-s5pc100/gpiolib.c +++ b/arch/arm/mach-s5pc100/gpiolib.c | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | /* | 1 | /* linux/arch/arm/mach-s5pc100/gpiolib.c |
| 2 | * arch/arm/plat-s5pc100/gpiolib.c | 2 | * |
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 3 | * | 5 | * |
| 4 | * Copyright 2009 Samsung Electronics Co | 6 | * Copyright 2009 Samsung Electronics Co |
| 5 | * Kyungmin Park <kyungmin.park@samsung.com> | 7 | * Kyungmin Park <kyungmin.park@samsung.com> |
| @@ -61,30 +63,6 @@ | |||
| 61 | * L3 8 4Bit None | 63 | * L3 8 4Bit None |
| 62 | */ | 64 | */ |
| 63 | 65 | ||
| 64 | static int s5pc100_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) | ||
| 65 | { | ||
| 66 | return S3C_IRQ_GPIO(chip->base + offset); | ||
| 67 | } | ||
| 68 | |||
| 69 | static int s5pc100_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset) | ||
| 70 | { | ||
| 71 | int base; | ||
| 72 | |||
| 73 | base = chip->base - S5PC100_GPH0(0); | ||
| 74 | if (base == 0) | ||
| 75 | return IRQ_EINT(offset); | ||
| 76 | base = chip->base - S5PC100_GPH1(0); | ||
| 77 | if (base == 0) | ||
| 78 | return IRQ_EINT(8 + offset); | ||
| 79 | base = chip->base - S5PC100_GPH2(0); | ||
| 80 | if (base == 0) | ||
| 81 | return IRQ_EINT(16 + offset); | ||
| 82 | base = chip->base - S5PC100_GPH3(0); | ||
| 83 | if (base == 0) | ||
| 84 | return IRQ_EINT(24 + offset); | ||
| 85 | return -EINVAL; | ||
| 86 | } | ||
| 87 | |||
| 88 | static struct s3c_gpio_cfg gpio_cfg = { | 66 | static struct s3c_gpio_cfg gpio_cfg = { |
| 89 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | 67 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, |
| 90 | .set_pull = s3c_gpio_setpull_updown, | 68 | .set_pull = s3c_gpio_setpull_updown, |
| @@ -104,209 +82,150 @@ static struct s3c_gpio_cfg gpio_cfg_noint = { | |||
| 104 | .get_pull = s3c_gpio_getpull_updown, | 82 | .get_pull = s3c_gpio_getpull_updown, |
| 105 | }; | 83 | }; |
| 106 | 84 | ||
| 85 | /* | ||
| 86 | * GPIO bank's base address given the index of the bank in the | ||
| 87 | * list of all gpio banks. | ||
| 88 | */ | ||
| 89 | #define S5PC100_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)) | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Following are the gpio banks in S5PC100. | ||
| 93 | * | ||
| 94 | * The 'config' member when left to NULL, is initialized to the default | ||
| 95 | * structure gpio_cfg in the init function below. | ||
| 96 | * | ||
| 97 | * The 'base' member is also initialized in the init function below. | ||
| 98 | * Note: The initialization of 'base' member of s3c_gpio_chip structure | ||
| 99 | * uses the above macro and depends on the banks being listed in order here. | ||
| 100 | */ | ||
| 107 | static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | 101 | static struct s3c_gpio_chip s5pc100_gpio_chips[] = { |
| 108 | { | 102 | { |
| 109 | .base = S5PC100_GPA0_BASE, | ||
| 110 | .config = &gpio_cfg, | ||
| 111 | .chip = { | 103 | .chip = { |
| 112 | .base = S5PC100_GPA0(0), | 104 | .base = S5PC100_GPA0(0), |
| 113 | .ngpio = S5PC100_GPIO_A0_NR, | 105 | .ngpio = S5PC100_GPIO_A0_NR, |
| 114 | .label = "GPA0", | 106 | .label = "GPA0", |
| 115 | }, | 107 | }, |
| 116 | }, { | 108 | }, { |
| 117 | .base = S5PC100_GPA1_BASE, | ||
| 118 | .config = &gpio_cfg, | ||
| 119 | .chip = { | 109 | .chip = { |
| 120 | .base = S5PC100_GPA1(0), | 110 | .base = S5PC100_GPA1(0), |
| 121 | .ngpio = S5PC100_GPIO_A1_NR, | 111 | .ngpio = S5PC100_GPIO_A1_NR, |
| 122 | .label = "GPA1", | 112 | .label = "GPA1", |
| 123 | }, | 113 | }, |
| 124 | }, { | 114 | }, { |
| 125 | .base = S5PC100_GPB_BASE, | ||
| 126 | .config = &gpio_cfg, | ||
| 127 | .chip = { | 115 | .chip = { |
| 128 | .base = S5PC100_GPB(0), | 116 | .base = S5PC100_GPB(0), |
| 129 | .ngpio = S5PC100_GPIO_B_NR, | 117 | .ngpio = S5PC100_GPIO_B_NR, |
| 130 | .label = "GPB", | 118 | .label = "GPB", |
| 131 | }, | 119 | }, |
| 132 | }, { | 120 | }, { |
| 133 | .base = S5PC100_GPC_BASE, | ||
| 134 | .config = &gpio_cfg, | ||
| 135 | .chip = { | 121 | .chip = { |
| 136 | .base = S5PC100_GPC(0), | 122 | .base = S5PC100_GPC(0), |
| 137 | .ngpio = S5PC100_GPIO_C_NR, | 123 | .ngpio = S5PC100_GPIO_C_NR, |
| 138 | .label = "GPC", | 124 | .label = "GPC", |
| 139 | }, | 125 | }, |
| 140 | }, { | 126 | }, { |
| 141 | .base = S5PC100_GPD_BASE, | ||
| 142 | .config = &gpio_cfg, | ||
| 143 | .chip = { | 127 | .chip = { |
| 144 | .base = S5PC100_GPD(0), | 128 | .base = S5PC100_GPD(0), |
| 145 | .ngpio = S5PC100_GPIO_D_NR, | 129 | .ngpio = S5PC100_GPIO_D_NR, |
| 146 | .label = "GPD", | 130 | .label = "GPD", |
| 147 | }, | 131 | }, |
| 148 | }, { | 132 | }, { |
| 149 | .base = S5PC100_GPE0_BASE, | ||
| 150 | .config = &gpio_cfg, | ||
| 151 | .chip = { | 133 | .chip = { |
| 152 | .base = S5PC100_GPE0(0), | 134 | .base = S5PC100_GPE0(0), |
| 153 | .ngpio = S5PC100_GPIO_E0_NR, | 135 | .ngpio = S5PC100_GPIO_E0_NR, |
| 154 | .label = "GPE0", | 136 | .label = "GPE0", |
| 155 | }, | 137 | }, |
| 156 | }, { | 138 | }, { |
| 157 | .base = S5PC100_GPE1_BASE, | ||
| 158 | .config = &gpio_cfg, | ||
| 159 | .chip = { | 139 | .chip = { |
| 160 | .base = S5PC100_GPE1(0), | 140 | .base = S5PC100_GPE1(0), |
| 161 | .ngpio = S5PC100_GPIO_E1_NR, | 141 | .ngpio = S5PC100_GPIO_E1_NR, |
| 162 | .label = "GPE1", | 142 | .label = "GPE1", |
| 163 | }, | 143 | }, |
| 164 | }, { | 144 | }, { |
| 165 | .base = S5PC100_GPF0_BASE, | ||
| 166 | .config = &gpio_cfg, | ||
| 167 | .chip = { | 145 | .chip = { |
| 168 | .base = S5PC100_GPF0(0), | 146 | .base = S5PC100_GPF0(0), |
| 169 | .ngpio = S5PC100_GPIO_F0_NR, | 147 | .ngpio = S5PC100_GPIO_F0_NR, |
| 170 | .label = "GPF0", | 148 | .label = "GPF0", |
| 171 | }, | 149 | }, |
| 172 | }, { | 150 | }, { |
| 173 | .base = S5PC100_GPF1_BASE, | ||
| 174 | .config = &gpio_cfg, | ||
| 175 | .chip = { | 151 | .chip = { |
| 176 | .base = S5PC100_GPF1(0), | 152 | .base = S5PC100_GPF1(0), |
| 177 | .ngpio = S5PC100_GPIO_F1_NR, | 153 | .ngpio = S5PC100_GPIO_F1_NR, |
| 178 | .label = "GPF1", | 154 | .label = "GPF1", |
| 179 | }, | 155 | }, |
| 180 | }, { | 156 | }, { |
| 181 | .base = S5PC100_GPF2_BASE, | ||
| 182 | .config = &gpio_cfg, | ||
| 183 | .chip = { | 157 | .chip = { |
| 184 | .base = S5PC100_GPF2(0), | 158 | .base = S5PC100_GPF2(0), |
| 185 | .ngpio = S5PC100_GPIO_F2_NR, | 159 | .ngpio = S5PC100_GPIO_F2_NR, |
| 186 | .label = "GPF2", | 160 | .label = "GPF2", |
| 187 | }, | 161 | }, |
| 188 | }, { | 162 | }, { |
| 189 | .base = S5PC100_GPF3_BASE, | ||
| 190 | .config = &gpio_cfg, | ||
| 191 | .chip = { | 163 | .chip = { |
| 192 | .base = S5PC100_GPF3(0), | 164 | .base = S5PC100_GPF3(0), |
| 193 | .ngpio = S5PC100_GPIO_F3_NR, | 165 | .ngpio = S5PC100_GPIO_F3_NR, |
| 194 | .label = "GPF3", | 166 | .label = "GPF3", |
| 195 | }, | 167 | }, |
| 196 | }, { | 168 | }, { |
| 197 | .base = S5PC100_GPG0_BASE, | ||
| 198 | .config = &gpio_cfg, | ||
| 199 | .chip = { | 169 | .chip = { |
| 200 | .base = S5PC100_GPG0(0), | 170 | .base = S5PC100_GPG0(0), |
| 201 | .ngpio = S5PC100_GPIO_G0_NR, | 171 | .ngpio = S5PC100_GPIO_G0_NR, |
| 202 | .label = "GPG0", | 172 | .label = "GPG0", |
| 203 | }, | 173 | }, |
| 204 | }, { | 174 | }, { |
| 205 | .base = S5PC100_GPG1_BASE, | ||
| 206 | .config = &gpio_cfg, | ||
| 207 | .chip = { | 175 | .chip = { |
| 208 | .base = S5PC100_GPG1(0), | 176 | .base = S5PC100_GPG1(0), |
| 209 | .ngpio = S5PC100_GPIO_G1_NR, | 177 | .ngpio = S5PC100_GPIO_G1_NR, |
| 210 | .label = "GPG1", | 178 | .label = "GPG1", |
| 211 | }, | 179 | }, |
| 212 | }, { | 180 | }, { |
| 213 | .base = S5PC100_GPG2_BASE, | ||
| 214 | .config = &gpio_cfg, | ||
| 215 | .chip = { | 181 | .chip = { |
| 216 | .base = S5PC100_GPG2(0), | 182 | .base = S5PC100_GPG2(0), |
| 217 | .ngpio = S5PC100_GPIO_G2_NR, | 183 | .ngpio = S5PC100_GPIO_G2_NR, |
| 218 | .label = "GPG2", | 184 | .label = "GPG2", |
| 219 | }, | 185 | }, |
| 220 | }, { | 186 | }, { |
| 221 | .base = S5PC100_GPG3_BASE, | ||
| 222 | .config = &gpio_cfg, | ||
| 223 | .chip = { | 187 | .chip = { |
| 224 | .base = S5PC100_GPG3(0), | 188 | .base = S5PC100_GPG3(0), |
| 225 | .ngpio = S5PC100_GPIO_G3_NR, | 189 | .ngpio = S5PC100_GPIO_G3_NR, |
| 226 | .label = "GPG3", | 190 | .label = "GPG3", |
| 227 | }, | 191 | }, |
| 228 | }, { | 192 | }, { |
| 229 | .base = S5PC100_GPH0_BASE, | ||
| 230 | .config = &gpio_cfg_eint, | ||
| 231 | .chip = { | ||
| 232 | .base = S5PC100_GPH0(0), | ||
| 233 | .ngpio = S5PC100_GPIO_H0_NR, | ||
| 234 | .label = "GPH0", | ||
| 235 | }, | ||
| 236 | }, { | ||
| 237 | .base = S5PC100_GPH1_BASE, | ||
| 238 | .config = &gpio_cfg_eint, | ||
| 239 | .chip = { | ||
| 240 | .base = S5PC100_GPH1(0), | ||
| 241 | .ngpio = S5PC100_GPIO_H1_NR, | ||
| 242 | .label = "GPH1", | ||
| 243 | }, | ||
| 244 | }, { | ||
| 245 | .base = S5PC100_GPH2_BASE, | ||
| 246 | .config = &gpio_cfg_eint, | ||
| 247 | .chip = { | ||
| 248 | .base = S5PC100_GPH2(0), | ||
| 249 | .ngpio = S5PC100_GPIO_H2_NR, | ||
| 250 | .label = "GPH2", | ||
| 251 | }, | ||
| 252 | }, { | ||
| 253 | .base = S5PC100_GPH3_BASE, | ||
| 254 | .config = &gpio_cfg_eint, | ||
| 255 | .chip = { | ||
| 256 | .base = S5PC100_GPH3(0), | ||
| 257 | .ngpio = S5PC100_GPIO_H3_NR, | ||
| 258 | .label = "GPH3", | ||
| 259 | }, | ||
| 260 | }, { | ||
| 261 | .base = S5PC100_GPI_BASE, | ||
| 262 | .config = &gpio_cfg, | ||
| 263 | .chip = { | 193 | .chip = { |
| 264 | .base = S5PC100_GPI(0), | 194 | .base = S5PC100_GPI(0), |
| 265 | .ngpio = S5PC100_GPIO_I_NR, | 195 | .ngpio = S5PC100_GPIO_I_NR, |
| 266 | .label = "GPI", | 196 | .label = "GPI", |
| 267 | }, | 197 | }, |
| 268 | }, { | 198 | }, { |
| 269 | .base = S5PC100_GPJ0_BASE, | ||
| 270 | .config = &gpio_cfg, | ||
| 271 | .chip = { | 199 | .chip = { |
| 272 | .base = S5PC100_GPJ0(0), | 200 | .base = S5PC100_GPJ0(0), |
| 273 | .ngpio = S5PC100_GPIO_J0_NR, | 201 | .ngpio = S5PC100_GPIO_J0_NR, |
| 274 | .label = "GPJ0", | 202 | .label = "GPJ0", |
| 275 | }, | 203 | }, |
| 276 | }, { | 204 | }, { |
| 277 | .base = S5PC100_GPJ1_BASE, | ||
| 278 | .config = &gpio_cfg, | ||
| 279 | .chip = { | 205 | .chip = { |
| 280 | .base = S5PC100_GPJ1(0), | 206 | .base = S5PC100_GPJ1(0), |
| 281 | .ngpio = S5PC100_GPIO_J1_NR, | 207 | .ngpio = S5PC100_GPIO_J1_NR, |
| 282 | .label = "GPJ1", | 208 | .label = "GPJ1", |
| 283 | }, | 209 | }, |
| 284 | }, { | 210 | }, { |
| 285 | .base = S5PC100_GPJ2_BASE, | ||
| 286 | .config = &gpio_cfg, | ||
| 287 | .chip = { | 211 | .chip = { |
| 288 | .base = S5PC100_GPJ2(0), | 212 | .base = S5PC100_GPJ2(0), |
| 289 | .ngpio = S5PC100_GPIO_J2_NR, | 213 | .ngpio = S5PC100_GPIO_J2_NR, |
| 290 | .label = "GPJ2", | 214 | .label = "GPJ2", |
| 291 | }, | 215 | }, |
| 292 | }, { | 216 | }, { |
| 293 | .base = S5PC100_GPJ3_BASE, | ||
| 294 | .config = &gpio_cfg, | ||
| 295 | .chip = { | 217 | .chip = { |
| 296 | .base = S5PC100_GPJ3(0), | 218 | .base = S5PC100_GPJ3(0), |
| 297 | .ngpio = S5PC100_GPIO_J3_NR, | 219 | .ngpio = S5PC100_GPIO_J3_NR, |
| 298 | .label = "GPJ3", | 220 | .label = "GPJ3", |
| 299 | }, | 221 | }, |
| 300 | }, { | 222 | }, { |
| 301 | .base = S5PC100_GPJ4_BASE, | ||
| 302 | .config = &gpio_cfg, | ||
| 303 | .chip = { | 223 | .chip = { |
| 304 | .base = S5PC100_GPJ4(0), | 224 | .base = S5PC100_GPJ4(0), |
| 305 | .ngpio = S5PC100_GPIO_J4_NR, | 225 | .ngpio = S5PC100_GPIO_J4_NR, |
| 306 | .label = "GPJ4", | 226 | .label = "GPJ4", |
| 307 | }, | 227 | }, |
| 308 | }, { | 228 | }, { |
| 309 | .base = S5PC100_GPK0_BASE, | ||
| 310 | .config = &gpio_cfg_noint, | 229 | .config = &gpio_cfg_noint, |
| 311 | .chip = { | 230 | .chip = { |
| 312 | .base = S5PC100_GPK0(0), | 231 | .base = S5PC100_GPK0(0), |
| @@ -314,7 +233,6 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 314 | .label = "GPK0", | 233 | .label = "GPK0", |
| 315 | }, | 234 | }, |
| 316 | }, { | 235 | }, { |
| 317 | .base = S5PC100_GPK1_BASE, | ||
| 318 | .config = &gpio_cfg_noint, | 236 | .config = &gpio_cfg_noint, |
| 319 | .chip = { | 237 | .chip = { |
| 320 | .base = S5PC100_GPK1(0), | 238 | .base = S5PC100_GPK1(0), |
| @@ -322,7 +240,6 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 322 | .label = "GPK1", | 240 | .label = "GPK1", |
| 323 | }, | 241 | }, |
| 324 | }, { | 242 | }, { |
| 325 | .base = S5PC100_GPK2_BASE, | ||
| 326 | .config = &gpio_cfg_noint, | 243 | .config = &gpio_cfg_noint, |
| 327 | .chip = { | 244 | .chip = { |
| 328 | .base = S5PC100_GPK2(0), | 245 | .base = S5PC100_GPK2(0), |
| @@ -330,7 +247,6 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 330 | .label = "GPK2", | 247 | .label = "GPK2", |
| 331 | }, | 248 | }, |
| 332 | }, { | 249 | }, { |
| 333 | .base = S5PC100_GPK3_BASE, | ||
| 334 | .config = &gpio_cfg_noint, | 250 | .config = &gpio_cfg_noint, |
| 335 | .chip = { | 251 | .chip = { |
| 336 | .base = S5PC100_GPK3(0), | 252 | .base = S5PC100_GPK3(0), |
| @@ -338,7 +254,6 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 338 | .label = "GPK3", | 254 | .label = "GPK3", |
| 339 | }, | 255 | }, |
| 340 | }, { | 256 | }, { |
| 341 | .base = S5PC100_GPL0_BASE, | ||
| 342 | .config = &gpio_cfg_noint, | 257 | .config = &gpio_cfg_noint, |
| 343 | .chip = { | 258 | .chip = { |
| 344 | .base = S5PC100_GPL0(0), | 259 | .base = S5PC100_GPL0(0), |
| @@ -346,7 +261,6 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 346 | .label = "GPL0", | 261 | .label = "GPL0", |
| 347 | }, | 262 | }, |
| 348 | }, { | 263 | }, { |
| 349 | .base = S5PC100_GPL1_BASE, | ||
| 350 | .config = &gpio_cfg_noint, | 264 | .config = &gpio_cfg_noint, |
| 351 | .chip = { | 265 | .chip = { |
| 352 | .base = S5PC100_GPL1(0), | 266 | .base = S5PC100_GPL1(0), |
| @@ -354,7 +268,6 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 354 | .label = "GPL1", | 268 | .label = "GPL1", |
| 355 | }, | 269 | }, |
| 356 | }, { | 270 | }, { |
| 357 | .base = S5PC100_GPL2_BASE, | ||
| 358 | .config = &gpio_cfg_noint, | 271 | .config = &gpio_cfg_noint, |
| 359 | .chip = { | 272 | .chip = { |
| 360 | .base = S5PC100_GPL2(0), | 273 | .base = S5PC100_GPL2(0), |
| @@ -362,7 +275,6 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 362 | .label = "GPL2", | 275 | .label = "GPL2", |
| 363 | }, | 276 | }, |
| 364 | }, { | 277 | }, { |
| 365 | .base = S5PC100_GPL3_BASE, | ||
| 366 | .config = &gpio_cfg_noint, | 278 | .config = &gpio_cfg_noint, |
| 367 | .chip = { | 279 | .chip = { |
| 368 | .base = S5PC100_GPL3(0), | 280 | .base = S5PC100_GPL3(0), |
| @@ -370,56 +282,72 @@ static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | |||
| 370 | .label = "GPL3", | 282 | .label = "GPL3", |
| 371 | }, | 283 | }, |
| 372 | }, { | 284 | }, { |
| 373 | .base = S5PC100_GPL4_BASE, | ||
| 374 | .config = &gpio_cfg_noint, | 285 | .config = &gpio_cfg_noint, |
| 375 | .chip = { | 286 | .chip = { |
| 376 | .base = S5PC100_GPL4(0), | 287 | .base = S5PC100_GPL4(0), |
| 377 | .ngpio = S5PC100_GPIO_L4_NR, | 288 | .ngpio = S5PC100_GPIO_L4_NR, |
| 378 | .label = "GPL4", | 289 | .label = "GPL4", |
| 379 | }, | 290 | }, |
| 291 | }, { | ||
| 292 | .base = (S5P_VA_GPIO + 0xC00), | ||
| 293 | .config = &gpio_cfg_eint, | ||
| 294 | .irq_base = IRQ_EINT(0), | ||
| 295 | .chip = { | ||
| 296 | .base = S5PC100_GPH0(0), | ||
| 297 | .ngpio = S5PC100_GPIO_H0_NR, | ||
| 298 | .label = "GPH0", | ||
| 299 | .to_irq = samsung_gpiolib_to_irq, | ||
| 300 | }, | ||
| 301 | }, { | ||
| 302 | .base = (S5P_VA_GPIO + 0xC20), | ||
| 303 | .config = &gpio_cfg_eint, | ||
| 304 | .irq_base = IRQ_EINT(8), | ||
| 305 | .chip = { | ||
| 306 | .base = S5PC100_GPH1(0), | ||
| 307 | .ngpio = S5PC100_GPIO_H1_NR, | ||
| 308 | .label = "GPH1", | ||
| 309 | .to_irq = samsung_gpiolib_to_irq, | ||
| 310 | }, | ||
| 311 | }, { | ||
| 312 | .base = (S5P_VA_GPIO + 0xC40), | ||
| 313 | .config = &gpio_cfg_eint, | ||
| 314 | .irq_base = IRQ_EINT(16), | ||
| 315 | .chip = { | ||
| 316 | .base = S5PC100_GPH2(0), | ||
| 317 | .ngpio = S5PC100_GPIO_H2_NR, | ||
| 318 | .label = "GPH2", | ||
| 319 | .to_irq = samsung_gpiolib_to_irq, | ||
| 320 | }, | ||
| 321 | }, { | ||
| 322 | .base = (S5P_VA_GPIO + 0xC60), | ||
| 323 | .config = &gpio_cfg_eint, | ||
| 324 | .irq_base = IRQ_EINT(24), | ||
| 325 | .chip = { | ||
| 326 | .base = S5PC100_GPH3(0), | ||
| 327 | .ngpio = S5PC100_GPIO_H3_NR, | ||
| 328 | .label = "GPH3", | ||
| 329 | .to_irq = samsung_gpiolib_to_irq, | ||
| 330 | }, | ||
| 380 | }, | 331 | }, |
| 381 | }; | 332 | }; |
| 382 | 333 | ||
| 383 | /* FIXME move from irq-gpio.c */ | 334 | static __init int s5pc100_gpiolib_init(void) |
| 384 | extern struct irq_chip s5pc100_gpioint; | ||
| 385 | extern void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc); | ||
| 386 | |||
| 387 | static __init void s5pc100_gpiolib_link(struct s3c_gpio_chip *chip) | ||
| 388 | { | 335 | { |
| 389 | /* Interrupt */ | 336 | struct s3c_gpio_chip *chip = s5pc100_gpio_chips; |
| 390 | if (chip->config == &gpio_cfg) { | 337 | int nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); |
| 391 | int i, irq; | 338 | int gpioint_group = 0; |
| 392 | 339 | int i; | |
| 393 | chip->chip.to_irq = s5pc100_gpiolib_to_irq; | ||
| 394 | 340 | ||
| 395 | for (i = 0; i < chip->chip.ngpio; i++) { | 341 | for (i = 0; i < nr_chips; i++, chip++) { |
| 396 | irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i; | 342 | if (chip->config == NULL) { |
| 397 | set_irq_chip(irq, &s5pc100_gpioint); | 343 | chip->config = &gpio_cfg; |
| 398 | set_irq_data(irq, &chip->chip); | 344 | chip->group = gpioint_group++; |
| 399 | set_irq_handler(irq, handle_level_irq); | ||
| 400 | set_irq_flags(irq, IRQF_VALID); | ||
| 401 | } | 345 | } |
| 402 | } else if (chip->config == &gpio_cfg_eint) { | 346 | if (chip->base == NULL) |
| 403 | chip->chip.to_irq = s5pc100_gpiolib_to_eint; | 347 | chip->base = S5PC100_BANK_BASE(i); |
| 404 | } | 348 | } |
| 405 | } | ||
| 406 | |||
| 407 | static __init int s5pc100_gpiolib_init(void) | ||
| 408 | { | ||
| 409 | struct s3c_gpio_chip *chip; | ||
| 410 | int nr_chips; | ||
| 411 | |||
| 412 | chip = s5pc100_gpio_chips; | ||
| 413 | nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); | ||
| 414 | |||
| 415 | for (; nr_chips > 0; nr_chips--, chip++) | ||
| 416 | s5pc100_gpiolib_link(chip); | ||
| 417 | |||
| 418 | samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, | ||
| 419 | ARRAY_SIZE(s5pc100_gpio_chips)); | ||
| 420 | 349 | ||
| 421 | /* Interrupt */ | 350 | samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips); |
| 422 | set_irq_chained_handler(IRQ_GPIOINT, s5pc100_irq_gpioint_handler); | ||
| 423 | 351 | ||
| 424 | return 0; | 352 | return 0; |
| 425 | } | 353 | } |
diff --git a/arch/arm/mach-s5pc100/include/mach/gpio.h b/arch/arm/mach-s5pc100/include/mach/gpio.h index 71ae1f52df1d..29a8a12d9b4f 100644 --- a/arch/arm/mach-s5pc100/include/mach/gpio.h +++ b/arch/arm/mach-s5pc100/include/mach/gpio.h | |||
| @@ -146,13 +146,6 @@ enum s5p_gpio_number { | |||
| 146 | /* define the number of gpios we need to the one after the MP04() range */ | 146 | /* define the number of gpios we need to the one after the MP04() range */ |
| 147 | #define ARCH_NR_GPIOS (S5PC100_GPIO_END + 1) | 147 | #define ARCH_NR_GPIOS (S5PC100_GPIO_END + 1) |
| 148 | 148 | ||
| 149 | #define EINT_MODE S3C_GPIO_SFN(0x2) | ||
| 150 | |||
| 151 | #define EINT_GPIO_0(x) S5PC100_GPH0(x) | ||
| 152 | #define EINT_GPIO_1(x) S5PC100_GPH1(x) | ||
| 153 | #define EINT_GPIO_2(x) S5PC100_GPH2(x) | ||
| 154 | #define EINT_GPIO_3(x) S5PC100_GPH3(x) | ||
| 155 | |||
| 156 | #include <asm-generic/gpio.h> | 149 | #include <asm-generic/gpio.h> |
| 157 | 150 | ||
| 158 | #endif /* __ASM_ARCH_GPIO_H */ | 151 | #endif /* __ASM_ARCH_GPIO_H */ |
diff --git a/arch/arm/mach-s5pc100/include/mach/irqs.h b/arch/arm/mach-s5pc100/include/mach/irqs.h index 06513e647242..d2eb4757381f 100644 --- a/arch/arm/mach-s5pc100/include/mach/irqs.h +++ b/arch/arm/mach-s5pc100/include/mach/irqs.h | |||
| @@ -48,8 +48,8 @@ | |||
| 48 | #define IRQ_SPI1 S5P_IRQ_VIC1(16) | 48 | #define IRQ_SPI1 S5P_IRQ_VIC1(16) |
| 49 | #define IRQ_SPI2 S5P_IRQ_VIC1(17) | 49 | #define IRQ_SPI2 S5P_IRQ_VIC1(17) |
| 50 | #define IRQ_IRDA S5P_IRQ_VIC1(18) | 50 | #define IRQ_IRDA S5P_IRQ_VIC1(18) |
| 51 | #define IRQ_CAN0 S5P_IRQ_VIC1(19) | 51 | #define IRQ_IIC2 S5P_IRQ_VIC1(19) |
| 52 | #define IRQ_CAN1 S5P_IRQ_VIC1(20) | 52 | #define IRQ_IIC3 S5P_IRQ_VIC1(20) |
| 53 | #define IRQ_HSIRX S5P_IRQ_VIC1(21) | 53 | #define IRQ_HSIRX S5P_IRQ_VIC1(21) |
| 54 | #define IRQ_HSITX S5P_IRQ_VIC1(22) | 54 | #define IRQ_HSITX S5P_IRQ_VIC1(22) |
| 55 | #define IRQ_UHOST S5P_IRQ_VIC1(23) | 55 | #define IRQ_UHOST S5P_IRQ_VIC1(23) |
| @@ -100,11 +100,12 @@ | |||
| 100 | #define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0)) | 100 | #define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0)) |
| 101 | #define S5P_EINT_BASE2 (IRQ_VIC_END + 1) | 101 | #define S5P_EINT_BASE2 (IRQ_VIC_END + 1) |
| 102 | 102 | ||
| 103 | #define S3C_IRQ_GPIO_BASE (IRQ_EINT(31) + 1) | 103 | /* GPIO interrupt */ |
| 104 | #define S3C_IRQ_GPIO(x) (S3C_IRQ_GPIO_BASE + (x)) | 104 | #define S5P_GPIOINT_BASE (IRQ_EINT(31) + 1) |
| 105 | #define S5P_GPIOINT_GROUP_MAXNR 21 | ||
| 105 | 106 | ||
| 106 | /* Until MP04 Groups -> 40 (exactly 39) Groups * 8 ~= 320 GPIOs */ | 107 | /* Set the default NR_IRQS */ |
| 107 | #define NR_IRQS (S3C_IRQ_GPIO(320) + 1) | 108 | #define NR_IRQS (IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1) |
| 108 | 109 | ||
| 109 | /* Compatibility */ | 110 | /* Compatibility */ |
| 110 | #define IRQ_LCD_FIFO IRQ_LCD0 | 111 | #define IRQ_LCD_FIFO IRQ_LCD0 |
diff --git a/arch/arm/mach-s5pc100/include/mach/map.h b/arch/arm/mach-s5pc100/include/mach/map.h index 8751ef4a6804..32e9cab5c864 100644 --- a/arch/arm/mach-s5pc100/include/mach/map.h +++ b/arch/arm/mach-s5pc100/include/mach/map.h | |||
| @@ -110,6 +110,8 @@ | |||
| 110 | #define S5PC100_PA_PCM0 0xF2400000 | 110 | #define S5PC100_PA_PCM0 0xF2400000 |
| 111 | #define S5PC100_PA_PCM1 0xF2500000 | 111 | #define S5PC100_PA_PCM1 0xF2500000 |
| 112 | 112 | ||
| 113 | #define S5PC100_PA_SPDIF 0xF2600000 | ||
| 114 | |||
| 113 | #define S5PC100_PA_TSADC (0xF3000000) | 115 | #define S5PC100_PA_TSADC (0xF3000000) |
| 114 | 116 | ||
| 115 | /* KEYPAD */ | 117 | /* KEYPAD */ |
diff --git a/arch/arm/mach-s5pc100/include/mach/regs-gpio.h b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h index dd6295e1251d..0bf73209ec7b 100644 --- a/arch/arm/mach-s5pc100/include/mach/regs-gpio.h +++ b/arch/arm/mach-s5pc100/include/mach/regs-gpio.h | |||
| @@ -11,43 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | #include <mach/map.h> | 12 | #include <mach/map.h> |
| 13 | 13 | ||
| 14 | /* S5PC100 */ | ||
| 15 | #define S5PC100_GPIO_BASE S5P_VA_GPIO | ||
| 16 | #define S5PC100_GPA0_BASE (S5PC100_GPIO_BASE + 0x0000) | ||
| 17 | #define S5PC100_GPA1_BASE (S5PC100_GPIO_BASE + 0x0020) | ||
| 18 | #define S5PC100_GPB_BASE (S5PC100_GPIO_BASE + 0x0040) | ||
| 19 | #define S5PC100_GPC_BASE (S5PC100_GPIO_BASE + 0x0060) | ||
| 20 | #define S5PC100_GPD_BASE (S5PC100_GPIO_BASE + 0x0080) | ||
| 21 | #define S5PC100_GPE0_BASE (S5PC100_GPIO_BASE + 0x00A0) | ||
| 22 | #define S5PC100_GPE1_BASE (S5PC100_GPIO_BASE + 0x00C0) | ||
| 23 | #define S5PC100_GPF0_BASE (S5PC100_GPIO_BASE + 0x00E0) | ||
| 24 | #define S5PC100_GPF1_BASE (S5PC100_GPIO_BASE + 0x0100) | ||
| 25 | #define S5PC100_GPF2_BASE (S5PC100_GPIO_BASE + 0x0120) | ||
| 26 | #define S5PC100_GPF3_BASE (S5PC100_GPIO_BASE + 0x0140) | ||
| 27 | #define S5PC100_GPG0_BASE (S5PC100_GPIO_BASE + 0x0160) | ||
| 28 | #define S5PC100_GPG1_BASE (S5PC100_GPIO_BASE + 0x0180) | ||
| 29 | #define S5PC100_GPG2_BASE (S5PC100_GPIO_BASE + 0x01A0) | ||
| 30 | #define S5PC100_GPG3_BASE (S5PC100_GPIO_BASE + 0x01C0) | ||
| 31 | #define S5PC100_GPH0_BASE (S5PC100_GPIO_BASE + 0x0C00) | ||
| 32 | #define S5PC100_GPH1_BASE (S5PC100_GPIO_BASE + 0x0C20) | ||
| 33 | #define S5PC100_GPH2_BASE (S5PC100_GPIO_BASE + 0x0C40) | ||
| 34 | #define S5PC100_GPH3_BASE (S5PC100_GPIO_BASE + 0x0C60) | ||
| 35 | #define S5PC100_GPI_BASE (S5PC100_GPIO_BASE + 0x01E0) | ||
| 36 | #define S5PC100_GPJ0_BASE (S5PC100_GPIO_BASE + 0x0200) | ||
| 37 | #define S5PC100_GPJ1_BASE (S5PC100_GPIO_BASE + 0x0220) | ||
| 38 | #define S5PC100_GPJ2_BASE (S5PC100_GPIO_BASE + 0x0240) | ||
| 39 | #define S5PC100_GPJ3_BASE (S5PC100_GPIO_BASE + 0x0260) | ||
| 40 | #define S5PC100_GPJ4_BASE (S5PC100_GPIO_BASE + 0x0280) | ||
| 41 | #define S5PC100_GPK0_BASE (S5PC100_GPIO_BASE + 0x02A0) | ||
| 42 | #define S5PC100_GPK1_BASE (S5PC100_GPIO_BASE + 0x02C0) | ||
| 43 | #define S5PC100_GPK2_BASE (S5PC100_GPIO_BASE + 0x02E0) | ||
| 44 | #define S5PC100_GPK3_BASE (S5PC100_GPIO_BASE + 0x0300) | ||
| 45 | #define S5PC100_GPL0_BASE (S5PC100_GPIO_BASE + 0x0320) | ||
| 46 | #define S5PC100_GPL1_BASE (S5PC100_GPIO_BASE + 0x0340) | ||
| 47 | #define S5PC100_GPL2_BASE (S5PC100_GPIO_BASE + 0x0360) | ||
| 48 | #define S5PC100_GPL3_BASE (S5PC100_GPIO_BASE + 0x0380) | ||
| 49 | #define S5PC100_GPL4_BASE (S5PC100_GPIO_BASE + 0x03A0) | ||
| 50 | |||
| 51 | #define S5PC100EINT30CON (S5P_VA_GPIO + 0xE00) | 14 | #define S5PC100EINT30CON (S5P_VA_GPIO + 0xE00) |
| 52 | #define S5P_EINT_CON(x) (S5PC100EINT30CON + ((x) * 0x4)) | 15 | #define S5P_EINT_CON(x) (S5PC100EINT30CON + ((x) * 0x4)) |
| 53 | 16 | ||
| @@ -64,12 +27,12 @@ | |||
| 64 | 27 | ||
| 65 | #define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7)) | 28 | #define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7)) |
| 66 | 29 | ||
| 67 | /* values for S5P_EXTINT0 */ | 30 | #define EINT_MODE S3C_GPIO_SFN(0x2) |
| 68 | #define S5P_EXTINT_LOWLEV (0x00) | 31 | |
| 69 | #define S5P_EXTINT_HILEV (0x01) | 32 | #define EINT_GPIO_0(x) S5PC100_GPH0(x) |
| 70 | #define S5P_EXTINT_FALLEDGE (0x02) | 33 | #define EINT_GPIO_1(x) S5PC100_GPH1(x) |
| 71 | #define S5P_EXTINT_RISEEDGE (0x03) | 34 | #define EINT_GPIO_2(x) S5PC100_GPH2(x) |
| 72 | #define S5P_EXTINT_BOTHEDGE (0x04) | 35 | #define EINT_GPIO_3(x) S5PC100_GPH3(x) |
| 73 | 36 | ||
| 74 | #endif /* __ASM_MACH_S5PC100_REGS_GPIO_H */ | 37 | #endif /* __ASM_MACH_S5PC100_REGS_GPIO_H */ |
| 75 | 38 | ||
diff --git a/arch/arm/mach-s5pc100/include/mach/vmalloc.h b/arch/arm/mach-s5pc100/include/mach/vmalloc.h index be9df79903ed..44c8e5726d9d 100644 --- a/arch/arm/mach-s5pc100/include/mach/vmalloc.h +++ b/arch/arm/mach-s5pc100/include/mach/vmalloc.h | |||
| @@ -12,6 +12,6 @@ | |||
| 12 | #ifndef __ASM_ARCH_VMALLOC_H | 12 | #ifndef __ASM_ARCH_VMALLOC_H |
| 13 | #define __ASM_ARCH_VMALLOC_H | 13 | #define __ASM_ARCH_VMALLOC_H |
| 14 | 14 | ||
| 15 | #define VMALLOC_END (0xe0000000UL) | 15 | #define VMALLOC_END 0xF6000000UL |
| 16 | 16 | ||
| 17 | #endif /* __ASM_ARCH_VMALLOC_H */ | 17 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s5pc100/irq-gpio.c b/arch/arm/mach-s5pc100/irq-gpio.c deleted file mode 100644 index 2bf86c18bc73..000000000000 --- a/arch/arm/mach-s5pc100/irq-gpio.c +++ /dev/null | |||
| @@ -1,266 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/mach-s5pc100/irq-gpio.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Samsung Electronics | ||
| 5 | * | ||
| 6 | * S5PC100 - Interrupt handling for IRQ_GPIO${group}(x) | ||
| 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/kernel.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/irq.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/gpio.h> | ||
| 18 | |||
| 19 | #include <mach/map.h> | ||
| 20 | #include <plat/gpio-cfg.h> | ||
| 21 | |||
| 22 | #define S5P_GPIOREG(x) (S5P_VA_GPIO + (x)) | ||
| 23 | |||
| 24 | #define CON_OFFSET 0x700 | ||
| 25 | #define MASK_OFFSET 0x900 | ||
| 26 | #define PEND_OFFSET 0xA00 | ||
| 27 | #define CON_OFFSET_2 0xE00 | ||
| 28 | #define MASK_OFFSET_2 0xF00 | ||
| 29 | #define PEND_OFFSET_2 0xF40 | ||
| 30 | |||
| 31 | #define GPIOINT_LEVEL_LOW 0x0 | ||
| 32 | #define GPIOINT_LEVEL_HIGH 0x1 | ||
| 33 | #define GPIOINT_EDGE_FALLING 0x2 | ||
| 34 | #define GPIOINT_EDGE_RISING 0x3 | ||
| 35 | #define GPIOINT_EDGE_BOTH 0x4 | ||
| 36 | |||
| 37 | static int group_to_con_offset(int group) | ||
| 38 | { | ||
| 39 | return group << 2; | ||
| 40 | } | ||
| 41 | |||
| 42 | static int group_to_mask_offset(int group) | ||
| 43 | { | ||
| 44 | return group << 2; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int group_to_pend_offset(int group) | ||
| 48 | { | ||
| 49 | return group << 2; | ||
| 50 | } | ||
| 51 | |||
| 52 | static int s5pc100_get_start(unsigned int group) | ||
| 53 | { | ||
| 54 | switch (group) { | ||
| 55 | case 0: return S5PC100_GPIO_A0_START; | ||
| 56 | case 1: return S5PC100_GPIO_A1_START; | ||
| 57 | case 2: return S5PC100_GPIO_B_START; | ||
| 58 | case 3: return S5PC100_GPIO_C_START; | ||
| 59 | case 4: return S5PC100_GPIO_D_START; | ||
| 60 | case 5: return S5PC100_GPIO_E0_START; | ||
| 61 | case 6: return S5PC100_GPIO_E1_START; | ||
| 62 | case 7: return S5PC100_GPIO_F0_START; | ||
| 63 | case 8: return S5PC100_GPIO_F1_START; | ||
| 64 | case 9: return S5PC100_GPIO_F2_START; | ||
| 65 | case 10: return S5PC100_GPIO_F3_START; | ||
| 66 | case 11: return S5PC100_GPIO_G0_START; | ||
| 67 | case 12: return S5PC100_GPIO_G1_START; | ||
| 68 | case 13: return S5PC100_GPIO_G2_START; | ||
| 69 | case 14: return S5PC100_GPIO_G3_START; | ||
| 70 | case 15: return S5PC100_GPIO_I_START; | ||
| 71 | case 16: return S5PC100_GPIO_J0_START; | ||
| 72 | case 17: return S5PC100_GPIO_J1_START; | ||
| 73 | case 18: return S5PC100_GPIO_J2_START; | ||
| 74 | case 19: return S5PC100_GPIO_J3_START; | ||
| 75 | case 20: return S5PC100_GPIO_J4_START; | ||
| 76 | default: | ||
| 77 | BUG(); | ||
| 78 | } | ||
| 79 | |||
| 80 | return -EINVAL; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int s5pc100_get_group(unsigned int irq) | ||
| 84 | { | ||
| 85 | irq -= S3C_IRQ_GPIO(0); | ||
| 86 | |||
| 87 | switch (irq) { | ||
| 88 | case S5PC100_GPIO_A0_START ... S5PC100_GPIO_A1_START - 1: | ||
| 89 | return 0; | ||
| 90 | case S5PC100_GPIO_A1_START ... S5PC100_GPIO_B_START - 1: | ||
| 91 | return 1; | ||
| 92 | case S5PC100_GPIO_B_START ... S5PC100_GPIO_C_START - 1: | ||
| 93 | return 2; | ||
| 94 | case S5PC100_GPIO_C_START ... S5PC100_GPIO_D_START - 1: | ||
| 95 | return 3; | ||
| 96 | case S5PC100_GPIO_D_START ... S5PC100_GPIO_E0_START - 1: | ||
| 97 | return 4; | ||
| 98 | case S5PC100_GPIO_E0_START ... S5PC100_GPIO_E1_START - 1: | ||
| 99 | return 5; | ||
| 100 | case S5PC100_GPIO_E1_START ... S5PC100_GPIO_F0_START - 1: | ||
| 101 | return 6; | ||
| 102 | case S5PC100_GPIO_F0_START ... S5PC100_GPIO_F1_START - 1: | ||
| 103 | return 7; | ||
| 104 | case S5PC100_GPIO_F1_START ... S5PC100_GPIO_F2_START - 1: | ||
| 105 | return 8; | ||
| 106 | case S5PC100_GPIO_F2_START ... S5PC100_GPIO_F3_START - 1: | ||
| 107 | return 9; | ||
| 108 | case S5PC100_GPIO_F3_START ... S5PC100_GPIO_G0_START - 1: | ||
| 109 | return 10; | ||
| 110 | case S5PC100_GPIO_G0_START ... S5PC100_GPIO_G1_START - 1: | ||
| 111 | return 11; | ||
| 112 | case S5PC100_GPIO_G1_START ... S5PC100_GPIO_G2_START - 1: | ||
| 113 | return 12; | ||
| 114 | case S5PC100_GPIO_G2_START ... S5PC100_GPIO_G3_START - 1: | ||
| 115 | return 13; | ||
| 116 | case S5PC100_GPIO_G3_START ... S5PC100_GPIO_H0_START - 1: | ||
| 117 | return 14; | ||
| 118 | case S5PC100_GPIO_I_START ... S5PC100_GPIO_J0_START - 1: | ||
| 119 | return 15; | ||
| 120 | case S5PC100_GPIO_J0_START ... S5PC100_GPIO_J1_START - 1: | ||
| 121 | return 16; | ||
| 122 | case S5PC100_GPIO_J1_START ... S5PC100_GPIO_J2_START - 1: | ||
| 123 | return 17; | ||
| 124 | case S5PC100_GPIO_J2_START ... S5PC100_GPIO_J3_START - 1: | ||
| 125 | return 18; | ||
| 126 | case S5PC100_GPIO_J3_START ... S5PC100_GPIO_J4_START - 1: | ||
| 127 | return 19; | ||
| 128 | case S5PC100_GPIO_J4_START ... S5PC100_GPIO_K0_START - 1: | ||
| 129 | return 20; | ||
| 130 | default: | ||
| 131 | BUG(); | ||
| 132 | } | ||
| 133 | |||
| 134 | return -EINVAL; | ||
| 135 | } | ||
| 136 | |||
| 137 | static int s5pc100_get_offset(unsigned int irq) | ||
| 138 | { | ||
| 139 | struct gpio_chip *chip = get_irq_data(irq); | ||
| 140 | return irq - S3C_IRQ_GPIO(chip->base); | ||
| 141 | } | ||
| 142 | |||
| 143 | static void s5pc100_gpioint_ack(unsigned int irq) | ||
| 144 | { | ||
| 145 | int group, offset, pend_offset; | ||
| 146 | unsigned int value; | ||
| 147 | |||
| 148 | group = s5pc100_get_group(irq); | ||
| 149 | offset = s5pc100_get_offset(irq); | ||
| 150 | pend_offset = group_to_pend_offset(group); | ||
| 151 | |||
| 152 | value = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset); | ||
| 153 | value |= 1 << offset; | ||
| 154 | __raw_writel(value, S5P_GPIOREG(PEND_OFFSET) + pend_offset); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void s5pc100_gpioint_mask(unsigned int irq) | ||
| 158 | { | ||
| 159 | int group, offset, mask_offset; | ||
| 160 | unsigned int value; | ||
| 161 | |||
| 162 | group = s5pc100_get_group(irq); | ||
| 163 | offset = s5pc100_get_offset(irq); | ||
| 164 | mask_offset = group_to_mask_offset(group); | ||
| 165 | |||
| 166 | value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset); | ||
| 167 | value |= 1 << offset; | ||
| 168 | __raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset); | ||
| 169 | } | ||
| 170 | |||
| 171 | static void s5pc100_gpioint_unmask(unsigned int irq) | ||
| 172 | { | ||
| 173 | int group, offset, mask_offset; | ||
| 174 | unsigned int value; | ||
| 175 | |||
| 176 | group = s5pc100_get_group(irq); | ||
| 177 | offset = s5pc100_get_offset(irq); | ||
| 178 | mask_offset = group_to_mask_offset(group); | ||
| 179 | |||
| 180 | value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset); | ||
| 181 | value &= ~(1 << offset); | ||
| 182 | __raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset); | ||
| 183 | } | ||
| 184 | |||
| 185 | static void s5pc100_gpioint_mask_ack(unsigned int irq) | ||
| 186 | { | ||
| 187 | s5pc100_gpioint_mask(irq); | ||
| 188 | s5pc100_gpioint_ack(irq); | ||
| 189 | } | ||
| 190 | |||
| 191 | static int s5pc100_gpioint_set_type(unsigned int irq, unsigned int type) | ||
| 192 | { | ||
| 193 | int group, offset, con_offset; | ||
| 194 | unsigned int value; | ||
| 195 | |||
| 196 | group = s5pc100_get_group(irq); | ||
| 197 | offset = s5pc100_get_offset(irq); | ||
| 198 | con_offset = group_to_con_offset(group); | ||
| 199 | |||
| 200 | switch (type) { | ||
| 201 | case IRQ_TYPE_NONE: | ||
| 202 | printk(KERN_WARNING "No irq type\n"); | ||
| 203 | return -EINVAL; | ||
| 204 | case IRQ_TYPE_EDGE_RISING: | ||
| 205 | type = GPIOINT_EDGE_RISING; | ||
| 206 | break; | ||
| 207 | case IRQ_TYPE_EDGE_FALLING: | ||
| 208 | type = GPIOINT_EDGE_FALLING; | ||
| 209 | break; | ||
| 210 | case IRQ_TYPE_EDGE_BOTH: | ||
| 211 | type = GPIOINT_EDGE_BOTH; | ||
| 212 | break; | ||
| 213 | case IRQ_TYPE_LEVEL_HIGH: | ||
| 214 | type = GPIOINT_LEVEL_HIGH; | ||
| 215 | break; | ||
| 216 | case IRQ_TYPE_LEVEL_LOW: | ||
| 217 | type = GPIOINT_LEVEL_LOW; | ||
| 218 | break; | ||
| 219 | default: | ||
| 220 | BUG(); | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | value = __raw_readl(S5P_GPIOREG(CON_OFFSET) + con_offset); | ||
| 225 | value &= ~(0xf << (offset * 0x4)); | ||
| 226 | value |= (type << (offset * 0x4)); | ||
| 227 | __raw_writel(value, S5P_GPIOREG(CON_OFFSET) + con_offset); | ||
| 228 | |||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | struct irq_chip s5pc100_gpioint = { | ||
| 233 | .name = "GPIO", | ||
| 234 | .ack = s5pc100_gpioint_ack, | ||
| 235 | .mask = s5pc100_gpioint_mask, | ||
| 236 | .mask_ack = s5pc100_gpioint_mask_ack, | ||
| 237 | .unmask = s5pc100_gpioint_unmask, | ||
| 238 | .set_type = s5pc100_gpioint_set_type, | ||
| 239 | }; | ||
| 240 | |||
| 241 | void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc) | ||
| 242 | { | ||
| 243 | int group, offset, pend_offset, mask_offset; | ||
| 244 | int real_irq, group_end; | ||
| 245 | unsigned int pend, mask; | ||
| 246 | |||
| 247 | group_end = 21; | ||
| 248 | |||
| 249 | for (group = 0; group < group_end; group++) { | ||
| 250 | pend_offset = group_to_pend_offset(group); | ||
| 251 | pend = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset); | ||
| 252 | if (!pend) | ||
| 253 | continue; | ||
| 254 | |||
| 255 | mask_offset = group_to_mask_offset(group); | ||
| 256 | mask = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset); | ||
| 257 | pend &= ~mask; | ||
| 258 | |||
| 259 | for (offset = 0; offset < 8; offset++) { | ||
| 260 | if (pend & (1 << offset)) { | ||
| 261 | real_irq = s5pc100_get_start(group) + offset; | ||
| 262 | generic_handle_irq(S3C_IRQ_GPIO(real_irq)); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | } | ||
diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c index 880fb075092c..18b405d514d6 100644 --- a/arch/arm/mach-s5pc100/mach-smdkc100.c +++ b/arch/arm/mach-s5pc100/mach-smdkc100.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include <plat/adc.h> | 47 | #include <plat/adc.h> |
| 48 | #include <plat/keypad.h> | 48 | #include <plat/keypad.h> |
| 49 | #include <plat/ts.h> | 49 | #include <plat/ts.h> |
| 50 | #include <plat/audio.h> | ||
| 50 | 51 | ||
| 51 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | 52 | /* Following are default values for UCON, ULCON and UFCON UART registers */ |
| 52 | #define SMDKC100_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ | 53 | #define SMDKC100_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ |
| @@ -196,6 +197,7 @@ static struct platform_device *smdkc100_devices[] __initdata = { | |||
| 196 | &s5p_device_fimc0, | 197 | &s5p_device_fimc0, |
| 197 | &s5p_device_fimc1, | 198 | &s5p_device_fimc1, |
| 198 | &s5p_device_fimc2, | 199 | &s5p_device_fimc2, |
| 200 | &s5pc100_device_spdif, | ||
| 199 | }; | 201 | }; |
| 200 | 202 | ||
| 201 | static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = { | 203 | static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = { |
| @@ -226,6 +228,8 @@ static void __init smdkc100_machine_init(void) | |||
| 226 | 228 | ||
| 227 | samsung_keypad_set_platdata(&smdkc100_keypad_data); | 229 | samsung_keypad_set_platdata(&smdkc100_keypad_data); |
| 228 | 230 | ||
| 231 | s5pc100_spdif_setup_gpio(S5PC100_SPDIF_GPD); | ||
| 232 | |||
| 229 | /* LCD init */ | 233 | /* LCD init */ |
| 230 | gpio_request(S5PC100_GPD(0), "GPD"); | 234 | gpio_request(S5PC100_GPD(0), "GPD"); |
| 231 | gpio_request(S5PC100_GPH0(6), "GPH0"); | 235 | gpio_request(S5PC100_GPH0(6), "GPH0"); |
diff --git a/arch/arm/mach-s5pc100/setup-fb-24bpp.c b/arch/arm/mach-s5pc100/setup-fb-24bpp.c index 6eba6cb8e2f4..d31c0f3fe222 100644 --- a/arch/arm/mach-s5pc100/setup-fb-24bpp.c +++ b/arch/arm/mach-s5pc100/setup-fb-24bpp.c | |||
| @@ -22,27 +22,15 @@ | |||
| 22 | 22 | ||
| 23 | #define DISR_OFFSET 0x7008 | 23 | #define DISR_OFFSET 0x7008 |
| 24 | 24 | ||
| 25 | void s5pc100_fb_gpio_setup_24bpp(void) | 25 | static void s5pc100_fb_setgpios(unsigned int base, unsigned int nr) |
| 26 | { | 26 | { |
| 27 | unsigned int gpio = 0; | 27 | s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(2)); |
| 28 | 28 | } | |
| 29 | for (gpio = S5PC100_GPF0(0); gpio <= S5PC100_GPF0(7); gpio++) { | ||
| 30 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 31 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 32 | } | ||
| 33 | |||
| 34 | for (gpio = S5PC100_GPF1(0); gpio <= S5PC100_GPF1(7); gpio++) { | ||
| 35 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 36 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 37 | } | ||
| 38 | |||
| 39 | for (gpio = S5PC100_GPF2(0); gpio <= S5PC100_GPF2(7); gpio++) { | ||
| 40 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 41 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 42 | } | ||
| 43 | 29 | ||
| 44 | for (gpio = S5PC100_GPF3(0); gpio <= S5PC100_GPF3(3); gpio++) { | 30 | void s5pc100_fb_gpio_setup_24bpp(void) |
| 45 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | 31 | { |
| 46 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | 32 | s5pc100_fb_setgpios(S5PC100_GPF0(0), 8); |
| 47 | } | 33 | s5pc100_fb_setgpios(S5PC100_GPF1(0), 8); |
| 34 | s5pc100_fb_setgpios(S5PC100_GPF2(0), 8); | ||
| 35 | s5pc100_fb_setgpios(S5PC100_GPF3(0), 4); | ||
| 48 | } | 36 | } |
diff --git a/arch/arm/mach-s5pc100/setup-i2c0.c b/arch/arm/mach-s5pc100/setup-i2c0.c index dd3174e6ecc5..eaef7a3bda49 100644 --- a/arch/arm/mach-s5pc100/setup-i2c0.c +++ b/arch/arm/mach-s5pc100/setup-i2c0.c | |||
| @@ -23,8 +23,6 @@ struct platform_device; /* don't need the contents */ | |||
| 23 | 23 | ||
| 24 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) | 24 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) |
| 25 | { | 25 | { |
| 26 | s3c_gpio_cfgpin(S5PC100_GPD(3), S3C_GPIO_SFN(2)); | 26 | s3c_gpio_cfgall_range(S5PC100_GPD(3), 2, |
| 27 | s3c_gpio_setpull(S5PC100_GPD(3), S3C_GPIO_PULL_UP); | 27 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 28 | s3c_gpio_cfgpin(S5PC100_GPD(4), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_setpull(S5PC100_GPD(4), S3C_GPIO_PULL_UP); | ||
| 30 | } | 28 | } |
diff --git a/arch/arm/mach-s5pc100/setup-i2c1.c b/arch/arm/mach-s5pc100/setup-i2c1.c index d1fec26b69ee..aaff74a90dee 100644 --- a/arch/arm/mach-s5pc100/setup-i2c1.c +++ b/arch/arm/mach-s5pc100/setup-i2c1.c | |||
| @@ -23,8 +23,6 @@ struct platform_device; /* don't need the contents */ | |||
| 23 | 23 | ||
| 24 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) | 24 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) |
| 25 | { | 25 | { |
| 26 | s3c_gpio_cfgpin(S5PC100_GPD(5), S3C_GPIO_SFN(2)); | 26 | s3c_gpio_cfgall_range(S5PC100_GPD(5), 2, |
| 27 | s3c_gpio_setpull(S5PC100_GPD(5), S3C_GPIO_PULL_UP); | 27 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 28 | s3c_gpio_cfgpin(S5PC100_GPD(6), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_setpull(S5PC100_GPD(6), S3C_GPIO_PULL_UP); | ||
| 30 | } | 28 | } |
diff --git a/arch/arm/mach-s5pc100/setup-ide.c b/arch/arm/mach-s5pc100/setup-ide.c index 83575671fb59..223aae044466 100644 --- a/arch/arm/mach-s5pc100/setup-ide.c +++ b/arch/arm/mach-s5pc100/setup-ide.c | |||
| @@ -17,52 +17,39 @@ | |||
| 17 | #include <mach/regs-clock.h> | 17 | #include <mach/regs-clock.h> |
| 18 | #include <plat/gpio-cfg.h> | 18 | #include <plat/gpio-cfg.h> |
| 19 | 19 | ||
| 20 | static void s5pc100_ide_cfg_gpios(unsigned int base, unsigned int nr) | ||
| 21 | { | ||
| 22 | s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(4)); | ||
| 23 | |||
| 24 | for (; nr > 0; nr--, base++) | ||
| 25 | s5p_gpio_set_drvstr(base, S5P_GPIO_DRVSTR_LV4); | ||
| 26 | } | ||
| 27 | |||
| 20 | void s5pc100_ide_setup_gpio(void) | 28 | void s5pc100_ide_setup_gpio(void) |
| 21 | { | 29 | { |
| 22 | u32 reg; | 30 | u32 reg; |
| 23 | u32 gpio = 0; | ||
| 24 | 31 | ||
| 25 | /* Independent CF interface, CF chip select configuration */ | 32 | /* Independent CF interface, CF chip select configuration */ |
| 26 | reg = readl(S5PC100_MEM_SYS_CFG) & (~0x3f); | 33 | reg = readl(S5PC100_MEM_SYS_CFG) & (~0x3f); |
| 27 | writel(reg | MEM_SYS_CFG_EBI_FIX_PRI_CFCON, S5PC100_MEM_SYS_CFG); | 34 | writel(reg | MEM_SYS_CFG_EBI_FIX_PRI_CFCON, S5PC100_MEM_SYS_CFG); |
| 28 | 35 | ||
| 29 | /* CF_Add[0 - 2], CF_IORDY, CF_INTRQ, CF_DMARQ, CF_DMARST, CF_DMACK */ | 36 | /* CF_Add[0 - 2], CF_IORDY, CF_INTRQ, CF_DMARQ, CF_DMARST, CF_DMACK */ |
| 30 | for (gpio = S5PC100_GPJ0(0); gpio <= S5PC100_GPJ0(7); gpio++) { | 37 | s5pc100_ide_cfg_gpios(S5PC100_GPJ0(0), 8); |
| 31 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | ||
| 32 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 33 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 34 | } | ||
| 35 | 38 | ||
| 36 | /*CF_Data[0 - 7] */ | 39 | /*CF_Data[0 - 7] */ |
| 37 | for (gpio = S5PC100_GPJ2(0); gpio <= S5PC100_GPJ2(7); gpio++) { | 40 | s5pc100_ide_cfg_gpios(S5PC100_GPJ2(0), 8); |
| 38 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | ||
| 39 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 40 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 41 | } | ||
| 42 | 41 | ||
| 43 | /* CF_Data[8 - 15] */ | 42 | /* CF_Data[8 - 15] */ |
| 44 | for (gpio = S5PC100_GPJ3(0); gpio <= S5PC100_GPJ3(7); gpio++) { | 43 | s5pc100_ide_cfg_gpios(S5PC100_GPJ3(0), 8); |
| 45 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | ||
| 46 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 47 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 48 | } | ||
| 49 | 44 | ||
| 50 | /* CF_CS0, CF_CS1, CF_IORD, CF_IOWR */ | 45 | /* CF_CS0, CF_CS1, CF_IORD, CF_IOWR */ |
| 51 | for (gpio = S5PC100_GPJ4(0); gpio <= S5PC100_GPJ4(3); gpio++) { | 46 | s5pc100_ide_cfg_gpios(S5PC100_GPJ4(0), 4); |
| 52 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | ||
| 53 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 54 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 55 | } | ||
| 56 | 47 | ||
| 57 | /* EBI_OE, EBI_WE */ | 48 | /* EBI_OE, EBI_WE */ |
| 58 | for (gpio = S5PC100_GPK0(6); gpio <= S5PC100_GPK0(7); gpio++) | 49 | s3c_gpio_cfgpin_range(S5PC100_GPK0(6), 2, S3C_GPIO_SFN(0)); |
| 59 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0)); | ||
| 60 | 50 | ||
| 61 | /* CF_OE, CF_WE */ | 51 | /* CF_OE, CF_WE */ |
| 62 | for (gpio = S5PC100_GPK1(6); gpio <= S5PC100_GPK1(7); gpio++) { | 52 | s3c_gpio_cfgrange_nopull(S5PC100_GPK1(6), 8, S3C_GPIO_SFN(2)); |
| 63 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 64 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 65 | } | ||
| 66 | 53 | ||
| 67 | /* CF_CD */ | 54 | /* CF_CD */ |
| 68 | s3c_gpio_cfgpin(S5PC100_GPK3(5), S3C_GPIO_SFN(2)); | 55 | s3c_gpio_cfgpin(S5PC100_GPK3(5), S3C_GPIO_SFN(2)); |
diff --git a/arch/arm/mach-s5pc100/setup-keypad.c b/arch/arm/mach-s5pc100/setup-keypad.c index d0837a72a58e..ada377f0c206 100644 --- a/arch/arm/mach-s5pc100/setup-keypad.c +++ b/arch/arm/mach-s5pc100/setup-keypad.c | |||
| @@ -15,20 +15,9 @@ | |||
| 15 | 15 | ||
| 16 | void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) | 16 | void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) |
| 17 | { | 17 | { |
| 18 | unsigned int gpio; | ||
| 19 | unsigned int end; | ||
| 20 | |||
| 21 | /* Set all the necessary GPH3 pins to special-function 3: KP_ROW[x] */ | 18 | /* Set all the necessary GPH3 pins to special-function 3: KP_ROW[x] */ |
| 22 | end = S5PC100_GPH3(rows); | 19 | s3c_gpio_cfgrange_nopull(S5PC100_GPH3(0), rows, S3C_GPIO_SFN(3)); |
| 23 | for (gpio = S5PC100_GPH3(0); gpio < end; gpio++) { | ||
| 24 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 25 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 26 | } | ||
| 27 | 20 | ||
| 28 | /* Set all the necessary GPH2 pins to special-function 3: KP_COL[x] */ | 21 | /* Set all the necessary GPH2 pins to special-function 3: KP_COL[x] */ |
| 29 | end = S5PC100_GPH2(cols); | 22 | s3c_gpio_cfgrange_nopull(S5PC100_GPH2(0), cols, S3C_GPIO_SFN(3)); |
| 30 | for (gpio = S5PC100_GPH2(0); gpio < end; gpio++) { | ||
| 31 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 32 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 33 | } | ||
| 34 | } | 23 | } |
diff --git a/arch/arm/mach-s5pc100/setup-sdhci-gpio.c b/arch/arm/mach-s5pc100/setup-sdhci-gpio.c index dc7208c639ea..03c02d04c68c 100644 --- a/arch/arm/mach-s5pc100/setup-sdhci-gpio.c +++ b/arch/arm/mach-s5pc100/setup-sdhci-gpio.c | |||
| @@ -25,8 +25,6 @@ | |||
| 25 | void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | 25 | void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) |
| 26 | { | 26 | { |
| 27 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 27 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 28 | unsigned int gpio; | ||
| 29 | unsigned int end; | ||
| 30 | unsigned int num; | 28 | unsigned int num; |
| 31 | 29 | ||
| 32 | num = width; | 30 | num = width; |
| @@ -34,20 +32,11 @@ void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | |||
| 34 | if (width == 8) | 32 | if (width == 8) |
| 35 | num = width - 2; | 33 | num = width - 2; |
| 36 | 34 | ||
| 37 | end = S5PC100_GPG0(2 + num); | ||
| 38 | |||
| 39 | /* Set all the necessary GPG0/GPG1 pins to special-function 0 */ | 35 | /* Set all the necessary GPG0/GPG1 pins to special-function 0 */ |
| 40 | for (gpio = S5PC100_GPG0(0); gpio < end; gpio++) { | 36 | s3c_gpio_cfgrange_nopull(S5PC100_GPG0(0), 2 + num, S3C_GPIO_SFN(2)); |
| 41 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 42 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 43 | } | ||
| 44 | 37 | ||
| 45 | if (width == 8) { | 38 | if (width == 8) |
| 46 | for (gpio = S5PC100_GPG1(0); gpio <= S5PC100_GPG1(1); gpio++) { | 39 | s3c_gpio_cfgrange_nopull(S5PC100_GPG1(0), 2, S3C_GPIO_SFN(2)); |
| 47 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 48 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | 40 | ||
| 52 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | 41 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { |
| 53 | s3c_gpio_setpull(S5PC100_GPG1(2), S3C_GPIO_PULL_UP); | 42 | s3c_gpio_setpull(S5PC100_GPG1(2), S3C_GPIO_PULL_UP); |
| @@ -58,16 +47,9 @@ void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | |||
| 58 | void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) | 47 | void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) |
| 59 | { | 48 | { |
| 60 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 49 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 61 | unsigned int gpio; | ||
| 62 | unsigned int end; | ||
| 63 | |||
| 64 | end = S5PC100_GPG2(2 + width); | ||
| 65 | 50 | ||
| 66 | /* Set all the necessary GPG2 pins to special-function 2 */ | 51 | /* Set all the necessary GPG2 pins to special-function 2 */ |
| 67 | for (gpio = S5PC100_GPG2(0); gpio < end; gpio++) { | 52 | s3c_gpio_cfgrange_nopull(S5PC100_GPG2(0), 2 + width, S3C_GPIO_SFN(2)); |
| 68 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 69 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 70 | } | ||
| 71 | 53 | ||
| 72 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | 54 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { |
| 73 | s3c_gpio_setpull(S5PC100_GPG2(6), S3C_GPIO_PULL_UP); | 55 | s3c_gpio_setpull(S5PC100_GPG2(6), S3C_GPIO_PULL_UP); |
| @@ -78,16 +60,9 @@ void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) | |||
| 78 | void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) | 60 | void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) |
| 79 | { | 61 | { |
| 80 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 62 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 81 | unsigned int gpio; | ||
| 82 | unsigned int end; | ||
| 83 | |||
| 84 | end = S5PC100_GPG3(2 + width); | ||
| 85 | 63 | ||
| 86 | /* Set all the necessary GPG3 pins to special-function 2 */ | 64 | /* Set all the necessary GPG3 pins to special-function 2 */ |
| 87 | for (gpio = S5PC100_GPG3(0); gpio < end; gpio++) { | 65 | s3c_gpio_cfgrange_nopull(S5PC100_GPG3(0), 2 + width, S3C_GPIO_SFN(2)); |
| 88 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 89 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 90 | } | ||
| 91 | 66 | ||
| 92 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | 67 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { |
| 93 | s3c_gpio_setpull(S5PC100_GPG3(6), S3C_GPIO_PULL_UP); | 68 | s3c_gpio_setpull(S5PC100_GPG3(6), S3C_GPIO_PULL_UP); |
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index 5315fec3db86..862f239a0fdb 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig | |||
| @@ -11,9 +11,9 @@ if ARCH_S5PV210 | |||
| 11 | 11 | ||
| 12 | config CPU_S5PV210 | 12 | config CPU_S5PV210 |
| 13 | bool | 13 | bool |
| 14 | select PLAT_S5P | ||
| 15 | select S3C_PL330_DMA | 14 | select S3C_PL330_DMA |
| 16 | select S5P_EXT_INT | 15 | select S5P_EXT_INT |
| 16 | select S5PV210_PM if PM | ||
| 17 | help | 17 | help |
| 18 | Enable S5PV210 CPU support | 18 | Enable S5PV210 CPU support |
| 19 | 19 | ||
| @@ -58,7 +58,6 @@ menu "S5PC110 Machines" | |||
| 58 | config MACH_AQUILA | 58 | config MACH_AQUILA |
| 59 | bool "Aquila" | 59 | bool "Aquila" |
| 60 | select CPU_S5PV210 | 60 | select CPU_S5PV210 |
| 61 | select ARCH_SPARSEMEM_ENABLE | ||
| 62 | select S3C_DEV_FB | 61 | select S3C_DEV_FB |
| 63 | select S5P_DEV_FIMC0 | 62 | select S5P_DEV_FIMC0 |
| 64 | select S5P_DEV_FIMC1 | 63 | select S5P_DEV_FIMC1 |
| @@ -75,7 +74,7 @@ config MACH_AQUILA | |||
| 75 | config MACH_GONI | 74 | config MACH_GONI |
| 76 | bool "GONI" | 75 | bool "GONI" |
| 77 | select CPU_S5PV210 | 76 | select CPU_S5PV210 |
| 78 | select ARCH_SPARSEMEM_ENABLE | 77 | select S5P_GPIO_INT |
| 79 | select S3C_DEV_FB | 78 | select S3C_DEV_FB |
| 80 | select S5P_DEV_FIMC0 | 79 | select S5P_DEV_FIMC0 |
| 81 | select S5P_DEV_FIMC1 | 80 | select S5P_DEV_FIMC1 |
| @@ -83,8 +82,15 @@ config MACH_GONI | |||
| 83 | select S3C_DEV_HSMMC | 82 | select S3C_DEV_HSMMC |
| 84 | select S3C_DEV_HSMMC1 | 83 | select S3C_DEV_HSMMC1 |
| 85 | select S3C_DEV_HSMMC2 | 84 | select S3C_DEV_HSMMC2 |
| 85 | select S3C_DEV_I2C1 | ||
| 86 | select S3C_DEV_I2C2 | ||
| 87 | select S3C_DEV_USB_HSOTG | ||
| 86 | select S5P_DEV_ONENAND | 88 | select S5P_DEV_ONENAND |
| 89 | select SAMSUNG_DEV_KEYPAD | ||
| 87 | select S5PV210_SETUP_FB_24BPP | 90 | select S5PV210_SETUP_FB_24BPP |
| 91 | select S5PV210_SETUP_I2C1 | ||
| 92 | select S5PV210_SETUP_I2C2 | ||
| 93 | select S5PV210_SETUP_KEYPAD | ||
| 88 | select S5PV210_SETUP_SDHCI | 94 | select S5PV210_SETUP_SDHCI |
| 89 | help | 95 | help |
| 90 | Machine support for Samsung GONI board | 96 | Machine support for Samsung GONI board |
| @@ -93,7 +99,6 @@ config MACH_GONI | |||
| 93 | config MACH_SMDKC110 | 99 | config MACH_SMDKC110 |
| 94 | bool "SMDKC110" | 100 | bool "SMDKC110" |
| 95 | select CPU_S5PV210 | 101 | select CPU_S5PV210 |
| 96 | select ARCH_SPARSEMEM_ENABLE | ||
| 97 | select S3C_DEV_I2C1 | 102 | select S3C_DEV_I2C1 |
| 98 | select S3C_DEV_I2C2 | 103 | select S3C_DEV_I2C2 |
| 99 | select S3C_DEV_RTC | 104 | select S3C_DEV_RTC |
| @@ -113,7 +118,6 @@ menu "S5PV210 Machines" | |||
| 113 | config MACH_SMDKV210 | 118 | config MACH_SMDKV210 |
| 114 | bool "SMDKV210" | 119 | bool "SMDKV210" |
| 115 | select CPU_S5PV210 | 120 | select CPU_S5PV210 |
| 116 | select ARCH_SPARSEMEM_ENABLE | ||
| 117 | select S3C_DEV_HSMMC | 121 | select S3C_DEV_HSMMC |
| 118 | select S3C_DEV_HSMMC1 | 122 | select S3C_DEV_HSMMC1 |
| 119 | select S3C_DEV_HSMMC2 | 123 | select S3C_DEV_HSMMC2 |
| @@ -134,6 +138,29 @@ config MACH_SMDKV210 | |||
| 134 | help | 138 | help |
| 135 | Machine support for Samsung SMDKV210 | 139 | Machine support for Samsung SMDKV210 |
| 136 | 140 | ||
| 141 | config MACH_TORBRECK | ||
| 142 | bool "Torbreck" | ||
| 143 | select CPU_S5PV210 | ||
| 144 | select ARCH_SPARSEMEM_ENABLE | ||
| 145 | select S3C_DEV_HSMMC | ||
| 146 | select S3C_DEV_HSMMC1 | ||
| 147 | select S3C_DEV_HSMMC2 | ||
| 148 | select S3C_DEV_HSMMC3 | ||
| 149 | select S3C_DEV_I2C1 | ||
| 150 | select S3C_DEV_I2C2 | ||
| 151 | select S3C_DEV_RTC | ||
| 152 | select S3C_DEV_WDT | ||
| 153 | select S5PV210_SETUP_I2C1 | ||
| 154 | select S5PV210_SETUP_I2C2 | ||
| 155 | select S5PV210_SETUP_SDHCI | ||
| 156 | help | ||
| 157 | Machine support for aESOP Torbreck | ||
| 158 | |||
| 137 | endmenu | 159 | endmenu |
| 138 | 160 | ||
| 161 | config S5PV210_PM | ||
| 162 | bool | ||
| 163 | help | ||
| 164 | Power Management code common to S5PV210 | ||
| 165 | |||
| 139 | endif | 166 | endif |
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile index 704548912408..ff1a0db57a2f 100644 --- a/arch/arm/mach-s5pv210/Makefile +++ b/arch/arm/mach-s5pv210/Makefile | |||
| @@ -14,6 +14,8 @@ obj- := | |||
| 14 | 14 | ||
| 15 | obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o gpiolib.o | 15 | obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o gpiolib.o |
| 16 | obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o | 16 | obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o |
| 17 | obj-$(CONFIG_S5PV210_PM) += pm.o sleep.o | ||
| 18 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | ||
| 17 | 19 | ||
| 18 | # machine support | 20 | # machine support |
| 19 | 21 | ||
| @@ -21,6 +23,7 @@ obj-$(CONFIG_MACH_AQUILA) += mach-aquila.o | |||
| 21 | obj-$(CONFIG_MACH_SMDKV210) += mach-smdkv210.o | 23 | obj-$(CONFIG_MACH_SMDKV210) += mach-smdkv210.o |
| 22 | obj-$(CONFIG_MACH_SMDKC110) += mach-smdkc110.o | 24 | obj-$(CONFIG_MACH_SMDKC110) += mach-smdkc110.o |
| 23 | obj-$(CONFIG_MACH_GONI) += mach-goni.o | 25 | obj-$(CONFIG_MACH_GONI) += mach-goni.o |
| 26 | obj-$(CONFIG_MACH_TORBRECK) += mach-torbreck.o | ||
| 24 | 27 | ||
| 25 | # device support | 28 | # device support |
| 26 | 29 | ||
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index d562670e1b0b..019c3a69b0e4 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c | |||
| @@ -31,6 +31,8 @@ | |||
| 31 | #include <plat/clock-clksrc.h> | 31 | #include <plat/clock-clksrc.h> |
| 32 | #include <plat/s5pv210.h> | 32 | #include <plat/s5pv210.h> |
| 33 | 33 | ||
| 34 | static unsigned long xtal; | ||
| 35 | |||
| 34 | static struct clksrc_clk clk_mout_apll = { | 36 | static struct clksrc_clk clk_mout_apll = { |
| 35 | .clk = { | 37 | .clk = { |
| 36 | .name = "mout_apll", | 38 | .name = "mout_apll", |
| @@ -259,6 +261,36 @@ static struct clksrc_clk clk_sclk_vpll = { | |||
| 259 | .reg_src = { .reg = S5P_CLK_SRC0, .shift = 12, .size = 1 }, | 261 | .reg_src = { .reg = S5P_CLK_SRC0, .shift = 12, .size = 1 }, |
| 260 | }; | 262 | }; |
| 261 | 263 | ||
| 264 | static struct clk *clkset_moutdmc0src_list[] = { | ||
| 265 | [0] = &clk_sclk_a2m.clk, | ||
| 266 | [1] = &clk_mout_mpll.clk, | ||
| 267 | [2] = NULL, | ||
| 268 | [3] = NULL, | ||
| 269 | }; | ||
| 270 | |||
| 271 | static struct clksrc_sources clkset_moutdmc0src = { | ||
| 272 | .sources = clkset_moutdmc0src_list, | ||
| 273 | .nr_sources = ARRAY_SIZE(clkset_moutdmc0src_list), | ||
| 274 | }; | ||
| 275 | |||
| 276 | static struct clksrc_clk clk_mout_dmc0 = { | ||
| 277 | .clk = { | ||
| 278 | .name = "mout_dmc0", | ||
| 279 | .id = -1, | ||
| 280 | }, | ||
| 281 | .sources = &clkset_moutdmc0src, | ||
| 282 | .reg_src = { .reg = S5P_CLK_SRC6, .shift = 24, .size = 2 }, | ||
| 283 | }; | ||
| 284 | |||
| 285 | static struct clksrc_clk clk_sclk_dmc0 = { | ||
| 286 | .clk = { | ||
| 287 | .name = "sclk_dmc0", | ||
| 288 | .id = -1, | ||
| 289 | .parent = &clk_mout_dmc0.clk, | ||
| 290 | }, | ||
| 291 | .reg_div = { .reg = S5P_CLK_DIV6, .shift = 28, .size = 4 }, | ||
| 292 | }; | ||
| 293 | |||
| 262 | static unsigned long s5pv210_clk_imem_get_rate(struct clk *clk) | 294 | static unsigned long s5pv210_clk_imem_get_rate(struct clk *clk) |
| 263 | { | 295 | { |
| 264 | return clk_get_rate(clk->parent) / 2; | 296 | return clk_get_rate(clk->parent) / 2; |
| @@ -268,8 +300,29 @@ static struct clk_ops clk_hclk_imem_ops = { | |||
| 268 | .get_rate = s5pv210_clk_imem_get_rate, | 300 | .get_rate = s5pv210_clk_imem_get_rate, |
| 269 | }; | 301 | }; |
| 270 | 302 | ||
| 303 | static unsigned long s5pv210_clk_fout_apll_get_rate(struct clk *clk) | ||
| 304 | { | ||
| 305 | return s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508); | ||
| 306 | } | ||
| 307 | |||
| 308 | static struct clk_ops clk_fout_apll_ops = { | ||
| 309 | .get_rate = s5pv210_clk_fout_apll_get_rate, | ||
| 310 | }; | ||
| 311 | |||
| 271 | static struct clk init_clocks_disable[] = { | 312 | static struct clk init_clocks_disable[] = { |
| 272 | { | 313 | { |
| 314 | .name = "pdma", | ||
| 315 | .id = 0, | ||
| 316 | .parent = &clk_hclk_psys.clk, | ||
| 317 | .enable = s5pv210_clk_ip0_ctrl, | ||
| 318 | .ctrlbit = (1 << 3), | ||
| 319 | }, { | ||
| 320 | .name = "pdma", | ||
| 321 | .id = 1, | ||
| 322 | .parent = &clk_hclk_psys.clk, | ||
| 323 | .enable = s5pv210_clk_ip0_ctrl, | ||
| 324 | .ctrlbit = (1 << 4), | ||
| 325 | }, { | ||
| 273 | .name = "rot", | 326 | .name = "rot", |
| 274 | .id = -1, | 327 | .id = -1, |
| 275 | .parent = &clk_hclk_dsys.clk, | 328 | .parent = &clk_hclk_dsys.clk, |
| @@ -431,6 +484,12 @@ static struct clk init_clocks_disable[] = { | |||
| 431 | .parent = &clk_p, | 484 | .parent = &clk_p, |
| 432 | .enable = s5pv210_clk_ip3_ctrl, | 485 | .enable = s5pv210_clk_ip3_ctrl, |
| 433 | .ctrlbit = (1 << 6), | 486 | .ctrlbit = (1 << 6), |
| 487 | }, { | ||
| 488 | .name = "spdif", | ||
| 489 | .id = -1, | ||
| 490 | .parent = &clk_p, | ||
| 491 | .enable = s5pv210_clk_ip3_ctrl, | ||
| 492 | .ctrlbit = (1 << 0), | ||
| 434 | }, | 493 | }, |
| 435 | }; | 494 | }; |
| 436 | 495 | ||
| @@ -660,6 +719,53 @@ static struct clksrc_sources clkset_sclk_spdif = { | |||
| 660 | .nr_sources = ARRAY_SIZE(clkset_sclk_spdif_list), | 719 | .nr_sources = ARRAY_SIZE(clkset_sclk_spdif_list), |
| 661 | }; | 720 | }; |
| 662 | 721 | ||
| 722 | static int s5pv210_spdif_set_rate(struct clk *clk, unsigned long rate) | ||
| 723 | { | ||
| 724 | struct clk *pclk; | ||
| 725 | int ret; | ||
| 726 | |||
| 727 | pclk = clk_get_parent(clk); | ||
| 728 | if (IS_ERR(pclk)) | ||
| 729 | return -EINVAL; | ||
| 730 | |||
| 731 | ret = pclk->ops->set_rate(pclk, rate); | ||
| 732 | clk_put(pclk); | ||
| 733 | |||
| 734 | return ret; | ||
| 735 | } | ||
| 736 | |||
| 737 | static unsigned long s5pv210_spdif_get_rate(struct clk *clk) | ||
| 738 | { | ||
| 739 | struct clk *pclk; | ||
| 740 | int rate; | ||
| 741 | |||
| 742 | pclk = clk_get_parent(clk); | ||
| 743 | if (IS_ERR(pclk)) | ||
| 744 | return -EINVAL; | ||
| 745 | |||
| 746 | rate = pclk->ops->get_rate(clk); | ||
| 747 | clk_put(pclk); | ||
| 748 | |||
| 749 | return rate; | ||
| 750 | } | ||
| 751 | |||
| 752 | static struct clk_ops s5pv210_sclk_spdif_ops = { | ||
| 753 | .set_rate = s5pv210_spdif_set_rate, | ||
| 754 | .get_rate = s5pv210_spdif_get_rate, | ||
| 755 | }; | ||
| 756 | |||
| 757 | static struct clksrc_clk clk_sclk_spdif = { | ||
| 758 | .clk = { | ||
| 759 | .name = "sclk_spdif", | ||
| 760 | .id = -1, | ||
| 761 | .enable = s5pv210_clk_mask0_ctrl, | ||
| 762 | .ctrlbit = (1 << 27), | ||
| 763 | .ops = &s5pv210_sclk_spdif_ops, | ||
| 764 | }, | ||
| 765 | .sources = &clkset_sclk_spdif, | ||
| 766 | .reg_src = { .reg = S5P_CLK_SRC6, .shift = 12, .size = 2 }, | ||
| 767 | }; | ||
| 768 | |||
| 663 | static struct clk *clkset_group2_list[] = { | 769 | static struct clk *clkset_group2_list[] = { |
| 664 | [0] = &clk_ext_xtal_mux, | 770 | [0] = &clk_ext_xtal_mux, |
| 665 | [1] = &clk_xusbxti, | 771 | [1] = &clk_xusbxti, |
| @@ -744,15 +850,6 @@ static struct clksrc_clk clksrcs[] = { | |||
| 744 | .sources = &clkset_sclk_mixer, | 850 | .sources = &clkset_sclk_mixer, |
| 745 | .reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 1 }, | 851 | .reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 1 }, |
| 746 | }, { | 852 | }, { |
| 747 | .clk = { | ||
| 748 | .name = "sclk_spdif", | ||
| 749 | .id = -1, | ||
| 750 | .enable = s5pv210_clk_mask0_ctrl, | ||
| 751 | .ctrlbit = (1 << 27), | ||
| 752 | }, | ||
| 753 | .sources = &clkset_sclk_spdif, | ||
| 754 | .reg_src = { .reg = S5P_CLK_SRC6, .shift = 12, .size = 2 }, | ||
| 755 | }, { | ||
| 756 | .clk = { | 853 | .clk = { |
| 757 | .name = "sclk_fimc", | 854 | .name = "sclk_fimc", |
| 758 | .id = 0, | 855 | .id = 0, |
| @@ -953,12 +1050,93 @@ static struct clksrc_clk *sysclks[] = { | |||
| 953 | &clk_sclk_dac, | 1050 | &clk_sclk_dac, |
| 954 | &clk_sclk_pixel, | 1051 | &clk_sclk_pixel, |
| 955 | &clk_sclk_hdmi, | 1052 | &clk_sclk_hdmi, |
| 1053 | &clk_mout_dmc0, | ||
| 1054 | &clk_sclk_dmc0, | ||
| 1055 | &clk_sclk_audio0, | ||
| 1056 | &clk_sclk_audio1, | ||
| 1057 | &clk_sclk_audio2, | ||
| 1058 | &clk_sclk_spdif, | ||
| 1059 | }; | ||
| 1060 | |||
| 1061 | static u32 epll_div[][6] = { | ||
| 1062 | { 48000000, 0, 48, 3, 3, 0 }, | ||
| 1063 | { 96000000, 0, 48, 3, 2, 0 }, | ||
| 1064 | { 144000000, 1, 72, 3, 2, 0 }, | ||
| 1065 | { 192000000, 0, 48, 3, 1, 0 }, | ||
| 1066 | { 288000000, 1, 72, 3, 1, 0 }, | ||
| 1067 | { 32750000, 1, 65, 3, 4, 35127 }, | ||
| 1068 | { 32768000, 1, 65, 3, 4, 35127 }, | ||
| 1069 | { 45158400, 0, 45, 3, 3, 10355 }, | ||
| 1070 | { 45000000, 0, 45, 3, 3, 10355 }, | ||
| 1071 | { 45158000, 0, 45, 3, 3, 10355 }, | ||
| 1072 | { 49125000, 0, 49, 3, 3, 9961 }, | ||
| 1073 | { 49152000, 0, 49, 3, 3, 9961 }, | ||
| 1074 | { 67737600, 1, 67, 3, 3, 48366 }, | ||
| 1075 | { 67738000, 1, 67, 3, 3, 48366 }, | ||
| 1076 | { 73800000, 1, 73, 3, 3, 47710 }, | ||
| 1077 | { 73728000, 1, 73, 3, 3, 47710 }, | ||
| 1078 | { 36000000, 1, 32, 3, 4, 0 }, | ||
| 1079 | { 60000000, 1, 60, 3, 3, 0 }, | ||
| 1080 | { 72000000, 1, 72, 3, 3, 0 }, | ||
| 1081 | { 80000000, 1, 80, 3, 3, 0 }, | ||
| 1082 | { 84000000, 0, 42, 3, 2, 0 }, | ||
| 1083 | { 50000000, 0, 50, 3, 3, 0 }, | ||
| 1084 | }; | ||
| 1085 | |||
| 1086 | static int s5pv210_epll_set_rate(struct clk *clk, unsigned long rate) | ||
| 1087 | { | ||
| 1088 | unsigned int epll_con, epll_con_k; | ||
| 1089 | unsigned int i; | ||
| 1090 | |||
| 1091 | /* Return if nothing changed */ | ||
| 1092 | if (clk->rate == rate) | ||
| 1093 | return 0; | ||
| 1094 | |||
| 1095 | epll_con = __raw_readl(S5P_EPLL_CON); | ||
| 1096 | epll_con_k = __raw_readl(S5P_EPLL_CON1); | ||
| 1097 | |||
| 1098 | epll_con_k &= ~PLL46XX_KDIV_MASK; | ||
| 1099 | epll_con &= ~(1 << 27 | | ||
| 1100 | PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT | | ||
| 1101 | PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | | ||
| 1102 | PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); | ||
| 1103 | |||
| 1104 | for (i = 0; i < ARRAY_SIZE(epll_div); i++) { | ||
| 1105 | if (epll_div[i][0] == rate) { | ||
| 1106 | epll_con_k |= epll_div[i][5] << 0; | ||
| 1107 | epll_con |= (epll_div[i][1] << 27 | | ||
| 1108 | epll_div[i][2] << PLL46XX_MDIV_SHIFT | | ||
| 1109 | epll_div[i][3] << PLL46XX_PDIV_SHIFT | | ||
| 1110 | epll_div[i][4] << PLL46XX_SDIV_SHIFT); | ||
| 1111 | break; | ||
| 1112 | } | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | if (i == ARRAY_SIZE(epll_div)) { | ||
| 1116 | printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", | ||
| 1117 | __func__); | ||
| 1118 | return -EINVAL; | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | __raw_writel(epll_con, S5P_EPLL_CON); | ||
| 1122 | __raw_writel(epll_con_k, S5P_EPLL_CON1); | ||
| 1123 | |||
| 1124 | printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n", | ||
| 1125 | clk->rate, rate); | ||
| 1126 | |||
| 1127 | clk->rate = rate; | ||
| 1128 | |||
| 1129 | return 0; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | static struct clk_ops s5pv210_epll_ops = { | ||
| 1133 | .set_rate = s5pv210_epll_set_rate, | ||
| 1134 | .get_rate = s5p_epll_get_rate, | ||
| 956 | }; | 1135 | }; |
| 957 | 1136 | ||
| 958 | void __init_or_cpufreq s5pv210_setup_clocks(void) | 1137 | void __init_or_cpufreq s5pv210_setup_clocks(void) |
| 959 | { | 1138 | { |
| 960 | struct clk *xtal_clk; | 1139 | struct clk *xtal_clk; |
| 961 | unsigned long xtal; | ||
| 962 | unsigned long vpllsrc; | 1140 | unsigned long vpllsrc; |
| 963 | unsigned long armclk; | 1141 | unsigned long armclk; |
| 964 | unsigned long hclk_msys; | 1142 | unsigned long hclk_msys; |
| @@ -974,6 +1152,10 @@ void __init_or_cpufreq s5pv210_setup_clocks(void) | |||
| 974 | unsigned int ptr; | 1152 | unsigned int ptr; |
| 975 | u32 clkdiv0, clkdiv1; | 1153 | u32 clkdiv0, clkdiv1; |
| 976 | 1154 | ||
| 1155 | /* Set functions for clk_fout_epll */ | ||
| 1156 | clk_fout_epll.enable = s5p_epll_enable; | ||
| 1157 | clk_fout_epll.ops = &s5pv210_epll_ops; | ||
| 1158 | |||
| 977 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); | 1159 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); |
| 978 | 1160 | ||
| 979 | clkdiv0 = __raw_readl(S5P_CLK_DIV0); | 1161 | clkdiv0 = __raw_readl(S5P_CLK_DIV0); |
| @@ -992,11 +1174,12 @@ void __init_or_cpufreq s5pv210_setup_clocks(void) | |||
| 992 | 1174 | ||
| 993 | apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508); | 1175 | apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508); |
| 994 | mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502); | 1176 | mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502); |
| 995 | epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500); | 1177 | epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON), |
| 1178 | __raw_readl(S5P_EPLL_CON1), pll_4600); | ||
| 996 | vpllsrc = clk_get_rate(&clk_vpllsrc.clk); | 1179 | vpllsrc = clk_get_rate(&clk_vpllsrc.clk); |
| 997 | vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502); | 1180 | vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502); |
| 998 | 1181 | ||
| 999 | clk_fout_apll.rate = apll; | 1182 | clk_fout_apll.ops = &clk_fout_apll_ops; |
| 1000 | clk_fout_mpll.rate = mpll; | 1183 | clk_fout_mpll.rate = mpll; |
| 1001 | clk_fout_epll.rate = epll; | 1184 | clk_fout_epll.rate = epll; |
| 1002 | clk_fout_vpll.rate = vpll; | 1185 | clk_fout_vpll.rate = vpll; |
diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c index 2f16bfc0a116..8eb480e201b0 100644 --- a/arch/arm/mach-s5pv210/cpu.c +++ b/arch/arm/mach-s5pv210/cpu.c | |||
| @@ -85,6 +85,21 @@ static struct map_desc s5pv210_iodesc[] __initdata = { | |||
| 85 | .pfn = __phys_to_pfn(S5PV210_PA_SROMC), | 85 | .pfn = __phys_to_pfn(S5PV210_PA_SROMC), |
| 86 | .length = SZ_4K, | 86 | .length = SZ_4K, |
| 87 | .type = MT_DEVICE, | 87 | .type = MT_DEVICE, |
| 88 | }, { | ||
| 89 | .virtual = (unsigned long)S5P_VA_DMC0, | ||
| 90 | .pfn = __phys_to_pfn(S5PV210_PA_DMC0), | ||
| 91 | .length = SZ_4K, | ||
| 92 | .type = MT_DEVICE, | ||
| 93 | }, { | ||
| 94 | .virtual = (unsigned long)S5P_VA_DMC1, | ||
| 95 | .pfn = __phys_to_pfn(S5PV210_PA_DMC1), | ||
| 96 | .length = SZ_4K, | ||
| 97 | .type = MT_DEVICE, | ||
| 98 | }, { | ||
| 99 | .virtual = (unsigned long)S3C_VA_USB_HSPHY, | ||
| 100 | .pfn =__phys_to_pfn(S5PV210_PA_HSPHY), | ||
| 101 | .length = SZ_4K, | ||
| 102 | .type = MT_DEVICE, | ||
| 88 | } | 103 | } |
| 89 | }; | 104 | }; |
| 90 | 105 | ||
diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c new file mode 100644 index 000000000000..a6f22920a2c2 --- /dev/null +++ b/arch/arm/mach-s5pv210/cpufreq.c | |||
| @@ -0,0 +1,484 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv210/cpufreq.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * CPU frequency scaling for S5PC110/S5PV210 | ||
| 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/types.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/clk.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/cpufreq.h> | ||
| 20 | |||
| 21 | #include <mach/map.h> | ||
| 22 | #include <mach/regs-clock.h> | ||
| 23 | |||
| 24 | static struct clk *cpu_clk; | ||
| 25 | static struct clk *dmc0_clk; | ||
| 26 | static struct clk *dmc1_clk; | ||
| 27 | static struct cpufreq_freqs freqs; | ||
| 28 | |||
| 29 | /* APLL M,P,S values for 1G/800Mhz */ | ||
| 30 | #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) | ||
| 31 | #define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1) | ||
| 32 | |||
| 33 | /* | ||
| 34 | * DRAM configurations to calculate refresh counter for changing | ||
| 35 | * frequency of memory. | ||
| 36 | */ | ||
| 37 | struct dram_conf { | ||
| 38 | unsigned long freq; /* HZ */ | ||
| 39 | unsigned long refresh; /* DRAM refresh counter * 1000 */ | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* DRAM configuration (DMC0 and DMC1) */ | ||
| 43 | static struct dram_conf s5pv210_dram_conf[2]; | ||
| 44 | |||
| 45 | enum perf_level { | ||
| 46 | L0, L1, L2, L3, L4, | ||
| 47 | }; | ||
| 48 | |||
| 49 | enum s5pv210_mem_type { | ||
| 50 | LPDDR = 0x1, | ||
| 51 | LPDDR2 = 0x2, | ||
| 52 | DDR2 = 0x4, | ||
| 53 | }; | ||
| 54 | |||
| 55 | enum s5pv210_dmc_port { | ||
| 56 | DMC0 = 0, | ||
| 57 | DMC1, | ||
| 58 | }; | ||
| 59 | |||
| 60 | static struct cpufreq_frequency_table s5pv210_freq_table[] = { | ||
| 61 | {L0, 1000*1000}, | ||
| 62 | {L1, 800*1000}, | ||
| 63 | {L2, 400*1000}, | ||
| 64 | {L3, 200*1000}, | ||
| 65 | {L4, 100*1000}, | ||
| 66 | {0, CPUFREQ_TABLE_END}, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static u32 clkdiv_val[5][11] = { | ||
| 70 | /* | ||
| 71 | * Clock divider value for following | ||
| 72 | * { APLL, A2M, HCLK_MSYS, PCLK_MSYS, | ||
| 73 | * HCLK_DSYS, PCLK_DSYS, HCLK_PSYS, PCLK_PSYS, | ||
| 74 | * ONEDRAM, MFC, G3D } | ||
| 75 | */ | ||
| 76 | |||
| 77 | /* L0 : [1000/200/100][166/83][133/66][200/200] */ | ||
| 78 | {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0}, | ||
| 79 | |||
| 80 | /* L1 : [800/200/100][166/83][133/66][200/200] */ | ||
| 81 | {0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0}, | ||
| 82 | |||
| 83 | /* L2 : [400/200/100][166/83][133/66][200/200] */ | ||
| 84 | {1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0}, | ||
| 85 | |||
| 86 | /* L3 : [200/200/100][166/83][133/66][200/200] */ | ||
| 87 | {3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0}, | ||
| 88 | |||
| 89 | /* L4 : [100/100/100][83/83][66/66][100/100] */ | ||
| 90 | {7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0}, | ||
| 91 | }; | ||
| 92 | |||
| 93 | /* | ||
| 94 | * This function set DRAM refresh counter | ||
| 95 | * accoriding to operating frequency of DRAM | ||
| 96 | * ch: DMC port number 0 or 1 | ||
| 97 | * freq: Operating frequency of DRAM(KHz) | ||
| 98 | */ | ||
| 99 | static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) | ||
| 100 | { | ||
| 101 | unsigned long tmp, tmp1; | ||
| 102 | void __iomem *reg = NULL; | ||
| 103 | |||
| 104 | if (ch == DMC0) | ||
| 105 | reg = (S5P_VA_DMC0 + 0x30); | ||
| 106 | else if (ch == DMC1) | ||
| 107 | reg = (S5P_VA_DMC1 + 0x30); | ||
| 108 | else | ||
| 109 | printk(KERN_ERR "Cannot find DMC port\n"); | ||
| 110 | |||
| 111 | /* Find current DRAM frequency */ | ||
| 112 | tmp = s5pv210_dram_conf[ch].freq; | ||
| 113 | |||
| 114 | do_div(tmp, freq); | ||
| 115 | |||
| 116 | tmp1 = s5pv210_dram_conf[ch].refresh; | ||
| 117 | |||
| 118 | do_div(tmp1, tmp); | ||
| 119 | |||
| 120 | __raw_writel(tmp1, reg); | ||
| 121 | } | ||
| 122 | |||
| 123 | int s5pv210_verify_speed(struct cpufreq_policy *policy) | ||
| 124 | { | ||
| 125 | if (policy->cpu) | ||
| 126 | return -EINVAL; | ||
| 127 | |||
| 128 | return cpufreq_frequency_table_verify(policy, s5pv210_freq_table); | ||
| 129 | } | ||
| 130 | |||
| 131 | unsigned int s5pv210_getspeed(unsigned int cpu) | ||
| 132 | { | ||
| 133 | if (cpu) | ||
| 134 | return 0; | ||
| 135 | |||
| 136 | return clk_get_rate(cpu_clk) / 1000; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int s5pv210_target(struct cpufreq_policy *policy, | ||
| 140 | unsigned int target_freq, | ||
| 141 | unsigned int relation) | ||
| 142 | { | ||
| 143 | unsigned long reg; | ||
| 144 | unsigned int index, priv_index; | ||
| 145 | unsigned int pll_changing = 0; | ||
| 146 | unsigned int bus_speed_changing = 0; | ||
| 147 | |||
| 148 | freqs.old = s5pv210_getspeed(0); | ||
| 149 | |||
| 150 | if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, | ||
| 151 | target_freq, relation, &index)) | ||
| 152 | return -EINVAL; | ||
| 153 | |||
| 154 | freqs.new = s5pv210_freq_table[index].frequency; | ||
| 155 | freqs.cpu = 0; | ||
| 156 | |||
| 157 | if (freqs.new == freqs.old) | ||
| 158 | return 0; | ||
| 159 | |||
| 160 | /* Finding current running level index */ | ||
| 161 | if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, | ||
| 162 | freqs.old, relation, &priv_index)) | ||
| 163 | return -EINVAL; | ||
| 164 | |||
| 165 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
| 166 | |||
| 167 | if (freqs.new > freqs.old) { | ||
| 168 | /* Voltage up: will be implemented */ | ||
| 169 | } | ||
| 170 | |||
| 171 | /* Check if there need to change PLL */ | ||
| 172 | if ((index == L0) || (priv_index == L0)) | ||
| 173 | pll_changing = 1; | ||
| 174 | |||
| 175 | /* Check if there need to change System bus clock */ | ||
| 176 | if ((index == L4) || (priv_index == L4)) | ||
| 177 | bus_speed_changing = 1; | ||
| 178 | |||
| 179 | if (bus_speed_changing) { | ||
| 180 | /* | ||
| 181 | * Reconfigure DRAM refresh counter value for minimum | ||
| 182 | * temporary clock while changing divider. | ||
| 183 | * expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287 | ||
| 184 | */ | ||
| 185 | if (pll_changing) | ||
| 186 | s5pv210_set_refresh(DMC1, 83000); | ||
| 187 | else | ||
| 188 | s5pv210_set_refresh(DMC1, 100000); | ||
| 189 | |||
| 190 | s5pv210_set_refresh(DMC0, 83000); | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 194 | * APLL should be changed in this level | ||
| 195 | * APLL -> MPLL(for stable transition) -> APLL | ||
| 196 | * Some clock source's clock API are not prepared. | ||
| 197 | * Do not use clock API in below code. | ||
| 198 | */ | ||
| 199 | if (pll_changing) { | ||
| 200 | /* | ||
| 201 | * 1. Temporary Change divider for MFC and G3D | ||
| 202 | * SCLKA2M(200/1=200)->(200/4=50)Mhz | ||
| 203 | */ | ||
| 204 | reg = __raw_readl(S5P_CLK_DIV2); | ||
| 205 | reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK); | ||
| 206 | reg |= (3 << S5P_CLKDIV2_G3D_SHIFT) | | ||
| 207 | (3 << S5P_CLKDIV2_MFC_SHIFT); | ||
| 208 | __raw_writel(reg, S5P_CLK_DIV2); | ||
| 209 | |||
| 210 | /* For MFC, G3D dividing */ | ||
| 211 | do { | ||
| 212 | reg = __raw_readl(S5P_CLKDIV_STAT0); | ||
| 213 | } while (reg & ((1 << 16) | (1 << 17))); | ||
| 214 | |||
| 215 | /* | ||
| 216 | * 2. Change SCLKA2M(200Mhz)to SCLKMPLL in MFC_MUX, G3D MUX | ||
| 217 | * (200/4=50)->(667/4=166)Mhz | ||
| 218 | */ | ||
| 219 | reg = __raw_readl(S5P_CLK_SRC2); | ||
| 220 | reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK); | ||
| 221 | reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) | | ||
| 222 | (1 << S5P_CLKSRC2_MFC_SHIFT); | ||
| 223 | __raw_writel(reg, S5P_CLK_SRC2); | ||
| 224 | |||
| 225 | do { | ||
| 226 | reg = __raw_readl(S5P_CLKMUX_STAT1); | ||
| 227 | } while (reg & ((1 << 7) | (1 << 3))); | ||
| 228 | |||
| 229 | /* | ||
| 230 | * 3. DMC1 refresh count for 133Mhz if (index == L4) is | ||
| 231 | * true refresh counter is already programed in upper | ||
| 232 | * code. 0x287@83Mhz | ||
| 233 | */ | ||
| 234 | if (!bus_speed_changing) | ||
| 235 | s5pv210_set_refresh(DMC1, 133000); | ||
| 236 | |||
| 237 | /* 4. SCLKAPLL -> SCLKMPLL */ | ||
| 238 | reg = __raw_readl(S5P_CLK_SRC0); | ||
| 239 | reg &= ~(S5P_CLKSRC0_MUX200_MASK); | ||
| 240 | reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT); | ||
| 241 | __raw_writel(reg, S5P_CLK_SRC0); | ||
| 242 | |||
| 243 | do { | ||
| 244 | reg = __raw_readl(S5P_CLKMUX_STAT0); | ||
| 245 | } while (reg & (0x1 << 18)); | ||
| 246 | |||
| 247 | } | ||
| 248 | |||
| 249 | /* Change divider */ | ||
| 250 | reg = __raw_readl(S5P_CLK_DIV0); | ||
| 251 | |||
| 252 | reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK | | ||
| 253 | S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK | | ||
| 254 | S5P_CLKDIV0_HCLK166_MASK | S5P_CLKDIV0_PCLK83_MASK | | ||
| 255 | S5P_CLKDIV0_HCLK133_MASK | S5P_CLKDIV0_PCLK66_MASK); | ||
| 256 | |||
| 257 | reg |= ((clkdiv_val[index][0] << S5P_CLKDIV0_APLL_SHIFT) | | ||
| 258 | (clkdiv_val[index][1] << S5P_CLKDIV0_A2M_SHIFT) | | ||
| 259 | (clkdiv_val[index][2] << S5P_CLKDIV0_HCLK200_SHIFT) | | ||
| 260 | (clkdiv_val[index][3] << S5P_CLKDIV0_PCLK100_SHIFT) | | ||
| 261 | (clkdiv_val[index][4] << S5P_CLKDIV0_HCLK166_SHIFT) | | ||
| 262 | (clkdiv_val[index][5] << S5P_CLKDIV0_PCLK83_SHIFT) | | ||
| 263 | (clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT) | | ||
| 264 | (clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT)); | ||
| 265 | |||
| 266 | __raw_writel(reg, S5P_CLK_DIV0); | ||
| 267 | |||
| 268 | do { | ||
| 269 | reg = __raw_readl(S5P_CLKDIV_STAT0); | ||
| 270 | } while (reg & 0xff); | ||
| 271 | |||
| 272 | /* ARM MCS value changed */ | ||
| 273 | reg = __raw_readl(S5P_ARM_MCS_CON); | ||
| 274 | reg &= ~0x3; | ||
| 275 | if (index >= L3) | ||
| 276 | reg |= 0x3; | ||
| 277 | else | ||
| 278 | reg |= 0x1; | ||
| 279 | |||
| 280 | __raw_writel(reg, S5P_ARM_MCS_CON); | ||
| 281 | |||
| 282 | if (pll_changing) { | ||
| 283 | /* 5. Set Lock time = 30us*24Mhz = 0x2cf */ | ||
| 284 | __raw_writel(0x2cf, S5P_APLL_LOCK); | ||
| 285 | |||
| 286 | /* | ||
| 287 | * 6. Turn on APLL | ||
| 288 | * 6-1. Set PMS values | ||
| 289 | * 6-2. Wait untile the PLL is locked | ||
| 290 | */ | ||
| 291 | if (index == L0) | ||
| 292 | __raw_writel(APLL_VAL_1000, S5P_APLL_CON); | ||
| 293 | else | ||
| 294 | __raw_writel(APLL_VAL_800, S5P_APLL_CON); | ||
| 295 | |||
| 296 | do { | ||
| 297 | reg = __raw_readl(S5P_APLL_CON); | ||
| 298 | } while (!(reg & (0x1 << 29))); | ||
| 299 | |||
| 300 | /* | ||
| 301 | * 7. Change souce clock from SCLKMPLL(667Mhz) | ||
| 302 | * to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX | ||
| 303 | * (667/4=166)->(200/4=50)Mhz | ||
| 304 | */ | ||
| 305 | reg = __raw_readl(S5P_CLK_SRC2); | ||
| 306 | reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK); | ||
| 307 | reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) | | ||
| 308 | (0 << S5P_CLKSRC2_MFC_SHIFT); | ||
| 309 | __raw_writel(reg, S5P_CLK_SRC2); | ||
| 310 | |||
| 311 | do { | ||
| 312 | reg = __raw_readl(S5P_CLKMUX_STAT1); | ||
| 313 | } while (reg & ((1 << 7) | (1 << 3))); | ||
| 314 | |||
| 315 | /* | ||
| 316 | * 8. Change divider for MFC and G3D | ||
| 317 | * (200/4=50)->(200/1=200)Mhz | ||
| 318 | */ | ||
| 319 | reg = __raw_readl(S5P_CLK_DIV2); | ||
| 320 | reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK); | ||
| 321 | reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) | | ||
| 322 | (clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT); | ||
| 323 | __raw_writel(reg, S5P_CLK_DIV2); | ||
| 324 | |||
| 325 | /* For MFC, G3D dividing */ | ||
| 326 | do { | ||
| 327 | reg = __raw_readl(S5P_CLKDIV_STAT0); | ||
| 328 | } while (reg & ((1 << 16) | (1 << 17))); | ||
| 329 | |||
| 330 | /* 9. Change MPLL to APLL in MSYS_MUX */ | ||
| 331 | reg = __raw_readl(S5P_CLK_SRC0); | ||
| 332 | reg &= ~(S5P_CLKSRC0_MUX200_MASK); | ||
| 333 | reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT); | ||
| 334 | __raw_writel(reg, S5P_CLK_SRC0); | ||
| 335 | |||
| 336 | do { | ||
| 337 | reg = __raw_readl(S5P_CLKMUX_STAT0); | ||
| 338 | } while (reg & (0x1 << 18)); | ||
| 339 | |||
| 340 | /* | ||
| 341 | * 10. DMC1 refresh counter | ||
| 342 | * L4 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c | ||
| 343 | * Others : DMC1 = 200Mhz 7.8us/(1/200) = 0x618 | ||
| 344 | */ | ||
| 345 | if (!bus_speed_changing) | ||
| 346 | s5pv210_set_refresh(DMC1, 200000); | ||
| 347 | } | ||
| 348 | |||
| 349 | /* | ||
| 350 | * L4 level need to change memory bus speed, hence onedram clock divier | ||
| 351 | * and memory refresh parameter should be changed | ||
| 352 | */ | ||
| 353 | if (bus_speed_changing) { | ||
| 354 | reg = __raw_readl(S5P_CLK_DIV6); | ||
| 355 | reg &= ~S5P_CLKDIV6_ONEDRAM_MASK; | ||
| 356 | reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT); | ||
| 357 | __raw_writel(reg, S5P_CLK_DIV6); | ||
| 358 | |||
| 359 | do { | ||
| 360 | reg = __raw_readl(S5P_CLKDIV_STAT1); | ||
| 361 | } while (reg & (1 << 15)); | ||
| 362 | |||
| 363 | /* Reconfigure DRAM refresh counter value */ | ||
| 364 | if (index != L4) { | ||
| 365 | /* | ||
| 366 | * DMC0 : 166Mhz | ||
| 367 | * DMC1 : 200Mhz | ||
| 368 | */ | ||
| 369 | s5pv210_set_refresh(DMC0, 166000); | ||
| 370 | s5pv210_set_refresh(DMC1, 200000); | ||
| 371 | } else { | ||
| 372 | /* | ||
| 373 | * DMC0 : 83Mhz | ||
| 374 | * DMC1 : 100Mhz | ||
| 375 | */ | ||
| 376 | s5pv210_set_refresh(DMC0, 83000); | ||
| 377 | s5pv210_set_refresh(DMC1, 100000); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | if (freqs.new < freqs.old) { | ||
| 382 | /* Voltage down: will be implemented */ | ||
| 383 | } | ||
| 384 | |||
| 385 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
| 386 | |||
| 387 | printk(KERN_DEBUG "Perf changed[L%d]\n", index); | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | #ifdef CONFIG_PM | ||
| 393 | static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy, | ||
| 394 | pm_message_t pmsg) | ||
| 395 | { | ||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy) | ||
| 400 | { | ||
| 401 | return 0; | ||
| 402 | } | ||
| 403 | #endif | ||
| 404 | |||
| 405 | static int check_mem_type(void __iomem *dmc_reg) | ||
| 406 | { | ||
| 407 | unsigned long val; | ||
| 408 | |||
| 409 | val = __raw_readl(dmc_reg + 0x4); | ||
| 410 | val = (val & (0xf << 8)); | ||
| 411 | |||
| 412 | return val >> 8; | ||
| 413 | } | ||
| 414 | |||
| 415 | static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) | ||
| 416 | { | ||
| 417 | unsigned long mem_type; | ||
| 418 | |||
| 419 | cpu_clk = clk_get(NULL, "armclk"); | ||
| 420 | if (IS_ERR(cpu_clk)) | ||
| 421 | return PTR_ERR(cpu_clk); | ||
| 422 | |||
| 423 | dmc0_clk = clk_get(NULL, "sclk_dmc0"); | ||
| 424 | if (IS_ERR(dmc0_clk)) { | ||
| 425 | clk_put(cpu_clk); | ||
| 426 | return PTR_ERR(dmc0_clk); | ||
| 427 | } | ||
| 428 | |||
| 429 | dmc1_clk = clk_get(NULL, "hclk_msys"); | ||
| 430 | if (IS_ERR(dmc1_clk)) { | ||
| 431 | clk_put(dmc0_clk); | ||
| 432 | clk_put(cpu_clk); | ||
| 433 | return PTR_ERR(dmc1_clk); | ||
| 434 | } | ||
| 435 | |||
| 436 | if (policy->cpu != 0) | ||
| 437 | return -EINVAL; | ||
| 438 | |||
| 439 | /* | ||
| 440 | * check_mem_type : This driver only support LPDDR & LPDDR2. | ||
| 441 | * other memory type is not supported. | ||
| 442 | */ | ||
| 443 | mem_type = check_mem_type(S5P_VA_DMC0); | ||
| 444 | |||
| 445 | if ((mem_type != LPDDR) && (mem_type != LPDDR2)) { | ||
| 446 | printk(KERN_ERR "CPUFreq doesn't support this memory type\n"); | ||
| 447 | return -EINVAL; | ||
| 448 | } | ||
| 449 | |||
| 450 | /* Find current refresh counter and frequency each DMC */ | ||
| 451 | s5pv210_dram_conf[0].refresh = (__raw_readl(S5P_VA_DMC0 + 0x30) * 1000); | ||
| 452 | s5pv210_dram_conf[0].freq = clk_get_rate(dmc0_clk); | ||
| 453 | |||
| 454 | s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000); | ||
| 455 | s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk); | ||
| 456 | |||
| 457 | policy->cur = policy->min = policy->max = s5pv210_getspeed(0); | ||
| 458 | |||
| 459 | cpufreq_frequency_table_get_attr(s5pv210_freq_table, policy->cpu); | ||
| 460 | |||
| 461 | policy->cpuinfo.transition_latency = 40000; | ||
| 462 | |||
| 463 | return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); | ||
| 464 | } | ||
| 465 | |||
| 466 | static struct cpufreq_driver s5pv210_driver = { | ||
| 467 | .flags = CPUFREQ_STICKY, | ||
| 468 | .verify = s5pv210_verify_speed, | ||
| 469 | .target = s5pv210_target, | ||
| 470 | .get = s5pv210_getspeed, | ||
| 471 | .init = s5pv210_cpu_init, | ||
| 472 | .name = "s5pv210", | ||
| 473 | #ifdef CONFIG_PM | ||
| 474 | .suspend = s5pv210_cpufreq_suspend, | ||
| 475 | .resume = s5pv210_cpufreq_resume, | ||
| 476 | #endif | ||
| 477 | }; | ||
| 478 | |||
| 479 | static int __init s5pv210_cpufreq_init(void) | ||
| 480 | { | ||
| 481 | return cpufreq_register_driver(&s5pv210_driver); | ||
| 482 | } | ||
| 483 | |||
| 484 | late_initcall(s5pv210_cpufreq_init); | ||
diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c index 21dc6cf955c3..1303fcb12b51 100644 --- a/arch/arm/mach-s5pv210/dev-audio.c +++ b/arch/arm/mach-s5pv210/dev-audio.c | |||
| @@ -24,29 +24,15 @@ static int s5pv210_cfg_i2s(struct platform_device *pdev) | |||
| 24 | /* configure GPIO for i2s port */ | 24 | /* configure GPIO for i2s port */ |
| 25 | switch (pdev->id) { | 25 | switch (pdev->id) { |
| 26 | case 1: | 26 | case 1: |
| 27 | s3c_gpio_cfgpin(S5PV210_GPC0(0), S3C_GPIO_SFN(2)); | 27 | s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(2)); |
| 28 | s3c_gpio_cfgpin(S5PV210_GPC0(1), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_cfgpin(S5PV210_GPC0(2), S3C_GPIO_SFN(2)); | ||
| 30 | s3c_gpio_cfgpin(S5PV210_GPC0(3), S3C_GPIO_SFN(2)); | ||
| 31 | s3c_gpio_cfgpin(S5PV210_GPC0(4), S3C_GPIO_SFN(2)); | ||
| 32 | break; | 28 | break; |
| 33 | 29 | ||
| 34 | case 2: | 30 | case 2: |
| 35 | s3c_gpio_cfgpin(S5PV210_GPC1(0), S3C_GPIO_SFN(4)); | 31 | s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 5, S3C_GPIO_SFN(4)); |
| 36 | s3c_gpio_cfgpin(S5PV210_GPC1(1), S3C_GPIO_SFN(4)); | ||
| 37 | s3c_gpio_cfgpin(S5PV210_GPC1(2), S3C_GPIO_SFN(4)); | ||
| 38 | s3c_gpio_cfgpin(S5PV210_GPC1(3), S3C_GPIO_SFN(4)); | ||
| 39 | s3c_gpio_cfgpin(S5PV210_GPC1(4), S3C_GPIO_SFN(4)); | ||
| 40 | break; | 32 | break; |
| 41 | 33 | ||
| 42 | case -1: | 34 | case -1: |
| 43 | s3c_gpio_cfgpin(S5PV210_GPI(0), S3C_GPIO_SFN(2)); | 35 | s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2)); |
| 44 | s3c_gpio_cfgpin(S5PV210_GPI(1), S3C_GPIO_SFN(2)); | ||
| 45 | s3c_gpio_cfgpin(S5PV210_GPI(2), S3C_GPIO_SFN(2)); | ||
| 46 | s3c_gpio_cfgpin(S5PV210_GPI(3), S3C_GPIO_SFN(2)); | ||
| 47 | s3c_gpio_cfgpin(S5PV210_GPI(4), S3C_GPIO_SFN(2)); | ||
| 48 | s3c_gpio_cfgpin(S5PV210_GPI(5), S3C_GPIO_SFN(2)); | ||
| 49 | s3c_gpio_cfgpin(S5PV210_GPI(6), S3C_GPIO_SFN(2)); | ||
| 50 | break; | 36 | break; |
| 51 | 37 | ||
| 52 | default: | 38 | default: |
| @@ -151,25 +137,13 @@ static int s5pv210_pcm_cfg_gpio(struct platform_device *pdev) | |||
| 151 | { | 137 | { |
| 152 | switch (pdev->id) { | 138 | switch (pdev->id) { |
| 153 | case 0: | 139 | case 0: |
| 154 | s3c_gpio_cfgpin(S5PV210_GPI(0), S3C_GPIO_SFN(3)); | 140 | s3c_gpio_cfgpin_range(S5PV210_GPI(0), 5, S3C_GPIO_SFN(3)); |
| 155 | s3c_gpio_cfgpin(S5PV210_GPI(1), S3C_GPIO_SFN(3)); | ||
| 156 | s3c_gpio_cfgpin(S5PV210_GPI(2), S3C_GPIO_SFN(3)); | ||
| 157 | s3c_gpio_cfgpin(S5PV210_GPI(3), S3C_GPIO_SFN(3)); | ||
| 158 | s3c_gpio_cfgpin(S5PV210_GPI(4), S3C_GPIO_SFN(3)); | ||
| 159 | break; | 141 | break; |
| 160 | case 1: | 142 | case 1: |
| 161 | s3c_gpio_cfgpin(S5PV210_GPC0(0), S3C_GPIO_SFN(3)); | 143 | s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(3)); |
| 162 | s3c_gpio_cfgpin(S5PV210_GPC0(1), S3C_GPIO_SFN(3)); | ||
| 163 | s3c_gpio_cfgpin(S5PV210_GPC0(2), S3C_GPIO_SFN(3)); | ||
| 164 | s3c_gpio_cfgpin(S5PV210_GPC0(3), S3C_GPIO_SFN(3)); | ||
| 165 | s3c_gpio_cfgpin(S5PV210_GPC0(4), S3C_GPIO_SFN(3)); | ||
| 166 | break; | 144 | break; |
| 167 | case 2: | 145 | case 2: |
| 168 | s3c_gpio_cfgpin(S5PV210_GPC1(0), S3C_GPIO_SFN(2)); | 146 | s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 5, S3C_GPIO_SFN(2)); |
| 169 | s3c_gpio_cfgpin(S5PV210_GPC1(1), S3C_GPIO_SFN(2)); | ||
| 170 | s3c_gpio_cfgpin(S5PV210_GPC1(2), S3C_GPIO_SFN(2)); | ||
| 171 | s3c_gpio_cfgpin(S5PV210_GPC1(3), S3C_GPIO_SFN(2)); | ||
| 172 | s3c_gpio_cfgpin(S5PV210_GPC1(4), S3C_GPIO_SFN(2)); | ||
| 173 | break; | 147 | break; |
| 174 | default: | 148 | default: |
| 175 | printk(KERN_DEBUG "Invalid PCM Controller number!"); | 149 | printk(KERN_DEBUG "Invalid PCM Controller number!"); |
| @@ -271,13 +245,7 @@ struct platform_device s5pv210_device_pcm2 = { | |||
| 271 | 245 | ||
| 272 | static int s5pv210_ac97_cfg_gpio(struct platform_device *pdev) | 246 | static int s5pv210_ac97_cfg_gpio(struct platform_device *pdev) |
| 273 | { | 247 | { |
| 274 | s3c_gpio_cfgpin(S5PV210_GPC0(0), S3C_GPIO_SFN(4)); | 248 | return s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(4)); |
| 275 | s3c_gpio_cfgpin(S5PV210_GPC0(1), S3C_GPIO_SFN(4)); | ||
| 276 | s3c_gpio_cfgpin(S5PV210_GPC0(2), S3C_GPIO_SFN(4)); | ||
| 277 | s3c_gpio_cfgpin(S5PV210_GPC0(3), S3C_GPIO_SFN(4)); | ||
| 278 | s3c_gpio_cfgpin(S5PV210_GPC0(4), S3C_GPIO_SFN(4)); | ||
| 279 | |||
| 280 | return 0; | ||
| 281 | } | 249 | } |
| 282 | 250 | ||
| 283 | static struct resource s5pv210_ac97_resource[] = { | 251 | static struct resource s5pv210_ac97_resource[] = { |
| @@ -325,3 +293,43 @@ struct platform_device s5pv210_device_ac97 = { | |||
| 325 | .coherent_dma_mask = DMA_BIT_MASK(32), | 293 | .coherent_dma_mask = DMA_BIT_MASK(32), |
| 326 | }, | 294 | }, |
| 327 | }; | 295 | }; |
| 296 | |||
| 297 | /* S/PDIF Controller platform_device */ | ||
| 298 | |||
| 299 | static int s5pv210_spdif_cfg_gpio(struct platform_device *pdev) | ||
| 300 | { | ||
| 301 | s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 2, S3C_GPIO_SFN(3)); | ||
| 302 | |||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | |||
| 306 | static struct resource s5pv210_spdif_resource[] = { | ||
| 307 | [0] = { | ||
| 308 | .start = S5PV210_PA_SPDIF, | ||
| 309 | .end = S5PV210_PA_SPDIF + 0x100 - 1, | ||
| 310 | .flags = IORESOURCE_MEM, | ||
| 311 | }, | ||
| 312 | [1] = { | ||
| 313 | .start = DMACH_SPDIF, | ||
| 314 | .end = DMACH_SPDIF, | ||
| 315 | .flags = IORESOURCE_DMA, | ||
| 316 | }, | ||
| 317 | }; | ||
| 318 | |||
| 319 | static struct s3c_audio_pdata samsung_spdif_pdata = { | ||
| 320 | .cfg_gpio = s5pv210_spdif_cfg_gpio, | ||
| 321 | }; | ||
| 322 | |||
| 323 | static u64 s5pv210_spdif_dmamask = DMA_BIT_MASK(32); | ||
| 324 | |||
| 325 | struct platform_device s5pv210_device_spdif = { | ||
| 326 | .name = "samsung-spdif", | ||
| 327 | .id = -1, | ||
| 328 | .num_resources = ARRAY_SIZE(s5pv210_spdif_resource), | ||
| 329 | .resource = s5pv210_spdif_resource, | ||
| 330 | .dev = { | ||
| 331 | .platform_data = &samsung_spdif_pdata, | ||
| 332 | .dma_mask = &s5pv210_spdif_dmamask, | ||
| 333 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
| 334 | }, | ||
| 335 | }; | ||
diff --git a/arch/arm/mach-s5pv210/dev-spi.c b/arch/arm/mach-s5pv210/dev-spi.c index 826cdbc43e20..e3249a47e3b1 100644 --- a/arch/arm/mach-s5pv210/dev-spi.c +++ b/arch/arm/mach-s5pv210/dev-spi.c | |||
| @@ -35,23 +35,15 @@ static char *spi_src_clks[] = { | |||
| 35 | */ | 35 | */ |
| 36 | static int s5pv210_spi_cfg_gpio(struct platform_device *pdev) | 36 | static int s5pv210_spi_cfg_gpio(struct platform_device *pdev) |
| 37 | { | 37 | { |
| 38 | unsigned int base; | ||
| 39 | |||
| 38 | switch (pdev->id) { | 40 | switch (pdev->id) { |
| 39 | case 0: | 41 | case 0: |
| 40 | s3c_gpio_cfgpin(S5PV210_GPB(0), S3C_GPIO_SFN(2)); | 42 | base = S5PV210_GPB(0); |
| 41 | s3c_gpio_cfgpin(S5PV210_GPB(1), S3C_GPIO_SFN(2)); | ||
| 42 | s3c_gpio_cfgpin(S5PV210_GPB(2), S3C_GPIO_SFN(2)); | ||
| 43 | s3c_gpio_setpull(S5PV210_GPB(0), S3C_GPIO_PULL_UP); | ||
| 44 | s3c_gpio_setpull(S5PV210_GPB(1), S3C_GPIO_PULL_UP); | ||
| 45 | s3c_gpio_setpull(S5PV210_GPB(2), S3C_GPIO_PULL_UP); | ||
| 46 | break; | 43 | break; |
| 47 | 44 | ||
| 48 | case 1: | 45 | case 1: |
| 49 | s3c_gpio_cfgpin(S5PV210_GPB(4), S3C_GPIO_SFN(2)); | 46 | base = S5PV210_GPB(4); |
| 50 | s3c_gpio_cfgpin(S5PV210_GPB(5), S3C_GPIO_SFN(2)); | ||
| 51 | s3c_gpio_cfgpin(S5PV210_GPB(6), S3C_GPIO_SFN(2)); | ||
| 52 | s3c_gpio_setpull(S5PV210_GPB(4), S3C_GPIO_PULL_UP); | ||
| 53 | s3c_gpio_setpull(S5PV210_GPB(5), S3C_GPIO_PULL_UP); | ||
| 54 | s3c_gpio_setpull(S5PV210_GPB(6), S3C_GPIO_PULL_UP); | ||
| 55 | break; | 47 | break; |
| 56 | 48 | ||
| 57 | default: | 49 | default: |
| @@ -59,6 +51,9 @@ static int s5pv210_spi_cfg_gpio(struct platform_device *pdev) | |||
| 59 | return -EINVAL; | 51 | return -EINVAL; |
| 60 | } | 52 | } |
| 61 | 53 | ||
| 54 | s3c_gpio_cfgall_range(base, 3, | ||
| 55 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); | ||
| 56 | |||
| 62 | return 0; | 57 | return 0; |
| 63 | } | 58 | } |
| 64 | 59 | ||
diff --git a/arch/arm/mach-s5pv210/dma.c b/arch/arm/mach-s5pv210/dma.c index 778ad5fe231a..497d3439a142 100644 --- a/arch/arm/mach-s5pv210/dma.c +++ b/arch/arm/mach-s5pv210/dma.c | |||
| @@ -82,7 +82,7 @@ static struct s3c_pl330_platdata s5pv210_pdma0_pdata = { | |||
| 82 | 82 | ||
| 83 | static struct platform_device s5pv210_device_pdma0 = { | 83 | static struct platform_device s5pv210_device_pdma0 = { |
| 84 | .name = "s3c-pl330", | 84 | .name = "s3c-pl330", |
| 85 | .id = 1, | 85 | .id = 0, |
| 86 | .num_resources = ARRAY_SIZE(s5pv210_pdma0_resource), | 86 | .num_resources = ARRAY_SIZE(s5pv210_pdma0_resource), |
| 87 | .resource = s5pv210_pdma0_resource, | 87 | .resource = s5pv210_pdma0_resource, |
| 88 | .dev = { | 88 | .dev = { |
| @@ -144,7 +144,7 @@ static struct s3c_pl330_platdata s5pv210_pdma1_pdata = { | |||
| 144 | 144 | ||
| 145 | static struct platform_device s5pv210_device_pdma1 = { | 145 | static struct platform_device s5pv210_device_pdma1 = { |
| 146 | .name = "s3c-pl330", | 146 | .name = "s3c-pl330", |
| 147 | .id = 2, | 147 | .id = 1, |
| 148 | .num_resources = ARRAY_SIZE(s5pv210_pdma1_resource), | 148 | .num_resources = ARRAY_SIZE(s5pv210_pdma1_resource), |
| 149 | .resource = s5pv210_pdma1_resource, | 149 | .resource = s5pv210_pdma1_resource, |
| 150 | .dev = { | 150 | .dev = { |
diff --git a/arch/arm/mach-s5pv210/gpiolib.c b/arch/arm/mach-s5pv210/gpiolib.c index 0d459112d039..ab673effd767 100644 --- a/arch/arm/mach-s5pv210/gpiolib.c +++ b/arch/arm/mach-s5pv210/gpiolib.c | |||
| @@ -150,6 +150,7 @@ static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { | |||
| 150 | .label = "GPG3", | 150 | .label = "GPG3", |
| 151 | }, | 151 | }, |
| 152 | }, { | 152 | }, { |
| 153 | .config = &gpio_cfg_noint, | ||
| 153 | .chip = { | 154 | .chip = { |
| 154 | .base = S5PV210_GPI(0), | 155 | .base = S5PV210_GPI(0), |
| 155 | .ngpio = S5PV210_GPIO_I_NR, | 156 | .ngpio = S5PV210_GPIO_I_NR, |
| @@ -223,34 +224,42 @@ static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { | |||
| 223 | }, { | 224 | }, { |
| 224 | .base = (S5P_VA_GPIO + 0xC00), | 225 | .base = (S5P_VA_GPIO + 0xC00), |
| 225 | .config = &gpio_cfg_noint, | 226 | .config = &gpio_cfg_noint, |
| 227 | .irq_base = IRQ_EINT(0), | ||
| 226 | .chip = { | 228 | .chip = { |
| 227 | .base = S5PV210_GPH0(0), | 229 | .base = S5PV210_GPH0(0), |
| 228 | .ngpio = S5PV210_GPIO_H0_NR, | 230 | .ngpio = S5PV210_GPIO_H0_NR, |
| 229 | .label = "GPH0", | 231 | .label = "GPH0", |
| 232 | .to_irq = samsung_gpiolib_to_irq, | ||
| 230 | }, | 233 | }, |
| 231 | }, { | 234 | }, { |
| 232 | .base = (S5P_VA_GPIO + 0xC20), | 235 | .base = (S5P_VA_GPIO + 0xC20), |
| 233 | .config = &gpio_cfg_noint, | 236 | .config = &gpio_cfg_noint, |
| 237 | .irq_base = IRQ_EINT(8), | ||
| 234 | .chip = { | 238 | .chip = { |
| 235 | .base = S5PV210_GPH1(0), | 239 | .base = S5PV210_GPH1(0), |
| 236 | .ngpio = S5PV210_GPIO_H1_NR, | 240 | .ngpio = S5PV210_GPIO_H1_NR, |
| 237 | .label = "GPH1", | 241 | .label = "GPH1", |
| 242 | .to_irq = samsung_gpiolib_to_irq, | ||
| 238 | }, | 243 | }, |
| 239 | }, { | 244 | }, { |
| 240 | .base = (S5P_VA_GPIO + 0xC40), | 245 | .base = (S5P_VA_GPIO + 0xC40), |
| 241 | .config = &gpio_cfg_noint, | 246 | .config = &gpio_cfg_noint, |
| 247 | .irq_base = IRQ_EINT(16), | ||
| 242 | .chip = { | 248 | .chip = { |
| 243 | .base = S5PV210_GPH2(0), | 249 | .base = S5PV210_GPH2(0), |
| 244 | .ngpio = S5PV210_GPIO_H2_NR, | 250 | .ngpio = S5PV210_GPIO_H2_NR, |
| 245 | .label = "GPH2", | 251 | .label = "GPH2", |
| 252 | .to_irq = samsung_gpiolib_to_irq, | ||
| 246 | }, | 253 | }, |
| 247 | }, { | 254 | }, { |
| 248 | .base = (S5P_VA_GPIO + 0xC60), | 255 | .base = (S5P_VA_GPIO + 0xC60), |
| 249 | .config = &gpio_cfg_noint, | 256 | .config = &gpio_cfg_noint, |
| 257 | .irq_base = IRQ_EINT(24), | ||
| 250 | .chip = { | 258 | .chip = { |
| 251 | .base = S5PV210_GPH3(0), | 259 | .base = S5PV210_GPH3(0), |
| 252 | .ngpio = S5PV210_GPIO_H3_NR, | 260 | .ngpio = S5PV210_GPIO_H3_NR, |
| 253 | .label = "GPH3", | 261 | .label = "GPH3", |
| 262 | .to_irq = samsung_gpiolib_to_irq, | ||
| 254 | }, | 263 | }, |
| 255 | }, | 264 | }, |
| 256 | }; | 265 | }; |
| @@ -259,11 +268,14 @@ static __init int s5pv210_gpiolib_init(void) | |||
| 259 | { | 268 | { |
| 260 | struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; | 269 | struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; |
| 261 | int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); | 270 | int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); |
| 271 | int gpioint_group = 0; | ||
| 262 | int i = 0; | 272 | int i = 0; |
| 263 | 273 | ||
| 264 | for (i = 0; i < nr_chips; i++, chip++) { | 274 | for (i = 0; i < nr_chips; i++, chip++) { |
| 265 | if (chip->config == NULL) | 275 | if (chip->config == NULL) { |
| 266 | chip->config = &gpio_cfg; | 276 | chip->config = &gpio_cfg; |
| 277 | chip->group = gpioint_group++; | ||
| 278 | } | ||
| 267 | if (chip->base == NULL) | 279 | if (chip->base == NULL) |
| 268 | chip->base = S5PV210_BANK_BASE(i); | 280 | chip->base = S5PV210_BANK_BASE(i); |
| 269 | } | 281 | } |
diff --git a/arch/arm/mach-s5pv210/include/mach/irqs.h b/arch/arm/mach-s5pv210/include/mach/irqs.h index e1c020e5a49b..119b95fdc3ce 100644 --- a/arch/arm/mach-s5pv210/include/mach/irqs.h +++ b/arch/arm/mach-s5pv210/include/mach/irqs.h | |||
| @@ -55,8 +55,8 @@ | |||
| 55 | #define IRQ_SPI1 S5P_IRQ_VIC1(16) | 55 | #define IRQ_SPI1 S5P_IRQ_VIC1(16) |
| 56 | #define IRQ_SPI2 S5P_IRQ_VIC1(17) | 56 | #define IRQ_SPI2 S5P_IRQ_VIC1(17) |
| 57 | #define IRQ_IRDA S5P_IRQ_VIC1(18) | 57 | #define IRQ_IRDA S5P_IRQ_VIC1(18) |
| 58 | #define IRQ_CAN0 S5P_IRQ_VIC1(19) | 58 | #define IRQ_IIC2 S5P_IRQ_VIC1(19) |
| 59 | #define IRQ_CAN1 S5P_IRQ_VIC1(20) | 59 | #define IRQ_IIC3 S5P_IRQ_VIC1(20) |
| 60 | #define IRQ_HSIRX S5P_IRQ_VIC1(21) | 60 | #define IRQ_HSIRX S5P_IRQ_VIC1(21) |
| 61 | #define IRQ_HSITX S5P_IRQ_VIC1(22) | 61 | #define IRQ_HSITX S5P_IRQ_VIC1(22) |
| 62 | #define IRQ_UHOST S5P_IRQ_VIC1(23) | 62 | #define IRQ_UHOST S5P_IRQ_VIC1(23) |
| @@ -109,7 +109,7 @@ | |||
| 109 | 109 | ||
| 110 | #define IRQ_IPC S5P_IRQ_VIC3(0) | 110 | #define IRQ_IPC S5P_IRQ_VIC3(0) |
| 111 | #define IRQ_HOSTIF S5P_IRQ_VIC3(1) | 111 | #define IRQ_HOSTIF S5P_IRQ_VIC3(1) |
| 112 | #define IRQ_MMC3 S5P_IRQ_VIC3(2) | 112 | #define IRQ_HSMMC3 S5P_IRQ_VIC3(2) |
| 113 | #define IRQ_CEC S5P_IRQ_VIC3(3) | 113 | #define IRQ_CEC S5P_IRQ_VIC3(3) |
| 114 | #define IRQ_TSI S5P_IRQ_VIC3(4) | 114 | #define IRQ_TSI S5P_IRQ_VIC3(4) |
| 115 | #define IRQ_MDNIE0 S5P_IRQ_VIC3(5) | 115 | #define IRQ_MDNIE0 S5P_IRQ_VIC3(5) |
| @@ -121,8 +121,12 @@ | |||
| 121 | #define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0)) | 121 | #define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0)) |
| 122 | #define S5P_EINT_BASE2 (IRQ_VIC_END + 1) | 122 | #define S5P_EINT_BASE2 (IRQ_VIC_END + 1) |
| 123 | 123 | ||
| 124 | /* GPIO interrupt */ | ||
| 125 | #define S5P_GPIOINT_BASE (IRQ_EINT(31) + 1) | ||
| 126 | #define S5P_GPIOINT_GROUP_MAXNR 22 | ||
| 127 | |||
| 124 | /* Set the default NR_IRQS */ | 128 | /* Set the default NR_IRQS */ |
| 125 | #define NR_IRQS (IRQ_EINT(31) + 1) | 129 | #define NR_IRQS (IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1) |
| 126 | 130 | ||
| 127 | /* Compatibility */ | 131 | /* Compatibility */ |
| 128 | #define IRQ_LCD_FIFO IRQ_LCD0 | 132 | #define IRQ_LCD_FIFO IRQ_LCD0 |
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h index bd9afd52466a..861d7fe11fc9 100644 --- a/arch/arm/mach-s5pv210/include/mach/map.h +++ b/arch/arm/mach-s5pv210/include/mach/map.h | |||
| @@ -57,6 +57,8 @@ | |||
| 57 | 57 | ||
| 58 | #define S5P_SZ_UART SZ_256 | 58 | #define S5P_SZ_UART SZ_256 |
| 59 | 59 | ||
| 60 | #define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) | ||
| 61 | |||
| 60 | #define S5PV210_PA_SROMC (0xE8000000) | 62 | #define S5PV210_PA_SROMC (0xE8000000) |
| 61 | 63 | ||
| 62 | #define S5PV210_PA_CFCON (0xE8200000) | 64 | #define S5PV210_PA_CFCON (0xE8200000) |
| @@ -73,6 +75,9 @@ | |||
| 73 | 75 | ||
| 74 | #define S5PV210_PA_HSMMC(x) (0xEB000000 + ((x) * 0x100000)) | 76 | #define S5PV210_PA_HSMMC(x) (0xEB000000 + ((x) * 0x100000)) |
| 75 | 77 | ||
| 78 | #define S5PV210_PA_HSOTG (0xEC000000) | ||
| 79 | #define S5PV210_PA_HSPHY (0xEC100000) | ||
| 80 | |||
| 76 | #define S5PV210_PA_VIC0 (0xF2000000) | 81 | #define S5PV210_PA_VIC0 (0xF2000000) |
| 77 | #define S5PV210_PA_VIC1 (0xF2100000) | 82 | #define S5PV210_PA_VIC1 (0xF2100000) |
| 78 | #define S5PV210_PA_VIC2 (0xF2200000) | 83 | #define S5PV210_PA_VIC2 (0xF2200000) |
| @@ -81,6 +86,9 @@ | |||
| 81 | #define S5PV210_PA_SDRAM (0x20000000) | 86 | #define S5PV210_PA_SDRAM (0x20000000) |
| 82 | #define S5P_PA_SDRAM S5PV210_PA_SDRAM | 87 | #define S5P_PA_SDRAM S5PV210_PA_SDRAM |
| 83 | 88 | ||
| 89 | /* S/PDIF */ | ||
| 90 | #define S5PV210_PA_SPDIF 0xE1100000 | ||
| 91 | |||
| 84 | /* I2S */ | 92 | /* I2S */ |
| 85 | #define S5PV210_PA_IIS0 0xEEE30000 | 93 | #define S5PV210_PA_IIS0 0xEEE30000 |
| 86 | #define S5PV210_PA_IIS1 0xE2100000 | 94 | #define S5PV210_PA_IIS1 0xE2100000 |
| @@ -96,6 +104,9 @@ | |||
| 96 | 104 | ||
| 97 | #define S5PV210_PA_ADC (0xE1700000) | 105 | #define S5PV210_PA_ADC (0xE1700000) |
| 98 | 106 | ||
| 107 | #define S5PV210_PA_DMC0 (0xF0000000) | ||
| 108 | #define S5PV210_PA_DMC1 (0xF1400000) | ||
| 109 | |||
| 99 | /* compatibiltiy defines. */ | 110 | /* compatibiltiy defines. */ |
| 100 | #define S3C_PA_UART S5PV210_PA_UART | 111 | #define S3C_PA_UART S5PV210_PA_UART |
| 101 | #define S3C_PA_HSMMC0 S5PV210_PA_HSMMC(0) | 112 | #define S3C_PA_HSMMC0 S5PV210_PA_HSMMC(0) |
| @@ -108,6 +119,7 @@ | |||
| 108 | #define S3C_PA_FB S5PV210_PA_FB | 119 | #define S3C_PA_FB S5PV210_PA_FB |
| 109 | #define S3C_PA_RTC S5PV210_PA_RTC | 120 | #define S3C_PA_RTC S5PV210_PA_RTC |
| 110 | #define S3C_PA_WDT S5PV210_PA_WATCHDOG | 121 | #define S3C_PA_WDT S5PV210_PA_WATCHDOG |
| 122 | #define S3C_PA_USB_HSOTG S5PV210_PA_HSOTG | ||
| 111 | #define S5P_PA_FIMC0 S5PV210_PA_FIMC0 | 123 | #define S5P_PA_FIMC0 S5PV210_PA_FIMC0 |
| 112 | #define S5P_PA_FIMC1 S5PV210_PA_FIMC1 | 124 | #define S5P_PA_FIMC1 S5PV210_PA_FIMC1 |
| 113 | #define S5P_PA_FIMC2 S5PV210_PA_FIMC2 | 125 | #define S5P_PA_FIMC2 S5PV210_PA_FIMC2 |
diff --git a/arch/arm/mach-s5pv210/include/mach/pm-core.h b/arch/arm/mach-s5pv210/include/mach/pm-core.h new file mode 100644 index 000000000000..e8d394f8b057 --- /dev/null +++ b/arch/arm/mach-s5pv210/include/mach/pm-core.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv210/include/mach/pm-core.h | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * Based on arch/arm/mach-s3c2410/include/mach/pm-core.h, | ||
| 7 | * Copyright 2008 Simtec Electronics | ||
| 8 | * Ben Dooks <ben@simtec.co.uk> | ||
| 9 | * http://armlinux.simtec.co.uk/ | ||
| 10 | * | ||
| 11 | * S5PV210 - PM core support for arch/arm/plat-s5p/pm.c | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License version 2 as | ||
| 15 | * published by the Free Software Foundation. | ||
| 16 | */ | ||
| 17 | |||
| 18 | static inline void s3c_pm_debug_init_uart(void) | ||
| 19 | { | ||
| 20 | /* nothing here yet */ | ||
| 21 | } | ||
| 22 | |||
| 23 | static inline void s3c_pm_arch_prepare_irqs(void) | ||
| 24 | { | ||
| 25 | __raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK); | ||
| 26 | __raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK); | ||
| 27 | } | ||
| 28 | |||
| 29 | static inline void s3c_pm_arch_stop_clocks(void) | ||
| 30 | { | ||
| 31 | /* nothing here yet */ | ||
| 32 | } | ||
| 33 | |||
| 34 | static inline void s3c_pm_arch_show_resume_irqs(void) | ||
| 35 | { | ||
| 36 | /* nothing here yet */ | ||
| 37 | } | ||
| 38 | |||
| 39 | static inline void s3c_pm_arch_update_uart(void __iomem *regs, | ||
| 40 | struct pm_uart_save *save) | ||
| 41 | { | ||
| 42 | /* nothing here yet */ | ||
| 43 | } | ||
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h index 499aef737476..ebaabe021af9 100644 --- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #define S5P_APLL_CON S5P_CLKREG(0x100) | 25 | #define S5P_APLL_CON S5P_CLKREG(0x100) |
| 26 | #define S5P_MPLL_CON S5P_CLKREG(0x108) | 26 | #define S5P_MPLL_CON S5P_CLKREG(0x108) |
| 27 | #define S5P_EPLL_CON S5P_CLKREG(0x110) | 27 | #define S5P_EPLL_CON S5P_CLKREG(0x110) |
| 28 | #define S5P_EPLL_CON1 S5P_CLKREG(0x114) | ||
| 28 | #define S5P_VPLL_CON S5P_CLKREG(0x120) | 29 | #define S5P_VPLL_CON S5P_CLKREG(0x120) |
| 29 | 30 | ||
| 30 | #define S5P_CLK_SRC0 S5P_CLKREG(0x200) | 31 | #define S5P_CLK_SRC0 S5P_CLKREG(0x200) |
| @@ -67,11 +68,28 @@ | |||
| 67 | #define S5P_CLKGATE_BUS1 S5P_CLKREG(0x488) | 68 | #define S5P_CLKGATE_BUS1 S5P_CLKREG(0x488) |
| 68 | #define S5P_CLK_OUT S5P_CLKREG(0x500) | 69 | #define S5P_CLK_OUT S5P_CLKREG(0x500) |
| 69 | 70 | ||
| 71 | /* DIV/MUX STATUS */ | ||
| 72 | #define S5P_CLKDIV_STAT0 S5P_CLKREG(0x1000) | ||
| 73 | #define S5P_CLKDIV_STAT1 S5P_CLKREG(0x1004) | ||
| 74 | #define S5P_CLKMUX_STAT0 S5P_CLKREG(0x1100) | ||
| 75 | #define S5P_CLKMUX_STAT1 S5P_CLKREG(0x1104) | ||
| 76 | |||
| 70 | /* CLKSRC0 */ | 77 | /* CLKSRC0 */ |
| 71 | #define S5P_CLKSRC0_MUX200_MASK (0x1<<16) | 78 | #define S5P_CLKSRC0_MUX200_SHIFT (16) |
| 79 | #define S5P_CLKSRC0_MUX200_MASK (0x1 << S5P_CLKSRC0_MUX200_SHIFT) | ||
| 72 | #define S5P_CLKSRC0_MUX166_MASK (0x1<<20) | 80 | #define S5P_CLKSRC0_MUX166_MASK (0x1<<20) |
| 73 | #define S5P_CLKSRC0_MUX133_MASK (0x1<<24) | 81 | #define S5P_CLKSRC0_MUX133_MASK (0x1<<24) |
| 74 | 82 | ||
| 83 | /* CLKSRC2 */ | ||
| 84 | #define S5P_CLKSRC2_G3D_SHIFT (0) | ||
| 85 | #define S5P_CLKSRC2_G3D_MASK (0x3 << S5P_CLKSRC2_G3D_SHIFT) | ||
| 86 | #define S5P_CLKSRC2_MFC_SHIFT (4) | ||
| 87 | #define S5P_CLKSRC2_MFC_MASK (0x3 << S5P_CLKSRC2_MFC_SHIFT) | ||
| 88 | |||
| 89 | /* CLKSRC6*/ | ||
| 90 | #define S5P_CLKSRC6_ONEDRAM_SHIFT (24) | ||
| 91 | #define S5P_CLKSRC6_ONEDRAM_MASK (0x3 << S5P_CLKSRC6_ONEDRAM_SHIFT) | ||
| 92 | |||
| 75 | /* CLKDIV0 */ | 93 | /* CLKDIV0 */ |
| 76 | #define S5P_CLKDIV0_APLL_SHIFT (0) | 94 | #define S5P_CLKDIV0_APLL_SHIFT (0) |
| 77 | #define S5P_CLKDIV0_APLL_MASK (0x7 << S5P_CLKDIV0_APLL_SHIFT) | 95 | #define S5P_CLKDIV0_APLL_MASK (0x7 << S5P_CLKDIV0_APLL_SHIFT) |
| @@ -90,12 +108,24 @@ | |||
| 90 | #define S5P_CLKDIV0_PCLK66_SHIFT (28) | 108 | #define S5P_CLKDIV0_PCLK66_SHIFT (28) |
| 91 | #define S5P_CLKDIV0_PCLK66_MASK (0x7 << S5P_CLKDIV0_PCLK66_SHIFT) | 109 | #define S5P_CLKDIV0_PCLK66_MASK (0x7 << S5P_CLKDIV0_PCLK66_SHIFT) |
| 92 | 110 | ||
| 111 | /* CLKDIV2 */ | ||
| 112 | #define S5P_CLKDIV2_G3D_SHIFT (0) | ||
| 113 | #define S5P_CLKDIV2_G3D_MASK (0xF << S5P_CLKDIV2_G3D_SHIFT) | ||
| 114 | #define S5P_CLKDIV2_MFC_SHIFT (4) | ||
| 115 | #define S5P_CLKDIV2_MFC_MASK (0xF << S5P_CLKDIV2_MFC_SHIFT) | ||
| 116 | |||
| 117 | /* CLKDIV6 */ | ||
| 118 | #define S5P_CLKDIV6_ONEDRAM_SHIFT (28) | ||
| 119 | #define S5P_CLKDIV6_ONEDRAM_MASK (0xF << S5P_CLKDIV6_ONEDRAM_SHIFT) | ||
| 120 | |||
| 93 | #define S5P_SWRESET S5P_CLKREG(0x2000) | 121 | #define S5P_SWRESET S5P_CLKREG(0x2000) |
| 94 | 122 | ||
| 123 | #define S5P_ARM_MCS_CON S5P_CLKREG(0x6100) | ||
| 124 | |||
| 95 | /* Registers related to power management */ | 125 | /* Registers related to power management */ |
| 96 | #define S5P_PWR_CFG S5P_CLKREG(0xC000) | 126 | #define S5P_PWR_CFG S5P_CLKREG(0xC000) |
| 97 | #define S5P_EINT_WAKEUP_MASK S5P_CLKREG(0xC004) | 127 | #define S5P_EINT_WAKEUP_MASK S5P_CLKREG(0xC004) |
| 98 | #define S5P_WAKEUP_MASK S5P_CLKREG(0xC008) | 128 | #define S5P_WAKEUP_MASK S5P_CLKREG(0xC008) |
| 99 | #define S5P_PWR_MODE S5P_CLKREG(0xC00C) | 129 | #define S5P_PWR_MODE S5P_CLKREG(0xC00C) |
| 100 | #define S5P_NORMAL_CFG S5P_CLKREG(0xC010) | 130 | #define S5P_NORMAL_CFG S5P_CLKREG(0xC010) |
| 101 | #define S5P_IDLE_CFG S5P_CLKREG(0xC020) | 131 | #define S5P_IDLE_CFG S5P_CLKREG(0xC020) |
| @@ -159,8 +189,11 @@ | |||
| 159 | #define S5P_SLEEP_CFG_USBOSC_EN (1 << 1) | 189 | #define S5P_SLEEP_CFG_USBOSC_EN (1 << 1) |
| 160 | 190 | ||
| 161 | /* OTHERS Resgister */ | 191 | /* OTHERS Resgister */ |
| 192 | #define S5P_OTHERS_RET_IO (1 << 31) | ||
| 193 | #define S5P_OTHERS_RET_CF (1 << 30) | ||
| 194 | #define S5P_OTHERS_RET_MMC (1 << 29) | ||
| 195 | #define S5P_OTHERS_RET_UART (1 << 28) | ||
| 162 | #define S5P_OTHERS_USB_SIG_MASK (1 << 16) | 196 | #define S5P_OTHERS_USB_SIG_MASK (1 << 16) |
| 163 | #define S5P_OTHERS_MIPI_DPHY_EN (1 << 28) | ||
| 164 | 197 | ||
| 165 | /* MIPI */ | 198 | /* MIPI */ |
| 166 | #define S5P_MIPI_DPHY_EN (3) | 199 | #define S5P_MIPI_DPHY_EN (3) |
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-gpio.h b/arch/arm/mach-s5pv210/include/mach/regs-gpio.h index 49e029b4978a..de0c89976078 100644 --- a/arch/arm/mach-s5pv210/include/mach/regs-gpio.h +++ b/arch/arm/mach-s5pv210/include/mach/regs-gpio.h | |||
| @@ -31,13 +31,6 @@ | |||
| 31 | 31 | ||
| 32 | #define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7)) | 32 | #define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7)) |
| 33 | 33 | ||
| 34 | /* values for S5P_EXTINT0 */ | ||
| 35 | #define S5P_EXTINT_LOWLEV (0x00) | ||
| 36 | #define S5P_EXTINT_HILEV (0x01) | ||
| 37 | #define S5P_EXTINT_FALLEDGE (0x02) | ||
| 38 | #define S5P_EXTINT_RISEEDGE (0x03) | ||
| 39 | #define S5P_EXTINT_BOTHEDGE (0x04) | ||
| 40 | |||
| 41 | #define EINT_MODE S3C_GPIO_SFN(0xf) | 34 | #define EINT_MODE S3C_GPIO_SFN(0xf) |
| 42 | 35 | ||
| 43 | #define EINT_GPIO_0(x) S5PV210_GPH0(x) | 36 | #define EINT_GPIO_0(x) S5PV210_GPH0(x) |
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-sys.h b/arch/arm/mach-s5pv210/include/mach/regs-sys.h new file mode 100644 index 000000000000..26691d39d0f4 --- /dev/null +++ b/arch/arm/mach-s5pv210/include/mach/regs-sys.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* arch/arm/mach-s5pv210/include/mach/regs-sys.h | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5PV210 - System registers definitions | ||
| 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 | #define S5PV210_USB_PHY_CON (S3C_VA_SYS + 0xE80C) | ||
| 14 | #define S5PV210_USB_PHY0_EN (1 << 0) | ||
| 15 | #define S5PV210_USB_PHY1_EN (1 << 1) | ||
| 16 | |||
| 17 | /* compatibility defines for s3c-hsotg driver */ | ||
| 18 | #define S3C64XX_OTHERS S5PV210_USB_PHY_CON | ||
| 19 | #define S3C64XX_OTHERS_USBMASK S5PV210_USB_PHY0_EN | ||
diff --git a/arch/arm/mach-s5pv210/include/mach/vmalloc.h b/arch/arm/mach-s5pv210/include/mach/vmalloc.h index df9a28808323..a6c659d68a5d 100644 --- a/arch/arm/mach-s5pv210/include/mach/vmalloc.h +++ b/arch/arm/mach-s5pv210/include/mach/vmalloc.h | |||
| @@ -17,6 +17,6 @@ | |||
| 17 | #ifndef __ASM_ARCH_VMALLOC_H | 17 | #ifndef __ASM_ARCH_VMALLOC_H |
| 18 | #define __ASM_ARCH_VMALLOC_H __FILE__ | 18 | #define __ASM_ARCH_VMALLOC_H __FILE__ |
| 19 | 19 | ||
| 20 | #define VMALLOC_END (0xE0000000UL) | 20 | #define VMALLOC_END 0xF6000000UL |
| 21 | 21 | ||
| 22 | #endif /* __ASM_ARCH_VMALLOC_H */ | 22 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c index 00883087363c..28677caf3613 100644 --- a/arch/arm/mach-s5pv210/mach-aquila.c +++ b/arch/arm/mach-s5pv210/mach-aquila.c | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
| 17 | #include <linux/i2c-gpio.h> | 17 | #include <linux/i2c-gpio.h> |
| 18 | #include <linux/mfd/max8998.h> | 18 | #include <linux/mfd/max8998.h> |
| 19 | #include <linux/mfd/wm8994/pdata.h> | ||
| 20 | #include <linux/regulator/fixed.h> | ||
| 19 | #include <linux/gpio_keys.h> | 21 | #include <linux/gpio_keys.h> |
| 20 | #include <linux/input.h> | 22 | #include <linux/input.h> |
| 21 | #include <linux/gpio.h> | 23 | #include <linux/gpio.h> |
| @@ -379,6 +381,119 @@ static struct max8998_platform_data aquila_max8998_pdata = { | |||
| 379 | }; | 381 | }; |
| 380 | #endif | 382 | #endif |
| 381 | 383 | ||
| 384 | static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = { | ||
| 385 | { | ||
| 386 | .dev_name = "5-001a", | ||
| 387 | .supply = "DBVDD", | ||
| 388 | }, { | ||
| 389 | .dev_name = "5-001a", | ||
| 390 | .supply = "AVDD2", | ||
| 391 | }, { | ||
| 392 | .dev_name = "5-001a", | ||
| 393 | .supply = "CPVDD", | ||
| 394 | }, | ||
| 395 | }; | ||
| 396 | |||
| 397 | static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = { | ||
| 398 | { | ||
| 399 | .dev_name = "5-001a", | ||
| 400 | .supply = "SPKVDD1", | ||
| 401 | }, { | ||
| 402 | .dev_name = "5-001a", | ||
| 403 | .supply = "SPKVDD2", | ||
| 404 | }, | ||
| 405 | }; | ||
| 406 | |||
| 407 | static struct regulator_init_data wm8994_fixed_voltage0_init_data = { | ||
| 408 | .constraints = { | ||
| 409 | .always_on = 1, | ||
| 410 | }, | ||
| 411 | .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage0_supplies), | ||
| 412 | .consumer_supplies = wm8994_fixed_voltage0_supplies, | ||
| 413 | }; | ||
| 414 | |||
| 415 | static struct regulator_init_data wm8994_fixed_voltage1_init_data = { | ||
| 416 | .constraints = { | ||
| 417 | .always_on = 1, | ||
| 418 | }, | ||
| 419 | .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage1_supplies), | ||
| 420 | .consumer_supplies = wm8994_fixed_voltage1_supplies, | ||
| 421 | }; | ||
| 422 | |||
| 423 | static struct fixed_voltage_config wm8994_fixed_voltage0_config = { | ||
| 424 | .supply_name = "VCC_1.8V_PDA", | ||
| 425 | .microvolts = 1800000, | ||
| 426 | .gpio = -EINVAL, | ||
| 427 | .init_data = &wm8994_fixed_voltage0_init_data, | ||
| 428 | }; | ||
| 429 | |||
| 430 | static struct fixed_voltage_config wm8994_fixed_voltage1_config = { | ||
| 431 | .supply_name = "V_BAT", | ||
| 432 | .microvolts = 3700000, | ||
| 433 | .gpio = -EINVAL, | ||
| 434 | .init_data = &wm8994_fixed_voltage1_init_data, | ||
| 435 | }; | ||
| 436 | |||
| 437 | static struct platform_device wm8994_fixed_voltage0 = { | ||
| 438 | .name = "reg-fixed-voltage", | ||
| 439 | .id = 0, | ||
| 440 | .dev = { | ||
| 441 | .platform_data = &wm8994_fixed_voltage0_config, | ||
| 442 | }, | ||
| 443 | }; | ||
| 444 | |||
| 445 | static struct platform_device wm8994_fixed_voltage1 = { | ||
| 446 | .name = "reg-fixed-voltage", | ||
| 447 | .id = 1, | ||
| 448 | .dev = { | ||
| 449 | .platform_data = &wm8994_fixed_voltage1_config, | ||
| 450 | }, | ||
| 451 | }; | ||
| 452 | |||
| 453 | static struct regulator_consumer_supply wm8994_avdd1_supply = { | ||
| 454 | .dev_name = "5-001a", | ||
| 455 | .supply = "AVDD1", | ||
| 456 | }; | ||
| 457 | |||
| 458 | static struct regulator_consumer_supply wm8994_dcvdd_supply = { | ||
| 459 | .dev_name = "5-001a", | ||
| 460 | .supply = "DCVDD", | ||
| 461 | }; | ||
| 462 | |||
| 463 | static struct regulator_init_data wm8994_ldo1_data = { | ||
| 464 | .constraints = { | ||
| 465 | .name = "AVDD1_3.0V", | ||
| 466 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
| 467 | }, | ||
| 468 | .num_consumer_supplies = 1, | ||
| 469 | .consumer_supplies = &wm8994_avdd1_supply, | ||
| 470 | }; | ||
| 471 | |||
| 472 | static struct regulator_init_data wm8994_ldo2_data = { | ||
| 473 | .constraints = { | ||
| 474 | .name = "DCVDD_1.0V", | ||
| 475 | }, | ||
| 476 | .num_consumer_supplies = 1, | ||
| 477 | .consumer_supplies = &wm8994_dcvdd_supply, | ||
| 478 | }; | ||
| 479 | |||
| 480 | static struct wm8994_pdata wm8994_platform_data = { | ||
| 481 | /* configure gpio1 function: 0x0001(Logic level input/output) */ | ||
| 482 | .gpio_defaults[0] = 0x0001, | ||
| 483 | /* configure gpio3/4/5/7 function for AIF2 voice */ | ||
| 484 | .gpio_defaults[2] = 0x8100, | ||
| 485 | .gpio_defaults[3] = 0x8100, | ||
| 486 | .gpio_defaults[4] = 0x8100, | ||
| 487 | .gpio_defaults[6] = 0x0100, | ||
| 488 | /* configure gpio8/9/10/11 function for AIF3 BT */ | ||
| 489 | .gpio_defaults[7] = 0x8100, | ||
| 490 | .gpio_defaults[8] = 0x0100, | ||
| 491 | .gpio_defaults[9] = 0x0100, | ||
| 492 | .gpio_defaults[10] = 0x0100, | ||
| 493 | .ldo[0] = { S5PV210_MP03(6), NULL, &wm8994_ldo1_data }, /* XM0FRNB_2 */ | ||
| 494 | .ldo[1] = { 0, NULL, &wm8994_ldo2_data }, | ||
| 495 | }; | ||
| 496 | |||
| 382 | /* GPIO I2C PMIC */ | 497 | /* GPIO I2C PMIC */ |
| 383 | #define AP_I2C_GPIO_PMIC_BUS_4 4 | 498 | #define AP_I2C_GPIO_PMIC_BUS_4 4 |
| 384 | static struct i2c_gpio_platform_data aquila_i2c_gpio_pmic_data = { | 499 | static struct i2c_gpio_platform_data aquila_i2c_gpio_pmic_data = { |
| @@ -404,6 +519,29 @@ static struct i2c_board_info i2c_gpio_pmic_devs[] __initdata = { | |||
| 404 | #endif | 519 | #endif |
| 405 | }; | 520 | }; |
| 406 | 521 | ||
| 522 | /* GPIO I2C AP 1.8V */ | ||
| 523 | #define AP_I2C_GPIO_BUS_5 5 | ||
| 524 | static struct i2c_gpio_platform_data aquila_i2c_gpio5_data = { | ||
| 525 | .sda_pin = S5PV210_MP05(3), /* XM0ADDR_11 */ | ||
| 526 | .scl_pin = S5PV210_MP05(2), /* XM0ADDR_10 */ | ||
| 527 | }; | ||
| 528 | |||
| 529 | static struct platform_device aquila_i2c_gpio5 = { | ||
| 530 | .name = "i2c-gpio", | ||
| 531 | .id = AP_I2C_GPIO_BUS_5, | ||
| 532 | .dev = { | ||
| 533 | .platform_data = &aquila_i2c_gpio5_data, | ||
| 534 | }, | ||
| 535 | }; | ||
| 536 | |||
| 537 | static struct i2c_board_info i2c_gpio5_devs[] __initdata = { | ||
| 538 | { | ||
| 539 | /* CS/ADDR = low 0x34 (FYI: high = 0x36) */ | ||
| 540 | I2C_BOARD_INFO("wm8994", 0x1a), | ||
| 541 | .platform_data = &wm8994_platform_data, | ||
| 542 | }, | ||
| 543 | }; | ||
| 544 | |||
| 407 | /* PMIC Power button */ | 545 | /* PMIC Power button */ |
| 408 | static struct gpio_keys_button aquila_gpio_keys_table[] = { | 546 | static struct gpio_keys_button aquila_gpio_keys_table[] = { |
| 409 | { | 547 | { |
| @@ -475,6 +613,7 @@ static void aquila_setup_sdhci(void) | |||
| 475 | 613 | ||
| 476 | static struct platform_device *aquila_devices[] __initdata = { | 614 | static struct platform_device *aquila_devices[] __initdata = { |
| 477 | &aquila_i2c_gpio_pmic, | 615 | &aquila_i2c_gpio_pmic, |
| 616 | &aquila_i2c_gpio5, | ||
| 478 | &aquila_device_gpiokeys, | 617 | &aquila_device_gpiokeys, |
| 479 | &s3c_device_fb, | 618 | &s3c_device_fb, |
| 480 | &s5p_device_onenand, | 619 | &s5p_device_onenand, |
| @@ -484,8 +623,33 @@ static struct platform_device *aquila_devices[] __initdata = { | |||
| 484 | &s5p_device_fimc0, | 623 | &s5p_device_fimc0, |
| 485 | &s5p_device_fimc1, | 624 | &s5p_device_fimc1, |
| 486 | &s5p_device_fimc2, | 625 | &s5p_device_fimc2, |
| 626 | &s5pv210_device_iis0, | ||
| 627 | &wm8994_fixed_voltage0, | ||
| 628 | &wm8994_fixed_voltage1, | ||
| 487 | }; | 629 | }; |
| 488 | 630 | ||
| 631 | static void __init aquila_sound_init(void) | ||
| 632 | { | ||
| 633 | unsigned int gpio; | ||
| 634 | |||
| 635 | /* CODEC_XTAL_EN | ||
| 636 | * | ||
| 637 | * The Aquila board have a oscillator which provide main clock | ||
| 638 | * to WM8994 codec. The oscillator provide 24MHz clock to WM8994 | ||
| 639 | * clock. Set gpio setting of "CODEC_XTAL_EN" to enable a oscillator. | ||
| 640 | * */ | ||
| 641 | gpio = S5PV210_GPH3(2); /* XEINT_26 */ | ||
| 642 | gpio_request(gpio, "CODEC_XTAL_EN"); | ||
| 643 | s3c_gpio_cfgpin(gpio, S3C_GPIO_OUTPUT); | ||
| 644 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 645 | |||
| 646 | /* Ths main clock of WM8994 codec uses the output of CLKOUT pin. | ||
| 647 | * The CLKOUT[9:8] set to 0x3(XUSBXTI) of 0xE010E000(OTHERS) | ||
| 648 | * because it needs 24MHz clock to operate WM8994 codec. | ||
| 649 | */ | ||
| 650 | __raw_writel(__raw_readl(S5P_OTHERS) | (0x3 << 8), S5P_OTHERS); | ||
| 651 | } | ||
| 652 | |||
| 489 | static void __init aquila_map_io(void) | 653 | static void __init aquila_map_io(void) |
| 490 | { | 654 | { |
| 491 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); | 655 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); |
| @@ -506,6 +670,11 @@ static void __init aquila_machine_init(void) | |||
| 506 | s3c_fimc_setname(1, "s5p-fimc"); | 670 | s3c_fimc_setname(1, "s5p-fimc"); |
| 507 | s3c_fimc_setname(2, "s5p-fimc"); | 671 | s3c_fimc_setname(2, "s5p-fimc"); |
| 508 | 672 | ||
| 673 | /* SOUND */ | ||
| 674 | aquila_sound_init(); | ||
| 675 | i2c_register_board_info(AP_I2C_GPIO_BUS_5, i2c_gpio5_devs, | ||
| 676 | ARRAY_SIZE(i2c_gpio5_devs)); | ||
| 677 | |||
| 509 | /* FB */ | 678 | /* FB */ |
| 510 | s3c_fb_set_platdata(&aquila_lcd_pdata); | 679 | s3c_fb_set_platdata(&aquila_lcd_pdata); |
| 511 | 680 | ||
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c index d9ecf57fc2a5..b1dcf964a768 100644 --- a/arch/arm/mach-s5pv210/mach-goni.c +++ b/arch/arm/mach-s5pv210/mach-goni.c | |||
| @@ -15,7 +15,13 @@ | |||
| 15 | #include <linux/fb.h> | 15 | #include <linux/fb.h> |
| 16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
| 17 | #include <linux/i2c-gpio.h> | 17 | #include <linux/i2c-gpio.h> |
| 18 | #include <linux/i2c/qt602240_ts.h> | ||
| 18 | #include <linux/mfd/max8998.h> | 19 | #include <linux/mfd/max8998.h> |
| 20 | #include <linux/mfd/wm8994/pdata.h> | ||
| 21 | #include <linux/regulator/fixed.h> | ||
| 22 | #include <linux/spi/spi.h> | ||
| 23 | #include <linux/spi/spi_gpio.h> | ||
| 24 | #include <linux/lcd.h> | ||
| 19 | #include <linux/gpio_keys.h> | 25 | #include <linux/gpio_keys.h> |
| 20 | #include <linux/input.h> | 26 | #include <linux/input.h> |
| 21 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
| @@ -35,7 +41,10 @@ | |||
| 35 | #include <plat/devs.h> | 41 | #include <plat/devs.h> |
| 36 | #include <plat/cpu.h> | 42 | #include <plat/cpu.h> |
| 37 | #include <plat/fb.h> | 43 | #include <plat/fb.h> |
| 44 | #include <plat/iic.h> | ||
| 45 | #include <plat/keypad.h> | ||
| 38 | #include <plat/sdhci.h> | 46 | #include <plat/sdhci.h> |
| 47 | #include <plat/clock.h> | ||
| 39 | 48 | ||
| 40 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | 49 | /* Following are default values for UCON, ULCON and UFCON UART registers */ |
| 41 | #define GONI_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ | 50 | #define GONI_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ |
| @@ -87,13 +96,12 @@ static struct s3c2410_uartcfg goni_uartcfgs[] __initdata = { | |||
| 87 | /* Frame Buffer */ | 96 | /* Frame Buffer */ |
| 88 | static struct s3c_fb_pd_win goni_fb_win0 = { | 97 | static struct s3c_fb_pd_win goni_fb_win0 = { |
| 89 | .win_mode = { | 98 | .win_mode = { |
| 90 | .pixclock = 1000000000000ULL / ((16+16+2+480)*(28+3+2+800)*55), | ||
| 91 | .left_margin = 16, | 99 | .left_margin = 16, |
| 92 | .right_margin = 16, | 100 | .right_margin = 16, |
| 93 | .upper_margin = 3, | 101 | .upper_margin = 2, |
| 94 | .lower_margin = 28, | 102 | .lower_margin = 28, |
| 95 | .hsync_len = 2, | 103 | .hsync_len = 2, |
| 96 | .vsync_len = 2, | 104 | .vsync_len = 1, |
| 97 | .xres = 480, | 105 | .xres = 480, |
| 98 | .yres = 800, | 106 | .yres = 800, |
| 99 | .refresh = 55, | 107 | .refresh = 55, |
| @@ -111,9 +119,160 @@ static struct s3c_fb_platdata goni_lcd_pdata __initdata = { | |||
| 111 | .setup_gpio = s5pv210_fb_gpio_setup_24bpp, | 119 | .setup_gpio = s5pv210_fb_gpio_setup_24bpp, |
| 112 | }; | 120 | }; |
| 113 | 121 | ||
| 122 | static int lcd_power_on(struct lcd_device *ld, int enable) | ||
| 123 | { | ||
| 124 | return 1; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int reset_lcd(struct lcd_device *ld) | ||
| 128 | { | ||
| 129 | static unsigned int first = 1; | ||
| 130 | int reset_gpio = -1; | ||
| 131 | |||
| 132 | reset_gpio = S5PV210_MP05(5); | ||
| 133 | |||
| 134 | if (first) { | ||
| 135 | gpio_request(reset_gpio, "MLCD_RST"); | ||
| 136 | first = 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | gpio_direction_output(reset_gpio, 1); | ||
| 140 | return 1; | ||
| 141 | } | ||
| 142 | |||
| 143 | static struct lcd_platform_data goni_lcd_platform_data = { | ||
| 144 | .reset = reset_lcd, | ||
| 145 | .power_on = lcd_power_on, | ||
| 146 | .lcd_enabled = 0, | ||
| 147 | .reset_delay = 120, /* 120ms */ | ||
| 148 | .power_on_delay = 25, /* 25ms */ | ||
| 149 | .power_off_delay = 200, /* 200ms */ | ||
| 150 | }; | ||
| 151 | |||
| 152 | #define LCD_BUS_NUM 3 | ||
| 153 | static struct spi_board_info spi_board_info[] __initdata = { | ||
| 154 | { | ||
| 155 | .modalias = "s6e63m0", | ||
| 156 | .platform_data = &goni_lcd_platform_data, | ||
| 157 | .max_speed_hz = 1200000, | ||
| 158 | .bus_num = LCD_BUS_NUM, | ||
| 159 | .chip_select = 0, | ||
| 160 | .mode = SPI_MODE_3, | ||
| 161 | .controller_data = (void *)S5PV210_MP01(1), /* DISPLAY_CS */ | ||
| 162 | }, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static struct spi_gpio_platform_data lcd_spi_gpio_data = { | ||
| 166 | .sck = S5PV210_MP04(1), /* DISPLAY_CLK */ | ||
| 167 | .mosi = S5PV210_MP04(3), /* DISPLAY_SI */ | ||
| 168 | .miso = SPI_GPIO_NO_MISO, | ||
| 169 | .num_chipselect = 1, | ||
| 170 | }; | ||
| 171 | |||
| 172 | static struct platform_device goni_spi_gpio = { | ||
| 173 | .name = "spi_gpio", | ||
| 174 | .id = LCD_BUS_NUM, | ||
| 175 | .dev = { | ||
| 176 | .parent = &s3c_device_fb.dev, | ||
| 177 | .platform_data = &lcd_spi_gpio_data, | ||
| 178 | }, | ||
| 179 | }; | ||
| 180 | |||
| 181 | /* KEYPAD */ | ||
| 182 | static uint32_t keymap[] __initdata = { | ||
| 183 | /* KEY(row, col, keycode) */ | ||
| 184 | KEY(0, 1, KEY_MENU), /* Send */ | ||
| 185 | KEY(0, 2, KEY_BACK), /* End */ | ||
| 186 | KEY(1, 1, KEY_CONFIG), /* Half shot */ | ||
| 187 | KEY(1, 2, KEY_VOLUMEUP), | ||
| 188 | KEY(2, 1, KEY_CAMERA), /* Full shot */ | ||
| 189 | KEY(2, 2, KEY_VOLUMEDOWN), | ||
| 190 | }; | ||
| 191 | |||
| 192 | static struct matrix_keymap_data keymap_data __initdata = { | ||
| 193 | .keymap = keymap, | ||
| 194 | .keymap_size = ARRAY_SIZE(keymap), | ||
| 195 | }; | ||
| 196 | |||
| 197 | static struct samsung_keypad_platdata keypad_data __initdata = { | ||
| 198 | .keymap_data = &keymap_data, | ||
| 199 | .rows = 3, | ||
| 200 | .cols = 3, | ||
| 201 | }; | ||
| 202 | |||
| 203 | /* Radio */ | ||
| 204 | static struct i2c_board_info i2c1_devs[] __initdata = { | ||
| 205 | { | ||
| 206 | I2C_BOARD_INFO("si470x", 0x10), | ||
| 207 | }, | ||
| 208 | }; | ||
| 209 | |||
| 210 | static void __init goni_radio_init(void) | ||
| 211 | { | ||
| 212 | int gpio; | ||
| 213 | |||
| 214 | gpio = S5PV210_GPJ2(4); /* XMSMDATA_4 */ | ||
| 215 | gpio_request(gpio, "FM_INT"); | ||
| 216 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf)); | ||
| 217 | i2c1_devs[0].irq = gpio_to_irq(gpio); | ||
| 218 | |||
| 219 | gpio = S5PV210_GPJ2(5); /* XMSMDATA_5 */ | ||
| 220 | gpio_request(gpio, "FM_RST"); | ||
| 221 | gpio_direction_output(gpio, 1); | ||
| 222 | } | ||
| 223 | |||
| 224 | /* TSP */ | ||
| 225 | static struct qt602240_platform_data qt602240_platform_data = { | ||
| 226 | .x_line = 17, | ||
| 227 | .y_line = 11, | ||
| 228 | .x_size = 800, | ||
| 229 | .y_size = 480, | ||
| 230 | .blen = 0x21, | ||
| 231 | .threshold = 0x28, | ||
| 232 | .voltage = 2800000, /* 2.8V */ | ||
| 233 | .orient = QT602240_DIAGONAL, | ||
| 234 | }; | ||
| 235 | |||
| 236 | static struct s3c2410_platform_i2c i2c2_data __initdata = { | ||
| 237 | .flags = 0, | ||
| 238 | .bus_num = 2, | ||
| 239 | .slave_addr = 0x10, | ||
| 240 | .frequency = 400 * 1000, | ||
| 241 | .sda_delay = 100, | ||
| 242 | }; | ||
| 243 | |||
| 244 | static struct i2c_board_info i2c2_devs[] __initdata = { | ||
| 245 | { | ||
| 246 | I2C_BOARD_INFO("qt602240_ts", 0x4a), | ||
| 247 | .platform_data = &qt602240_platform_data, | ||
| 248 | }, | ||
| 249 | }; | ||
| 250 | |||
| 251 | static void __init goni_tsp_init(void) | ||
| 252 | { | ||
| 253 | int gpio; | ||
| 254 | |||
| 255 | gpio = S5PV210_GPJ1(3); /* XMSMADDR_11 */ | ||
| 256 | gpio_request(gpio, "TSP_LDO_ON"); | ||
| 257 | gpio_direction_output(gpio, 1); | ||
| 258 | gpio_export(gpio, 0); | ||
| 259 | |||
| 260 | gpio = S5PV210_GPJ0(5); /* XMSMADDR_5 */ | ||
| 261 | gpio_request(gpio, "TSP_INT"); | ||
| 262 | |||
| 263 | s5p_register_gpio_interrupt(gpio); | ||
| 264 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf)); | ||
| 265 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); | ||
| 266 | i2c2_devs[0].irq = gpio_to_irq(gpio); | ||
| 267 | } | ||
| 268 | |||
| 114 | /* MAX8998 regulators */ | 269 | /* MAX8998 regulators */ |
| 115 | #if defined(CONFIG_REGULATOR_MAX8998) || defined(CONFIG_REGULATOR_MAX8998_MODULE) | 270 | #if defined(CONFIG_REGULATOR_MAX8998) || defined(CONFIG_REGULATOR_MAX8998_MODULE) |
| 116 | 271 | ||
| 272 | static struct regulator_consumer_supply goni_ldo5_consumers[] = { | ||
| 273 | REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"), | ||
| 274 | }; | ||
| 275 | |||
| 117 | static struct regulator_init_data goni_ldo2_data = { | 276 | static struct regulator_init_data goni_ldo2_data = { |
| 118 | .constraints = { | 277 | .constraints = { |
| 119 | .name = "VALIVE_1.1V", | 278 | .name = "VALIVE_1.1V", |
| @@ -153,6 +312,8 @@ static struct regulator_init_data goni_ldo5_data = { | |||
| 153 | .max_uV = 2800000, | 312 | .max_uV = 2800000, |
| 154 | .apply_uV = 1, | 313 | .apply_uV = 1, |
| 155 | }, | 314 | }, |
| 315 | .num_consumer_supplies = ARRAY_SIZE(goni_ldo5_consumers), | ||
| 316 | .consumer_supplies = goni_ldo5_consumers, | ||
| 156 | }; | 317 | }; |
| 157 | 318 | ||
| 158 | static struct regulator_init_data goni_ldo6_data = { | 319 | static struct regulator_init_data goni_ldo6_data = { |
| @@ -360,6 +521,119 @@ static struct max8998_platform_data goni_max8998_pdata = { | |||
| 360 | }; | 521 | }; |
| 361 | #endif | 522 | #endif |
| 362 | 523 | ||
| 524 | static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = { | ||
| 525 | { | ||
| 526 | .dev_name = "5-001a", | ||
| 527 | .supply = "DBVDD", | ||
| 528 | }, { | ||
| 529 | .dev_name = "5-001a", | ||
| 530 | .supply = "AVDD2", | ||
| 531 | }, { | ||
| 532 | .dev_name = "5-001a", | ||
| 533 | .supply = "CPVDD", | ||
| 534 | }, | ||
| 535 | }; | ||
| 536 | |||
| 537 | static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = { | ||
| 538 | { | ||
| 539 | .dev_name = "5-001a", | ||
| 540 | .supply = "SPKVDD1", | ||
| 541 | }, { | ||
| 542 | .dev_name = "5-001a", | ||
| 543 | .supply = "SPKVDD2", | ||
| 544 | }, | ||
| 545 | }; | ||
| 546 | |||
| 547 | static struct regulator_init_data wm8994_fixed_voltage0_init_data = { | ||
| 548 | .constraints = { | ||
| 549 | .always_on = 1, | ||
| 550 | }, | ||
| 551 | .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage0_supplies), | ||
| 552 | .consumer_supplies = wm8994_fixed_voltage0_supplies, | ||
| 553 | }; | ||
| 554 | |||
| 555 | static struct regulator_init_data wm8994_fixed_voltage1_init_data = { | ||
| 556 | .constraints = { | ||
| 557 | .always_on = 1, | ||
| 558 | }, | ||
| 559 | .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage1_supplies), | ||
| 560 | .consumer_supplies = wm8994_fixed_voltage1_supplies, | ||
| 561 | }; | ||
| 562 | |||
| 563 | static struct fixed_voltage_config wm8994_fixed_voltage0_config = { | ||
| 564 | .supply_name = "VCC_1.8V_PDA", | ||
| 565 | .microvolts = 1800000, | ||
| 566 | .gpio = -EINVAL, | ||
| 567 | .init_data = &wm8994_fixed_voltage0_init_data, | ||
| 568 | }; | ||
| 569 | |||
| 570 | static struct fixed_voltage_config wm8994_fixed_voltage1_config = { | ||
| 571 | .supply_name = "V_BAT", | ||
| 572 | .microvolts = 3700000, | ||
| 573 | .gpio = -EINVAL, | ||
| 574 | .init_data = &wm8994_fixed_voltage1_init_data, | ||
| 575 | }; | ||
| 576 | |||
| 577 | static struct platform_device wm8994_fixed_voltage0 = { | ||
| 578 | .name = "reg-fixed-voltage", | ||
| 579 | .id = 0, | ||
| 580 | .dev = { | ||
| 581 | .platform_data = &wm8994_fixed_voltage0_config, | ||
| 582 | }, | ||
| 583 | }; | ||
| 584 | |||
| 585 | static struct platform_device wm8994_fixed_voltage1 = { | ||
| 586 | .name = "reg-fixed-voltage", | ||
| 587 | .id = 1, | ||
| 588 | .dev = { | ||
| 589 | .platform_data = &wm8994_fixed_voltage1_config, | ||
| 590 | }, | ||
| 591 | }; | ||
| 592 | |||
| 593 | static struct regulator_consumer_supply wm8994_avdd1_supply = { | ||
| 594 | .dev_name = "5-001a", | ||
| 595 | .supply = "AVDD1", | ||
| 596 | }; | ||
| 597 | |||
| 598 | static struct regulator_consumer_supply wm8994_dcvdd_supply = { | ||
| 599 | .dev_name = "5-001a", | ||
| 600 | .supply = "DCVDD", | ||
| 601 | }; | ||
| 602 | |||
| 603 | static struct regulator_init_data wm8994_ldo1_data = { | ||
| 604 | .constraints = { | ||
| 605 | .name = "AVDD1_3.0V", | ||
| 606 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
| 607 | }, | ||
| 608 | .num_consumer_supplies = 1, | ||
| 609 | .consumer_supplies = &wm8994_avdd1_supply, | ||
| 610 | }; | ||
| 611 | |||
| 612 | static struct regulator_init_data wm8994_ldo2_data = { | ||
| 613 | .constraints = { | ||
| 614 | .name = "DCVDD_1.0V", | ||
| 615 | }, | ||
| 616 | .num_consumer_supplies = 1, | ||
| 617 | .consumer_supplies = &wm8994_dcvdd_supply, | ||
| 618 | }; | ||
| 619 | |||
| 620 | static struct wm8994_pdata wm8994_platform_data = { | ||
| 621 | /* configure gpio1 function: 0x0001(Logic level input/output) */ | ||
| 622 | .gpio_defaults[0] = 0x0001, | ||
| 623 | /* configure gpio3/4/5/7 function for AIF2 voice */ | ||
| 624 | .gpio_defaults[2] = 0x8100, | ||
| 625 | .gpio_defaults[3] = 0x8100, | ||
| 626 | .gpio_defaults[4] = 0x8100, | ||
| 627 | .gpio_defaults[6] = 0x0100, | ||
| 628 | /* configure gpio8/9/10/11 function for AIF3 BT */ | ||
| 629 | .gpio_defaults[7] = 0x8100, | ||
| 630 | .gpio_defaults[8] = 0x0100, | ||
| 631 | .gpio_defaults[9] = 0x0100, | ||
| 632 | .gpio_defaults[10] = 0x0100, | ||
| 633 | .ldo[0] = { S5PV210_MP03(6), NULL, &wm8994_ldo1_data }, /* XM0FRNB_2 */ | ||
| 634 | .ldo[1] = { 0, NULL, &wm8994_ldo2_data }, | ||
| 635 | }; | ||
| 636 | |||
| 363 | /* GPIO I2C PMIC */ | 637 | /* GPIO I2C PMIC */ |
| 364 | #define AP_I2C_GPIO_PMIC_BUS_4 4 | 638 | #define AP_I2C_GPIO_PMIC_BUS_4 4 |
| 365 | static struct i2c_gpio_platform_data goni_i2c_gpio_pmic_data = { | 639 | static struct i2c_gpio_platform_data goni_i2c_gpio_pmic_data = { |
| @@ -385,6 +659,29 @@ static struct i2c_board_info i2c_gpio_pmic_devs[] __initdata = { | |||
| 385 | #endif | 659 | #endif |
| 386 | }; | 660 | }; |
| 387 | 661 | ||
| 662 | /* GPIO I2C AP 1.8V */ | ||
| 663 | #define AP_I2C_GPIO_BUS_5 5 | ||
| 664 | static struct i2c_gpio_platform_data goni_i2c_gpio5_data = { | ||
| 665 | .sda_pin = S5PV210_MP05(3), /* XM0ADDR_11 */ | ||
| 666 | .scl_pin = S5PV210_MP05(2), /* XM0ADDR_10 */ | ||
| 667 | }; | ||
| 668 | |||
| 669 | static struct platform_device goni_i2c_gpio5 = { | ||
| 670 | .name = "i2c-gpio", | ||
| 671 | .id = AP_I2C_GPIO_BUS_5, | ||
| 672 | .dev = { | ||
| 673 | .platform_data = &goni_i2c_gpio5_data, | ||
| 674 | }, | ||
| 675 | }; | ||
| 676 | |||
| 677 | static struct i2c_board_info i2c_gpio5_devs[] __initdata = { | ||
| 678 | { | ||
| 679 | /* CS/ADDR = low 0x34 (FYI: high = 0x36) */ | ||
| 680 | I2C_BOARD_INFO("wm8994", 0x1a), | ||
| 681 | .platform_data = &wm8994_platform_data, | ||
| 682 | }, | ||
| 683 | }; | ||
| 684 | |||
| 388 | /* PMIC Power button */ | 685 | /* PMIC Power button */ |
| 389 | static struct gpio_keys_button goni_gpio_keys_table[] = { | 686 | static struct gpio_keys_button goni_gpio_keys_table[] = { |
| 390 | { | 687 | { |
| @@ -444,11 +741,37 @@ static struct s3c_sdhci_platdata goni_hsmmc2_data __initdata = { | |||
| 444 | .ext_cd_gpio_invert = 1, | 741 | .ext_cd_gpio_invert = 1, |
| 445 | }; | 742 | }; |
| 446 | 743 | ||
| 744 | static struct regulator_consumer_supply mmc2_supplies[] = { | ||
| 745 | REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"), | ||
| 746 | }; | ||
| 747 | |||
| 748 | static struct regulator_init_data mmc2_fixed_voltage_init_data = { | ||
| 749 | .constraints = { | ||
| 750 | .name = "V_TF_2.8V", | ||
| 751 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
| 752 | }, | ||
| 753 | .num_consumer_supplies = ARRAY_SIZE(mmc2_supplies), | ||
| 754 | .consumer_supplies = mmc2_supplies, | ||
| 755 | }; | ||
| 756 | |||
| 757 | static struct fixed_voltage_config mmc2_fixed_voltage_config = { | ||
| 758 | .supply_name = "EXT_FLASH_EN", | ||
| 759 | .microvolts = 2800000, | ||
| 760 | .gpio = GONI_EXT_FLASH_EN, | ||
| 761 | .enable_high = true, | ||
| 762 | .init_data = &mmc2_fixed_voltage_init_data, | ||
| 763 | }; | ||
| 764 | |||
| 765 | static struct platform_device mmc2_fixed_voltage = { | ||
| 766 | .name = "reg-fixed-voltage", | ||
| 767 | .id = 2, | ||
| 768 | .dev = { | ||
| 769 | .platform_data = &mmc2_fixed_voltage_config, | ||
| 770 | }, | ||
| 771 | }; | ||
| 772 | |||
| 447 | static void goni_setup_sdhci(void) | 773 | static void goni_setup_sdhci(void) |
| 448 | { | 774 | { |
| 449 | gpio_request(GONI_EXT_FLASH_EN, "FLASH_EN"); | ||
| 450 | gpio_direction_output(GONI_EXT_FLASH_EN, 1); | ||
| 451 | |||
| 452 | s3c_sdhci0_set_platdata(&goni_hsmmc0_data); | 775 | s3c_sdhci0_set_platdata(&goni_hsmmc0_data); |
| 453 | s3c_sdhci1_set_platdata(&goni_hsmmc1_data); | 776 | s3c_sdhci1_set_platdata(&goni_hsmmc1_data); |
| 454 | s3c_sdhci2_set_platdata(&goni_hsmmc2_data); | 777 | s3c_sdhci2_set_platdata(&goni_hsmmc2_data); |
| @@ -457,7 +780,10 @@ static void goni_setup_sdhci(void) | |||
| 457 | static struct platform_device *goni_devices[] __initdata = { | 780 | static struct platform_device *goni_devices[] __initdata = { |
| 458 | &s3c_device_fb, | 781 | &s3c_device_fb, |
| 459 | &s5p_device_onenand, | 782 | &s5p_device_onenand, |
| 783 | &goni_spi_gpio, | ||
| 460 | &goni_i2c_gpio_pmic, | 784 | &goni_i2c_gpio_pmic, |
| 785 | &goni_i2c_gpio5, | ||
| 786 | &mmc2_fixed_voltage, | ||
| 461 | &goni_device_gpiokeys, | 787 | &goni_device_gpiokeys, |
| 462 | &s5p_device_fimc0, | 788 | &s5p_device_fimc0, |
| 463 | &s5p_device_fimc1, | 789 | &s5p_device_fimc1, |
| @@ -465,8 +791,24 @@ static struct platform_device *goni_devices[] __initdata = { | |||
| 465 | &s3c_device_hsmmc0, | 791 | &s3c_device_hsmmc0, |
| 466 | &s3c_device_hsmmc1, | 792 | &s3c_device_hsmmc1, |
| 467 | &s3c_device_hsmmc2, | 793 | &s3c_device_hsmmc2, |
| 794 | &s5pv210_device_iis0, | ||
| 795 | &s3c_device_usb_hsotg, | ||
| 796 | &samsung_device_keypad, | ||
| 797 | &s3c_device_i2c1, | ||
| 798 | &s3c_device_i2c2, | ||
| 799 | &wm8994_fixed_voltage0, | ||
| 800 | &wm8994_fixed_voltage1, | ||
| 468 | }; | 801 | }; |
| 469 | 802 | ||
| 803 | static void __init goni_sound_init(void) | ||
| 804 | { | ||
| 805 | /* Ths main clock of WM8994 codec uses the output of CLKOUT pin. | ||
| 806 | * The CLKOUT[9:8] set to 0x3(XUSBXTI) of 0xE010E000(OTHERS) | ||
| 807 | * because it needs 24MHz clock to operate WM8994 codec. | ||
| 808 | */ | ||
| 809 | __raw_writel(__raw_readl(S5P_OTHERS) | (0x3 << 8), S5P_OTHERS); | ||
| 810 | } | ||
| 811 | |||
| 470 | static void __init goni_map_io(void) | 812 | static void __init goni_map_io(void) |
| 471 | { | 813 | { |
| 472 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); | 814 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); |
| @@ -476,6 +818,20 @@ static void __init goni_map_io(void) | |||
| 476 | 818 | ||
| 477 | static void __init goni_machine_init(void) | 819 | static void __init goni_machine_init(void) |
| 478 | { | 820 | { |
| 821 | /* Radio: call before I2C 1 registeration */ | ||
| 822 | goni_radio_init(); | ||
| 823 | |||
| 824 | /* I2C1 */ | ||
| 825 | s3c_i2c1_set_platdata(NULL); | ||
| 826 | i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs)); | ||
| 827 | |||
| 828 | /* TSP: call before I2C 2 registeration */ | ||
| 829 | goni_tsp_init(); | ||
| 830 | |||
| 831 | /* I2C2 */ | ||
| 832 | s3c_i2c2_set_platdata(&i2c2_data); | ||
| 833 | i2c_register_board_info(2, i2c2_devs, ARRAY_SIZE(i2c2_devs)); | ||
| 834 | |||
| 479 | /* PMIC */ | 835 | /* PMIC */ |
| 480 | goni_pmic_init(); | 836 | goni_pmic_init(); |
| 481 | i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs, | 837 | i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs, |
| @@ -483,9 +839,22 @@ static void __init goni_machine_init(void) | |||
| 483 | /* SDHCI */ | 839 | /* SDHCI */ |
| 484 | goni_setup_sdhci(); | 840 | goni_setup_sdhci(); |
| 485 | 841 | ||
| 842 | /* SOUND */ | ||
| 843 | goni_sound_init(); | ||
| 844 | i2c_register_board_info(AP_I2C_GPIO_BUS_5, i2c_gpio5_devs, | ||
| 845 | ARRAY_SIZE(i2c_gpio5_devs)); | ||
| 846 | |||
| 486 | /* FB */ | 847 | /* FB */ |
| 487 | s3c_fb_set_platdata(&goni_lcd_pdata); | 848 | s3c_fb_set_platdata(&goni_lcd_pdata); |
| 488 | 849 | ||
| 850 | /* SPI */ | ||
| 851 | spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); | ||
| 852 | |||
| 853 | /* KEYPAD */ | ||
| 854 | samsung_keypad_set_platdata(&keypad_data); | ||
| 855 | |||
| 856 | clk_xusbxti.rate = 24000000; | ||
| 857 | |||
| 489 | platform_add_devices(goni_devices, ARRAY_SIZE(goni_devices)); | 858 | platform_add_devices(goni_devices, ARRAY_SIZE(goni_devices)); |
| 490 | } | 859 | } |
| 491 | 860 | ||
diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c index cea9bca79d88..0ad7924fe62e 100644 --- a/arch/arm/mach-s5pv210/mach-smdkc110.c +++ b/arch/arm/mach-s5pv210/mach-smdkc110.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <plat/cpu.h> | 28 | #include <plat/cpu.h> |
| 29 | #include <plat/ata.h> | 29 | #include <plat/ata.h> |
| 30 | #include <plat/iic.h> | 30 | #include <plat/iic.h> |
| 31 | #include <plat/pm.h> | ||
| 31 | 32 | ||
| 32 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | 33 | /* Following are default values for UCON, ULCON and UFCON UART registers */ |
| 33 | #define SMDKC110_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ | 34 | #define SMDKC110_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ |
| @@ -81,6 +82,7 @@ static struct s3c_ide_platdata smdkc110_ide_pdata __initdata = { | |||
| 81 | static struct platform_device *smdkc110_devices[] __initdata = { | 82 | static struct platform_device *smdkc110_devices[] __initdata = { |
| 82 | &s5pv210_device_iis0, | 83 | &s5pv210_device_iis0, |
| 83 | &s5pv210_device_ac97, | 84 | &s5pv210_device_ac97, |
| 85 | &s5pv210_device_spdif, | ||
| 84 | &s3c_device_cfcon, | 86 | &s3c_device_cfcon, |
| 85 | &s3c_device_i2c0, | 87 | &s3c_device_i2c0, |
| 86 | &s3c_device_i2c1, | 88 | &s3c_device_i2c1, |
| @@ -110,6 +112,8 @@ static void __init smdkc110_map_io(void) | |||
| 110 | 112 | ||
| 111 | static void __init smdkc110_machine_init(void) | 113 | static void __init smdkc110_machine_init(void) |
| 112 | { | 114 | { |
| 115 | s3c_pm_init(); | ||
| 116 | |||
| 113 | s3c_i2c0_set_platdata(NULL); | 117 | s3c_i2c0_set_platdata(NULL); |
| 114 | s3c_i2c1_set_platdata(NULL); | 118 | s3c_i2c1_set_platdata(NULL); |
| 115 | s3c_i2c2_set_platdata(NULL); | 119 | s3c_i2c2_set_platdata(NULL); |
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index 83189ae9da9a..bcd7a5d53401 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <plat/ata.h> | 31 | #include <plat/ata.h> |
| 32 | #include <plat/iic.h> | 32 | #include <plat/iic.h> |
| 33 | #include <plat/keypad.h> | 33 | #include <plat/keypad.h> |
| 34 | #include <plat/pm.h> | ||
| 34 | 35 | ||
| 35 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | 36 | /* Following are default values for UCON, ULCON and UFCON UART registers */ |
| 36 | #define SMDKV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ | 37 | #define SMDKV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ |
| @@ -103,6 +104,7 @@ static struct samsung_keypad_platdata smdkv210_keypad_data __initdata = { | |||
| 103 | static struct platform_device *smdkv210_devices[] __initdata = { | 104 | static struct platform_device *smdkv210_devices[] __initdata = { |
| 104 | &s5pv210_device_iis0, | 105 | &s5pv210_device_iis0, |
| 105 | &s5pv210_device_ac97, | 106 | &s5pv210_device_ac97, |
| 107 | &s5pv210_device_spdif, | ||
| 106 | &s3c_device_adc, | 108 | &s3c_device_adc, |
| 107 | &s3c_device_cfcon, | 109 | &s3c_device_cfcon, |
| 108 | &s3c_device_hsmmc0, | 110 | &s3c_device_hsmmc0, |
| @@ -145,6 +147,8 @@ static void __init smdkv210_map_io(void) | |||
| 145 | 147 | ||
| 146 | static void __init smdkv210_machine_init(void) | 148 | static void __init smdkv210_machine_init(void) |
| 147 | { | 149 | { |
| 150 | s3c_pm_init(); | ||
| 151 | |||
| 148 | samsung_keypad_set_platdata(&smdkv210_keypad_data); | 152 | samsung_keypad_set_platdata(&smdkv210_keypad_data); |
| 149 | s3c24xx_ts_set_platdata(&s3c_ts_platform); | 153 | s3c24xx_ts_set_platdata(&s3c_ts_platform); |
| 150 | 154 | ||
diff --git a/arch/arm/mach-s5pv210/mach-torbreck.c b/arch/arm/mach-s5pv210/mach-torbreck.c new file mode 100644 index 000000000000..043c938806b0 --- /dev/null +++ b/arch/arm/mach-s5pv210/mach-torbreck.c | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv210/mach-torbreck.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 aESOP Community | ||
| 4 | * http://www.aesop.or.kr/ | ||
| 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/types.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/serial_core.h> | ||
| 16 | |||
| 17 | #include <asm/mach/arch.h> | ||
| 18 | #include <asm/mach/map.h> | ||
| 19 | #include <asm/setup.h> | ||
| 20 | #include <asm/mach-types.h> | ||
| 21 | |||
| 22 | #include <mach/map.h> | ||
| 23 | #include <mach/regs-clock.h> | ||
| 24 | |||
| 25 | #include <plat/regs-serial.h> | ||
| 26 | #include <plat/s5pv210.h> | ||
| 27 | #include <plat/devs.h> | ||
| 28 | #include <plat/cpu.h> | ||
| 29 | #include <plat/iic.h> | ||
| 30 | |||
| 31 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | ||
| 32 | #define TORBRECK_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ | ||
| 33 | S3C2410_UCON_RXILEVEL | \ | ||
| 34 | S3C2410_UCON_TXIRQMODE | \ | ||
| 35 | S3C2410_UCON_RXIRQMODE | \ | ||
| 36 | S3C2410_UCON_RXFIFO_TOI | \ | ||
| 37 | S3C2443_UCON_RXERR_IRQEN) | ||
| 38 | |||
| 39 | #define TORBRECK_ULCON_DEFAULT S3C2410_LCON_CS8 | ||
| 40 | |||
| 41 | #define TORBRECK_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ | ||
| 42 | S5PV210_UFCON_TXTRIG4 | \ | ||
| 43 | S5PV210_UFCON_RXTRIG4) | ||
| 44 | |||
| 45 | static struct s3c2410_uartcfg torbreck_uartcfgs[] __initdata = { | ||
| 46 | [0] = { | ||
| 47 | .hwport = 0, | ||
| 48 | .flags = 0, | ||
| 49 | .ucon = TORBRECK_UCON_DEFAULT, | ||
| 50 | .ulcon = TORBRECK_ULCON_DEFAULT, | ||
| 51 | .ufcon = TORBRECK_UFCON_DEFAULT, | ||
| 52 | }, | ||
| 53 | [1] = { | ||
| 54 | .hwport = 1, | ||
| 55 | .flags = 0, | ||
| 56 | .ucon = TORBRECK_UCON_DEFAULT, | ||
| 57 | .ulcon = TORBRECK_ULCON_DEFAULT, | ||
| 58 | .ufcon = TORBRECK_UFCON_DEFAULT, | ||
| 59 | }, | ||
| 60 | [2] = { | ||
| 61 | .hwport = 2, | ||
| 62 | .flags = 0, | ||
| 63 | .ucon = TORBRECK_UCON_DEFAULT, | ||
| 64 | .ulcon = TORBRECK_ULCON_DEFAULT, | ||
| 65 | .ufcon = TORBRECK_UFCON_DEFAULT, | ||
| 66 | }, | ||
| 67 | [3] = { | ||
| 68 | .hwport = 3, | ||
| 69 | .flags = 0, | ||
| 70 | .ucon = TORBRECK_UCON_DEFAULT, | ||
| 71 | .ulcon = TORBRECK_ULCON_DEFAULT, | ||
| 72 | .ufcon = TORBRECK_UFCON_DEFAULT, | ||
| 73 | }, | ||
| 74 | }; | ||
| 75 | |||
| 76 | static struct platform_device *torbreck_devices[] __initdata = { | ||
| 77 | &s5pv210_device_iis0, | ||
| 78 | &s3c_device_cfcon, | ||
| 79 | &s3c_device_hsmmc0, | ||
| 80 | &s3c_device_hsmmc1, | ||
| 81 | &s3c_device_hsmmc2, | ||
| 82 | &s3c_device_hsmmc3, | ||
| 83 | &s3c_device_i2c0, | ||
| 84 | &s3c_device_i2c1, | ||
| 85 | &s3c_device_i2c2, | ||
| 86 | &s3c_device_rtc, | ||
| 87 | &s3c_device_wdt, | ||
| 88 | }; | ||
| 89 | |||
| 90 | static struct i2c_board_info torbreck_i2c_devs0[] __initdata = { | ||
| 91 | /* To Be Updated */ | ||
| 92 | }; | ||
| 93 | |||
| 94 | static struct i2c_board_info torbreck_i2c_devs1[] __initdata = { | ||
| 95 | /* To Be Updated */ | ||
| 96 | }; | ||
| 97 | |||
| 98 | static struct i2c_board_info torbreck_i2c_devs2[] __initdata = { | ||
| 99 | /* To Be Updated */ | ||
| 100 | }; | ||
| 101 | |||
| 102 | static void __init torbreck_map_io(void) | ||
| 103 | { | ||
| 104 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); | ||
| 105 | s3c24xx_init_clocks(24000000); | ||
| 106 | s3c24xx_init_uarts(torbreck_uartcfgs, ARRAY_SIZE(torbreck_uartcfgs)); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void __init torbreck_machine_init(void) | ||
| 110 | { | ||
| 111 | s3c_i2c0_set_platdata(NULL); | ||
| 112 | s3c_i2c1_set_platdata(NULL); | ||
| 113 | s3c_i2c2_set_platdata(NULL); | ||
| 114 | i2c_register_board_info(0, torbreck_i2c_devs0, | ||
| 115 | ARRAY_SIZE(torbreck_i2c_devs0)); | ||
| 116 | i2c_register_board_info(1, torbreck_i2c_devs1, | ||
| 117 | ARRAY_SIZE(torbreck_i2c_devs1)); | ||
| 118 | i2c_register_board_info(2, torbreck_i2c_devs2, | ||
| 119 | ARRAY_SIZE(torbreck_i2c_devs2)); | ||
| 120 | |||
| 121 | platform_add_devices(torbreck_devices, ARRAY_SIZE(torbreck_devices)); | ||
| 122 | } | ||
| 123 | |||
| 124 | MACHINE_START(TORBRECK, "TORBRECK") | ||
| 125 | /* Maintainer: Hyunchul Ko <ghcstop@gmail.com> */ | ||
| 126 | .boot_params = S5P_PA_SDRAM + 0x100, | ||
| 127 | .init_irq = s5pv210_init_irq, | ||
| 128 | .map_io = torbreck_map_io, | ||
| 129 | .init_machine = torbreck_machine_init, | ||
| 130 | .timer = &s3c24xx_timer, | ||
| 131 | MACHINE_END | ||
diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c new file mode 100644 index 000000000000..549d7924fd4c --- /dev/null +++ b/arch/arm/mach-s5pv210/pm.c | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv210/pm.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S5PV210 - Power Management support | ||
| 7 | * | ||
| 8 | * Based on arch/arm/mach-s3c2410/pm.c | ||
| 9 | * Copyright (c) 2006 Simtec Electronics | ||
| 10 | * Ben Dooks <ben@simtec.co.uk> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License version 2 as | ||
| 14 | * published by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/suspend.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | |||
| 21 | #include <plat/cpu.h> | ||
| 22 | #include <plat/pm.h> | ||
| 23 | #include <plat/regs-timer.h> | ||
| 24 | |||
| 25 | #include <mach/regs-irq.h> | ||
| 26 | #include <mach/regs-clock.h> | ||
| 27 | |||
| 28 | static struct sleep_save s5pv210_core_save[] = { | ||
| 29 | /* Clock source */ | ||
| 30 | SAVE_ITEM(S5P_CLK_SRC0), | ||
| 31 | SAVE_ITEM(S5P_CLK_SRC1), | ||
| 32 | SAVE_ITEM(S5P_CLK_SRC2), | ||
| 33 | SAVE_ITEM(S5P_CLK_SRC3), | ||
| 34 | SAVE_ITEM(S5P_CLK_SRC4), | ||
| 35 | SAVE_ITEM(S5P_CLK_SRC5), | ||
| 36 | SAVE_ITEM(S5P_CLK_SRC6), | ||
| 37 | |||
| 38 | /* Clock source Mask */ | ||
| 39 | SAVE_ITEM(S5P_CLK_SRC_MASK0), | ||
| 40 | SAVE_ITEM(S5P_CLK_SRC_MASK1), | ||
| 41 | |||
| 42 | /* Clock Divider */ | ||
| 43 | SAVE_ITEM(S5P_CLK_DIV0), | ||
| 44 | SAVE_ITEM(S5P_CLK_DIV1), | ||
| 45 | SAVE_ITEM(S5P_CLK_DIV2), | ||
| 46 | SAVE_ITEM(S5P_CLK_DIV3), | ||
| 47 | SAVE_ITEM(S5P_CLK_DIV4), | ||
| 48 | SAVE_ITEM(S5P_CLK_DIV5), | ||
| 49 | SAVE_ITEM(S5P_CLK_DIV6), | ||
| 50 | SAVE_ITEM(S5P_CLK_DIV7), | ||
| 51 | |||
| 52 | /* Clock Main Gate */ | ||
| 53 | SAVE_ITEM(S5P_CLKGATE_MAIN0), | ||
| 54 | SAVE_ITEM(S5P_CLKGATE_MAIN1), | ||
| 55 | SAVE_ITEM(S5P_CLKGATE_MAIN2), | ||
| 56 | |||
| 57 | /* Clock source Peri Gate */ | ||
| 58 | SAVE_ITEM(S5P_CLKGATE_PERI0), | ||
| 59 | SAVE_ITEM(S5P_CLKGATE_PERI1), | ||
| 60 | |||
| 61 | /* Clock source SCLK Gate */ | ||
| 62 | SAVE_ITEM(S5P_CLKGATE_SCLK0), | ||
| 63 | SAVE_ITEM(S5P_CLKGATE_SCLK1), | ||
| 64 | |||
| 65 | /* Clock IP Clock gate */ | ||
| 66 | SAVE_ITEM(S5P_CLKGATE_IP0), | ||
| 67 | SAVE_ITEM(S5P_CLKGATE_IP1), | ||
| 68 | SAVE_ITEM(S5P_CLKGATE_IP2), | ||
| 69 | SAVE_ITEM(S5P_CLKGATE_IP3), | ||
| 70 | SAVE_ITEM(S5P_CLKGATE_IP4), | ||
| 71 | |||
| 72 | /* Clock Blcok and Bus gate */ | ||
| 73 | SAVE_ITEM(S5P_CLKGATE_BLOCK), | ||
| 74 | SAVE_ITEM(S5P_CLKGATE_BUS0), | ||
| 75 | |||
| 76 | /* Clock ETC */ | ||
| 77 | SAVE_ITEM(S5P_CLK_OUT), | ||
| 78 | SAVE_ITEM(S5P_MDNIE_SEL), | ||
| 79 | |||
| 80 | /* PWM Register */ | ||
| 81 | SAVE_ITEM(S3C2410_TCFG0), | ||
| 82 | SAVE_ITEM(S3C2410_TCFG1), | ||
| 83 | SAVE_ITEM(S3C64XX_TINT_CSTAT), | ||
| 84 | SAVE_ITEM(S3C2410_TCON), | ||
| 85 | SAVE_ITEM(S3C2410_TCNTB(0)), | ||
| 86 | SAVE_ITEM(S3C2410_TCMPB(0)), | ||
| 87 | SAVE_ITEM(S3C2410_TCNTO(0)), | ||
| 88 | }; | ||
| 89 | |||
| 90 | void s5pv210_cpu_suspend(void) | ||
| 91 | { | ||
| 92 | unsigned long tmp; | ||
| 93 | |||
| 94 | /* issue the standby signal into the pm unit. Note, we | ||
| 95 | * issue a write-buffer drain just in case */ | ||
| 96 | |||
| 97 | tmp = 0; | ||
| 98 | |||
| 99 | asm("b 1f\n\t" | ||
| 100 | ".align 5\n\t" | ||
| 101 | "1:\n\t" | ||
| 102 | "mcr p15, 0, %0, c7, c10, 5\n\t" | ||
| 103 | "mcr p15, 0, %0, c7, c10, 4\n\t" | ||
| 104 | "wfi" : : "r" (tmp)); | ||
| 105 | |||
| 106 | /* we should never get past here */ | ||
| 107 | panic("sleep resumed to originator?"); | ||
| 108 | } | ||
| 109 | |||
| 110 | static void s5pv210_pm_prepare(void) | ||
| 111 | { | ||
| 112 | unsigned int tmp; | ||
| 113 | |||
| 114 | /* ensure at least INFORM0 has the resume address */ | ||
| 115 | __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0); | ||
| 116 | |||
| 117 | tmp = __raw_readl(S5P_SLEEP_CFG); | ||
| 118 | tmp &= ~(S5P_SLEEP_CFG_OSC_EN | S5P_SLEEP_CFG_USBOSC_EN); | ||
| 119 | __raw_writel(tmp, S5P_SLEEP_CFG); | ||
| 120 | |||
| 121 | /* WFI for SLEEP mode configuration by SYSCON */ | ||
| 122 | tmp = __raw_readl(S5P_PWR_CFG); | ||
| 123 | tmp &= S5P_CFG_WFI_CLEAN; | ||
| 124 | tmp |= S5P_CFG_WFI_SLEEP; | ||
| 125 | __raw_writel(tmp, S5P_PWR_CFG); | ||
| 126 | |||
| 127 | /* SYSCON interrupt handling disable */ | ||
| 128 | tmp = __raw_readl(S5P_OTHERS); | ||
| 129 | tmp |= S5P_OTHER_SYSC_INTOFF; | ||
| 130 | __raw_writel(tmp, S5P_OTHERS); | ||
| 131 | |||
| 132 | s3c_pm_do_save(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save)); | ||
| 133 | } | ||
| 134 | |||
| 135 | static int s5pv210_pm_add(struct sys_device *sysdev) | ||
| 136 | { | ||
| 137 | pm_cpu_prep = s5pv210_pm_prepare; | ||
| 138 | pm_cpu_sleep = s5pv210_cpu_suspend; | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int s5pv210_pm_resume(struct sys_device *dev) | ||
| 144 | { | ||
| 145 | u32 tmp; | ||
| 146 | |||
| 147 | tmp = __raw_readl(S5P_OTHERS); | ||
| 148 | tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF |\ | ||
| 149 | S5P_OTHERS_RET_MMC | S5P_OTHERS_RET_UART); | ||
| 150 | __raw_writel(tmp , S5P_OTHERS); | ||
| 151 | |||
| 152 | s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save)); | ||
| 153 | |||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static struct sysdev_driver s5pv210_pm_driver = { | ||
| 158 | .add = s5pv210_pm_add, | ||
| 159 | .resume = s5pv210_pm_resume, | ||
| 160 | }; | ||
| 161 | |||
| 162 | static __init int s5pv210_pm_drvinit(void) | ||
| 163 | { | ||
| 164 | return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver); | ||
| 165 | } | ||
| 166 | arch_initcall(s5pv210_pm_drvinit); | ||
diff --git a/arch/arm/mach-s5pv210/setup-fb-24bpp.c b/arch/arm/mach-s5pv210/setup-fb-24bpp.c index 928cf1f125fa..e932ebfac56d 100644 --- a/arch/arm/mach-s5pv210/setup-fb-24bpp.c +++ b/arch/arm/mach-s5pv210/setup-fb-24bpp.c | |||
| @@ -21,33 +21,21 @@ | |||
| 21 | #include <mach/regs-clock.h> | 21 | #include <mach/regs-clock.h> |
| 22 | #include <plat/gpio-cfg.h> | 22 | #include <plat/gpio-cfg.h> |
| 23 | 23 | ||
| 24 | void s5pv210_fb_gpio_setup_24bpp(void) | 24 | static void s5pv210_fb_cfg_gpios(unsigned int base, unsigned int nr) |
| 25 | { | 25 | { |
| 26 | unsigned int gpio = 0; | 26 | s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(2)); |
| 27 | |||
| 28 | for (gpio = S5PV210_GPF0(0); gpio <= S5PV210_GPF0(7); gpio++) { | ||
| 29 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 30 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 31 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 32 | } | ||
| 33 | 27 | ||
| 34 | for (gpio = S5PV210_GPF1(0); gpio <= S5PV210_GPF1(7); gpio++) { | 28 | for (; nr > 0; nr--, base++) |
| 35 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | 29 | s5p_gpio_set_drvstr(base, S5P_GPIO_DRVSTR_LV4); |
| 36 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | 30 | } |
| 37 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 38 | } | ||
| 39 | 31 | ||
| 40 | for (gpio = S5PV210_GPF2(0); gpio <= S5PV210_GPF2(7); gpio++) { | ||
| 41 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 42 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 43 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 44 | } | ||
| 45 | 32 | ||
| 46 | for (gpio = S5PV210_GPF3(0); gpio <= S5PV210_GPF3(3); gpio++) { | 33 | void s5pv210_fb_gpio_setup_24bpp(void) |
| 47 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | 34 | { |
| 48 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | 35 | s5pv210_fb_cfg_gpios(S5PV210_GPF0(0), 8); |
| 49 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | 36 | s5pv210_fb_cfg_gpios(S5PV210_GPF1(0), 8); |
| 50 | } | 37 | s5pv210_fb_cfg_gpios(S5PV210_GPF2(0), 8); |
| 38 | s5pv210_fb_cfg_gpios(S5PV210_GPF3(0), 4); | ||
| 51 | 39 | ||
| 52 | /* Set DISPLAY_CONTROL register for Display path selection. | 40 | /* Set DISPLAY_CONTROL register for Display path selection. |
| 53 | * | 41 | * |
diff --git a/arch/arm/mach-s5pv210/setup-i2c0.c b/arch/arm/mach-s5pv210/setup-i2c0.c index d38f7cb7e662..0f1cc3a1c1e8 100644 --- a/arch/arm/mach-s5pv210/setup-i2c0.c +++ b/arch/arm/mach-s5pv210/setup-i2c0.c | |||
| @@ -23,8 +23,6 @@ struct platform_device; /* don't need the contents */ | |||
| 23 | 23 | ||
| 24 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) | 24 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) |
| 25 | { | 25 | { |
| 26 | s3c_gpio_cfgpin(S5PV210_GPD1(0), S3C_GPIO_SFN(2)); | 26 | s3c_gpio_cfgall_range(S5PV210_GPD1(0), 2, |
| 27 | s3c_gpio_setpull(S5PV210_GPD1(0), S3C_GPIO_PULL_UP); | 27 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 28 | s3c_gpio_cfgpin(S5PV210_GPD1(1), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_setpull(S5PV210_GPD1(1), S3C_GPIO_PULL_UP); | ||
| 30 | } | 28 | } |
diff --git a/arch/arm/mach-s5pv210/setup-i2c1.c b/arch/arm/mach-s5pv210/setup-i2c1.c index 148bb7857d89..f61365a34c56 100644 --- a/arch/arm/mach-s5pv210/setup-i2c1.c +++ b/arch/arm/mach-s5pv210/setup-i2c1.c | |||
| @@ -23,8 +23,6 @@ struct platform_device; /* don't need the contents */ | |||
| 23 | 23 | ||
| 24 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) | 24 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) |
| 25 | { | 25 | { |
| 26 | s3c_gpio_cfgpin(S5PV210_GPD1(2), S3C_GPIO_SFN(2)); | 26 | s3c_gpio_cfgall_range(S5PV210_GPD1(2), 2, |
| 27 | s3c_gpio_setpull(S5PV210_GPD1(2), S3C_GPIO_PULL_UP); | 27 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 28 | s3c_gpio_cfgpin(S5PV210_GPD1(3), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_setpull(S5PV210_GPD1(3), S3C_GPIO_PULL_UP); | ||
| 30 | } | 28 | } |
diff --git a/arch/arm/mach-s5pv210/setup-i2c2.c b/arch/arm/mach-s5pv210/setup-i2c2.c index 2396cb8c373e..2f91b5cefbc6 100644 --- a/arch/arm/mach-s5pv210/setup-i2c2.c +++ b/arch/arm/mach-s5pv210/setup-i2c2.c | |||
| @@ -23,8 +23,6 @@ struct platform_device; /* don't need the contents */ | |||
| 23 | 23 | ||
| 24 | void s3c_i2c2_cfg_gpio(struct platform_device *dev) | 24 | void s3c_i2c2_cfg_gpio(struct platform_device *dev) |
| 25 | { | 25 | { |
| 26 | s3c_gpio_cfgpin(S5PV210_GPD1(4), S3C_GPIO_SFN(2)); | 26 | s3c_gpio_cfgall_range(S5PV210_GPD1(4), 2, |
| 27 | s3c_gpio_setpull(S5PV210_GPD1(4), S3C_GPIO_PULL_UP); | 27 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 28 | s3c_gpio_cfgpin(S5PV210_GPD1(5), S3C_GPIO_SFN(2)); | ||
| 29 | s3c_gpio_setpull(S5PV210_GPD1(5), S3C_GPIO_PULL_UP); | ||
| 30 | } | 28 | } |
diff --git a/arch/arm/mach-s5pv210/setup-ide.c b/arch/arm/mach-s5pv210/setup-ide.c index b558b1cc8d60..ea123d546bd2 100644 --- a/arch/arm/mach-s5pv210/setup-ide.c +++ b/arch/arm/mach-s5pv210/setup-ide.c | |||
| @@ -15,36 +15,25 @@ | |||
| 15 | 15 | ||
| 16 | #include <plat/gpio-cfg.h> | 16 | #include <plat/gpio-cfg.h> |
| 17 | 17 | ||
| 18 | static void s5pv210_ide_cfg_gpios(unsigned int base, unsigned int nr) | ||
| 19 | { | ||
| 20 | s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(4)); | ||
| 21 | |||
| 22 | for (; nr > 0; nr--, base++) | ||
| 23 | s5p_gpio_set_drvstr(base, S5P_GPIO_DRVSTR_LV4); | ||
| 24 | } | ||
| 25 | |||
| 18 | void s5pv210_ide_setup_gpio(void) | 26 | void s5pv210_ide_setup_gpio(void) |
| 19 | { | 27 | { |
| 20 | unsigned int gpio = 0; | 28 | /* CF_Add[0 - 2], CF_IORDY, CF_INTRQ, CF_DMARQ, CF_DMARST, CF_DMACK */ |
| 21 | 29 | s5pv210_ide_cfg_gpios(S5PV210_GPJ0(0), 8); | |
| 22 | for (gpio = S5PV210_GPJ0(0); gpio <= S5PV210_GPJ0(7); gpio++) { | 30 | |
| 23 | /* CF_Add[0 - 2], CF_IORDY, CF_INTRQ, CF_DMARQ, CF_DMARST, | 31 | /* CF_Data[0 - 7] */ |
| 24 | CF_DMACK */ | 32 | s5pv210_ide_cfg_gpios(S5PV210_GPJ2(0), 8); |
| 25 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | 33 | |
| 26 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | 34 | /* CF_Data[8 - 15] */ |
| 27 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | 35 | s5pv210_ide_cfg_gpios(S5PV210_GPJ3(0), 8); |
| 28 | } | 36 | |
| 29 | 37 | /* CF_CS0, CF_CS1, CF_IORD, CF_IOWR */ | |
| 30 | for (gpio = S5PV210_GPJ2(0); gpio <= S5PV210_GPJ2(7); gpio++) { | 38 | s5pv210_ide_cfg_gpios(S5PV210_GPJ4(0), 4); |
| 31 | /*CF_Data[0 - 7] */ | ||
| 32 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | ||
| 33 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 34 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 35 | } | ||
| 36 | |||
| 37 | for (gpio = S5PV210_GPJ3(0); gpio <= S5PV210_GPJ3(7); gpio++) { | ||
| 38 | /* CF_Data[8 - 15] */ | ||
| 39 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | ||
| 40 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 41 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 42 | } | ||
| 43 | |||
| 44 | for (gpio = S5PV210_GPJ4(0); gpio <= S5PV210_GPJ4(3); gpio++) { | ||
| 45 | /* CF_CS0, CF_CS1, CF_IORD, CF_IOWR */ | ||
| 46 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); | ||
| 47 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 48 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 49 | } | ||
| 50 | } | 39 | } |
diff --git a/arch/arm/mach-s5pv210/setup-keypad.c b/arch/arm/mach-s5pv210/setup-keypad.c index 37b2790aafc3..c56420a52f48 100644 --- a/arch/arm/mach-s5pv210/setup-keypad.c +++ b/arch/arm/mach-s5pv210/setup-keypad.c | |||
| @@ -16,19 +16,9 @@ | |||
| 16 | 16 | ||
| 17 | void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) | 17 | void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) |
| 18 | { | 18 | { |
| 19 | unsigned int gpio, end; | ||
| 20 | |||
| 21 | /* Set all the necessary GPH3 pins to special-function 3: KP_ROW[x] */ | 19 | /* Set all the necessary GPH3 pins to special-function 3: KP_ROW[x] */ |
| 22 | end = S5PV210_GPH3(rows); | 20 | s3c_gpio_cfgrange_nopull(S5PV210_GPH3(0), rows, S3C_GPIO_SFN(3)); |
| 23 | for (gpio = S5PV210_GPH3(0); gpio < end; gpio++) { | ||
| 24 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 25 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 26 | } | ||
| 27 | 21 | ||
| 28 | /* Set all the necessary GPH2 pins to special-function 3: KP_COL[x] */ | 22 | /* Set all the necessary GPH2 pins to special-function 3: KP_COL[x] */ |
| 29 | end = S5PV210_GPH2(cols); | 23 | s3c_gpio_cfgrange_nopull(S5PV210_GPH2(0), cols, S3C_GPIO_SFN(3)); |
| 30 | for (gpio = S5PV210_GPH2(0); gpio < end; gpio++) { | ||
| 31 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 32 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 33 | } | ||
| 34 | } | 24 | } |
diff --git a/arch/arm/mach-s5pv210/setup-sdhci-gpio.c b/arch/arm/mach-s5pv210/setup-sdhci-gpio.c index b18587b1ec58..746777d56df9 100644 --- a/arch/arm/mach-s5pv210/setup-sdhci-gpio.c +++ b/arch/arm/mach-s5pv210/setup-sdhci-gpio.c | |||
| @@ -26,26 +26,17 @@ | |||
| 26 | void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | 26 | void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) |
| 27 | { | 27 | { |
| 28 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 28 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 29 | unsigned int gpio; | ||
| 30 | 29 | ||
| 31 | /* Set all the necessary GPG0/GPG1 pins to special-function 2 */ | 30 | /* Set all the necessary GPG0/GPG1 pins to special-function 2 */ |
| 32 | for (gpio = S5PV210_GPG0(0); gpio < S5PV210_GPG0(2); gpio++) { | 31 | s3c_gpio_cfgrange_nopull(S5PV210_GPG0(0), 2, S3C_GPIO_SFN(2)); |
| 33 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | 32 | |
| 34 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 35 | } | ||
| 36 | switch (width) { | 33 | switch (width) { |
| 37 | case 8: | 34 | case 8: |
| 38 | /* GPG1[3:6] special-funtion 3 */ | 35 | /* GPG1[3:6] special-funtion 3 */ |
| 39 | for (gpio = S5PV210_GPG1(3); gpio <= S5PV210_GPG1(6); gpio++) { | 36 | s3c_gpio_cfgrange_nopull(S5PV210_GPG1(3), 4, S3C_GPIO_SFN(3)); |
| 40 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 41 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 42 | } | ||
| 43 | case 4: | 37 | case 4: |
| 44 | /* GPG0[3:6] special-funtion 2 */ | 38 | /* GPG0[3:6] special-funtion 2 */ |
| 45 | for (gpio = S5PV210_GPG0(3); gpio <= S5PV210_GPG0(6); gpio++) { | 39 | s3c_gpio_cfgrange_nopull(S5PV210_GPG0(3), 4, S3C_GPIO_SFN(2)); |
| 46 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 47 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 48 | } | ||
| 49 | default: | 40 | default: |
| 50 | break; | 41 | break; |
| 51 | } | 42 | } |
| @@ -59,19 +50,12 @@ void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | |||
| 59 | void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) | 50 | void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) |
| 60 | { | 51 | { |
| 61 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 52 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 62 | unsigned int gpio; | ||
| 63 | 53 | ||
| 64 | /* Set all the necessary GPG1[0:1] pins to special-function 2 */ | 54 | /* Set all the necessary GPG1[0:1] pins to special-function 2 */ |
| 65 | for (gpio = S5PV210_GPG1(0); gpio < S5PV210_GPG1(2); gpio++) { | 55 | s3c_gpio_cfgrange_nopull(S5PV210_GPG1(0), 2, S3C_GPIO_SFN(2)); |
| 66 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 67 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 68 | } | ||
| 69 | 56 | ||
| 70 | /* Data pin GPG1[3:6] to special-function 2 */ | 57 | /* Data pin GPG1[3:6] to special-function 2 */ |
| 71 | for (gpio = S5PV210_GPG1(3); gpio <= S5PV210_GPG1(6); gpio++) { | 58 | s3c_gpio_cfgrange_nopull(S5PV210_GPG1(3), 4, S3C_GPIO_SFN(2)); |
| 72 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 73 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 74 | } | ||
| 75 | 59 | ||
| 76 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | 60 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { |
| 77 | s3c_gpio_setpull(S5PV210_GPG1(2), S3C_GPIO_PULL_UP); | 61 | s3c_gpio_setpull(S5PV210_GPG1(2), S3C_GPIO_PULL_UP); |
| @@ -82,27 +66,17 @@ void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) | |||
| 82 | void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) | 66 | void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) |
| 83 | { | 67 | { |
| 84 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 68 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 85 | unsigned int gpio; | ||
| 86 | 69 | ||
| 87 | /* Set all the necessary GPG2[0:1] pins to special-function 2 */ | 70 | /* Set all the necessary GPG2[0:1] pins to special-function 2 */ |
| 88 | for (gpio = S5PV210_GPG2(0); gpio < S5PV210_GPG2(2); gpio++) { | 71 | s3c_gpio_cfgrange_nopull(S5PV210_GPG2(0), 2, S3C_GPIO_SFN(2)); |
| 89 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 90 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 91 | } | ||
| 92 | 72 | ||
| 93 | switch (width) { | 73 | switch (width) { |
| 94 | case 8: | 74 | case 8: |
| 95 | /* Data pin GPG3[3:6] to special-function 3 */ | 75 | /* Data pin GPG3[3:6] to special-function 3 */ |
| 96 | for (gpio = S5PV210_GPG3(3); gpio <= S5PV210_GPG3(6); gpio++) { | 76 | s3c_gpio_cfgrange_nopull(S5PV210_GPG3(3), 4, S3C_GPIO_SFN(3)); |
| 97 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 98 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 99 | } | ||
| 100 | case 4: | 77 | case 4: |
| 101 | /* Data pin GPG2[3:6] to special-function 2 */ | 78 | /* Data pin GPG2[3:6] to special-function 2 */ |
| 102 | for (gpio = S5PV210_GPG2(3); gpio <= S5PV210_GPG2(6); gpio++) { | 79 | s3c_gpio_cfgrange_nopull(S5PV210_GPG2(3), 4, S3C_GPIO_SFN(2)); |
| 103 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 104 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 105 | } | ||
| 106 | default: | 80 | default: |
| 107 | break; | 81 | break; |
| 108 | } | 82 | } |
| @@ -116,19 +90,12 @@ void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) | |||
| 116 | void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width) | 90 | void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width) |
| 117 | { | 91 | { |
| 118 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | 92 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; |
| 119 | unsigned int gpio; | ||
| 120 | 93 | ||
| 121 | /* Set all the necessary GPG3[0:2] pins to special-function 2 */ | 94 | /* Set all the necessary GPG3[0:1] pins to special-function 2 */ |
| 122 | for (gpio = S5PV210_GPG3(0); gpio < S5PV210_GPG3(2); gpio++) { | 95 | s3c_gpio_cfgrange_nopull(S5PV210_GPG3(0), 2, S3C_GPIO_SFN(2)); |
| 123 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 124 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 125 | } | ||
| 126 | 96 | ||
| 127 | /* Data pin GPG3[3:6] to special-function 2 */ | 97 | /* Data pin GPG3[3:6] to special-function 2 */ |
| 128 | for (gpio = S5PV210_GPG3(3); gpio <= S5PV210_GPG3(6); gpio++) { | 98 | s3c_gpio_cfgrange_nopull(S5PV210_GPG3(3), 4, S3C_GPIO_SFN(2)); |
| 129 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 130 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 131 | } | ||
| 132 | 99 | ||
| 133 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | 100 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { |
| 134 | s3c_gpio_setpull(S5PV210_GPG3(2), S3C_GPIO_PULL_UP); | 101 | s3c_gpio_setpull(S5PV210_GPG3(2), S3C_GPIO_PULL_UP); |
diff --git a/arch/arm/mach-s5pv210/sleep.S b/arch/arm/mach-s5pv210/sleep.S new file mode 100644 index 000000000000..d4d222b716b4 --- /dev/null +++ b/arch/arm/mach-s5pv210/sleep.S | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | /* linux/arch/arm/plat-s5p/sleep.S | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S5PV210 power Manager (Suspend-To-RAM) support | ||
| 7 | * Based on S3C2410 sleep code by: | ||
| 8 | * Ben Dooks, (c) 2004 Simtec Electronics | ||
| 9 | * | ||
| 10 | * Based on PXA/SA1100 sleep code by: | ||
| 11 | * Nicolas Pitre, (c) 2002 Monta Vista Software Inc | ||
| 12 | * Cliff Brake, (c) 2001 | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or modify | ||
| 15 | * it under the terms of the GNU General Public License as published by | ||
| 16 | * the Free Software Foundation; either version 2 of the License, or | ||
| 17 | * (at your option) any later version. | ||
| 18 | * | ||
| 19 | * This program is distributed in the hope that it will be useful, | ||
| 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 22 | * GNU General Public License for more details. | ||
| 23 | * | ||
| 24 | * You should have received a copy of the GNU General Public License | ||
| 25 | * along with this program; if not, write to the Free Software | ||
| 26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/linkage.h> | ||
| 30 | #include <asm/assembler.h> | ||
| 31 | #include <asm/memory.h> | ||
| 32 | |||
| 33 | .text | ||
| 34 | |||
| 35 | /* s3c_cpu_save | ||
| 36 | * | ||
| 37 | * entry: | ||
| 38 | * r0 = save address (virtual addr of s3c_sleep_save_phys) | ||
| 39 | */ | ||
| 40 | |||
| 41 | ENTRY(s3c_cpu_save) | ||
| 42 | |||
| 43 | stmfd sp!, { r3 - r12, lr } | ||
| 44 | |||
| 45 | mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID | ||
| 46 | mrc p15, 0, r5, c3, c0, 0 @ Domain ID | ||
| 47 | mrc p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 | ||
| 48 | mrc p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 | ||
| 49 | mrc p15, 0, r8, c2, c0, 2 @ Translation Table Control | ||
| 50 | mrc p15, 0, r9, c1, c0, 0 @ Control register | ||
| 51 | mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register | ||
| 52 | mrc p15, 0, r11, c1, c0, 2 @ Co-processor access controls | ||
| 53 | mrc p15, 0, r12, c10, c2, 0 @ Read PRRR | ||
| 54 | mrc p15, 0, r3, c10, c2, 1 @ READ NMRR | ||
| 55 | |||
| 56 | stmia r0, { r3 - r13 } | ||
| 57 | |||
| 58 | bl s3c_pm_cb_flushcache | ||
| 59 | |||
| 60 | ldr r0, =pm_cpu_sleep | ||
| 61 | ldr r0, [ r0 ] | ||
| 62 | mov pc, r0 | ||
| 63 | |||
| 64 | resume_with_mmu: | ||
| 65 | /* | ||
| 66 | * After MMU is turned on, restore the previous MMU table. | ||
| 67 | */ | ||
| 68 | ldr r9 , =(PAGE_OFFSET - PHYS_OFFSET) | ||
| 69 | add r4, r4, r9 | ||
| 70 | str r12, [r4] | ||
| 71 | |||
| 72 | ldmfd sp!, { r3 - r12, pc } | ||
| 73 | |||
| 74 | .ltorg | ||
| 75 | |||
| 76 | .data | ||
| 77 | |||
| 78 | .global s3c_sleep_save_phys | ||
| 79 | s3c_sleep_save_phys: | ||
| 80 | .word 0 | ||
| 81 | |||
| 82 | /* sleep magic, to allow the bootloader to check for an valid | ||
| 83 | * image to resume to. Must be the first word before the | ||
| 84 | * s3c_cpu_resume entry. | ||
| 85 | */ | ||
| 86 | |||
| 87 | .word 0x2bedf00d | ||
| 88 | |||
| 89 | /* s3c_cpu_resume | ||
| 90 | * | ||
| 91 | * resume code entry for bootloader to call | ||
| 92 | * | ||
| 93 | * we must put this code here in the data segment as we have no | ||
| 94 | * other way of restoring the stack pointer after sleep, and we | ||
| 95 | * must not write to the code segment (code is read-only) | ||
| 96 | */ | ||
| 97 | |||
| 98 | ENTRY(s3c_cpu_resume) | ||
| 99 | mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE | ||
| 100 | msr cpsr_c, r0 | ||
| 101 | |||
| 102 | mov r1, #0 | ||
| 103 | mcr p15, 0, r1, c8, c7, 0 @ invalidate TLBs | ||
| 104 | mcr p15, 0, r1, c7, c5, 0 @ invalidate I Cache | ||
| 105 | |||
| 106 | ldr r0, s3c_sleep_save_phys @ address of restore block | ||
| 107 | ldmia r0, { r3 - r13 } | ||
| 108 | |||
| 109 | mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID | ||
| 110 | mcr p15, 0, r5, c3, c0, 0 @ Domain ID | ||
| 111 | |||
| 112 | mcr p15, 0, r8, c2, c0, 2 @ Translation Table Control | ||
| 113 | mcr p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 | ||
| 114 | mcr p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 | ||
| 115 | |||
| 116 | mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register | ||
| 117 | |||
| 118 | mov r0, #0 | ||
| 119 | mcr p15, 0, r0, c8, c7, 0 @ Invalidate I & D TLB | ||
| 120 | |||
| 121 | mov r0, #0 @ restore copro access | ||
| 122 | mcr p15, 0, r11, c1, c0, 2 @ Co-processor access | ||
| 123 | mcr p15, 0, r0, c7, c5, 4 | ||
| 124 | |||
| 125 | mcr p15, 0, r12, c10, c2, 0 @ write PRRR | ||
| 126 | mcr p15, 0, r3, c10, c2, 1 @ write NMRR | ||
| 127 | |||
| 128 | /* | ||
| 129 | * In Cortex-A8, when MMU is turned on, the pipeline is flushed. | ||
| 130 | * And there are no valid entries in the MMU table at this point. | ||
| 131 | * So before turning on the MMU, the MMU entry for the DRAM address | ||
| 132 | * range is added. After the MMU is turned on, the other entries | ||
| 133 | * in the MMU table will be restored. | ||
| 134 | */ | ||
| 135 | |||
| 136 | /* r6 = Translation Table BASE0 */ | ||
| 137 | mov r4, r6 | ||
| 138 | mov r4, r4, LSR #14 | ||
| 139 | mov r4, r4, LSL #14 | ||
| 140 | |||
| 141 | /* Load address for adding to MMU table list */ | ||
| 142 | ldr r11, =0xE010F000 @ INFORM0 reg. | ||
| 143 | ldr r10, [r11, #0] | ||
| 144 | mov r10, r10, LSR #18 | ||
| 145 | bic r10, r10, #0x3 | ||
| 146 | orr r4, r4, r10 | ||
| 147 | |||
| 148 | /* Calculate MMU table entry */ | ||
| 149 | mov r10, r10, LSL #18 | ||
| 150 | ldr r5, =0x40E | ||
| 151 | orr r10, r10, r5 | ||
| 152 | |||
| 153 | /* Back up originally data */ | ||
| 154 | ldr r12, [r4] | ||
| 155 | |||
| 156 | /* Add calculated MMU table entry into MMU table list */ | ||
| 157 | str r10, [r4] | ||
| 158 | |||
| 159 | ldr r2, =resume_with_mmu | ||
| 160 | mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, etc | ||
| 161 | |||
| 162 | nop | ||
| 163 | nop | ||
| 164 | nop | ||
| 165 | nop | ||
| 166 | nop @ second-to-last before mmu | ||
| 167 | |||
| 168 | mov pc, r2 @ go back to virtual address | ||
| 169 | |||
| 170 | .ltorg | ||
diff --git a/arch/arm/mach-s5pv310/Kconfig b/arch/arm/mach-s5pv310/Kconfig index 331b5bd97aba..1150b360f38c 100644 --- a/arch/arm/mach-s5pv310/Kconfig +++ b/arch/arm/mach-s5pv310/Kconfig | |||
| @@ -11,7 +11,6 @@ if ARCH_S5PV310 | |||
| 11 | 11 | ||
| 12 | config CPU_S5PV310 | 12 | config CPU_S5PV310 |
| 13 | bool | 13 | bool |
| 14 | select PLAT_S5P | ||
| 15 | help | 14 | help |
| 16 | Enable S5PV310 CPU support | 15 | Enable S5PV310 CPU support |
| 17 | 16 | ||
| @@ -25,21 +24,105 @@ config S5PV310_SETUP_I2C2 | |||
| 25 | help | 24 | help |
| 26 | Common setup code for i2c bus 2. | 25 | Common setup code for i2c bus 2. |
| 27 | 26 | ||
| 27 | config S5PV310_SETUP_I2C3 | ||
| 28 | bool | ||
| 29 | help | ||
| 30 | Common setup code for i2c bus 3. | ||
| 31 | |||
| 32 | config S5PV310_SETUP_I2C4 | ||
| 33 | bool | ||
| 34 | help | ||
| 35 | Common setup code for i2c bus 4. | ||
| 36 | |||
| 37 | config S5PV310_SETUP_I2C5 | ||
| 38 | bool | ||
| 39 | help | ||
| 40 | Common setup code for i2c bus 5. | ||
| 41 | |||
| 42 | config S5PV310_SETUP_I2C6 | ||
| 43 | bool | ||
| 44 | help | ||
| 45 | Common setup code for i2c bus 6. | ||
| 46 | |||
| 47 | config S5PV310_SETUP_I2C7 | ||
| 48 | bool | ||
| 49 | help | ||
| 50 | Common setup code for i2c bus 7. | ||
| 51 | |||
| 52 | config S5PV310_SETUP_SDHCI | ||
| 53 | bool | ||
| 54 | select S5PV310_SETUP_SDHCI_GPIO | ||
| 55 | help | ||
| 56 | Internal helper functions for S5PV310 based SDHCI systems. | ||
| 57 | |||
| 58 | config S5PV310_SETUP_SDHCI_GPIO | ||
| 59 | bool | ||
| 60 | help | ||
| 61 | Common setup code for SDHCI gpio. | ||
| 62 | |||
| 28 | # machine support | 63 | # machine support |
| 29 | 64 | ||
| 30 | config MACH_SMDKV310 | 65 | menu "S5PC210 Machines" |
| 31 | bool "SMDKV310" | 66 | |
| 67 | config MACH_SMDKC210 | ||
| 68 | bool "SMDKC210" | ||
| 32 | select CPU_S5PV310 | 69 | select CPU_S5PV310 |
| 33 | select ARCH_SPARSEMEM_ENABLE | 70 | select S3C_DEV_RTC |
| 71 | select S3C_DEV_WDT | ||
| 72 | select S3C_DEV_HSMMC | ||
| 73 | select S3C_DEV_HSMMC1 | ||
| 74 | select S3C_DEV_HSMMC2 | ||
| 75 | select S3C_DEV_HSMMC3 | ||
| 76 | select S5PV310_SETUP_SDHCI | ||
| 34 | help | 77 | help |
| 35 | Machine support for Samsung SMDKV310 | 78 | Machine support for Samsung SMDKC210 |
| 79 | S5PC210(MCP) is one of package option of S5PV310 | ||
| 36 | 80 | ||
| 37 | config MACH_UNIVERSAL_C210 | 81 | config MACH_UNIVERSAL_C210 |
| 38 | bool "Mobile UNIVERSAL_C210 Board" | 82 | bool "Mobile UNIVERSAL_C210 Board" |
| 39 | select CPU_S5PV310 | 83 | select CPU_S5PV310 |
| 40 | select ARCH_SPARSEMEM_ENABLE | 84 | select S5P_DEV_ONENAND |
| 85 | select S3C_DEV_I2C1 | ||
| 86 | select S5PV310_SETUP_I2C1 | ||
| 41 | help | 87 | help |
| 42 | Machine support for Samsung Mobile Universal S5PC210 Reference | 88 | Machine support for Samsung Mobile Universal S5PC210 Reference |
| 43 | Board. S5PC210(MCP) is one of package option of S5PV310 | 89 | Board. S5PC210(MCP) is one of package option of S5PV310 |
| 44 | 90 | ||
| 91 | endmenu | ||
| 92 | |||
| 93 | menu "S5PV310 Machines" | ||
| 94 | |||
| 95 | config MACH_SMDKV310 | ||
| 96 | bool "SMDKV310" | ||
| 97 | select CPU_S5PV310 | ||
| 98 | select S3C_DEV_RTC | ||
| 99 | select S3C_DEV_WDT | ||
| 100 | select S3C_DEV_HSMMC | ||
| 101 | select S3C_DEV_HSMMC1 | ||
| 102 | select S3C_DEV_HSMMC2 | ||
| 103 | select S3C_DEV_HSMMC3 | ||
| 104 | select S5PV310_SETUP_SDHCI | ||
| 105 | help | ||
| 106 | Machine support for Samsung SMDKV310 | ||
| 107 | |||
| 108 | endmenu | ||
| 109 | |||
| 110 | comment "Configuration for HSMMC bus width" | ||
| 111 | |||
| 112 | menu "Use 8-bit bus width" | ||
| 113 | |||
| 114 | config S5PV310_SDHCI_CH0_8BIT | ||
| 115 | bool "Channel 0 with 8-bit bus" | ||
| 116 | help | ||
| 117 | Support HSMMC Channel 0 8-bit bus. | ||
| 118 | If selected, Channel 1 is disabled. | ||
| 119 | |||
| 120 | config S5PV310_SDHCI_CH2_8BIT | ||
| 121 | bool "Channel 2 with 8-bit bus" | ||
| 122 | help | ||
| 123 | Support HSMMC Channel 2 8-bit bus. | ||
| 124 | If selected, Channel 3 is disabled. | ||
| 125 | |||
| 126 | endmenu | ||
| 127 | |||
| 45 | endif | 128 | endif |
diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile index d5b51c72340f..84afc64e7c01 100644 --- a/arch/arm/mach-s5pv310/Makefile +++ b/arch/arm/mach-s5pv310/Makefile | |||
| @@ -13,7 +13,7 @@ obj- := | |||
| 13 | # Core support for S5PV310 system | 13 | # Core support for S5PV310 system |
| 14 | 14 | ||
| 15 | obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o | 15 | obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o |
| 16 | obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o | 16 | obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o |
| 17 | 17 | ||
| 18 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 18 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
| 19 | obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o | 19 | obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o |
| @@ -21,6 +21,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | |||
| 21 | 21 | ||
| 22 | # machine support | 22 | # machine support |
| 23 | 23 | ||
| 24 | obj-$(CONFIG_MACH_SMDKC210) += mach-smdkc210.o | ||
| 24 | obj-$(CONFIG_MACH_SMDKV310) += mach-smdkv310.o | 25 | obj-$(CONFIG_MACH_SMDKV310) += mach-smdkv310.o |
| 25 | obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o | 26 | obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o |
| 26 | 27 | ||
| @@ -28,3 +29,10 @@ obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o | |||
| 28 | 29 | ||
| 29 | obj-$(CONFIG_S5PV310_SETUP_I2C1) += setup-i2c1.o | 30 | obj-$(CONFIG_S5PV310_SETUP_I2C1) += setup-i2c1.o |
| 30 | obj-$(CONFIG_S5PV310_SETUP_I2C2) += setup-i2c2.o | 31 | obj-$(CONFIG_S5PV310_SETUP_I2C2) += setup-i2c2.o |
| 32 | obj-$(CONFIG_S5PV310_SETUP_I2C3) += setup-i2c3.o | ||
| 33 | obj-$(CONFIG_S5PV310_SETUP_I2C4) += setup-i2c4.o | ||
| 34 | obj-$(CONFIG_S5PV310_SETUP_I2C5) += setup-i2c5.o | ||
| 35 | obj-$(CONFIG_S5PV310_SETUP_I2C6) += setup-i2c6.o | ||
| 36 | obj-$(CONFIG_S5PV310_SETUP_I2C7) += setup-i2c7.o | ||
| 37 | obj-$(CONFIG_S5PV310_SETUP_SDHCI) += setup-sdhci.o | ||
| 38 | obj-$(CONFIG_S5PV310_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o | ||
diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index 26a0f03df8ea..58c9d33f36fe 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c | |||
| @@ -30,16 +30,92 @@ static struct clk clk_sclk_hdmi27m = { | |||
| 30 | .rate = 27000000, | 30 | .rate = 27000000, |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | static struct clk clk_sclk_hdmiphy = { | ||
| 34 | .name = "sclk_hdmiphy", | ||
| 35 | .id = -1, | ||
| 36 | }; | ||
| 37 | |||
| 38 | static struct clk clk_sclk_usbphy0 = { | ||
| 39 | .name = "sclk_usbphy0", | ||
| 40 | .id = -1, | ||
| 41 | .rate = 27000000, | ||
| 42 | }; | ||
| 43 | |||
| 44 | static struct clk clk_sclk_usbphy1 = { | ||
| 45 | .name = "sclk_usbphy1", | ||
| 46 | .id = -1, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static int s5pv310_clksrc_mask_top_ctrl(struct clk *clk, int enable) | ||
| 50 | { | ||
| 51 | return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable); | ||
| 52 | } | ||
| 53 | |||
| 54 | static int s5pv310_clksrc_mask_cam_ctrl(struct clk *clk, int enable) | ||
| 55 | { | ||
| 56 | return s5p_gatectrl(S5P_CLKSRC_MASK_CAM, clk, enable); | ||
| 57 | } | ||
| 58 | |||
| 59 | static int s5pv310_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable) | ||
| 60 | { | ||
| 61 | return s5p_gatectrl(S5P_CLKSRC_MASK_LCD0, clk, enable); | ||
| 62 | } | ||
| 63 | |||
| 64 | static int s5pv310_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable) | ||
| 65 | { | ||
| 66 | return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable); | ||
| 67 | } | ||
| 68 | |||
| 69 | static int s5pv310_clksrc_mask_fsys_ctrl(struct clk *clk, int enable) | ||
| 70 | { | ||
| 71 | return s5p_gatectrl(S5P_CLKSRC_MASK_FSYS, clk, enable); | ||
| 72 | } | ||
| 73 | |||
| 33 | static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable) | 74 | static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable) |
| 34 | { | 75 | { |
| 35 | return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable); | 76 | return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable); |
| 36 | } | 77 | } |
| 37 | 78 | ||
| 79 | static int s5pv310_clksrc_mask_peril1_ctrl(struct clk *clk, int enable) | ||
| 80 | { | ||
| 81 | return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL1, clk, enable); | ||
| 82 | } | ||
| 83 | |||
| 84 | static int s5pv310_clk_ip_cam_ctrl(struct clk *clk, int enable) | ||
| 85 | { | ||
| 86 | return s5p_gatectrl(S5P_CLKGATE_IP_CAM, clk, enable); | ||
| 87 | } | ||
| 88 | |||
| 89 | static int s5pv310_clk_ip_image_ctrl(struct clk *clk, int enable) | ||
| 90 | { | ||
| 91 | return s5p_gatectrl(S5P_CLKGATE_IP_IMAGE, clk, enable); | ||
| 92 | } | ||
| 93 | |||
| 94 | static int s5pv310_clk_ip_lcd0_ctrl(struct clk *clk, int enable) | ||
| 95 | { | ||
| 96 | return s5p_gatectrl(S5P_CLKGATE_IP_LCD0, clk, enable); | ||
| 97 | } | ||
| 98 | |||
| 99 | static int s5pv310_clk_ip_lcd1_ctrl(struct clk *clk, int enable) | ||
| 100 | { | ||
| 101 | return s5p_gatectrl(S5P_CLKGATE_IP_LCD1, clk, enable); | ||
| 102 | } | ||
| 103 | |||
| 104 | static int s5pv310_clk_ip_fsys_ctrl(struct clk *clk, int enable) | ||
| 105 | { | ||
| 106 | return s5p_gatectrl(S5P_CLKGATE_IP_FSYS, clk, enable); | ||
| 107 | } | ||
| 108 | |||
| 38 | static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable) | 109 | static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable) |
| 39 | { | 110 | { |
| 40 | return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable); | 111 | return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable); |
| 41 | } | 112 | } |
| 42 | 113 | ||
| 114 | static int s5pv310_clk_ip_perir_ctrl(struct clk *clk, int enable) | ||
| 115 | { | ||
| 116 | return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable); | ||
| 117 | } | ||
| 118 | |||
| 43 | /* Core list of CMU_CPU side */ | 119 | /* Core list of CMU_CPU side */ |
| 44 | 120 | ||
| 45 | static struct clksrc_clk clk_mout_apll = { | 121 | static struct clksrc_clk clk_mout_apll = { |
| @@ -79,7 +155,7 @@ static struct clksrc_clk clk_mout_mpll = { | |||
| 79 | }; | 155 | }; |
| 80 | 156 | ||
| 81 | static struct clk *clkset_moutcore_list[] = { | 157 | static struct clk *clkset_moutcore_list[] = { |
| 82 | [0] = &clk_sclk_apll.clk, | 158 | [0] = &clk_mout_apll.clk, |
| 83 | [1] = &clk_mout_mpll.clk, | 159 | [1] = &clk_mout_mpll.clk, |
| 84 | }; | 160 | }; |
| 85 | 161 | ||
| @@ -150,24 +226,6 @@ static struct clksrc_clk clk_periphclk = { | |||
| 150 | .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 }, | 226 | .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 }, |
| 151 | }; | 227 | }; |
| 152 | 228 | ||
| 153 | static struct clksrc_clk clk_atclk = { | ||
| 154 | .clk = { | ||
| 155 | .name = "atclk", | ||
| 156 | .id = -1, | ||
| 157 | .parent = &clk_moutcore.clk, | ||
| 158 | }, | ||
| 159 | .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 16, .size = 3 }, | ||
| 160 | }; | ||
| 161 | |||
| 162 | static struct clksrc_clk clk_pclk_dbg = { | ||
| 163 | .clk = { | ||
| 164 | .name = "pclk_dbg", | ||
| 165 | .id = -1, | ||
| 166 | .parent = &clk_atclk.clk, | ||
| 167 | }, | ||
| 168 | .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 20, .size = 3 }, | ||
| 169 | }; | ||
| 170 | |||
| 171 | /* Core list of CMU_CORE side */ | 229 | /* Core list of CMU_CORE side */ |
| 172 | 230 | ||
| 173 | static struct clk *clkset_corebus_list[] = { | 231 | static struct clk *clkset_corebus_list[] = { |
| @@ -241,7 +299,7 @@ static struct clk *clkset_aclk_top_list[] = { | |||
| 241 | [1] = &clk_sclk_apll.clk, | 299 | [1] = &clk_sclk_apll.clk, |
| 242 | }; | 300 | }; |
| 243 | 301 | ||
| 244 | static struct clksrc_sources clkset_aclk_200 = { | 302 | static struct clksrc_sources clkset_aclk = { |
| 245 | .sources = clkset_aclk_top_list, | 303 | .sources = clkset_aclk_top_list, |
| 246 | .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), | 304 | .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), |
| 247 | }; | 305 | }; |
| @@ -251,52 +309,37 @@ static struct clksrc_clk clk_aclk_200 = { | |||
| 251 | .name = "aclk_200", | 309 | .name = "aclk_200", |
| 252 | .id = -1, | 310 | .id = -1, |
| 253 | }, | 311 | }, |
| 254 | .sources = &clkset_aclk_200, | 312 | .sources = &clkset_aclk, |
| 255 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 }, | 313 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 }, |
| 256 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 }, | 314 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 }, |
| 257 | }; | 315 | }; |
| 258 | 316 | ||
| 259 | static struct clksrc_sources clkset_aclk_100 = { | ||
| 260 | .sources = clkset_aclk_top_list, | ||
| 261 | .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), | ||
| 262 | }; | ||
| 263 | |||
| 264 | static struct clksrc_clk clk_aclk_100 = { | 317 | static struct clksrc_clk clk_aclk_100 = { |
| 265 | .clk = { | 318 | .clk = { |
| 266 | .name = "aclk_100", | 319 | .name = "aclk_100", |
| 267 | .id = -1, | 320 | .id = -1, |
| 268 | }, | 321 | }, |
| 269 | .sources = &clkset_aclk_100, | 322 | .sources = &clkset_aclk, |
| 270 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 }, | 323 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 }, |
| 271 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 }, | 324 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 }, |
| 272 | }; | 325 | }; |
| 273 | 326 | ||
| 274 | static struct clksrc_sources clkset_aclk_160 = { | ||
| 275 | .sources = clkset_aclk_top_list, | ||
| 276 | .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), | ||
| 277 | }; | ||
| 278 | |||
| 279 | static struct clksrc_clk clk_aclk_160 = { | 327 | static struct clksrc_clk clk_aclk_160 = { |
| 280 | .clk = { | 328 | .clk = { |
| 281 | .name = "aclk_160", | 329 | .name = "aclk_160", |
| 282 | .id = -1, | 330 | .id = -1, |
| 283 | }, | 331 | }, |
| 284 | .sources = &clkset_aclk_160, | 332 | .sources = &clkset_aclk, |
| 285 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 }, | 333 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 }, |
| 286 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 }, | 334 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 }, |
| 287 | }; | 335 | }; |
| 288 | 336 | ||
| 289 | static struct clksrc_sources clkset_aclk_133 = { | ||
| 290 | .sources = clkset_aclk_top_list, | ||
| 291 | .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), | ||
| 292 | }; | ||
| 293 | |||
| 294 | static struct clksrc_clk clk_aclk_133 = { | 337 | static struct clksrc_clk clk_aclk_133 = { |
| 295 | .clk = { | 338 | .clk = { |
| 296 | .name = "aclk_133", | 339 | .name = "aclk_133", |
| 297 | .id = -1, | 340 | .id = -1, |
| 298 | }, | 341 | }, |
| 299 | .sources = &clkset_aclk_133, | 342 | .sources = &clkset_aclk, |
| 300 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 }, | 343 | .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 }, |
| 301 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 }, | 344 | .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 }, |
| 302 | }; | 345 | }; |
| @@ -315,6 +358,8 @@ static struct clksrc_clk clk_vpllsrc = { | |||
| 315 | .clk = { | 358 | .clk = { |
| 316 | .name = "vpll_src", | 359 | .name = "vpll_src", |
| 317 | .id = -1, | 360 | .id = -1, |
| 361 | .enable = s5pv310_clksrc_mask_top_ctrl, | ||
| 362 | .ctrlbit = (1 << 0), | ||
| 318 | }, | 363 | }, |
| 319 | .sources = &clkset_vpllsrc, | 364 | .sources = &clkset_vpllsrc, |
| 320 | .reg_src = { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 }, | 365 | .reg_src = { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 }, |
| @@ -346,7 +391,175 @@ static struct clk init_clocks_disable[] = { | |||
| 346 | .parent = &clk_aclk_100.clk, | 391 | .parent = &clk_aclk_100.clk, |
| 347 | .enable = s5pv310_clk_ip_peril_ctrl, | 392 | .enable = s5pv310_clk_ip_peril_ctrl, |
| 348 | .ctrlbit = (1<<24), | 393 | .ctrlbit = (1<<24), |
| 349 | } | 394 | }, { |
| 395 | .name = "csis", | ||
| 396 | .id = 0, | ||
| 397 | .enable = s5pv310_clk_ip_cam_ctrl, | ||
| 398 | .ctrlbit = (1 << 4), | ||
| 399 | }, { | ||
| 400 | .name = "csis", | ||
| 401 | .id = 1, | ||
| 402 | .enable = s5pv310_clk_ip_cam_ctrl, | ||
| 403 | .ctrlbit = (1 << 5), | ||
| 404 | }, { | ||
| 405 | .name = "fimc", | ||
| 406 | .id = 0, | ||
| 407 | .enable = s5pv310_clk_ip_cam_ctrl, | ||
| 408 | .ctrlbit = (1 << 0), | ||
| 409 | }, { | ||
| 410 | .name = "fimc", | ||
| 411 | .id = 1, | ||
| 412 | .enable = s5pv310_clk_ip_cam_ctrl, | ||
| 413 | .ctrlbit = (1 << 1), | ||
| 414 | }, { | ||
| 415 | .name = "fimc", | ||
| 416 | .id = 2, | ||
| 417 | .enable = s5pv310_clk_ip_cam_ctrl, | ||
| 418 | .ctrlbit = (1 << 2), | ||
| 419 | }, { | ||
| 420 | .name = "fimc", | ||
| 421 | .id = 3, | ||
| 422 | .enable = s5pv310_clk_ip_cam_ctrl, | ||
| 423 | .ctrlbit = (1 << 3), | ||
| 424 | }, { | ||
| 425 | .name = "fimd", | ||
| 426 | .id = 0, | ||
| 427 | .enable = s5pv310_clk_ip_lcd0_ctrl, | ||
| 428 | .ctrlbit = (1 << 0), | ||
| 429 | }, { | ||
| 430 | .name = "fimd", | ||
| 431 | .id = 1, | ||
| 432 | .enable = s5pv310_clk_ip_lcd1_ctrl, | ||
| 433 | .ctrlbit = (1 << 0), | ||
| 434 | }, { | ||
| 435 | .name = "hsmmc", | ||
| 436 | .id = 0, | ||
| 437 | .parent = &clk_aclk_133.clk, | ||
| 438 | .enable = s5pv310_clk_ip_fsys_ctrl, | ||
| 439 | .ctrlbit = (1 << 5), | ||
| 440 | }, { | ||
| 441 | .name = "hsmmc", | ||
| 442 | .id = 1, | ||
| 443 | .parent = &clk_aclk_133.clk, | ||
| 444 | .enable = s5pv310_clk_ip_fsys_ctrl, | ||
| 445 | .ctrlbit = (1 << 6), | ||
| 446 | }, { | ||
| 447 | .name = "hsmmc", | ||
| 448 | .id = 2, | ||
| 449 | .parent = &clk_aclk_133.clk, | ||
| 450 | .enable = s5pv310_clk_ip_fsys_ctrl, | ||
| 451 | .ctrlbit = (1 << 7), | ||
| 452 | }, { | ||
| 453 | .name = "hsmmc", | ||
| 454 | .id = 3, | ||
| 455 | .parent = &clk_aclk_133.clk, | ||
| 456 | .enable = s5pv310_clk_ip_fsys_ctrl, | ||
| 457 | .ctrlbit = (1 << 8), | ||
| 458 | }, { | ||
| 459 | .name = "hsmmc", | ||
| 460 | .id = 4, | ||
| 461 | .parent = &clk_aclk_133.clk, | ||
| 462 | .enable = s5pv310_clk_ip_fsys_ctrl, | ||
| 463 | .ctrlbit = (1 << 9), | ||
| 464 | }, { | ||
| 465 | .name = "sata", | ||
| 466 | .id = -1, | ||
| 467 | .enable = s5pv310_clk_ip_fsys_ctrl, | ||
| 468 | .ctrlbit = (1 << 10), | ||
| 469 | }, { | ||
| 470 | .name = "adc", | ||
| 471 | .id = -1, | ||
| 472 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 473 | .ctrlbit = (1 << 15), | ||
| 474 | }, { | ||
| 475 | .name = "rtc", | ||
| 476 | .id = -1, | ||
| 477 | .enable = s5pv310_clk_ip_perir_ctrl, | ||
| 478 | .ctrlbit = (1 << 15), | ||
| 479 | }, { | ||
| 480 | .name = "watchdog", | ||
| 481 | .id = -1, | ||
| 482 | .enable = s5pv310_clk_ip_perir_ctrl, | ||
| 483 | .ctrlbit = (1 << 14), | ||
| 484 | }, { | ||
| 485 | .name = "usbhost", | ||
| 486 | .id = -1, | ||
| 487 | .enable = s5pv310_clk_ip_fsys_ctrl , | ||
| 488 | .ctrlbit = (1 << 12), | ||
| 489 | }, { | ||
| 490 | .name = "otg", | ||
| 491 | .id = -1, | ||
| 492 | .enable = s5pv310_clk_ip_fsys_ctrl, | ||
| 493 | .ctrlbit = (1 << 13), | ||
| 494 | }, { | ||
| 495 | .name = "spi", | ||
| 496 | .id = 0, | ||
| 497 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 498 | .ctrlbit = (1 << 16), | ||
| 499 | }, { | ||
| 500 | .name = "spi", | ||
| 501 | .id = 1, | ||
| 502 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 503 | .ctrlbit = (1 << 17), | ||
| 504 | }, { | ||
| 505 | .name = "spi", | ||
| 506 | .id = 2, | ||
| 507 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 508 | .ctrlbit = (1 << 18), | ||
| 509 | }, { | ||
| 510 | .name = "fimg2d", | ||
| 511 | .id = -1, | ||
| 512 | .enable = s5pv310_clk_ip_image_ctrl, | ||
| 513 | .ctrlbit = (1 << 0), | ||
| 514 | }, { | ||
| 515 | .name = "i2c", | ||
| 516 | .id = 0, | ||
| 517 | .parent = &clk_aclk_100.clk, | ||
| 518 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 519 | .ctrlbit = (1 << 6), | ||
| 520 | }, { | ||
| 521 | .name = "i2c", | ||
| 522 | .id = 1, | ||
| 523 | .parent = &clk_aclk_100.clk, | ||
| 524 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 525 | .ctrlbit = (1 << 7), | ||
| 526 | }, { | ||
| 527 | .name = "i2c", | ||
| 528 | .id = 2, | ||
| 529 | .parent = &clk_aclk_100.clk, | ||
| 530 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 531 | .ctrlbit = (1 << 8), | ||
| 532 | }, { | ||
| 533 | .name = "i2c", | ||
| 534 | .id = 3, | ||
| 535 | .parent = &clk_aclk_100.clk, | ||
| 536 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 537 | .ctrlbit = (1 << 9), | ||
| 538 | }, { | ||
| 539 | .name = "i2c", | ||
| 540 | .id = 4, | ||
| 541 | .parent = &clk_aclk_100.clk, | ||
| 542 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 543 | .ctrlbit = (1 << 10), | ||
| 544 | }, { | ||
| 545 | .name = "i2c", | ||
| 546 | .id = 5, | ||
| 547 | .parent = &clk_aclk_100.clk, | ||
| 548 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 549 | .ctrlbit = (1 << 11), | ||
| 550 | }, { | ||
| 551 | .name = "i2c", | ||
| 552 | .id = 6, | ||
| 553 | .parent = &clk_aclk_100.clk, | ||
| 554 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 555 | .ctrlbit = (1 << 12), | ||
| 556 | }, { | ||
| 557 | .name = "i2c", | ||
| 558 | .id = 7, | ||
| 559 | .parent = &clk_aclk_100.clk, | ||
| 560 | .enable = s5pv310_clk_ip_peril_ctrl, | ||
| 561 | .ctrlbit = (1 << 13), | ||
| 562 | }, | ||
| 350 | }; | 563 | }; |
| 351 | 564 | ||
| 352 | static struct clk init_clocks[] = { | 565 | static struct clk init_clocks[] = { |
| @@ -387,6 +600,9 @@ static struct clk *clkset_group_list[] = { | |||
| 387 | [0] = &clk_ext_xtal_mux, | 600 | [0] = &clk_ext_xtal_mux, |
| 388 | [1] = &clk_xusbxti, | 601 | [1] = &clk_xusbxti, |
| 389 | [2] = &clk_sclk_hdmi27m, | 602 | [2] = &clk_sclk_hdmi27m, |
| 603 | [3] = &clk_sclk_usbphy0, | ||
| 604 | [4] = &clk_sclk_usbphy1, | ||
| 605 | [5] = &clk_sclk_hdmiphy, | ||
| 390 | [6] = &clk_mout_mpll.clk, | 606 | [6] = &clk_mout_mpll.clk, |
| 391 | [7] = &clk_mout_epll.clk, | 607 | [7] = &clk_mout_epll.clk, |
| 392 | [8] = &clk_sclk_vpll.clk, | 608 | [8] = &clk_sclk_vpll.clk, |
| @@ -397,6 +613,104 @@ static struct clksrc_sources clkset_group = { | |||
| 397 | .nr_sources = ARRAY_SIZE(clkset_group_list), | 613 | .nr_sources = ARRAY_SIZE(clkset_group_list), |
| 398 | }; | 614 | }; |
| 399 | 615 | ||
| 616 | static struct clk *clkset_mout_g2d0_list[] = { | ||
| 617 | [0] = &clk_mout_mpll.clk, | ||
| 618 | [1] = &clk_sclk_apll.clk, | ||
| 619 | }; | ||
| 620 | |||
| 621 | static struct clksrc_sources clkset_mout_g2d0 = { | ||
| 622 | .sources = clkset_mout_g2d0_list, | ||
| 623 | .nr_sources = ARRAY_SIZE(clkset_mout_g2d0_list), | ||
| 624 | }; | ||
| 625 | |||
| 626 | static struct clksrc_clk clk_mout_g2d0 = { | ||
| 627 | .clk = { | ||
| 628 | .name = "mout_g2d0", | ||
| 629 | .id = -1, | ||
| 630 | }, | ||
| 631 | .sources = &clkset_mout_g2d0, | ||
| 632 | .reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 0, .size = 1 }, | ||
| 633 | }; | ||
| 634 | |||
| 635 | static struct clk *clkset_mout_g2d1_list[] = { | ||
| 636 | [0] = &clk_mout_epll.clk, | ||
| 637 | [1] = &clk_sclk_vpll.clk, | ||
| 638 | }; | ||
| 639 | |||
| 640 | static struct clksrc_sources clkset_mout_g2d1 = { | ||
| 641 | .sources = clkset_mout_g2d1_list, | ||
| 642 | .nr_sources = ARRAY_SIZE(clkset_mout_g2d1_list), | ||
| 643 | }; | ||
| 644 | |||
| 645 | static struct clksrc_clk clk_mout_g2d1 = { | ||
| 646 | .clk = { | ||
| 647 | .name = "mout_g2d1", | ||
| 648 | .id = -1, | ||
| 649 | }, | ||
| 650 | .sources = &clkset_mout_g2d1, | ||
| 651 | .reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 4, .size = 1 }, | ||
| 652 | }; | ||
| 653 | |||
| 654 | static struct clk *clkset_mout_g2d_list[] = { | ||
| 655 | [0] = &clk_mout_g2d0.clk, | ||
| 656 | [1] = &clk_mout_g2d1.clk, | ||
| 657 | }; | ||
| 658 | |||
| 659 | static struct clksrc_sources clkset_mout_g2d = { | ||
| 660 | .sources = clkset_mout_g2d_list, | ||
| 661 | .nr_sources = ARRAY_SIZE(clkset_mout_g2d_list), | ||
| 662 | }; | ||
| 663 | |||
| 664 | static struct clksrc_clk clk_dout_mmc0 = { | ||
| 665 | .clk = { | ||
| 666 | .name = "dout_mmc0", | ||
| 667 | .id = -1, | ||
| 668 | }, | ||
| 669 | .sources = &clkset_group, | ||
| 670 | .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 0, .size = 4 }, | ||
| 671 | .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 0, .size = 4 }, | ||
| 672 | }; | ||
| 673 | |||
| 674 | static struct clksrc_clk clk_dout_mmc1 = { | ||
| 675 | .clk = { | ||
| 676 | .name = "dout_mmc1", | ||
| 677 | .id = -1, | ||
| 678 | }, | ||
| 679 | .sources = &clkset_group, | ||
| 680 | .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 4, .size = 4 }, | ||
| 681 | .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 16, .size = 4 }, | ||
| 682 | }; | ||
| 683 | |||
| 684 | static struct clksrc_clk clk_dout_mmc2 = { | ||
| 685 | .clk = { | ||
| 686 | .name = "dout_mmc2", | ||
| 687 | .id = -1, | ||
| 688 | }, | ||
| 689 | .sources = &clkset_group, | ||
| 690 | .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 8, .size = 4 }, | ||
| 691 | .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 0, .size = 4 }, | ||
| 692 | }; | ||
| 693 | |||
| 694 | static struct clksrc_clk clk_dout_mmc3 = { | ||
| 695 | .clk = { | ||
| 696 | .name = "dout_mmc3", | ||
| 697 | .id = -1, | ||
| 698 | }, | ||
| 699 | .sources = &clkset_group, | ||
| 700 | .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 12, .size = 4 }, | ||
| 701 | .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 16, .size = 4 }, | ||
| 702 | }; | ||
| 703 | |||
| 704 | static struct clksrc_clk clk_dout_mmc4 = { | ||
| 705 | .clk = { | ||
| 706 | .name = "dout_mmc4", | ||
| 707 | .id = -1, | ||
| 708 | }, | ||
| 709 | .sources = &clkset_group, | ||
| 710 | .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 16, .size = 4 }, | ||
| 711 | .reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 0, .size = 4 }, | ||
| 712 | }; | ||
| 713 | |||
| 400 | static struct clksrc_clk clksrcs[] = { | 714 | static struct clksrc_clk clksrcs[] = { |
| 401 | { | 715 | { |
| 402 | .clk = { | 716 | .clk = { |
| @@ -448,7 +762,200 @@ static struct clksrc_clk clksrcs[] = { | |||
| 448 | .sources = &clkset_group, | 762 | .sources = &clkset_group, |
| 449 | .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 }, | 763 | .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 }, |
| 450 | .reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 }, | 764 | .reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 }, |
| 451 | }, | 765 | }, { |
| 766 | .clk = { | ||
| 767 | .name = "sclk_csis", | ||
| 768 | .id = 0, | ||
| 769 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 770 | .ctrlbit = (1 << 24), | ||
| 771 | }, | ||
| 772 | .sources = &clkset_group, | ||
| 773 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 24, .size = 4 }, | ||
| 774 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 24, .size = 4 }, | ||
| 775 | }, { | ||
| 776 | .clk = { | ||
| 777 | .name = "sclk_csis", | ||
| 778 | .id = 1, | ||
| 779 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 780 | .ctrlbit = (1 << 28), | ||
| 781 | }, | ||
| 782 | .sources = &clkset_group, | ||
| 783 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 28, .size = 4 }, | ||
| 784 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 28, .size = 4 }, | ||
| 785 | }, { | ||
| 786 | .clk = { | ||
| 787 | .name = "sclk_cam", | ||
| 788 | .id = 0, | ||
| 789 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 790 | .ctrlbit = (1 << 16), | ||
| 791 | }, | ||
| 792 | .sources = &clkset_group, | ||
| 793 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 16, .size = 4 }, | ||
| 794 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 16, .size = 4 }, | ||
| 795 | }, { | ||
| 796 | .clk = { | ||
| 797 | .name = "sclk_cam", | ||
| 798 | .id = 1, | ||
| 799 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 800 | .ctrlbit = (1 << 20), | ||
| 801 | }, | ||
| 802 | .sources = &clkset_group, | ||
| 803 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 20, .size = 4 }, | ||
| 804 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 20, .size = 4 }, | ||
| 805 | }, { | ||
| 806 | .clk = { | ||
| 807 | .name = "sclk_fimc", | ||
| 808 | .id = 0, | ||
| 809 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 810 | .ctrlbit = (1 << 0), | ||
| 811 | }, | ||
| 812 | .sources = &clkset_group, | ||
| 813 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 0, .size = 4 }, | ||
| 814 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 0, .size = 4 }, | ||
| 815 | }, { | ||
| 816 | .clk = { | ||
| 817 | .name = "sclk_fimc", | ||
| 818 | .id = 1, | ||
| 819 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 820 | .ctrlbit = (1 << 4), | ||
| 821 | }, | ||
| 822 | .sources = &clkset_group, | ||
| 823 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 4, .size = 4 }, | ||
| 824 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 4, .size = 4 }, | ||
| 825 | }, { | ||
| 826 | .clk = { | ||
| 827 | .name = "sclk_fimc", | ||
| 828 | .id = 2, | ||
| 829 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 830 | .ctrlbit = (1 << 8), | ||
| 831 | }, | ||
| 832 | .sources = &clkset_group, | ||
| 833 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 8, .size = 4 }, | ||
| 834 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 8, .size = 4 }, | ||
| 835 | }, { | ||
| 836 | .clk = { | ||
| 837 | .name = "sclk_fimc", | ||
| 838 | .id = 3, | ||
| 839 | .enable = s5pv310_clksrc_mask_cam_ctrl, | ||
| 840 | .ctrlbit = (1 << 12), | ||
| 841 | }, | ||
| 842 | .sources = &clkset_group, | ||
| 843 | .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 12, .size = 4 }, | ||
| 844 | .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 12, .size = 4 }, | ||
| 845 | }, { | ||
| 846 | .clk = { | ||
| 847 | .name = "sclk_fimd", | ||
| 848 | .id = 0, | ||
| 849 | .enable = s5pv310_clksrc_mask_lcd0_ctrl, | ||
| 850 | .ctrlbit = (1 << 0), | ||
| 851 | }, | ||
| 852 | .sources = &clkset_group, | ||
| 853 | .reg_src = { .reg = S5P_CLKSRC_LCD0, .shift = 0, .size = 4 }, | ||
| 854 | .reg_div = { .reg = S5P_CLKDIV_LCD0, .shift = 0, .size = 4 }, | ||
| 855 | }, { | ||
| 856 | .clk = { | ||
| 857 | .name = "sclk_fimd", | ||
| 858 | .id = 1, | ||
| 859 | .enable = s5pv310_clksrc_mask_lcd1_ctrl, | ||
| 860 | .ctrlbit = (1 << 0), | ||
| 861 | }, | ||
| 862 | .sources = &clkset_group, | ||
| 863 | .reg_src = { .reg = S5P_CLKSRC_LCD1, .shift = 0, .size = 4 }, | ||
| 864 | .reg_div = { .reg = S5P_CLKDIV_LCD1, .shift = 0, .size = 4 }, | ||
| 865 | }, { | ||
| 866 | .clk = { | ||
| 867 | .name = "sclk_sata", | ||
| 868 | .id = -1, | ||
| 869 | .enable = s5pv310_clksrc_mask_fsys_ctrl, | ||
| 870 | .ctrlbit = (1 << 24), | ||
| 871 | }, | ||
| 872 | .sources = &clkset_mout_corebus, | ||
| 873 | .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 24, .size = 1 }, | ||
| 874 | .reg_div = { .reg = S5P_CLKDIV_FSYS0, .shift = 20, .size = 4 }, | ||
| 875 | }, { | ||
| 876 | .clk = { | ||
| 877 | .name = "sclk_spi", | ||
| 878 | .id = 0, | ||
| 879 | .enable = s5pv310_clksrc_mask_peril1_ctrl, | ||
| 880 | .ctrlbit = (1 << 16), | ||
| 881 | }, | ||
| 882 | .sources = &clkset_group, | ||
| 883 | .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 16, .size = 4 }, | ||
| 884 | .reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 0, .size = 4 }, | ||
| 885 | }, { | ||
| 886 | .clk = { | ||
| 887 | .name = "sclk_spi", | ||
| 888 | .id = 1, | ||
| 889 | .enable = s5pv310_clksrc_mask_peril1_ctrl, | ||
| 890 | .ctrlbit = (1 << 20), | ||
| 891 | }, | ||
| 892 | .sources = &clkset_group, | ||
| 893 | .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 20, .size = 4 }, | ||
| 894 | .reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 16, .size = 4 }, | ||
| 895 | }, { | ||
| 896 | .clk = { | ||
| 897 | .name = "sclk_spi", | ||
| 898 | .id = 2, | ||
| 899 | .enable = s5pv310_clksrc_mask_peril1_ctrl, | ||
| 900 | .ctrlbit = (1 << 24), | ||
| 901 | }, | ||
| 902 | .sources = &clkset_group, | ||
| 903 | .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 24, .size = 4 }, | ||
| 904 | .reg_div = { .reg = S5P_CLKDIV_PERIL2, .shift = 0, .size = 4 }, | ||
| 905 | }, { | ||
| 906 | .clk = { | ||
| 907 | .name = "sclk_fimg2d", | ||
| 908 | .id = -1, | ||
| 909 | }, | ||
| 910 | .sources = &clkset_mout_g2d, | ||
| 911 | .reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 8, .size = 1 }, | ||
| 912 | .reg_div = { .reg = S5P_CLKDIV_IMAGE, .shift = 0, .size = 4 }, | ||
| 913 | }, { | ||
| 914 | .clk = { | ||
| 915 | .name = "sclk_mmc", | ||
| 916 | .id = 0, | ||
| 917 | .parent = &clk_dout_mmc0.clk, | ||
| 918 | .enable = s5pv310_clksrc_mask_fsys_ctrl, | ||
| 919 | .ctrlbit = (1 << 0), | ||
| 920 | }, | ||
| 921 | .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 }, | ||
| 922 | }, { | ||
| 923 | .clk = { | ||
| 924 | .name = "sclk_mmc", | ||
| 925 | .id = 1, | ||
| 926 | .parent = &clk_dout_mmc1.clk, | ||
| 927 | .enable = s5pv310_clksrc_mask_fsys_ctrl, | ||
| 928 | .ctrlbit = (1 << 4), | ||
| 929 | }, | ||
| 930 | .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 }, | ||
| 931 | }, { | ||
| 932 | .clk = { | ||
| 933 | .name = "sclk_mmc", | ||
| 934 | .id = 2, | ||
| 935 | .parent = &clk_dout_mmc2.clk, | ||
| 936 | .enable = s5pv310_clksrc_mask_fsys_ctrl, | ||
| 937 | .ctrlbit = (1 << 8), | ||
| 938 | }, | ||
| 939 | .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 }, | ||
| 940 | }, { | ||
| 941 | .clk = { | ||
| 942 | .name = "sclk_mmc", | ||
| 943 | .id = 3, | ||
| 944 | .parent = &clk_dout_mmc3.clk, | ||
| 945 | .enable = s5pv310_clksrc_mask_fsys_ctrl, | ||
| 946 | .ctrlbit = (1 << 12), | ||
| 947 | }, | ||
| 948 | .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 }, | ||
| 949 | }, { | ||
| 950 | .clk = { | ||
| 951 | .name = "sclk_mmc", | ||
| 952 | .id = 4, | ||
| 953 | .parent = &clk_dout_mmc4.clk, | ||
| 954 | .enable = s5pv310_clksrc_mask_fsys_ctrl, | ||
| 955 | .ctrlbit = (1 << 16), | ||
| 956 | }, | ||
| 957 | .reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 8, .size = 8 }, | ||
| 958 | } | ||
| 452 | }; | 959 | }; |
| 453 | 960 | ||
| 454 | /* Clock initialization code */ | 961 | /* Clock initialization code */ |
| @@ -464,8 +971,6 @@ static struct clksrc_clk *sysclks[] = { | |||
| 464 | &clk_aclk_cores, | 971 | &clk_aclk_cores, |
| 465 | &clk_aclk_corem1, | 972 | &clk_aclk_corem1, |
| 466 | &clk_periphclk, | 973 | &clk_periphclk, |
| 467 | &clk_atclk, | ||
| 468 | &clk_pclk_dbg, | ||
| 469 | &clk_mout_corebus, | 974 | &clk_mout_corebus, |
| 470 | &clk_sclk_dmc, | 975 | &clk_sclk_dmc, |
| 471 | &clk_aclk_cored, | 976 | &clk_aclk_cored, |
| @@ -478,6 +983,11 @@ static struct clksrc_clk *sysclks[] = { | |||
| 478 | &clk_aclk_100, | 983 | &clk_aclk_100, |
| 479 | &clk_aclk_160, | 984 | &clk_aclk_160, |
| 480 | &clk_aclk_133, | 985 | &clk_aclk_133, |
| 986 | &clk_dout_mmc0, | ||
| 987 | &clk_dout_mmc1, | ||
| 988 | &clk_dout_mmc2, | ||
| 989 | &clk_dout_mmc3, | ||
| 990 | &clk_dout_mmc4, | ||
| 481 | }; | 991 | }; |
| 482 | 992 | ||
| 483 | void __init_or_cpufreq s5pv310_setup_clocks(void) | 993 | void __init_or_cpufreq s5pv310_setup_clocks(void) |
| @@ -490,15 +1000,11 @@ void __init_or_cpufreq s5pv310_setup_clocks(void) | |||
| 490 | unsigned long vpllsrc; | 1000 | unsigned long vpllsrc; |
| 491 | unsigned long xtal; | 1001 | unsigned long xtal; |
| 492 | unsigned long armclk; | 1002 | unsigned long armclk; |
| 493 | unsigned long aclk_corem0; | ||
| 494 | unsigned long aclk_cores; | ||
| 495 | unsigned long aclk_corem1; | ||
| 496 | unsigned long periphclk; | ||
| 497 | unsigned long sclk_dmc; | 1003 | unsigned long sclk_dmc; |
| 498 | unsigned long aclk_cored; | 1004 | unsigned long aclk_200; |
| 499 | unsigned long aclk_corep; | 1005 | unsigned long aclk_100; |
| 500 | unsigned long aclk_acp; | 1006 | unsigned long aclk_160; |
| 501 | unsigned long pclk_acp; | 1007 | unsigned long aclk_133; |
| 502 | unsigned int ptr; | 1008 | unsigned int ptr; |
| 503 | 1009 | ||
| 504 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); | 1010 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); |
| @@ -529,26 +1035,21 @@ void __init_or_cpufreq s5pv310_setup_clocks(void) | |||
| 529 | apll, mpll, epll, vpll); | 1035 | apll, mpll, epll, vpll); |
| 530 | 1036 | ||
| 531 | armclk = clk_get_rate(&clk_armclk.clk); | 1037 | armclk = clk_get_rate(&clk_armclk.clk); |
| 532 | aclk_corem0 = clk_get_rate(&clk_aclk_corem0.clk); | ||
| 533 | aclk_cores = clk_get_rate(&clk_aclk_cores.clk); | ||
| 534 | aclk_corem1 = clk_get_rate(&clk_aclk_corem1.clk); | ||
| 535 | periphclk = clk_get_rate(&clk_periphclk.clk); | ||
| 536 | sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk); | 1038 | sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk); |
| 537 | aclk_cored = clk_get_rate(&clk_aclk_cored.clk); | 1039 | |
| 538 | aclk_corep = clk_get_rate(&clk_aclk_corep.clk); | 1040 | aclk_200 = clk_get_rate(&clk_aclk_200.clk); |
| 539 | aclk_acp = clk_get_rate(&clk_aclk_acp.clk); | 1041 | aclk_100 = clk_get_rate(&clk_aclk_100.clk); |
| 540 | pclk_acp = clk_get_rate(&clk_pclk_acp.clk); | 1042 | aclk_160 = clk_get_rate(&clk_aclk_160.clk); |
| 541 | 1043 | aclk_133 = clk_get_rate(&clk_aclk_133.clk); | |
| 542 | printk(KERN_INFO "S5PV310: ARMCLK=%ld, COREM0=%ld, CORES=%ld\n" | 1044 | |
| 543 | "COREM1=%ld, PERI=%ld, DMC=%ld, CORED=%ld\n" | 1045 | printk(KERN_INFO "S5PV310: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n" |
| 544 | "COREP=%ld, ACLK_ACP=%ld, PCLK_ACP=%ld", | 1046 | "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n", |
| 545 | armclk, aclk_corem0, aclk_cores, aclk_corem1, | 1047 | armclk, sclk_dmc, aclk_200, |
| 546 | periphclk, sclk_dmc, aclk_cored, aclk_corep, | 1048 | aclk_100, aclk_160, aclk_133); |
| 547 | aclk_acp, pclk_acp); | ||
| 548 | 1049 | ||
| 549 | clk_f.rate = armclk; | 1050 | clk_f.rate = armclk; |
| 550 | clk_h.rate = sclk_dmc; | 1051 | clk_h.rate = sclk_dmc; |
| 551 | clk_p.rate = periphclk; | 1052 | clk_p.rate = aclk_100; |
| 552 | 1053 | ||
| 553 | for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) | 1054 | for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) |
| 554 | s3c_set_clksrc(&clksrcs[ptr], true); | 1055 | s3c_set_clksrc(&clksrcs[ptr], true); |
diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c index 4add39853ff9..82ce4aa6d61a 100644 --- a/arch/arm/mach-s5pv310/cpu.c +++ b/arch/arm/mach-s5pv310/cpu.c | |||
| @@ -15,10 +15,12 @@ | |||
| 15 | #include <asm/mach/irq.h> | 15 | #include <asm/mach/irq.h> |
| 16 | 16 | ||
| 17 | #include <asm/proc-fns.h> | 17 | #include <asm/proc-fns.h> |
| 18 | #include <asm/hardware/cache-l2x0.h> | ||
| 18 | 19 | ||
| 19 | #include <plat/cpu.h> | 20 | #include <plat/cpu.h> |
| 20 | #include <plat/clock.h> | 21 | #include <plat/clock.h> |
| 21 | #include <plat/s5pv310.h> | 22 | #include <plat/s5pv310.h> |
| 23 | #include <plat/sdhci.h> | ||
| 22 | 24 | ||
| 23 | #include <mach/regs-irq.h> | 25 | #include <mach/regs-irq.h> |
| 24 | 26 | ||
| @@ -56,15 +58,30 @@ static struct map_desc s5pv310_iodesc[] __initdata = { | |||
| 56 | .length = SZ_4K, | 58 | .length = SZ_4K, |
| 57 | .type = MT_DEVICE, | 59 | .type = MT_DEVICE, |
| 58 | }, { | 60 | }, { |
| 59 | .virtual = (unsigned long)S5P_VA_GPIO, | 61 | .virtual = (unsigned long)S5P_VA_GPIO1, |
| 60 | .pfn = __phys_to_pfn(S5PV310_PA_GPIO1), | 62 | .pfn = __phys_to_pfn(S5PV310_PA_GPIO1), |
| 61 | .length = SZ_4K, | 63 | .length = SZ_4K, |
| 62 | .type = MT_DEVICE, | 64 | .type = MT_DEVICE, |
| 63 | }, { | 65 | }, { |
| 66 | .virtual = (unsigned long)S5P_VA_GPIO2, | ||
| 67 | .pfn = __phys_to_pfn(S5PV310_PA_GPIO2), | ||
| 68 | .length = SZ_4K, | ||
| 69 | .type = MT_DEVICE, | ||
| 70 | }, { | ||
| 71 | .virtual = (unsigned long)S5P_VA_GPIO3, | ||
| 72 | .pfn = __phys_to_pfn(S5PV310_PA_GPIO3), | ||
| 73 | .length = SZ_256, | ||
| 74 | .type = MT_DEVICE, | ||
| 75 | }, { | ||
| 64 | .virtual = (unsigned long)S3C_VA_UART, | 76 | .virtual = (unsigned long)S3C_VA_UART, |
| 65 | .pfn = __phys_to_pfn(S3C_PA_UART), | 77 | .pfn = __phys_to_pfn(S3C_PA_UART), |
| 66 | .length = SZ_512K, | 78 | .length = SZ_512K, |
| 67 | .type = MT_DEVICE, | 79 | .type = MT_DEVICE, |
| 80 | }, { | ||
| 81 | .virtual = (unsigned long)S5P_VA_SROMC, | ||
| 82 | .pfn = __phys_to_pfn(S5PV310_PA_SROMC), | ||
| 83 | .length = SZ_4K, | ||
| 84 | .type = MT_DEVICE, | ||
| 68 | }, | 85 | }, |
| 69 | }; | 86 | }; |
| 70 | 87 | ||
| @@ -83,6 +100,12 @@ static void s5pv310_idle(void) | |||
| 83 | void __init s5pv310_map_io(void) | 100 | void __init s5pv310_map_io(void) |
| 84 | { | 101 | { |
| 85 | iotable_init(s5pv310_iodesc, ARRAY_SIZE(s5pv310_iodesc)); | 102 | iotable_init(s5pv310_iodesc, ARRAY_SIZE(s5pv310_iodesc)); |
| 103 | |||
| 104 | /* initialize device information early */ | ||
| 105 | s5pv310_default_sdhci0(); | ||
| 106 | s5pv310_default_sdhci1(); | ||
| 107 | s5pv310_default_sdhci2(); | ||
| 108 | s5pv310_default_sdhci3(); | ||
| 86 | } | 109 | } |
| 87 | 110 | ||
| 88 | void __init s5pv310_init_clocks(int xtal) | 111 | void __init s5pv310_init_clocks(int xtal) |
| @@ -131,6 +154,28 @@ static int __init s5pv310_core_init(void) | |||
| 131 | 154 | ||
| 132 | core_initcall(s5pv310_core_init); | 155 | core_initcall(s5pv310_core_init); |
| 133 | 156 | ||
| 157 | #ifdef CONFIG_CACHE_L2X0 | ||
| 158 | static int __init s5pv310_l2x0_cache_init(void) | ||
| 159 | { | ||
| 160 | /* TAG, Data Latency Control: 2cycle */ | ||
| 161 | __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL); | ||
| 162 | __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); | ||
| 163 | |||
| 164 | /* L2X0 Prefetch Control */ | ||
| 165 | __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL); | ||
| 166 | |||
| 167 | /* L2X0 Power Control */ | ||
| 168 | __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN, | ||
| 169 | S5P_VA_L2CC + L2X0_POWER_CTRL); | ||
| 170 | |||
| 171 | l2x0_init(S5P_VA_L2CC, 0x7C070001, 0xC200ffff); | ||
| 172 | |||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | early_initcall(s5pv310_l2x0_cache_init); | ||
| 177 | #endif | ||
| 178 | |||
| 134 | int __init s5pv310_init(void) | 179 | int __init s5pv310_init(void) |
| 135 | { | 180 | { |
| 136 | printk(KERN_INFO "S5PV310: Initializing architecture\n"); | 181 | printk(KERN_INFO "S5PV310: Initializing architecture\n"); |
diff --git a/arch/arm/mach-s5pv310/gpiolib.c b/arch/arm/mach-s5pv310/gpiolib.c new file mode 100644 index 000000000000..55217b8923ec --- /dev/null +++ b/arch/arm/mach-s5pv310/gpiolib.c | |||
| @@ -0,0 +1,304 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv310/gpiolib.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S5PV310 - GPIOlib 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/kernel.h> | ||
| 14 | #include <linux/irq.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/gpio.h> | ||
| 17 | |||
| 18 | #include <mach/map.h> | ||
| 19 | |||
| 20 | #include <plat/gpio-core.h> | ||
| 21 | #include <plat/gpio-cfg.h> | ||
| 22 | #include <plat/gpio-cfg-helpers.h> | ||
| 23 | |||
| 24 | static struct s3c_gpio_cfg gpio_cfg = { | ||
| 25 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 26 | .set_pull = s3c_gpio_setpull_updown, | ||
| 27 | .get_pull = s3c_gpio_getpull_updown, | ||
| 28 | }; | ||
| 29 | |||
| 30 | static struct s3c_gpio_cfg gpio_cfg_noint = { | ||
| 31 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 32 | .set_pull = s3c_gpio_setpull_updown, | ||
| 33 | .get_pull = s3c_gpio_getpull_updown, | ||
| 34 | }; | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Following are the gpio banks in v310. | ||
| 38 | * | ||
| 39 | * The 'config' member when left to NULL, is initialized to the default | ||
| 40 | * structure gpio_cfg in the init function below. | ||
| 41 | * | ||
| 42 | * The 'base' member is also initialized in the init function below. | ||
| 43 | * Note: The initialization of 'base' member of s3c_gpio_chip structure | ||
| 44 | * uses the above macro and depends on the banks being listed in order here. | ||
| 45 | */ | ||
| 46 | static struct s3c_gpio_chip s5pv310_gpio_part1_4bit[] = { | ||
| 47 | { | ||
| 48 | .chip = { | ||
| 49 | .base = S5PV310_GPA0(0), | ||
| 50 | .ngpio = S5PV310_GPIO_A0_NR, | ||
| 51 | .label = "GPA0", | ||
| 52 | }, | ||
| 53 | }, { | ||
| 54 | .chip = { | ||
| 55 | .base = S5PV310_GPA1(0), | ||
| 56 | .ngpio = S5PV310_GPIO_A1_NR, | ||
| 57 | .label = "GPA1", | ||
| 58 | }, | ||
| 59 | }, { | ||
| 60 | .chip = { | ||
| 61 | .base = S5PV310_GPB(0), | ||
| 62 | .ngpio = S5PV310_GPIO_B_NR, | ||
| 63 | .label = "GPB", | ||
| 64 | }, | ||
| 65 | }, { | ||
| 66 | .chip = { | ||
| 67 | .base = S5PV310_GPC0(0), | ||
| 68 | .ngpio = S5PV310_GPIO_C0_NR, | ||
| 69 | .label = "GPC0", | ||
| 70 | }, | ||
| 71 | }, { | ||
| 72 | .chip = { | ||
| 73 | .base = S5PV310_GPC1(0), | ||
| 74 | .ngpio = S5PV310_GPIO_C1_NR, | ||
| 75 | .label = "GPC1", | ||
| 76 | }, | ||
| 77 | }, { | ||
| 78 | .chip = { | ||
| 79 | .base = S5PV310_GPD0(0), | ||
| 80 | .ngpio = S5PV310_GPIO_D0_NR, | ||
| 81 | .label = "GPD0", | ||
| 82 | }, | ||
| 83 | }, { | ||
| 84 | .chip = { | ||
| 85 | .base = S5PV310_GPD1(0), | ||
| 86 | .ngpio = S5PV310_GPIO_D1_NR, | ||
| 87 | .label = "GPD1", | ||
| 88 | }, | ||
| 89 | }, { | ||
| 90 | .chip = { | ||
| 91 | .base = S5PV310_GPE0(0), | ||
| 92 | .ngpio = S5PV310_GPIO_E0_NR, | ||
| 93 | .label = "GPE0", | ||
| 94 | }, | ||
| 95 | }, { | ||
| 96 | .chip = { | ||
| 97 | .base = S5PV310_GPE1(0), | ||
| 98 | .ngpio = S5PV310_GPIO_E1_NR, | ||
| 99 | .label = "GPE1", | ||
| 100 | }, | ||
| 101 | }, { | ||
| 102 | .chip = { | ||
| 103 | .base = S5PV310_GPE2(0), | ||
| 104 | .ngpio = S5PV310_GPIO_E2_NR, | ||
| 105 | .label = "GPE2", | ||
| 106 | }, | ||
| 107 | }, { | ||
| 108 | .chip = { | ||
| 109 | .base = S5PV310_GPE3(0), | ||
| 110 | .ngpio = S5PV310_GPIO_E3_NR, | ||
| 111 | .label = "GPE3", | ||
| 112 | }, | ||
| 113 | }, { | ||
| 114 | .chip = { | ||
| 115 | .base = S5PV310_GPE4(0), | ||
| 116 | .ngpio = S5PV310_GPIO_E4_NR, | ||
| 117 | .label = "GPE4", | ||
| 118 | }, | ||
| 119 | }, { | ||
| 120 | .chip = { | ||
| 121 | .base = S5PV310_GPF0(0), | ||
| 122 | .ngpio = S5PV310_GPIO_F0_NR, | ||
| 123 | .label = "GPF0", | ||
| 124 | }, | ||
| 125 | }, { | ||
| 126 | .chip = { | ||
| 127 | .base = S5PV310_GPF1(0), | ||
| 128 | .ngpio = S5PV310_GPIO_F1_NR, | ||
| 129 | .label = "GPF1", | ||
| 130 | }, | ||
| 131 | }, { | ||
| 132 | .chip = { | ||
| 133 | .base = S5PV310_GPF2(0), | ||
| 134 | .ngpio = S5PV310_GPIO_F2_NR, | ||
| 135 | .label = "GPF2", | ||
| 136 | }, | ||
| 137 | }, { | ||
| 138 | .chip = { | ||
| 139 | .base = S5PV310_GPF3(0), | ||
| 140 | .ngpio = S5PV310_GPIO_F3_NR, | ||
| 141 | .label = "GPF3", | ||
| 142 | }, | ||
| 143 | }, | ||
| 144 | }; | ||
| 145 | |||
| 146 | static struct s3c_gpio_chip s5pv310_gpio_part2_4bit[] = { | ||
| 147 | { | ||
| 148 | .chip = { | ||
| 149 | .base = S5PV310_GPJ0(0), | ||
| 150 | .ngpio = S5PV310_GPIO_J0_NR, | ||
| 151 | .label = "GPJ0", | ||
| 152 | }, | ||
| 153 | }, { | ||
| 154 | .chip = { | ||
| 155 | .base = S5PV310_GPJ1(0), | ||
| 156 | .ngpio = S5PV310_GPIO_J1_NR, | ||
| 157 | .label = "GPJ1", | ||
| 158 | }, | ||
| 159 | }, { | ||
| 160 | .chip = { | ||
| 161 | .base = S5PV310_GPK0(0), | ||
| 162 | .ngpio = S5PV310_GPIO_K0_NR, | ||
| 163 | .label = "GPK0", | ||
| 164 | }, | ||
| 165 | }, { | ||
| 166 | .chip = { | ||
| 167 | .base = S5PV310_GPK1(0), | ||
| 168 | .ngpio = S5PV310_GPIO_K1_NR, | ||
| 169 | .label = "GPK1", | ||
| 170 | }, | ||
| 171 | }, { | ||
| 172 | .chip = { | ||
| 173 | .base = S5PV310_GPK2(0), | ||
| 174 | .ngpio = S5PV310_GPIO_K2_NR, | ||
| 175 | .label = "GPK2", | ||
| 176 | }, | ||
| 177 | }, { | ||
| 178 | .chip = { | ||
| 179 | .base = S5PV310_GPK3(0), | ||
| 180 | .ngpio = S5PV310_GPIO_K3_NR, | ||
| 181 | .label = "GPK3", | ||
| 182 | }, | ||
| 183 | }, { | ||
| 184 | .chip = { | ||
| 185 | .base = S5PV310_GPL0(0), | ||
| 186 | .ngpio = S5PV310_GPIO_L0_NR, | ||
| 187 | .label = "GPL0", | ||
| 188 | }, | ||
| 189 | }, { | ||
| 190 | .chip = { | ||
| 191 | .base = S5PV310_GPL1(0), | ||
| 192 | .ngpio = S5PV310_GPIO_L1_NR, | ||
| 193 | .label = "GPL1", | ||
| 194 | }, | ||
| 195 | }, { | ||
| 196 | .chip = { | ||
| 197 | .base = S5PV310_GPL2(0), | ||
| 198 | .ngpio = S5PV310_GPIO_L2_NR, | ||
| 199 | .label = "GPL2", | ||
| 200 | }, | ||
| 201 | }, { | ||
| 202 | .base = (S5P_VA_GPIO2 + 0xC00), | ||
| 203 | .config = &gpio_cfg_noint, | ||
| 204 | .irq_base = IRQ_EINT(0), | ||
| 205 | .chip = { | ||
| 206 | .base = S5PV310_GPX0(0), | ||
| 207 | .ngpio = S5PV310_GPIO_X0_NR, | ||
| 208 | .label = "GPX0", | ||
| 209 | .to_irq = samsung_gpiolib_to_irq, | ||
| 210 | }, | ||
| 211 | }, { | ||
| 212 | .base = (S5P_VA_GPIO2 + 0xC20), | ||
| 213 | .config = &gpio_cfg_noint, | ||
| 214 | .irq_base = IRQ_EINT(8), | ||
| 215 | .chip = { | ||
| 216 | .base = S5PV310_GPX1(0), | ||
| 217 | .ngpio = S5PV310_GPIO_X1_NR, | ||
| 218 | .label = "GPX1", | ||
| 219 | .to_irq = samsung_gpiolib_to_irq, | ||
| 220 | }, | ||
| 221 | }, { | ||
| 222 | .base = (S5P_VA_GPIO2 + 0xC40), | ||
| 223 | .config = &gpio_cfg_noint, | ||
| 224 | .irq_base = IRQ_EINT(16), | ||
| 225 | .chip = { | ||
| 226 | .base = S5PV310_GPX2(0), | ||
| 227 | .ngpio = S5PV310_GPIO_X2_NR, | ||
| 228 | .label = "GPX2", | ||
| 229 | .to_irq = samsung_gpiolib_to_irq, | ||
| 230 | }, | ||
| 231 | }, { | ||
| 232 | .base = (S5P_VA_GPIO2 + 0xC60), | ||
| 233 | .config = &gpio_cfg_noint, | ||
| 234 | .irq_base = IRQ_EINT(24), | ||
| 235 | .chip = { | ||
| 236 | .base = S5PV310_GPX3(0), | ||
| 237 | .ngpio = S5PV310_GPIO_X3_NR, | ||
| 238 | .label = "GPX3", | ||
| 239 | .to_irq = samsung_gpiolib_to_irq, | ||
| 240 | }, | ||
| 241 | }, | ||
| 242 | }; | ||
| 243 | |||
| 244 | static struct s3c_gpio_chip s5pv310_gpio_part3_4bit[] = { | ||
| 245 | { | ||
| 246 | .chip = { | ||
| 247 | .base = S5PV310_GPZ(0), | ||
| 248 | .ngpio = S5PV310_GPIO_Z_NR, | ||
| 249 | .label = "GPZ", | ||
| 250 | }, | ||
| 251 | }, | ||
| 252 | }; | ||
| 253 | |||
| 254 | static __init int s5pv310_gpiolib_init(void) | ||
| 255 | { | ||
| 256 | struct s3c_gpio_chip *chip; | ||
| 257 | int i; | ||
| 258 | int nr_chips; | ||
| 259 | |||
| 260 | /* GPIO part 1 */ | ||
| 261 | |||
| 262 | chip = s5pv310_gpio_part1_4bit; | ||
| 263 | nr_chips = ARRAY_SIZE(s5pv310_gpio_part1_4bit); | ||
| 264 | |||
| 265 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 266 | if (chip->config == NULL) | ||
| 267 | chip->config = &gpio_cfg; | ||
| 268 | if (chip->base == NULL) | ||
| 269 | chip->base = S5P_VA_GPIO1 + (i) * 0x20; | ||
| 270 | } | ||
| 271 | |||
| 272 | samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part1_4bit, nr_chips); | ||
| 273 | |||
| 274 | /* GPIO part 2 */ | ||
| 275 | |||
| 276 | chip = s5pv310_gpio_part2_4bit; | ||
| 277 | nr_chips = ARRAY_SIZE(s5pv310_gpio_part2_4bit); | ||
| 278 | |||
| 279 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 280 | if (chip->config == NULL) | ||
| 281 | chip->config = &gpio_cfg; | ||
| 282 | if (chip->base == NULL) | ||
| 283 | chip->base = S5P_VA_GPIO2 + (i) * 0x20; | ||
| 284 | } | ||
| 285 | |||
| 286 | samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part2_4bit, nr_chips); | ||
| 287 | |||
| 288 | /* GPIO part 3 */ | ||
| 289 | |||
| 290 | chip = s5pv310_gpio_part3_4bit; | ||
| 291 | nr_chips = ARRAY_SIZE(s5pv310_gpio_part3_4bit); | ||
| 292 | |||
| 293 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 294 | if (chip->config == NULL) | ||
| 295 | chip->config = &gpio_cfg; | ||
| 296 | if (chip->base == NULL) | ||
| 297 | chip->base = S5P_VA_GPIO3 + (i) * 0x20; | ||
| 298 | } | ||
| 299 | |||
| 300 | samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part3_4bit, nr_chips); | ||
| 301 | |||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | core_initcall(s5pv310_gpiolib_init); | ||
diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c new file mode 100644 index 000000000000..03652c3605f6 --- /dev/null +++ b/arch/arm/mach-s5pv310/hotplug.c | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | /* linux arch/arm/mach-s5pv310/hotplug.c | ||
| 2 | * | ||
| 3 | * Cloned from linux/arch/arm/mach-realview/hotplug.c | ||
| 4 | * | ||
| 5 | * Copyright (C) 2002 ARM Ltd. | ||
| 6 | * All Rights Reserved | ||
| 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/kernel.h> | ||
| 14 | #include <linux/errno.h> | ||
| 15 | #include <linux/smp.h> | ||
| 16 | #include <linux/completion.h> | ||
| 17 | |||
| 18 | #include <asm/cacheflush.h> | ||
| 19 | |||
| 20 | extern volatile int pen_release; | ||
| 21 | |||
| 22 | static DECLARE_COMPLETION(cpu_killed); | ||
| 23 | |||
| 24 | static inline void cpu_enter_lowpower(void) | ||
| 25 | { | ||
| 26 | unsigned int v; | ||
| 27 | |||
| 28 | flush_cache_all(); | ||
| 29 | asm volatile( | ||
| 30 | " mcr p15, 0, %1, c7, c5, 0\n" | ||
| 31 | " mcr p15, 0, %1, c7, c10, 4\n" | ||
| 32 | /* | ||
| 33 | * Turn off coherency | ||
| 34 | */ | ||
| 35 | " mrc p15, 0, %0, c1, c0, 1\n" | ||
| 36 | " bic %0, %0, #0x20\n" | ||
| 37 | " mcr p15, 0, %0, c1, c0, 1\n" | ||
| 38 | " mrc p15, 0, %0, c1, c0, 0\n" | ||
| 39 | " bic %0, %0, #0x04\n" | ||
| 40 | " mcr p15, 0, %0, c1, c0, 0\n" | ||
| 41 | : "=&r" (v) | ||
| 42 | : "r" (0) | ||
| 43 | : "cc"); | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline void cpu_leave_lowpower(void) | ||
| 47 | { | ||
| 48 | unsigned int v; | ||
| 49 | |||
| 50 | asm volatile( | ||
| 51 | "mrc p15, 0, %0, c1, c0, 0\n" | ||
| 52 | " orr %0, %0, #0x04\n" | ||
| 53 | " mcr p15, 0, %0, c1, c0, 0\n" | ||
| 54 | " mrc p15, 0, %0, c1, c0, 1\n" | ||
| 55 | " orr %0, %0, #0x20\n" | ||
| 56 | " mcr p15, 0, %0, c1, c0, 1\n" | ||
| 57 | : "=&r" (v) | ||
| 58 | : | ||
| 59 | : "cc"); | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline void platform_do_lowpower(unsigned int cpu) | ||
| 63 | { | ||
| 64 | /* | ||
| 65 | * there is no power-control hardware on this platform, so all | ||
| 66 | * we can do is put the core into WFI; this is safe as the calling | ||
| 67 | * code will have already disabled interrupts | ||
| 68 | */ | ||
| 69 | for (;;) { | ||
| 70 | /* | ||
| 71 | * here's the WFI | ||
| 72 | */ | ||
| 73 | asm(".word 0xe320f003\n" | ||
| 74 | : | ||
| 75 | : | ||
| 76 | : "memory", "cc"); | ||
| 77 | |||
| 78 | if (pen_release == cpu) { | ||
| 79 | /* | ||
| 80 | * OK, proper wakeup, we're done | ||
| 81 | */ | ||
| 82 | break; | ||
| 83 | } | ||
| 84 | |||
| 85 | /* | ||
| 86 | * getting here, means that we have come out of WFI without | ||
| 87 | * having been woken up - this shouldn't happen | ||
| 88 | * | ||
| 89 | * The trouble is, letting people know about this is not really | ||
| 90 | * possible, since we are currently running incoherently, and | ||
| 91 | * therefore cannot safely call printk() or anything else | ||
| 92 | */ | ||
| 93 | #ifdef DEBUG | ||
| 94 | printk(KERN_WARN "CPU%u: spurious wakeup call\n", cpu); | ||
| 95 | #endif | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | int platform_cpu_kill(unsigned int cpu) | ||
| 100 | { | ||
| 101 | return wait_for_completion_timeout(&cpu_killed, 5000); | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * platform-specific code to shutdown a CPU | ||
| 106 | * | ||
| 107 | * Called with IRQs disabled | ||
| 108 | */ | ||
| 109 | void platform_cpu_die(unsigned int cpu) | ||
| 110 | { | ||
| 111 | #ifdef DEBUG | ||
| 112 | unsigned int this_cpu = hard_smp_processor_id(); | ||
| 113 | |||
| 114 | if (cpu != this_cpu) { | ||
| 115 | printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", | ||
| 116 | this_cpu, cpu); | ||
| 117 | BUG(); | ||
| 118 | } | ||
| 119 | #endif | ||
| 120 | |||
| 121 | printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); | ||
| 122 | complete(&cpu_killed); | ||
| 123 | |||
| 124 | /* | ||
| 125 | * we're ready for shutdown now, so do it | ||
| 126 | */ | ||
| 127 | cpu_enter_lowpower(); | ||
| 128 | platform_do_lowpower(cpu); | ||
| 129 | |||
| 130 | /* | ||
| 131 | * bring this CPU back into the world of cache | ||
| 132 | * coherency, and then restore interrupts | ||
| 133 | */ | ||
| 134 | cpu_leave_lowpower(); | ||
| 135 | } | ||
| 136 | |||
| 137 | int platform_cpu_disable(unsigned int cpu) | ||
| 138 | { | ||
| 139 | /* | ||
| 140 | * we don't allow CPU 0 to be shutdown (it is still too special | ||
| 141 | * e.g. clock tick interrupts) | ||
| 142 | */ | ||
| 143 | return cpu == 0 ? -EPERM : 0; | ||
| 144 | } | ||
diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h index 471fc3bb199a..99e7dad8a85a 100644 --- a/arch/arm/mach-s5pv310/include/mach/irqs.h +++ b/arch/arm/mach-s5pv310/include/mach/irqs.h | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. |
| 4 | * http://www.samsung.com/ | 4 | * http://www.samsung.com/ |
| 5 | * | 5 | * |
| 6 | * S5PV210 - IRQ definitions | 6 | * S5PV310 - IRQ definitions |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 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 | 9 | * it under the terms of the GNU General Public License version 2 as |
| @@ -60,6 +60,9 @@ | |||
| 60 | #define IRQ_TIMER3_VIC COMBINER_IRQ(22, 3) | 60 | #define IRQ_TIMER3_VIC COMBINER_IRQ(22, 3) |
| 61 | #define IRQ_TIMER4_VIC COMBINER_IRQ(22, 4) | 61 | #define IRQ_TIMER4_VIC COMBINER_IRQ(22, 4) |
| 62 | 62 | ||
| 63 | #define IRQ_RTC_ALARM COMBINER_IRQ(23, 0) | ||
| 64 | #define IRQ_RTC_TIC COMBINER_IRQ(23, 1) | ||
| 65 | |||
| 63 | #define IRQ_UART0 COMBINER_IRQ(26, 0) | 66 | #define IRQ_UART0 COMBINER_IRQ(26, 0) |
| 64 | #define IRQ_UART1 COMBINER_IRQ(26, 1) | 67 | #define IRQ_UART1 COMBINER_IRQ(26, 1) |
| 65 | #define IRQ_UART2 COMBINER_IRQ(26, 2) | 68 | #define IRQ_UART2 COMBINER_IRQ(26, 2) |
| @@ -67,13 +70,46 @@ | |||
| 67 | #define IRQ_UART4 COMBINER_IRQ(26, 4) | 70 | #define IRQ_UART4 COMBINER_IRQ(26, 4) |
| 68 | 71 | ||
| 69 | #define IRQ_IIC COMBINER_IRQ(27, 0) | 72 | #define IRQ_IIC COMBINER_IRQ(27, 0) |
| 73 | #define IRQ_IIC1 COMBINER_IRQ(27, 1) | ||
| 74 | #define IRQ_IIC2 COMBINER_IRQ(27, 2) | ||
| 75 | #define IRQ_IIC3 COMBINER_IRQ(27, 3) | ||
| 76 | #define IRQ_IIC4 COMBINER_IRQ(27, 4) | ||
| 77 | #define IRQ_IIC5 COMBINER_IRQ(27, 5) | ||
| 78 | #define IRQ_IIC6 COMBINER_IRQ(27, 6) | ||
| 79 | #define IRQ_IIC7 COMBINER_IRQ(27, 7) | ||
| 80 | |||
| 81 | #define IRQ_HSMMC0 COMBINER_IRQ(29, 0) | ||
| 82 | #define IRQ_HSMMC1 COMBINER_IRQ(29, 1) | ||
| 83 | #define IRQ_HSMMC2 COMBINER_IRQ(29, 2) | ||
| 84 | #define IRQ_HSMMC3 COMBINER_IRQ(29, 3) | ||
| 70 | 85 | ||
| 71 | #define IRQ_ONENAND_AUDI COMBINER_IRQ(34, 0) | 86 | #define IRQ_ONENAND_AUDI COMBINER_IRQ(34, 0) |
| 72 | 87 | ||
| 73 | /* Set the default NR_IRQS */ | 88 | #define IRQ_EINT4 COMBINER_IRQ(37, 0) |
| 89 | #define IRQ_EINT5 COMBINER_IRQ(37, 1) | ||
| 90 | #define IRQ_EINT6 COMBINER_IRQ(37, 2) | ||
| 91 | #define IRQ_EINT7 COMBINER_IRQ(37, 3) | ||
| 92 | #define IRQ_EINT8 COMBINER_IRQ(38, 0) | ||
| 93 | |||
| 94 | #define IRQ_EINT9 COMBINER_IRQ(38, 1) | ||
| 95 | #define IRQ_EINT10 COMBINER_IRQ(38, 2) | ||
| 96 | #define IRQ_EINT11 COMBINER_IRQ(38, 3) | ||
| 97 | #define IRQ_EINT12 COMBINER_IRQ(38, 4) | ||
| 98 | #define IRQ_EINT13 COMBINER_IRQ(38, 5) | ||
| 99 | #define IRQ_EINT14 COMBINER_IRQ(38, 6) | ||
| 100 | #define IRQ_EINT15 COMBINER_IRQ(38, 7) | ||
| 101 | |||
| 102 | #define IRQ_EINT16_31 COMBINER_IRQ(39, 0) | ||
| 74 | 103 | ||
| 75 | #define NR_IRQS COMBINER_IRQ(MAX_COMBINER_NR, 0) | 104 | #define MAX_COMBINER_NR 40 |
| 105 | |||
| 106 | #define S5P_IRQ_EINT_BASE COMBINER_IRQ(MAX_COMBINER_NR, 0) | ||
| 107 | |||
| 108 | #define S5P_EINT_BASE1 (S5P_IRQ_EINT_BASE + 0) | ||
| 109 | #define S5P_EINT_BASE2 (S5P_IRQ_EINT_BASE + 16) | ||
| 110 | |||
| 111 | /* Set the default NR_IRQS */ | ||
| 76 | 112 | ||
| 77 | #define MAX_COMBINER_NR 39 | 113 | #define NR_IRQS (S5P_IRQ_EINT_BASE + 32) |
| 78 | 114 | ||
| 79 | #endif /* __ASM_ARCH_IRQS_H */ | 115 | #endif /* __ASM_ARCH_IRQS_H */ |
diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h index aff6d23624bb..7acf4e77e92e 100644 --- a/arch/arm/mach-s5pv310/include/mach/map.h +++ b/arch/arm/mach-s5pv310/include/mach/map.h | |||
| @@ -25,6 +25,8 @@ | |||
| 25 | 25 | ||
| 26 | #define S5PV310_PA_SYSRAM (0x02025000) | 26 | #define S5PV310_PA_SYSRAM (0x02025000) |
| 27 | 27 | ||
| 28 | #define S5PV310_PA_SROM_BANK(x) (0x04000000 + ((x) * 0x01000000)) | ||
| 29 | |||
| 28 | #define S5PC210_PA_ONENAND (0x0C000000) | 30 | #define S5PC210_PA_ONENAND (0x0C000000) |
| 29 | #define S5P_PA_ONENAND S5PC210_PA_ONENAND | 31 | #define S5P_PA_ONENAND S5PC210_PA_ONENAND |
| 30 | 32 | ||
| @@ -34,12 +36,13 @@ | |||
| 34 | #define S5PV310_PA_CHIPID (0x10000000) | 36 | #define S5PV310_PA_CHIPID (0x10000000) |
| 35 | #define S5P_PA_CHIPID S5PV310_PA_CHIPID | 37 | #define S5P_PA_CHIPID S5PV310_PA_CHIPID |
| 36 | 38 | ||
| 37 | #define S5PV310_PA_SYSCON (0x10020000) | 39 | #define S5PV310_PA_SYSCON (0x10010000) |
| 38 | #define S5P_PA_SYSCON S5PV310_PA_SYSCON | 40 | #define S5P_PA_SYSCON S5PV310_PA_SYSCON |
| 39 | 41 | ||
| 40 | #define S5PV310_PA_CMU (0x10030000) | 42 | #define S5PV310_PA_CMU (0x10030000) |
| 41 | 43 | ||
| 42 | #define S5PV310_PA_WATCHDOG (0x10060000) | 44 | #define S5PV310_PA_WATCHDOG (0x10060000) |
| 45 | #define S5PV310_PA_RTC (0x10070000) | ||
| 43 | 46 | ||
| 44 | #define S5PV310_PA_COMBINER (0x10448000) | 47 | #define S5PV310_PA_COMBINER (0x10448000) |
| 45 | 48 | ||
| @@ -55,6 +58,8 @@ | |||
| 55 | 58 | ||
| 56 | #define S5PV310_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000)) | 59 | #define S5PV310_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000)) |
| 57 | 60 | ||
| 61 | #define S5PV310_PA_SROMC (0x12570000) | ||
| 62 | |||
| 58 | #define S5PV310_PA_UART (0x13800000) | 63 | #define S5PV310_PA_UART (0x13800000) |
| 59 | 64 | ||
| 60 | #define S5P_PA_UART(x) (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET)) | 65 | #define S5P_PA_UART(x) (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET)) |
| @@ -66,7 +71,7 @@ | |||
| 66 | 71 | ||
| 67 | #define S5P_SZ_UART SZ_256 | 72 | #define S5P_SZ_UART SZ_256 |
| 68 | 73 | ||
| 69 | #define S5PV310_PA_IIC0 (0x13860000) | 74 | #define S5PV310_PA_IIC(x) (0x13860000 + ((x) * 0x10000)) |
| 70 | 75 | ||
| 71 | #define S5PV310_PA_TIMER (0x139D0000) | 76 | #define S5PV310_PA_TIMER (0x139D0000) |
| 72 | #define S5P_PA_TIMER S5PV310_PA_TIMER | 77 | #define S5P_PA_TIMER S5PV310_PA_TIMER |
| @@ -80,7 +85,15 @@ | |||
| 80 | #define S3C_PA_HSMMC1 S5PV310_PA_HSMMC(1) | 85 | #define S3C_PA_HSMMC1 S5PV310_PA_HSMMC(1) |
| 81 | #define S3C_PA_HSMMC2 S5PV310_PA_HSMMC(2) | 86 | #define S3C_PA_HSMMC2 S5PV310_PA_HSMMC(2) |
| 82 | #define S3C_PA_HSMMC3 S5PV310_PA_HSMMC(3) | 87 | #define S3C_PA_HSMMC3 S5PV310_PA_HSMMC(3) |
| 83 | #define S3C_PA_IIC S5PV310_PA_IIC0 | 88 | #define S3C_PA_IIC S5PV310_PA_IIC(0) |
| 89 | #define S3C_PA_IIC1 S5PV310_PA_IIC(1) | ||
| 90 | #define S3C_PA_IIC2 S5PV310_PA_IIC(2) | ||
| 91 | #define S3C_PA_IIC3 S5PV310_PA_IIC(3) | ||
| 92 | #define S3C_PA_IIC4 S5PV310_PA_IIC(4) | ||
| 93 | #define S3C_PA_IIC5 S5PV310_PA_IIC(5) | ||
| 94 | #define S3C_PA_IIC6 S5PV310_PA_IIC(6) | ||
| 95 | #define S3C_PA_IIC7 S5PV310_PA_IIC(7) | ||
| 96 | #define S3C_PA_RTC S5PV310_PA_RTC | ||
| 84 | #define S3C_PA_WDT S5PV310_PA_WATCHDOG | 97 | #define S3C_PA_WDT S5PV310_PA_WATCHDOG |
| 85 | 98 | ||
| 86 | #endif /* __ASM_ARCH_MAP_H */ | 99 | #endif /* __ASM_ARCH_MAP_H */ |
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h index 4013553cd9be..f1028cad9788 100644 --- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h | |||
| @@ -26,11 +26,23 @@ | |||
| 26 | 26 | ||
| 27 | #define S5P_CLKSRC_TOP0 S5P_CLKREG(0x0C210) | 27 | #define S5P_CLKSRC_TOP0 S5P_CLKREG(0x0C210) |
| 28 | #define S5P_CLKSRC_TOP1 S5P_CLKREG(0x0C214) | 28 | #define S5P_CLKSRC_TOP1 S5P_CLKREG(0x0C214) |
| 29 | 29 | #define S5P_CLKSRC_CAM S5P_CLKREG(0x0C220) | |
| 30 | #define S5P_CLKSRC_IMAGE S5P_CLKREG(0x0C230) | ||
| 31 | #define S5P_CLKSRC_LCD0 S5P_CLKREG(0x0C234) | ||
| 32 | #define S5P_CLKSRC_LCD1 S5P_CLKREG(0x0C238) | ||
| 33 | #define S5P_CLKSRC_FSYS S5P_CLKREG(0x0C240) | ||
| 30 | #define S5P_CLKSRC_PERIL0 S5P_CLKREG(0x0C250) | 34 | #define S5P_CLKSRC_PERIL0 S5P_CLKREG(0x0C250) |
| 35 | #define S5P_CLKSRC_PERIL1 S5P_CLKREG(0x0C254) | ||
| 31 | 36 | ||
| 32 | #define S5P_CLKDIV_TOP S5P_CLKREG(0x0C510) | 37 | #define S5P_CLKDIV_TOP S5P_CLKREG(0x0C510) |
| 33 | 38 | #define S5P_CLKDIV_CAM S5P_CLKREG(0x0C520) | |
| 39 | #define S5P_CLKDIV_IMAGE S5P_CLKREG(0x0C530) | ||
| 40 | #define S5P_CLKDIV_LCD0 S5P_CLKREG(0x0C534) | ||
| 41 | #define S5P_CLKDIV_LCD1 S5P_CLKREG(0x0C538) | ||
| 42 | #define S5P_CLKDIV_FSYS0 S5P_CLKREG(0x0C540) | ||
| 43 | #define S5P_CLKDIV_FSYS1 S5P_CLKREG(0x0C544) | ||
| 44 | #define S5P_CLKDIV_FSYS2 S5P_CLKREG(0x0C548) | ||
| 45 | #define S5P_CLKDIV_FSYS3 S5P_CLKREG(0x0C54C) | ||
| 34 | #define S5P_CLKDIV_PERIL0 S5P_CLKREG(0x0C550) | 46 | #define S5P_CLKDIV_PERIL0 S5P_CLKREG(0x0C550) |
| 35 | #define S5P_CLKDIV_PERIL1 S5P_CLKREG(0x0C554) | 47 | #define S5P_CLKDIV_PERIL1 S5P_CLKREG(0x0C554) |
| 36 | #define S5P_CLKDIV_PERIL2 S5P_CLKREG(0x0C558) | 48 | #define S5P_CLKDIV_PERIL2 S5P_CLKREG(0x0C558) |
| @@ -38,9 +50,21 @@ | |||
| 38 | #define S5P_CLKDIV_PERIL4 S5P_CLKREG(0x0C560) | 50 | #define S5P_CLKDIV_PERIL4 S5P_CLKREG(0x0C560) |
| 39 | #define S5P_CLKDIV_PERIL5 S5P_CLKREG(0x0C564) | 51 | #define S5P_CLKDIV_PERIL5 S5P_CLKREG(0x0C564) |
| 40 | 52 | ||
| 53 | #define S5P_CLKSRC_MASK_TOP S5P_CLKREG(0x0C310) | ||
| 54 | #define S5P_CLKSRC_MASK_CAM S5P_CLKREG(0x0C320) | ||
| 55 | #define S5P_CLKSRC_MASK_LCD0 S5P_CLKREG(0x0C334) | ||
| 56 | #define S5P_CLKSRC_MASK_LCD1 S5P_CLKREG(0x0C338) | ||
| 57 | #define S5P_CLKSRC_MASK_FSYS S5P_CLKREG(0x0C340) | ||
| 41 | #define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) | 58 | #define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) |
| 59 | #define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354) | ||
| 42 | 60 | ||
| 61 | #define S5P_CLKGATE_IP_CAM S5P_CLKREG(0x0C920) | ||
| 62 | #define S5P_CLKGATE_IP_IMAGE S5P_CLKREG(0x0C930) | ||
| 63 | #define S5P_CLKGATE_IP_LCD0 S5P_CLKREG(0x0C934) | ||
| 64 | #define S5P_CLKGATE_IP_LCD1 S5P_CLKREG(0x0C938) | ||
| 65 | #define S5P_CLKGATE_IP_FSYS S5P_CLKREG(0x0C940) | ||
| 43 | #define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) | 66 | #define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) |
| 67 | #define S5P_CLKGATE_IP_PERIR S5P_CLKREG(0x0C960) | ||
| 44 | 68 | ||
| 45 | #define S5P_CLKSRC_CORE S5P_CLKREG(0x10200) | 69 | #define S5P_CLKSRC_CORE S5P_CLKREG(0x10200) |
| 46 | #define S5P_CLKDIV_CORE0 S5P_CLKREG(0x10500) | 70 | #define S5P_CLKDIV_CORE0 S5P_CLKREG(0x10500) |
| @@ -60,4 +84,8 @@ | |||
| 60 | 84 | ||
| 61 | #define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x14800) | 85 | #define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x14800) |
| 62 | 86 | ||
| 87 | /* Compatibility defines */ | ||
| 88 | |||
| 89 | #define S5P_EPLL_CON S5P_EPLL_CON0 | ||
| 90 | |||
| 63 | #endif /* __ASM_ARCH_REGS_CLOCK_H */ | 91 | #endif /* __ASM_ARCH_REGS_CLOCK_H */ |
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-gpio.h b/arch/arm/mach-s5pv310/include/mach/regs-gpio.h new file mode 100644 index 000000000000..82e9e0c9d452 --- /dev/null +++ b/arch/arm/mach-s5pv310/include/mach/regs-gpio.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv310/include/mach/regs-gpio.h | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S5PV310 - GPIO (including EINT) register definitions | ||
| 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_ARCH_REGS_GPIO_H | ||
| 14 | #define __ASM_ARCH_REGS_GPIO_H __FILE__ | ||
| 15 | |||
| 16 | #include <mach/map.h> | ||
| 17 | #include <mach/irqs.h> | ||
| 18 | |||
| 19 | #define S5PV310_EINT40CON (S5P_VA_GPIO2 + 0xE00) | ||
| 20 | #define S5P_EINT_CON(x) (S5PV310_EINT40CON + ((x) * 0x4)) | ||
| 21 | |||
| 22 | #define S5PV310_EINT40FLTCON0 (S5P_VA_GPIO2 + 0xE80) | ||
| 23 | #define S5P_EINT_FLTCON(x) (S5PV310_EINT40FLTCON0 + ((x) * 0x4)) | ||
| 24 | |||
| 25 | #define S5PV310_EINT40MASK (S5P_VA_GPIO2 + 0xF00) | ||
| 26 | #define S5P_EINT_MASK(x) (S5PV310_EINT40MASK + ((x) * 0x4)) | ||
| 27 | |||
| 28 | #define S5PV310_EINT40PEND (S5P_VA_GPIO2 + 0xF40) | ||
| 29 | #define S5P_EINT_PEND(x) (S5PV310_EINT40PEND + ((x) * 0x4)) | ||
| 30 | |||
| 31 | #define EINT_REG_NR(x) (EINT_OFFSET(x) >> 3) | ||
| 32 | |||
| 33 | #define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7)) | ||
| 34 | |||
| 35 | #define EINT_MODE S3C_GPIO_SFN(0xf) | ||
| 36 | |||
| 37 | #define EINT_GPIO_0(x) S5PV310_GPX0(x) | ||
| 38 | #define EINT_GPIO_1(x) S5PV310_GPX1(x) | ||
| 39 | #define EINT_GPIO_2(x) S5PV310_GPX2(x) | ||
| 40 | #define EINT_GPIO_3(x) S5PV310_GPX3(x) | ||
| 41 | |||
| 42 | #endif /* __ASM_ARCH_REGS_GPIO_H */ | ||
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-srom.h b/arch/arm/mach-s5pv310/include/mach/regs-srom.h new file mode 100644 index 000000000000..1898b3e10550 --- /dev/null +++ b/arch/arm/mach-s5pv310/include/mach/regs-srom.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv310/include/mach/regs-srom.h | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S5PV310 - SROMC register definitions | ||
| 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_ARCH_REGS_SROM_H | ||
| 14 | #define __ASM_ARCH_REGS_SROM_H __FILE__ | ||
| 15 | |||
| 16 | #include <mach/map.h> | ||
| 17 | |||
| 18 | #define S5PV310_SROMREG(x) (S5P_VA_SROMC + (x)) | ||
| 19 | |||
| 20 | #define S5PV310_SROM_BW S5PV310_SROMREG(0x0) | ||
| 21 | #define S5PV310_SROM_BC0 S5PV310_SROMREG(0x4) | ||
| 22 | #define S5PV310_SROM_BC1 S5PV310_SROMREG(0x8) | ||
| 23 | #define S5PV310_SROM_BC2 S5PV310_SROMREG(0xc) | ||
| 24 | #define S5PV310_SROM_BC3 S5PV310_SROMREG(0x10) | ||
| 25 | |||
| 26 | /* one register BW holds 4 x 4-bit packed settings for NCS0 - NCS3 */ | ||
| 27 | |||
| 28 | #define S5PV310_SROM_BW__DATAWIDTH__SHIFT 0 | ||
| 29 | #define S5PV310_SROM_BW__ADDRMODE__SHIFT 1 | ||
| 30 | #define S5PV310_SROM_BW__WAITENABLE__SHIFT 2 | ||
| 31 | #define S5PV310_SROM_BW__BYTEENABLE__SHIFT 3 | ||
| 32 | |||
| 33 | #define S5PV310_SROM_BW__CS_MASK 0xf | ||
| 34 | |||
| 35 | #define S5PV310_SROM_BW__NCS0__SHIFT 0 | ||
| 36 | #define S5PV310_SROM_BW__NCS1__SHIFT 4 | ||
| 37 | #define S5PV310_SROM_BW__NCS2__SHIFT 8 | ||
| 38 | #define S5PV310_SROM_BW__NCS3__SHIFT 12 | ||
| 39 | |||
| 40 | /* applies to same to BCS0 - BCS3 */ | ||
| 41 | |||
| 42 | #define S5PV310_SROM_BCX__PMC__SHIFT 0 | ||
| 43 | #define S5PV310_SROM_BCX__TACP__SHIFT 4 | ||
| 44 | #define S5PV310_SROM_BCX__TCAH__SHIFT 8 | ||
| 45 | #define S5PV310_SROM_BCX__TCOH__SHIFT 12 | ||
| 46 | #define S5PV310_SROM_BCX__TACC__SHIFT 16 | ||
| 47 | #define S5PV310_SROM_BCX__TCOS__SHIFT 24 | ||
| 48 | #define S5PV310_SROM_BCX__TACS__SHIFT 28 | ||
| 49 | |||
| 50 | #endif /* __ASM_ARCH_REGS_SROM_H */ | ||
diff --git a/arch/arm/mach-s5pv310/include/mach/vmalloc.h b/arch/arm/mach-s5pv310/include/mach/vmalloc.h index 256f221edf3a..65759fb97581 100644 --- a/arch/arm/mach-s5pv310/include/mach/vmalloc.h +++ b/arch/arm/mach-s5pv310/include/mach/vmalloc.h | |||
| @@ -17,6 +17,6 @@ | |||
| 17 | #ifndef __ASM_ARCH_VMALLOC_H | 17 | #ifndef __ASM_ARCH_VMALLOC_H |
| 18 | #define __ASM_ARCH_VMALLOC_H __FILE__ | 18 | #define __ASM_ARCH_VMALLOC_H __FILE__ |
| 19 | 19 | ||
| 20 | #define VMALLOC_END (0xF0000000UL) | 20 | #define VMALLOC_END 0xF6000000UL |
| 21 | 21 | ||
| 22 | #endif /* __ASM_ARCH_VMALLOC_H */ | 22 | #endif /* __ASM_ARCH_VMALLOC_H */ |
diff --git a/arch/arm/mach-s5pv310/irq-combiner.c b/arch/arm/mach-s5pv310/irq-combiner.c index 0f7052164f23..c3f88c3faf6c 100644 --- a/arch/arm/mach-s5pv310/irq-combiner.c +++ b/arch/arm/mach-s5pv310/irq-combiner.c | |||
| @@ -66,11 +66,7 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) | |||
| 66 | if (status == 0) | 66 | if (status == 0) |
| 67 | goto out; | 67 | goto out; |
| 68 | 68 | ||
| 69 | for (combiner_irq = 0; combiner_irq < 32; combiner_irq++) { | 69 | combiner_irq = __ffs(status); |
| 70 | if (status & 0x1) | ||
| 71 | break; | ||
| 72 | status >>= 1; | ||
| 73 | } | ||
| 74 | 70 | ||
| 75 | cascade_irq = combiner_irq + (chip_data->irq_offset & ~31); | 71 | cascade_irq = combiner_irq + (chip_data->irq_offset & ~31); |
| 76 | if (unlikely(cascade_irq >= NR_IRQS)) | 72 | if (unlikely(cascade_irq >= NR_IRQS)) |
diff --git a/arch/arm/mach-s5pv310/irq-eint.c b/arch/arm/mach-s5pv310/irq-eint.c new file mode 100644 index 000000000000..5877503e92c3 --- /dev/null +++ b/arch/arm/mach-s5pv310/irq-eint.c | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv310/irq-eint.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S5PV310 - IRQ EINT 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/kernel.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/irq.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/sysdev.h> | ||
| 18 | #include <linux/gpio.h> | ||
| 19 | |||
| 20 | #include <plat/pm.h> | ||
| 21 | #include <plat/cpu.h> | ||
| 22 | #include <plat/gpio-cfg.h> | ||
| 23 | |||
| 24 | #include <mach/regs-gpio.h> | ||
| 25 | |||
| 26 | static DEFINE_SPINLOCK(eint_lock); | ||
| 27 | |||
| 28 | static unsigned int eint0_15_data[16]; | ||
| 29 | |||
| 30 | static unsigned int s5pv310_get_irq_nr(unsigned int number) | ||
| 31 | { | ||
| 32 | u32 ret = 0; | ||
| 33 | |||
| 34 | switch (number) { | ||
| 35 | case 0 ... 3: | ||
| 36 | ret = (number + IRQ_EINT0); | ||
| 37 | break; | ||
| 38 | case 4 ... 7: | ||
| 39 | ret = (number + (IRQ_EINT4 - 4)); | ||
| 40 | break; | ||
| 41 | case 8 ... 15: | ||
| 42 | ret = (number + (IRQ_EINT8 - 8)); | ||
| 43 | break; | ||
| 44 | default: | ||
| 45 | printk(KERN_ERR "number available : %d\n", number); | ||
| 46 | } | ||
| 47 | |||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | static inline void s5pv310_irq_eint_mask(unsigned int irq) | ||
| 52 | { | ||
| 53 | u32 mask; | ||
| 54 | |||
| 55 | spin_lock(&eint_lock); | ||
| 56 | mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq))); | ||
| 57 | mask |= eint_irq_to_bit(irq); | ||
| 58 | __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq))); | ||
| 59 | spin_unlock(&eint_lock); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void s5pv310_irq_eint_unmask(unsigned int irq) | ||
| 63 | { | ||
| 64 | u32 mask; | ||
| 65 | |||
| 66 | spin_lock(&eint_lock); | ||
| 67 | mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq))); | ||
| 68 | mask &= ~(eint_irq_to_bit(irq)); | ||
| 69 | __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq))); | ||
| 70 | spin_unlock(&eint_lock); | ||
| 71 | } | ||
| 72 | |||
| 73 | static inline void s5pv310_irq_eint_ack(unsigned int irq) | ||
| 74 | { | ||
| 75 | __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq))); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void s5pv310_irq_eint_maskack(unsigned int irq) | ||
| 79 | { | ||
| 80 | s5pv310_irq_eint_mask(irq); | ||
| 81 | s5pv310_irq_eint_ack(irq); | ||
| 82 | } | ||
| 83 | |||
| 84 | static int s5pv310_irq_eint_set_type(unsigned int irq, unsigned int type) | ||
| 85 | { | ||
| 86 | int offs = EINT_OFFSET(irq); | ||
| 87 | int shift; | ||
| 88 | u32 ctrl, mask; | ||
| 89 | u32 newvalue = 0; | ||
| 90 | |||
| 91 | switch (type) { | ||
| 92 | case IRQ_TYPE_EDGE_RISING: | ||
| 93 | newvalue = S5P_IRQ_TYPE_EDGE_RISING; | ||
| 94 | break; | ||
| 95 | |||
| 96 | case IRQ_TYPE_EDGE_FALLING: | ||
| 97 | newvalue = S5P_IRQ_TYPE_EDGE_FALLING; | ||
| 98 | break; | ||
| 99 | |||
| 100 | case IRQ_TYPE_EDGE_BOTH: | ||
| 101 | newvalue = S5P_IRQ_TYPE_EDGE_BOTH; | ||
| 102 | break; | ||
| 103 | |||
| 104 | case IRQ_TYPE_LEVEL_LOW: | ||
| 105 | newvalue = S5P_IRQ_TYPE_LEVEL_LOW; | ||
| 106 | break; | ||
| 107 | |||
| 108 | case IRQ_TYPE_LEVEL_HIGH: | ||
| 109 | newvalue = S5P_IRQ_TYPE_LEVEL_HIGH; | ||
| 110 | break; | ||
| 111 | |||
| 112 | default: | ||
| 113 | printk(KERN_ERR "No such irq type %d", type); | ||
| 114 | return -EINVAL; | ||
| 115 | } | ||
| 116 | |||
| 117 | shift = (offs & 0x7) * 4; | ||
| 118 | mask = 0x7 << shift; | ||
| 119 | |||
| 120 | spin_lock(&eint_lock); | ||
| 121 | ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(irq))); | ||
| 122 | ctrl &= ~mask; | ||
| 123 | ctrl |= newvalue << shift; | ||
| 124 | __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(irq))); | ||
| 125 | spin_unlock(&eint_lock); | ||
| 126 | |||
| 127 | switch (offs) { | ||
| 128 | case 0 ... 7: | ||
| 129 | s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE); | ||
| 130 | break; | ||
| 131 | case 8 ... 15: | ||
| 132 | s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE); | ||
| 133 | break; | ||
| 134 | case 16 ... 23: | ||
| 135 | s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE); | ||
| 136 | break; | ||
| 137 | case 24 ... 31: | ||
| 138 | s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE); | ||
| 139 | break; | ||
| 140 | default: | ||
| 141 | printk(KERN_ERR "No such irq number %d", offs); | ||
| 142 | } | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | static struct irq_chip s5pv310_irq_eint = { | ||
| 148 | .name = "s5pv310-eint", | ||
| 149 | .mask = s5pv310_irq_eint_mask, | ||
| 150 | .unmask = s5pv310_irq_eint_unmask, | ||
| 151 | .mask_ack = s5pv310_irq_eint_maskack, | ||
| 152 | .ack = s5pv310_irq_eint_ack, | ||
| 153 | .set_type = s5pv310_irq_eint_set_type, | ||
| 154 | #ifdef CONFIG_PM | ||
| 155 | .set_wake = s3c_irqext_wake, | ||
| 156 | #endif | ||
| 157 | }; | ||
| 158 | |||
| 159 | /* s5pv310_irq_demux_eint | ||
| 160 | * | ||
| 161 | * This function demuxes the IRQ from from EINTs 16 to 31. | ||
| 162 | * It is designed to be inlined into the specific handler | ||
| 163 | * s5p_irq_demux_eintX_Y. | ||
| 164 | * | ||
| 165 | * Each EINT pend/mask registers handle eight of them. | ||
| 166 | */ | ||
| 167 | static inline void s5pv310_irq_demux_eint(unsigned int start) | ||
| 168 | { | ||
| 169 | unsigned int irq; | ||
| 170 | |||
| 171 | u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start))); | ||
| 172 | u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start))); | ||
| 173 | |||
| 174 | status &= ~mask; | ||
| 175 | status &= 0xff; | ||
| 176 | |||
| 177 | while (status) { | ||
| 178 | irq = fls(status) - 1; | ||
| 179 | generic_handle_irq(irq + start); | ||
| 180 | status &= ~(1 << irq); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | static void s5pv310_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) | ||
| 185 | { | ||
| 186 | s5pv310_irq_demux_eint(IRQ_EINT(16)); | ||
| 187 | s5pv310_irq_demux_eint(IRQ_EINT(24)); | ||
| 188 | } | ||
| 189 | |||
| 190 | static void s5pv310_irq_eint0_15(unsigned int irq, struct irq_desc *desc) | ||
| 191 | { | ||
| 192 | u32 *irq_data = get_irq_data(irq); | ||
| 193 | struct irq_chip *chip = get_irq_chip(irq); | ||
| 194 | |||
| 195 | chip->mask(irq); | ||
| 196 | |||
| 197 | if (chip->ack) | ||
| 198 | chip->ack(irq); | ||
| 199 | |||
| 200 | generic_handle_irq(*irq_data); | ||
| 201 | |||
| 202 | chip->unmask(irq); | ||
| 203 | } | ||
| 204 | |||
| 205 | int __init s5pv310_init_irq_eint(void) | ||
| 206 | { | ||
| 207 | int irq; | ||
| 208 | |||
| 209 | for (irq = 0 ; irq <= 31 ; irq++) { | ||
| 210 | set_irq_chip(IRQ_EINT(irq), &s5pv310_irq_eint); | ||
| 211 | set_irq_handler(IRQ_EINT(irq), handle_level_irq); | ||
| 212 | set_irq_flags(IRQ_EINT(irq), IRQF_VALID); | ||
| 213 | } | ||
| 214 | |||
| 215 | set_irq_chained_handler(IRQ_EINT16_31, s5pv310_irq_demux_eint16_31); | ||
| 216 | |||
| 217 | for (irq = 0 ; irq <= 15 ; irq++) { | ||
| 218 | eint0_15_data[irq] = IRQ_EINT(irq); | ||
| 219 | |||
| 220 | set_irq_data(s5pv310_get_irq_nr(irq), &eint0_15_data[irq]); | ||
| 221 | set_irq_chained_handler(s5pv310_get_irq_nr(irq), | ||
| 222 | s5pv310_irq_eint0_15); | ||
| 223 | } | ||
| 224 | |||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | arch_initcall(s5pv310_init_irq_eint); | ||
diff --git a/arch/arm/mach-s5pv310/mach-smdkc210.c b/arch/arm/mach-s5pv310/mach-smdkc210.c new file mode 100644 index 000000000000..2b8d4fc52d7c --- /dev/null +++ b/arch/arm/mach-s5pv310/mach-smdkc210.c | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv310/mach-smdkc210.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 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/serial_core.h> | ||
| 12 | #include <linux/gpio.h> | ||
| 13 | #include <linux/mmc/host.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <linux/smsc911x.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | |||
| 18 | #include <asm/mach/arch.h> | ||
| 19 | #include <asm/mach-types.h> | ||
| 20 | |||
| 21 | #include <plat/regs-serial.h> | ||
| 22 | #include <plat/s5pv310.h> | ||
| 23 | #include <plat/cpu.h> | ||
| 24 | #include <plat/devs.h> | ||
| 25 | #include <plat/sdhci.h> | ||
| 26 | |||
| 27 | #include <mach/map.h> | ||
| 28 | #include <mach/regs-srom.h> | ||
| 29 | |||
| 30 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | ||
| 31 | #define SMDKC210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ | ||
| 32 | S3C2410_UCON_RXILEVEL | \ | ||
| 33 | S3C2410_UCON_TXIRQMODE | \ | ||
| 34 | S3C2410_UCON_RXIRQMODE | \ | ||
| 35 | S3C2410_UCON_RXFIFO_TOI | \ | ||
| 36 | S3C2443_UCON_RXERR_IRQEN) | ||
| 37 | |||
| 38 | #define SMDKC210_ULCON_DEFAULT S3C2410_LCON_CS8 | ||
| 39 | |||
| 40 | #define SMDKC210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ | ||
| 41 | S5PV210_UFCON_TXTRIG4 | \ | ||
| 42 | S5PV210_UFCON_RXTRIG4) | ||
| 43 | |||
| 44 | static struct s3c2410_uartcfg smdkc210_uartcfgs[] __initdata = { | ||
| 45 | [0] = { | ||
| 46 | .hwport = 0, | ||
| 47 | .flags = 0, | ||
| 48 | .ucon = SMDKC210_UCON_DEFAULT, | ||
| 49 | .ulcon = SMDKC210_ULCON_DEFAULT, | ||
| 50 | .ufcon = SMDKC210_UFCON_DEFAULT, | ||
| 51 | }, | ||
| 52 | [1] = { | ||
| 53 | .hwport = 1, | ||
| 54 | .flags = 0, | ||
| 55 | .ucon = SMDKC210_UCON_DEFAULT, | ||
| 56 | .ulcon = SMDKC210_ULCON_DEFAULT, | ||
| 57 | .ufcon = SMDKC210_UFCON_DEFAULT, | ||
| 58 | }, | ||
| 59 | [2] = { | ||
| 60 | .hwport = 2, | ||
| 61 | .flags = 0, | ||
| 62 | .ucon = SMDKC210_UCON_DEFAULT, | ||
| 63 | .ulcon = SMDKC210_ULCON_DEFAULT, | ||
| 64 | .ufcon = SMDKC210_UFCON_DEFAULT, | ||
| 65 | }, | ||
| 66 | [3] = { | ||
| 67 | .hwport = 3, | ||
| 68 | .flags = 0, | ||
| 69 | .ucon = SMDKC210_UCON_DEFAULT, | ||
| 70 | .ulcon = SMDKC210_ULCON_DEFAULT, | ||
| 71 | .ufcon = SMDKC210_UFCON_DEFAULT, | ||
| 72 | }, | ||
| 73 | }; | ||
| 74 | |||
| 75 | static struct s3c_sdhci_platdata smdkc210_hsmmc0_pdata __initdata = { | ||
| 76 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 77 | .ext_cd_gpio = S5PV310_GPK0(2), | ||
| 78 | .ext_cd_gpio_invert = 1, | ||
| 79 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 80 | #ifdef CONFIG_S5PV310_SDHCI_CH0_8BIT | ||
| 81 | .max_width = 8, | ||
| 82 | .host_caps = MMC_CAP_8_BIT_DATA, | ||
| 83 | #endif | ||
| 84 | }; | ||
| 85 | |||
| 86 | static struct s3c_sdhci_platdata smdkc210_hsmmc1_pdata __initdata = { | ||
| 87 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 88 | .ext_cd_gpio = S5PV310_GPK0(2), | ||
| 89 | .ext_cd_gpio_invert = 1, | ||
| 90 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 91 | }; | ||
| 92 | |||
| 93 | static struct s3c_sdhci_platdata smdkc210_hsmmc2_pdata __initdata = { | ||
| 94 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 95 | .ext_cd_gpio = S5PV310_GPK2(2), | ||
| 96 | .ext_cd_gpio_invert = 1, | ||
| 97 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 98 | #ifdef CONFIG_S5PV310_SDHCI_CH2_8BIT | ||
| 99 | .max_width = 8, | ||
| 100 | .host_caps = MMC_CAP_8_BIT_DATA, | ||
| 101 | #endif | ||
| 102 | }; | ||
| 103 | |||
| 104 | static struct s3c_sdhci_platdata smdkc210_hsmmc3_pdata __initdata = { | ||
| 105 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 106 | .ext_cd_gpio = S5PV310_GPK2(2), | ||
| 107 | .ext_cd_gpio_invert = 1, | ||
| 108 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 109 | }; | ||
| 110 | |||
| 111 | static struct resource smdkc210_smsc911x_resources[] = { | ||
| 112 | [0] = { | ||
| 113 | .start = S5PV310_PA_SROM_BANK(1), | ||
| 114 | .end = S5PV310_PA_SROM_BANK(1) + SZ_64K - 1, | ||
| 115 | .flags = IORESOURCE_MEM, | ||
| 116 | }, | ||
| 117 | [1] = { | ||
| 118 | .start = IRQ_EINT(5), | ||
| 119 | .end = IRQ_EINT(5), | ||
| 120 | .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW, | ||
| 121 | }, | ||
| 122 | }; | ||
| 123 | |||
| 124 | static struct smsc911x_platform_config smsc9215_config = { | ||
| 125 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, | ||
| 126 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, | ||
| 127 | .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, | ||
| 128 | .phy_interface = PHY_INTERFACE_MODE_MII, | ||
| 129 | .mac = {0x00, 0x80, 0x00, 0x23, 0x45, 0x67}, | ||
| 130 | }; | ||
| 131 | |||
| 132 | static struct platform_device smdkc210_smsc911x = { | ||
| 133 | .name = "smsc911x", | ||
| 134 | .id = -1, | ||
| 135 | .num_resources = ARRAY_SIZE(smdkc210_smsc911x_resources), | ||
| 136 | .resource = smdkc210_smsc911x_resources, | ||
| 137 | .dev = { | ||
| 138 | .platform_data = &smsc9215_config, | ||
| 139 | }, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static struct platform_device *smdkc210_devices[] __initdata = { | ||
| 143 | &s3c_device_hsmmc0, | ||
| 144 | &s3c_device_hsmmc1, | ||
| 145 | &s3c_device_hsmmc2, | ||
| 146 | &s3c_device_hsmmc3, | ||
| 147 | &s3c_device_rtc, | ||
| 148 | &s3c_device_wdt, | ||
| 149 | &smdkc210_smsc911x, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static void __init smdkc210_smsc911x_init(void) | ||
| 153 | { | ||
| 154 | u32 cs1; | ||
| 155 | |||
| 156 | /* configure nCS1 width to 16 bits */ | ||
| 157 | cs1 = __raw_readl(S5PV310_SROM_BW) & | ||
| 158 | ~(S5PV310_SROM_BW__CS_MASK << | ||
| 159 | S5PV310_SROM_BW__NCS1__SHIFT); | ||
| 160 | cs1 |= ((1 << S5PV310_SROM_BW__DATAWIDTH__SHIFT) | | ||
| 161 | (1 << S5PV310_SROM_BW__WAITENABLE__SHIFT) | | ||
| 162 | (1 << S5PV310_SROM_BW__BYTEENABLE__SHIFT)) << | ||
| 163 | S5PV310_SROM_BW__NCS1__SHIFT; | ||
| 164 | __raw_writel(cs1, S5PV310_SROM_BW); | ||
| 165 | |||
| 166 | /* set timing for nCS1 suitable for ethernet chip */ | ||
| 167 | __raw_writel((0x1 << S5PV310_SROM_BCX__PMC__SHIFT) | | ||
| 168 | (0x9 << S5PV310_SROM_BCX__TACP__SHIFT) | | ||
| 169 | (0xc << S5PV310_SROM_BCX__TCAH__SHIFT) | | ||
| 170 | (0x1 << S5PV310_SROM_BCX__TCOH__SHIFT) | | ||
| 171 | (0x6 << S5PV310_SROM_BCX__TACC__SHIFT) | | ||
| 172 | (0x1 << S5PV310_SROM_BCX__TCOS__SHIFT) | | ||
| 173 | (0x1 << S5PV310_SROM_BCX__TACS__SHIFT), S5PV310_SROM_BC1); | ||
| 174 | } | ||
| 175 | |||
| 176 | static void __init smdkc210_map_io(void) | ||
| 177 | { | ||
| 178 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); | ||
| 179 | s3c24xx_init_clocks(24000000); | ||
| 180 | s3c24xx_init_uarts(smdkc210_uartcfgs, ARRAY_SIZE(smdkc210_uartcfgs)); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void __init smdkc210_machine_init(void) | ||
| 184 | { | ||
| 185 | smdkc210_smsc911x_init(); | ||
| 186 | |||
| 187 | s3c_sdhci0_set_platdata(&smdkc210_hsmmc0_pdata); | ||
| 188 | s3c_sdhci1_set_platdata(&smdkc210_hsmmc1_pdata); | ||
| 189 | s3c_sdhci2_set_platdata(&smdkc210_hsmmc2_pdata); | ||
| 190 | s3c_sdhci3_set_platdata(&smdkc210_hsmmc3_pdata); | ||
| 191 | |||
| 192 | platform_add_devices(smdkc210_devices, ARRAY_SIZE(smdkc210_devices)); | ||
| 193 | } | ||
| 194 | |||
| 195 | MACHINE_START(SMDKC210, "SMDKC210") | ||
| 196 | /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ | ||
| 197 | .boot_params = S5P_PA_SDRAM + 0x100, | ||
| 198 | .init_irq = s5pv310_init_irq, | ||
| 199 | .map_io = smdkc210_map_io, | ||
| 200 | .init_machine = smdkc210_machine_init, | ||
| 201 | .timer = &s5pv310_timer, | ||
| 202 | MACHINE_END | ||
diff --git a/arch/arm/mach-s5pv310/mach-smdkv310.c b/arch/arm/mach-s5pv310/mach-smdkv310.c index 46215a14b3bb..35826d66632c 100644 --- a/arch/arm/mach-s5pv310/mach-smdkv310.c +++ b/arch/arm/mach-s5pv310/mach-smdkv310.c | |||
| @@ -9,16 +9,23 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/serial_core.h> | 11 | #include <linux/serial_core.h> |
| 12 | #include <linux/gpio.h> | ||
| 13 | #include <linux/mmc/host.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <linux/smsc911x.h> | ||
| 16 | #include <linux/io.h> | ||
| 12 | 17 | ||
| 13 | #include <asm/mach/arch.h> | 18 | #include <asm/mach/arch.h> |
| 14 | #include <asm/mach-types.h> | 19 | #include <asm/mach-types.h> |
| 15 | #include <asm/hardware/cache-l2x0.h> | ||
| 16 | 20 | ||
| 17 | #include <plat/regs-serial.h> | 21 | #include <plat/regs-serial.h> |
| 18 | #include <plat/s5pv310.h> | 22 | #include <plat/s5pv310.h> |
| 19 | #include <plat/cpu.h> | 23 | #include <plat/cpu.h> |
| 24 | #include <plat/devs.h> | ||
| 25 | #include <plat/sdhci.h> | ||
| 20 | 26 | ||
| 21 | #include <mach/map.h> | 27 | #include <mach/map.h> |
| 28 | #include <mach/regs-srom.h> | ||
| 22 | 29 | ||
| 23 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | 30 | /* Following are default values for UCON, ULCON and UFCON UART registers */ |
| 24 | #define SMDKV310_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ | 31 | #define SMDKV310_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ |
| @@ -65,6 +72,107 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = { | |||
| 65 | }, | 72 | }, |
| 66 | }; | 73 | }; |
| 67 | 74 | ||
| 75 | static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = { | ||
| 76 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 77 | .ext_cd_gpio = S5PV310_GPK0(2), | ||
| 78 | .ext_cd_gpio_invert = 1, | ||
| 79 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 80 | #ifdef CONFIG_S5PV310_SDHCI_CH0_8BIT | ||
| 81 | .max_width = 8, | ||
| 82 | .host_caps = MMC_CAP_8_BIT_DATA, | ||
| 83 | #endif | ||
| 84 | }; | ||
| 85 | |||
| 86 | static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = { | ||
| 87 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 88 | .ext_cd_gpio = S5PV310_GPK0(2), | ||
| 89 | .ext_cd_gpio_invert = 1, | ||
| 90 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 91 | }; | ||
| 92 | |||
| 93 | static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = { | ||
| 94 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 95 | .ext_cd_gpio = S5PV310_GPK2(2), | ||
| 96 | .ext_cd_gpio_invert = 1, | ||
| 97 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 98 | #ifdef CONFIG_S5PV310_SDHCI_CH2_8BIT | ||
| 99 | .max_width = 8, | ||
| 100 | .host_caps = MMC_CAP_8_BIT_DATA, | ||
| 101 | #endif | ||
| 102 | }; | ||
| 103 | |||
| 104 | static struct s3c_sdhci_platdata smdkv310_hsmmc3_pdata __initdata = { | ||
| 105 | .cd_type = S3C_SDHCI_CD_GPIO, | ||
| 106 | .ext_cd_gpio = S5PV310_GPK2(2), | ||
| 107 | .ext_cd_gpio_invert = 1, | ||
| 108 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | ||
| 109 | }; | ||
| 110 | |||
| 111 | static struct resource smdkv310_smsc911x_resources[] = { | ||
| 112 | [0] = { | ||
| 113 | .start = S5PV310_PA_SROM_BANK(1), | ||
| 114 | .end = S5PV310_PA_SROM_BANK(1) + SZ_64K - 1, | ||
| 115 | .flags = IORESOURCE_MEM, | ||
| 116 | }, | ||
| 117 | [1] = { | ||
| 118 | .start = IRQ_EINT(5), | ||
| 119 | .end = IRQ_EINT(5), | ||
| 120 | .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW, | ||
| 121 | }, | ||
| 122 | }; | ||
| 123 | |||
| 124 | static struct smsc911x_platform_config smsc9215_config = { | ||
| 125 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, | ||
| 126 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, | ||
| 127 | .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, | ||
| 128 | .phy_interface = PHY_INTERFACE_MODE_MII, | ||
| 129 | .mac = {0x00, 0x80, 0x00, 0x23, 0x45, 0x67}, | ||
| 130 | }; | ||
| 131 | |||
| 132 | static struct platform_device smdkv310_smsc911x = { | ||
| 133 | .name = "smsc911x", | ||
| 134 | .id = -1, | ||
| 135 | .num_resources = ARRAY_SIZE(smdkv310_smsc911x_resources), | ||
| 136 | .resource = smdkv310_smsc911x_resources, | ||
| 137 | .dev = { | ||
| 138 | .platform_data = &smsc9215_config, | ||
| 139 | }, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static struct platform_device *smdkv310_devices[] __initdata = { | ||
| 143 | &s3c_device_hsmmc0, | ||
| 144 | &s3c_device_hsmmc1, | ||
| 145 | &s3c_device_hsmmc2, | ||
| 146 | &s3c_device_hsmmc3, | ||
| 147 | &s3c_device_rtc, | ||
| 148 | &s3c_device_wdt, | ||
| 149 | &smdkv310_smsc911x, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static void __init smdkv310_smsc911x_init(void) | ||
| 153 | { | ||
| 154 | u32 cs1; | ||
| 155 | |||
| 156 | /* configure nCS1 width to 16 bits */ | ||
| 157 | cs1 = __raw_readl(S5PV310_SROM_BW) & | ||
| 158 | ~(S5PV310_SROM_BW__CS_MASK << | ||
| 159 | S5PV310_SROM_BW__NCS1__SHIFT); | ||
| 160 | cs1 |= ((1 << S5PV310_SROM_BW__DATAWIDTH__SHIFT) | | ||
| 161 | (1 << S5PV310_SROM_BW__WAITENABLE__SHIFT) | | ||
| 162 | (1 << S5PV310_SROM_BW__BYTEENABLE__SHIFT)) << | ||
| 163 | S5PV310_SROM_BW__NCS1__SHIFT; | ||
| 164 | __raw_writel(cs1, S5PV310_SROM_BW); | ||
| 165 | |||
| 166 | /* set timing for nCS1 suitable for ethernet chip */ | ||
| 167 | __raw_writel((0x1 << S5PV310_SROM_BCX__PMC__SHIFT) | | ||
| 168 | (0x9 << S5PV310_SROM_BCX__TACP__SHIFT) | | ||
| 169 | (0xc << S5PV310_SROM_BCX__TCAH__SHIFT) | | ||
| 170 | (0x1 << S5PV310_SROM_BCX__TCOH__SHIFT) | | ||
| 171 | (0x6 << S5PV310_SROM_BCX__TACC__SHIFT) | | ||
| 172 | (0x1 << S5PV310_SROM_BCX__TCOS__SHIFT) | | ||
| 173 | (0x1 << S5PV310_SROM_BCX__TACS__SHIFT), S5PV310_SROM_BC1); | ||
| 174 | } | ||
| 175 | |||
| 68 | static void __init smdkv310_map_io(void) | 176 | static void __init smdkv310_map_io(void) |
| 69 | { | 177 | { |
| 70 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); | 178 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); |
| @@ -74,9 +182,14 @@ static void __init smdkv310_map_io(void) | |||
| 74 | 182 | ||
| 75 | static void __init smdkv310_machine_init(void) | 183 | static void __init smdkv310_machine_init(void) |
| 76 | { | 184 | { |
| 77 | #ifdef CONFIG_CACHE_L2X0 | 185 | smdkv310_smsc911x_init(); |
| 78 | l2x0_init(S5P_VA_L2CC, 1 << 28, 0xffffffff); | 186 | |
| 79 | #endif | 187 | s3c_sdhci0_set_platdata(&smdkv310_hsmmc0_pdata); |
| 188 | s3c_sdhci1_set_platdata(&smdkv310_hsmmc1_pdata); | ||
| 189 | s3c_sdhci2_set_platdata(&smdkv310_hsmmc2_pdata); | ||
| 190 | s3c_sdhci3_set_platdata(&smdkv310_hsmmc3_pdata); | ||
| 191 | |||
| 192 | platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); | ||
| 80 | } | 193 | } |
| 81 | 194 | ||
| 82 | MACHINE_START(SMDKV310, "SMDKV310") | 195 | MACHINE_START(SMDKV310, "SMDKV310") |
diff --git a/arch/arm/mach-s5pv310/mach-universal_c210.c b/arch/arm/mach-s5pv310/mach-universal_c210.c index d7c2ec770f88..16d8fc00cafd 100644 --- a/arch/arm/mach-s5pv310/mach-universal_c210.c +++ b/arch/arm/mach-s5pv310/mach-universal_c210.c | |||
| @@ -7,15 +7,20 @@ | |||
| 7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/platform_device.h> | ||
| 10 | #include <linux/serial_core.h> | 11 | #include <linux/serial_core.h> |
| 12 | #include <linux/input.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/gpio_keys.h> | ||
| 15 | #include <linux/gpio.h> | ||
| 11 | 16 | ||
| 12 | #include <asm/mach/arch.h> | 17 | #include <asm/mach/arch.h> |
| 13 | #include <asm/mach-types.h> | 18 | #include <asm/mach-types.h> |
| 14 | #include <asm/hardware/cache-l2x0.h> | ||
| 15 | 19 | ||
| 16 | #include <plat/regs-serial.h> | 20 | #include <plat/regs-serial.h> |
| 17 | #include <plat/s5pv310.h> | 21 | #include <plat/s5pv310.h> |
| 18 | #include <plat/cpu.h> | 22 | #include <plat/cpu.h> |
| 23 | #include <plat/devs.h> | ||
| 19 | 24 | ||
| 20 | #include <mach/map.h> | 25 | #include <mach/map.h> |
| 21 | 26 | ||
| @@ -60,6 +65,72 @@ static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = { | |||
| 60 | }, | 65 | }, |
| 61 | }; | 66 | }; |
| 62 | 67 | ||
| 68 | static struct gpio_keys_button universal_gpio_keys_tables[] = { | ||
| 69 | { | ||
| 70 | .code = KEY_VOLUMEUP, | ||
| 71 | .gpio = S5PV310_GPX2(0), /* XEINT16 */ | ||
| 72 | .desc = "gpio-keys: KEY_VOLUMEUP", | ||
| 73 | .type = EV_KEY, | ||
| 74 | .active_low = 1, | ||
| 75 | .debounce_interval = 1, | ||
| 76 | }, { | ||
| 77 | .code = KEY_VOLUMEDOWN, | ||
| 78 | .gpio = S5PV310_GPX2(1), /* XEINT17 */ | ||
| 79 | .desc = "gpio-keys: KEY_VOLUMEDOWN", | ||
| 80 | .type = EV_KEY, | ||
| 81 | .active_low = 1, | ||
| 82 | .debounce_interval = 1, | ||
| 83 | }, { | ||
| 84 | .code = KEY_CONFIG, | ||
| 85 | .gpio = S5PV310_GPX2(2), /* XEINT18 */ | ||
| 86 | .desc = "gpio-keys: KEY_CONFIG", | ||
| 87 | .type = EV_KEY, | ||
| 88 | .active_low = 1, | ||
| 89 | .debounce_interval = 1, | ||
| 90 | }, { | ||
| 91 | .code = KEY_CAMERA, | ||
| 92 | .gpio = S5PV310_GPX2(3), /* XEINT19 */ | ||
| 93 | .desc = "gpio-keys: KEY_CAMERA", | ||
| 94 | .type = EV_KEY, | ||
| 95 | .active_low = 1, | ||
| 96 | .debounce_interval = 1, | ||
| 97 | }, { | ||
| 98 | .code = KEY_OK, | ||
| 99 | .gpio = S5PV310_GPX3(5), /* XEINT29 */ | ||
| 100 | .desc = "gpio-keys: KEY_OK", | ||
| 101 | .type = EV_KEY, | ||
| 102 | .active_low = 1, | ||
| 103 | .debounce_interval = 1, | ||
| 104 | }, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static struct gpio_keys_platform_data universal_gpio_keys_data = { | ||
| 108 | .buttons = universal_gpio_keys_tables, | ||
| 109 | .nbuttons = ARRAY_SIZE(universal_gpio_keys_tables), | ||
| 110 | }; | ||
| 111 | |||
| 112 | static struct platform_device universal_gpio_keys = { | ||
| 113 | .name = "gpio-keys", | ||
| 114 | .dev = { | ||
| 115 | .platform_data = &universal_gpio_keys_data, | ||
| 116 | }, | ||
| 117 | }; | ||
| 118 | |||
| 119 | /* I2C0 */ | ||
| 120 | static struct i2c_board_info i2c0_devs[] __initdata = { | ||
| 121 | /* Camera, To be updated */ | ||
| 122 | }; | ||
| 123 | |||
| 124 | /* I2C1 */ | ||
| 125 | static struct i2c_board_info i2c1_devs[] __initdata = { | ||
| 126 | /* Gyro, To be updated */ | ||
| 127 | }; | ||
| 128 | |||
| 129 | static struct platform_device *universal_devices[] __initdata = { | ||
| 130 | &universal_gpio_keys, | ||
| 131 | &s5p_device_onenand, | ||
| 132 | }; | ||
| 133 | |||
| 63 | static void __init universal_map_io(void) | 134 | static void __init universal_map_io(void) |
| 64 | { | 135 | { |
| 65 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); | 136 | s5p_init_io(NULL, 0, S5P_VA_CHIPID); |
| @@ -69,9 +140,11 @@ static void __init universal_map_io(void) | |||
| 69 | 140 | ||
| 70 | static void __init universal_machine_init(void) | 141 | static void __init universal_machine_init(void) |
| 71 | { | 142 | { |
| 72 | #ifdef CONFIG_CACHE_L2X0 | 143 | i2c_register_board_info(0, i2c0_devs, ARRAY_SIZE(i2c0_devs)); |
| 73 | l2x0_init(S5P_VA_L2CC, 1 << 28, 0xffffffff); | 144 | i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs)); |
| 74 | #endif | 145 | |
| 146 | /* Last */ | ||
| 147 | platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices)); | ||
| 75 | } | 148 | } |
| 76 | 149 | ||
| 77 | MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") | 150 | MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") |
diff --git a/arch/arm/mach-s5pv310/setup-i2c0.c b/arch/arm/mach-s5pv310/setup-i2c0.c index 436712807383..f47f8f3152ec 100644 --- a/arch/arm/mach-s5pv310/setup-i2c0.c +++ b/arch/arm/mach-s5pv310/setup-i2c0.c | |||
| @@ -21,8 +21,6 @@ struct platform_device; /* don't need the contents */ | |||
| 21 | 21 | ||
| 22 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) | 22 | void s3c_i2c0_cfg_gpio(struct platform_device *dev) |
| 23 | { | 23 | { |
| 24 | s3c_gpio_cfgpin(S5PV310_GPD1(0), S3C_GPIO_SFN(2)); | 24 | s3c_gpio_cfgall_range(S5PV310_GPD1(0), 2, |
| 25 | s3c_gpio_setpull(S5PV310_GPD1(0), S3C_GPIO_PULL_UP); | 25 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 26 | s3c_gpio_cfgpin(S5PV310_GPD1(1), S3C_GPIO_SFN(2)); | ||
| 27 | s3c_gpio_setpull(S5PV310_GPD1(1), S3C_GPIO_PULL_UP); | ||
| 28 | } | 26 | } |
diff --git a/arch/arm/mach-s5pv310/setup-i2c1.c b/arch/arm/mach-s5pv310/setup-i2c1.c index 1ecd5bc35b5a..9d07e4e2f14c 100644 --- a/arch/arm/mach-s5pv310/setup-i2c1.c +++ b/arch/arm/mach-s5pv310/setup-i2c1.c | |||
| @@ -18,8 +18,6 @@ struct platform_device; /* don't need the contents */ | |||
| 18 | 18 | ||
| 19 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) | 19 | void s3c_i2c1_cfg_gpio(struct platform_device *dev) |
| 20 | { | 20 | { |
| 21 | s3c_gpio_cfgpin(S5PV310_GPD1(2), S3C_GPIO_SFN(2)); | 21 | s3c_gpio_cfgall_range(S5PV310_GPD1(2), 2, |
| 22 | s3c_gpio_setpull(S5PV310_GPD1(2), S3C_GPIO_PULL_UP); | 22 | S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); |
| 23 | s3c_gpio_cfgpin(S5PV310_GPD1(3), S3C_GPIO_SFN(2)); | ||
| 24 | s3c_gpio_setpull(S5PV310_GPD1(3), S3C_GPIO_PULL_UP); | ||
| 25 | } | 23 | } |
diff --git a/arch/arm/mach-s5pv310/setup-i2c2.c b/arch/arm/mach-s5pv310/setup-i2c2.c index 4c0d8def660a..4163b1233daf 100644 --- a/arch/arm/mach-s5pv310/setup-i2c2.c +++ b/arch/arm/mach-s5pv310/setup-i2c2.c | |||
| @@ -18,8 +18,6 @@ struct platform_device; /* don't need the contents */ | |||
| 18 | 18 | ||
| 19 | void s3c_i2c2_cfg_gpio(struct platform_device *dev) | 19 | void s3c_i2c2_cfg_gpio(struct platform_device *dev) |
| 20 | { | 20 | { |
| 21 | s3c_gpio_cfgpin(S5PV310_GPA0(6), S3C_GPIO_SFN(3)); | 21 | s3c_gpio_cfgall_range(S5PV310_GPA0(6), 2, |
| 22 | s3c_gpio_setpull(S5PV310_GPA0(6), S3C_GPIO_PULL_UP); | 22 | S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); |
| 23 | s3c_gpio_cfgpin(S5PV310_GPA0(7), S3C_GPIO_SFN(3)); | ||
| 24 | s3c_gpio_setpull(S5PV310_GPA0(7), S3C_GPIO_PULL_UP); | ||
| 25 | } | 23 | } |
diff --git a/arch/arm/mach-s5pv310/setup-i2c3.c b/arch/arm/mach-s5pv310/setup-i2c3.c new file mode 100644 index 000000000000..180f153d2a20 --- /dev/null +++ b/arch/arm/mach-s5pv310/setup-i2c3.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-s5pv310/setup-i2c3.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 5 | * | ||
| 6 | * I2C3 GPIO configuration. | ||
| 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 | struct platform_device; /* don't need the contents */ | ||
| 14 | |||
| 15 | #include <linux/gpio.h> | ||
| 16 | #include <plat/iic.h> | ||
| 17 | #include <plat/gpio-cfg.h> | ||
| 18 | |||
| 19 | void s3c_i2c3_cfg_gpio(struct platform_device *dev) | ||
| 20 | { | ||
| 21 | s3c_gpio_cfgall_range(S5PV310_GPA1(2), 2, | ||
| 22 | S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); | ||
| 23 | } | ||
diff --git a/arch/arm/mach-s5pv310/setup-i2c4.c b/arch/arm/mach-s5pv310/setup-i2c4.c new file mode 100644 index 000000000000..909e8dfc5316 --- /dev/null +++ b/arch/arm/mach-s5pv310/setup-i2c4.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-s5pv310/setup-i2c4.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 5 | * | ||
| 6 | * I2C4 GPIO configuration. | ||
| 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 | struct platform_device; /* don't need the contents */ | ||
| 14 | |||
| 15 | #include <linux/gpio.h> | ||
| 16 | #include <plat/iic.h> | ||
| 17 | #include <plat/gpio-cfg.h> | ||
| 18 | |||
| 19 | void s3c_i2c4_cfg_gpio(struct platform_device *dev) | ||
| 20 | { | ||
| 21 | s3c_gpio_cfgall_range(S5PV310_GPB(2), 2, | ||
| 22 | S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); | ||
| 23 | } | ||
diff --git a/arch/arm/mach-s5pv310/setup-i2c5.c b/arch/arm/mach-s5pv310/setup-i2c5.c new file mode 100644 index 000000000000..5d0fa4ac0283 --- /dev/null +++ b/arch/arm/mach-s5pv310/setup-i2c5.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-s5pv310/setup-i2c5.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 5 | * | ||
| 6 | * I2C5 GPIO configuration. | ||
| 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 | struct platform_device; /* don't need the contents */ | ||
| 14 | |||
| 15 | #include <linux/gpio.h> | ||
| 16 | #include <plat/iic.h> | ||
| 17 | #include <plat/gpio-cfg.h> | ||
| 18 | |||
| 19 | void s3c_i2c5_cfg_gpio(struct platform_device *dev) | ||
| 20 | { | ||
| 21 | s3c_gpio_cfgall_range(S5PV310_GPB(6), 2, | ||
| 22 | S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); | ||
| 23 | } | ||
diff --git a/arch/arm/mach-s5pv310/setup-i2c6.c b/arch/arm/mach-s5pv310/setup-i2c6.c new file mode 100644 index 000000000000..34aafab92ac4 --- /dev/null +++ b/arch/arm/mach-s5pv310/setup-i2c6.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-s5pv310/setup-i2c6.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 5 | * | ||
| 6 | * I2C6 GPIO configuration. | ||
| 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 | struct platform_device; /* don't need the contents */ | ||
| 14 | |||
| 15 | #include <linux/gpio.h> | ||
| 16 | #include <plat/iic.h> | ||
| 17 | #include <plat/gpio-cfg.h> | ||
| 18 | |||
| 19 | void s3c_i2c6_cfg_gpio(struct platform_device *dev) | ||
| 20 | { | ||
| 21 | s3c_gpio_cfgall_range(S5PV310_GPC1(3), 2, | ||
| 22 | S3C_GPIO_SFN(4), S3C_GPIO_PULL_UP); | ||
| 23 | } | ||
diff --git a/arch/arm/mach-s5pv310/setup-i2c7.c b/arch/arm/mach-s5pv310/setup-i2c7.c new file mode 100644 index 000000000000..9b25b8d18920 --- /dev/null +++ b/arch/arm/mach-s5pv310/setup-i2c7.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-s5pv310/setup-i2c7.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 5 | * | ||
| 6 | * I2C7 GPIO configuration. | ||
| 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 | struct platform_device; /* don't need the contents */ | ||
| 14 | |||
| 15 | #include <linux/gpio.h> | ||
| 16 | #include <plat/iic.h> | ||
| 17 | #include <plat/gpio-cfg.h> | ||
| 18 | |||
| 19 | void s3c_i2c7_cfg_gpio(struct platform_device *dev) | ||
| 20 | { | ||
| 21 | s3c_gpio_cfgall_range(S5PV310_GPD0(2), 2, | ||
| 22 | S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); | ||
| 23 | } | ||
diff --git a/arch/arm/mach-s5pv310/setup-sdhci-gpio.c b/arch/arm/mach-s5pv310/setup-sdhci-gpio.c new file mode 100644 index 000000000000..86d38cc49135 --- /dev/null +++ b/arch/arm/mach-s5pv310/setup-sdhci-gpio.c | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv310/setup-sdhci-gpio.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5PV310 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC) | ||
| 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/kernel.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/gpio.h> | ||
| 19 | #include <linux/mmc/host.h> | ||
| 20 | #include <linux/mmc/card.h> | ||
| 21 | |||
| 22 | #include <plat/gpio-cfg.h> | ||
| 23 | #include <plat/regs-sdhci.h> | ||
| 24 | #include <plat/sdhci.h> | ||
| 25 | |||
| 26 | void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) | ||
| 27 | { | ||
| 28 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | ||
| 29 | unsigned int gpio; | ||
| 30 | |||
| 31 | /* Set all the necessary GPK0[0:1] pins to special-function 2 */ | ||
| 32 | for (gpio = S5PV310_GPK0(0); gpio < S5PV310_GPK0(2); gpio++) { | ||
| 33 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 34 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 35 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 36 | } | ||
| 37 | |||
| 38 | switch (width) { | ||
| 39 | case 8: | ||
| 40 | for (gpio = S5PV310_GPK1(3); gpio <= S5PV310_GPK1(6); gpio++) { | ||
| 41 | /* Data pin GPK1[3:6] to special-funtion 3 */ | ||
| 42 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 43 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); | ||
| 44 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 45 | } | ||
| 46 | case 4: | ||
| 47 | for (gpio = S5PV310_GPK0(3); gpio <= S5PV310_GPK0(6); gpio++) { | ||
| 48 | /* Data pin GPK0[3:6] to special-funtion 2 */ | ||
| 49 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 50 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); | ||
| 51 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 52 | } | ||
| 53 | default: | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | |||
| 57 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | ||
| 58 | s3c_gpio_cfgpin(S5PV310_GPK0(2), S3C_GPIO_SFN(2)); | ||
| 59 | s3c_gpio_setpull(S5PV310_GPK0(2), S3C_GPIO_PULL_UP); | ||
| 60 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) | ||
| 65 | { | ||
| 66 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | ||
| 67 | unsigned int gpio; | ||
| 68 | |||
| 69 | /* Set all the necessary GPK1[0:1] pins to special-function 2 */ | ||
| 70 | for (gpio = S5PV310_GPK1(0); gpio < S5PV310_GPK1(2); gpio++) { | ||
| 71 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 72 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 73 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 74 | } | ||
| 75 | |||
| 76 | for (gpio = S5PV310_GPK1(3); gpio <= S5PV310_GPK1(6); gpio++) { | ||
| 77 | /* Data pin GPK1[3:6] to special-function 2 */ | ||
| 78 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 79 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); | ||
| 80 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 81 | } | ||
| 82 | |||
| 83 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | ||
| 84 | s3c_gpio_cfgpin(S5PV310_GPK1(2), S3C_GPIO_SFN(2)); | ||
| 85 | s3c_gpio_setpull(S5PV310_GPK1(2), S3C_GPIO_PULL_UP); | ||
| 86 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) | ||
| 91 | { | ||
| 92 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | ||
| 93 | unsigned int gpio; | ||
| 94 | |||
| 95 | /* Set all the necessary GPK2[0:1] pins to special-function 2 */ | ||
| 96 | for (gpio = S5PV310_GPK2(0); gpio < S5PV310_GPK2(2); gpio++) { | ||
| 97 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 98 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 99 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 100 | } | ||
| 101 | |||
| 102 | switch (width) { | ||
| 103 | case 8: | ||
| 104 | for (gpio = S5PV310_GPK3(3); gpio <= S5PV310_GPK3(6); gpio++) { | ||
| 105 | /* Data pin GPK3[3:6] to special-function 3 */ | ||
| 106 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); | ||
| 107 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); | ||
| 108 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 109 | } | ||
| 110 | case 4: | ||
| 111 | for (gpio = S5PV310_GPK2(3); gpio <= S5PV310_GPK2(6); gpio++) { | ||
| 112 | /* Data pin GPK2[3:6] to special-function 2 */ | ||
| 113 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 114 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); | ||
| 115 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 116 | } | ||
| 117 | default: | ||
| 118 | break; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | ||
| 122 | s3c_gpio_cfgpin(S5PV310_GPK2(2), S3C_GPIO_SFN(2)); | ||
| 123 | s3c_gpio_setpull(S5PV310_GPK2(2), S3C_GPIO_PULL_UP); | ||
| 124 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width) | ||
| 129 | { | ||
| 130 | struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; | ||
| 131 | unsigned int gpio; | ||
| 132 | |||
| 133 | /* Set all the necessary GPK3[0:1] pins to special-function 2 */ | ||
| 134 | for (gpio = S5PV310_GPK3(0); gpio < S5PV310_GPK3(2); gpio++) { | ||
| 135 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 136 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); | ||
| 137 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 138 | } | ||
| 139 | |||
| 140 | for (gpio = S5PV310_GPK3(3); gpio <= S5PV310_GPK3(6); gpio++) { | ||
| 141 | /* Data pin GPK3[3:6] to special-function 2 */ | ||
| 142 | s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); | ||
| 143 | s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); | ||
| 144 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 145 | } | ||
| 146 | |||
| 147 | if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { | ||
| 148 | s3c_gpio_cfgpin(S5PV310_GPK3(2), S3C_GPIO_SFN(2)); | ||
| 149 | s3c_gpio_setpull(S5PV310_GPK3(2), S3C_GPIO_PULL_UP); | ||
| 150 | s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); | ||
| 151 | } | ||
| 152 | } | ||
diff --git a/arch/arm/mach-s5pv310/setup-sdhci.c b/arch/arm/mach-s5pv310/setup-sdhci.c new file mode 100644 index 000000000000..db8358fc4662 --- /dev/null +++ b/arch/arm/mach-s5pv310/setup-sdhci.c | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* linux/arch/arm/mach-s5pv310/setup-sdhci.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5PV310 - Helper functions for settign up SDHCI device(s) (HSMMC) | ||
| 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/kernel.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | |||
| 19 | #include <linux/mmc/card.h> | ||
| 20 | #include <linux/mmc/host.h> | ||
| 21 | |||
| 22 | #include <plat/regs-sdhci.h> | ||
| 23 | |||
| 24 | /* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */ | ||
| 25 | |||
| 26 | char *s5pv310_hsmmc_clksrcs[4] = { | ||
| 27 | [0] = NULL, | ||
| 28 | [1] = NULL, | ||
| 29 | [2] = "sclk_mmc", /* mmc_bus */ | ||
| 30 | [3] = NULL, | ||
| 31 | }; | ||
| 32 | |||
| 33 | void s5pv310_setup_sdhci_cfg_card(struct platform_device *dev, void __iomem *r, | ||
| 34 | struct mmc_ios *ios, struct mmc_card *card) | ||
| 35 | { | ||
| 36 | u32 ctrl2, ctrl3; | ||
| 37 | |||
| 38 | /* don't need to alter anything acording to card-type */ | ||
| 39 | |||
| 40 | ctrl2 = readl(r + S3C_SDHCI_CONTROL2); | ||
| 41 | |||
| 42 | /* select base clock source to HCLK */ | ||
| 43 | |||
| 44 | ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * clear async mode, enable conflict mask, rx feedback ctrl, SD | ||
| 48 | * clk hold and no use debounce count | ||
| 49 | */ | ||
| 50 | |||
| 51 | ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR | | ||
| 52 | S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK | | ||
| 53 | S3C_SDHCI_CTRL2_ENFBCLKRX | | ||
| 54 | S3C_SDHCI_CTRL2_DFCNT_NONE | | ||
| 55 | S3C_SDHCI_CTRL2_ENCLKOUTHOLD); | ||
| 56 | |||
| 57 | /* Tx and Rx feedback clock delay control */ | ||
| 58 | |||
| 59 | if (ios->clock < 25 * 1000000) | ||
| 60 | ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 | | ||
| 61 | S3C_SDHCI_CTRL3_FCSEL2 | | ||
| 62 | S3C_SDHCI_CTRL3_FCSEL1 | | ||
| 63 | S3C_SDHCI_CTRL3_FCSEL0); | ||
| 64 | else | ||
| 65 | ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0); | ||
| 66 | |||
| 67 | writel(ctrl2, r + S3C_SDHCI_CONTROL2); | ||
| 68 | writel(ctrl3, r + S3C_SDHCI_CONTROL3); | ||
| 69 | } | ||
diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c index c0a13ef5436f..96f7dc103b59 100644 --- a/arch/arm/mach-sa1100/cpu-sa1100.c +++ b/arch/arm/mach-sa1100/cpu-sa1100.c | |||
| @@ -184,16 +184,15 @@ static int sa1100_target(struct cpufreq_policy *policy, | |||
| 184 | { | 184 | { |
| 185 | unsigned int cur = sa11x0_getspeed(0); | 185 | unsigned int cur = sa11x0_getspeed(0); |
| 186 | unsigned int new_ppcr; | 186 | unsigned int new_ppcr; |
| 187 | |||
| 188 | struct cpufreq_freqs freqs; | 187 | struct cpufreq_freqs freqs; |
| 188 | |||
| 189 | new_ppcr = sa11x0_freq_to_ppcr(target_freq); | ||
| 189 | switch(relation){ | 190 | switch(relation){ |
| 190 | case CPUFREQ_RELATION_L: | 191 | case CPUFREQ_RELATION_L: |
| 191 | new_ppcr = sa11x0_freq_to_ppcr(target_freq); | ||
| 192 | if (sa11x0_ppcr_to_freq(new_ppcr) > policy->max) | 192 | if (sa11x0_ppcr_to_freq(new_ppcr) > policy->max) |
| 193 | new_ppcr--; | 193 | new_ppcr--; |
| 194 | break; | 194 | break; |
| 195 | case CPUFREQ_RELATION_H: | 195 | case CPUFREQ_RELATION_H: |
| 196 | new_ppcr = sa11x0_freq_to_ppcr(target_freq); | ||
| 197 | if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) && | 196 | if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) && |
| 198 | (sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min)) | 197 | (sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min)) |
| 199 | new_ppcr--; | 198 | new_ppcr--; |
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 22a2b44ddb7b..46ca4d4abf91 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | #include <linux/mtd/mtd.h> | 30 | #include <linux/mtd/mtd.h> |
| 31 | #include <linux/mtd/partitions.h> | 31 | #include <linux/mtd/partitions.h> |
| 32 | #include <linux/mtd/physmap.h> | 32 | #include <linux/mtd/physmap.h> |
| 33 | #include <linux/mmc/host.h> | ||
| 34 | #include <linux/mmc/sh_mmcif.h> | 33 | #include <linux/mmc/sh_mmcif.h> |
| 35 | #include <linux/i2c.h> | 34 | #include <linux/i2c.h> |
| 36 | #include <linux/i2c/tsc2007.h> | 35 | #include <linux/i2c/tsc2007.h> |
| @@ -44,6 +43,10 @@ | |||
| 44 | #include <linux/input/sh_keysc.h> | 43 | #include <linux/input/sh_keysc.h> |
| 45 | #include <linux/usb/r8a66597.h> | 44 | #include <linux/usb/r8a66597.h> |
| 46 | 45 | ||
| 46 | #include <media/sh_mobile_ceu.h> | ||
| 47 | #include <media/sh_mobile_csi2.h> | ||
| 48 | #include <media/soc_camera.h> | ||
| 49 | |||
| 47 | #include <sound/sh_fsi.h> | 50 | #include <sound/sh_fsi.h> |
| 48 | 51 | ||
| 49 | #include <video/sh_mobile_hdmi.h> | 52 | #include <video/sh_mobile_hdmi.h> |
| @@ -250,7 +253,7 @@ static int slot_cn7_get_cd(struct platform_device *pdev) | |||
| 250 | /* SH_MMCIF */ | 253 | /* SH_MMCIF */ |
| 251 | static struct resource sh_mmcif_resources[] = { | 254 | static struct resource sh_mmcif_resources[] = { |
| 252 | [0] = { | 255 | [0] = { |
| 253 | .name = "SH_MMCIF", | 256 | .name = "MMCIF", |
| 254 | .start = 0xE6BD0000, | 257 | .start = 0xE6BD0000, |
| 255 | .end = 0xE6BD00FF, | 258 | .end = 0xE6BD00FF, |
| 256 | .flags = IORESOURCE_MEM, | 259 | .flags = IORESOURCE_MEM, |
| @@ -390,10 +393,40 @@ static struct platform_device usb1_host_device = { | |||
| 390 | .resource = usb1_host_resources, | 393 | .resource = usb1_host_resources, |
| 391 | }; | 394 | }; |
| 392 | 395 | ||
| 396 | const static struct fb_videomode ap4evb_lcdc_modes[] = { | ||
| 397 | { | ||
| 398 | #ifdef CONFIG_AP4EVB_QHD | ||
| 399 | .name = "R63302(QHD)", | ||
| 400 | .xres = 544, | ||
| 401 | .yres = 961, | ||
| 402 | .left_margin = 72, | ||
| 403 | .right_margin = 600, | ||
| 404 | .hsync_len = 16, | ||
| 405 | .upper_margin = 8, | ||
| 406 | .lower_margin = 8, | ||
| 407 | .vsync_len = 2, | ||
| 408 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, | ||
| 409 | #else | ||
| 410 | .name = "WVGA Panel", | ||
| 411 | .xres = 800, | ||
| 412 | .yres = 480, | ||
| 413 | .left_margin = 220, | ||
| 414 | .right_margin = 110, | ||
| 415 | .hsync_len = 70, | ||
| 416 | .upper_margin = 20, | ||
| 417 | .lower_margin = 5, | ||
| 418 | .vsync_len = 5, | ||
| 419 | .sync = 0, | ||
| 420 | #endif | ||
| 421 | }, | ||
| 422 | }; | ||
| 423 | |||
| 393 | static struct sh_mobile_lcdc_info lcdc_info = { | 424 | static struct sh_mobile_lcdc_info lcdc_info = { |
| 394 | .ch[0] = { | 425 | .ch[0] = { |
| 395 | .chan = LCDC_CHAN_MAINLCD, | 426 | .chan = LCDC_CHAN_MAINLCD, |
| 396 | .bpp = 16, | 427 | .bpp = 16, |
| 428 | .lcd_cfg = ap4evb_lcdc_modes, | ||
| 429 | .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), | ||
| 397 | } | 430 | } |
| 398 | }; | 431 | }; |
| 399 | 432 | ||
| @@ -532,27 +565,6 @@ static struct platform_device *qhd_devices[] __initdata = { | |||
| 532 | 565 | ||
| 533 | /* FSI */ | 566 | /* FSI */ |
| 534 | #define IRQ_FSI evt2irq(0x1840) | 567 | #define IRQ_FSI evt2irq(0x1840) |
| 535 | #define FSIACKCR 0xE6150018 | ||
| 536 | static void fsiackcr_init(struct clk *clk) | ||
| 537 | { | ||
| 538 | u32 status = __raw_readl(clk->enable_reg); | ||
| 539 | |||
| 540 | /* use external clock */ | ||
| 541 | status &= ~0x000000ff; | ||
| 542 | status |= 0x00000080; | ||
| 543 | __raw_writel(status, clk->enable_reg); | ||
| 544 | } | ||
| 545 | |||
| 546 | static struct clk_ops fsiackcr_clk_ops = { | ||
| 547 | .init = fsiackcr_init, | ||
| 548 | }; | ||
| 549 | |||
| 550 | static struct clk fsiackcr_clk = { | ||
| 551 | .ops = &fsiackcr_clk_ops, | ||
| 552 | .enable_reg = (void __iomem *)FSIACKCR, | ||
| 553 | .rate = 0, /* unknown */ | ||
| 554 | }; | ||
| 555 | |||
| 556 | static struct sh_fsi_platform_info fsi_info = { | 568 | static struct sh_fsi_platform_info fsi_info = { |
| 557 | .porta_flags = SH_FSI_BRS_INV | | 569 | .porta_flags = SH_FSI_BRS_INV | |
| 558 | SH_FSI_OUT_SLAVE_MODE | | 570 | SH_FSI_OUT_SLAVE_MODE | |
| @@ -592,26 +604,6 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = { | |||
| 592 | .interface_type = RGB24, | 604 | .interface_type = RGB24, |
| 593 | .clock_divider = 1, | 605 | .clock_divider = 1, |
| 594 | .flags = LCDC_FLAGS_DWPOL, | 606 | .flags = LCDC_FLAGS_DWPOL, |
| 595 | .lcd_cfg = { | ||
| 596 | .name = "HDMI", | ||
| 597 | /* So far only 720p is supported */ | ||
| 598 | .xres = 1280, | ||
| 599 | .yres = 720, | ||
| 600 | /* | ||
| 601 | * If left and right margins are not multiples of 8, | ||
| 602 | * LDHAJR will be adjusted accordingly by the LCDC | ||
| 603 | * driver. Until we start using EDID, these values | ||
| 604 | * might have to be adjusted for different monitors. | ||
| 605 | */ | ||
| 606 | .left_margin = 200, | ||
| 607 | .right_margin = 88, | ||
| 608 | .hsync_len = 48, | ||
| 609 | .upper_margin = 20, | ||
| 610 | .lower_margin = 5, | ||
| 611 | .vsync_len = 5, | ||
| 612 | .pixclock = 13468, | ||
| 613 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, | ||
| 614 | }, | ||
| 615 | } | 607 | } |
| 616 | }; | 608 | }; |
| 617 | 609 | ||
| @@ -623,7 +615,7 @@ static struct resource lcdc1_resources[] = { | |||
| 623 | .flags = IORESOURCE_MEM, | 615 | .flags = IORESOURCE_MEM, |
| 624 | }, | 616 | }, |
| 625 | [1] = { | 617 | [1] = { |
| 626 | .start = intcs_evt2irq(0x17a0), | 618 | .start = intcs_evt2irq(0x1780), |
| 627 | .flags = IORESOURCE_IRQ, | 619 | .flags = IORESOURCE_IRQ, |
| 628 | }, | 620 | }, |
| 629 | }; | 621 | }; |
| @@ -704,6 +696,95 @@ static struct platform_device leds_device = { | |||
| 704 | }, | 696 | }, |
| 705 | }; | 697 | }; |
| 706 | 698 | ||
| 699 | static struct i2c_board_info imx074_info = { | ||
| 700 | I2C_BOARD_INFO("imx074", 0x1a), | ||
| 701 | }; | ||
| 702 | |||
| 703 | struct soc_camera_link imx074_link = { | ||
| 704 | .bus_id = 0, | ||
| 705 | .board_info = &imx074_info, | ||
| 706 | .i2c_adapter_id = 0, | ||
| 707 | .module_name = "imx074", | ||
| 708 | }; | ||
| 709 | |||
| 710 | static struct platform_device ap4evb_camera = { | ||
| 711 | .name = "soc-camera-pdrv", | ||
| 712 | .id = 0, | ||
| 713 | .dev = { | ||
| 714 | .platform_data = &imx074_link, | ||
| 715 | }, | ||
| 716 | }; | ||
| 717 | |||
| 718 | static struct sh_csi2_client_config csi2_clients[] = { | ||
| 719 | { | ||
| 720 | .phy = SH_CSI2_PHY_MAIN, | ||
| 721 | .lanes = 3, | ||
| 722 | .channel = 0, | ||
| 723 | .pdev = &ap4evb_camera, | ||
| 724 | }, | ||
| 725 | }; | ||
| 726 | |||
| 727 | static struct sh_csi2_pdata csi2_info = { | ||
| 728 | .type = SH_CSI2C, | ||
| 729 | .clients = csi2_clients, | ||
| 730 | .num_clients = ARRAY_SIZE(csi2_clients), | ||
| 731 | .flags = SH_CSI2_ECC | SH_CSI2_CRC, | ||
| 732 | }; | ||
| 733 | |||
| 734 | static struct resource csi2_resources[] = { | ||
| 735 | [0] = { | ||
| 736 | .name = "CSI2", | ||
| 737 | .start = 0xffc90000, | ||
| 738 | .end = 0xffc90fff, | ||
| 739 | .flags = IORESOURCE_MEM, | ||
| 740 | }, | ||
| 741 | [1] = { | ||
| 742 | .start = intcs_evt2irq(0x17a0), | ||
| 743 | .flags = IORESOURCE_IRQ, | ||
| 744 | }, | ||
| 745 | }; | ||
| 746 | |||
| 747 | static struct platform_device csi2_device = { | ||
| 748 | .name = "sh-mobile-csi2", | ||
| 749 | .id = 0, | ||
| 750 | .num_resources = ARRAY_SIZE(csi2_resources), | ||
| 751 | .resource = csi2_resources, | ||
| 752 | .dev = { | ||
| 753 | .platform_data = &csi2_info, | ||
| 754 | }, | ||
| 755 | }; | ||
| 756 | |||
| 757 | static struct sh_mobile_ceu_info sh_mobile_ceu_info = { | ||
| 758 | .flags = SH_CEU_FLAG_USE_8BIT_BUS, | ||
| 759 | .csi2_dev = &csi2_device.dev, | ||
| 760 | }; | ||
| 761 | |||
| 762 | static struct resource ceu_resources[] = { | ||
| 763 | [0] = { | ||
| 764 | .name = "CEU", | ||
| 765 | .start = 0xfe910000, | ||
| 766 | .end = 0xfe91009f, | ||
| 767 | .flags = IORESOURCE_MEM, | ||
| 768 | }, | ||
| 769 | [1] = { | ||
| 770 | .start = intcs_evt2irq(0x880), | ||
| 771 | .flags = IORESOURCE_IRQ, | ||
| 772 | }, | ||
| 773 | [2] = { | ||
| 774 | /* place holder for contiguous memory */ | ||
| 775 | }, | ||
| 776 | }; | ||
| 777 | |||
| 778 | static struct platform_device ceu_device = { | ||
| 779 | .name = "sh_mobile_ceu", | ||
| 780 | .id = 0, /* "ceu0" clock */ | ||
| 781 | .num_resources = ARRAY_SIZE(ceu_resources), | ||
| 782 | .resource = ceu_resources, | ||
| 783 | .dev = { | ||
| 784 | .platform_data = &sh_mobile_ceu_info, | ||
| 785 | }, | ||
| 786 | }; | ||
| 787 | |||
| 707 | static struct platform_device *ap4evb_devices[] __initdata = { | 788 | static struct platform_device *ap4evb_devices[] __initdata = { |
| 708 | &leds_device, | 789 | &leds_device, |
| 709 | &nor_flash_device, | 790 | &nor_flash_device, |
| @@ -716,6 +797,9 @@ static struct platform_device *ap4evb_devices[] __initdata = { | |||
| 716 | &lcdc1_device, | 797 | &lcdc1_device, |
| 717 | &lcdc_device, | 798 | &lcdc_device, |
| 718 | &hdmi_device, | 799 | &hdmi_device, |
| 800 | &csi2_device, | ||
| 801 | &ceu_device, | ||
| 802 | &ap4evb_camera, | ||
| 719 | }; | 803 | }; |
| 720 | 804 | ||
| 721 | static int __init hdmi_init_pm_clock(void) | 805 | static int __init hdmi_init_pm_clock(void) |
| @@ -730,22 +814,22 @@ static int __init hdmi_init_pm_clock(void) | |||
| 730 | goto out; | 814 | goto out; |
| 731 | } | 815 | } |
| 732 | 816 | ||
| 733 | ret = clk_set_parent(&pllc2_clk, &dv_clki_div2_clk); | 817 | ret = clk_set_parent(&sh7372_pllc2_clk, &sh7372_dv_clki_div2_clk); |
| 734 | if (ret < 0) { | 818 | if (ret < 0) { |
| 735 | pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, pllc2_clk.usecount); | 819 | pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, sh7372_pllc2_clk.usecount); |
| 736 | goto out; | 820 | goto out; |
| 737 | } | 821 | } |
| 738 | 822 | ||
| 739 | pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&pllc2_clk)); | 823 | pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&sh7372_pllc2_clk)); |
| 740 | 824 | ||
| 741 | rate = clk_round_rate(&pllc2_clk, 594000000); | 825 | rate = clk_round_rate(&sh7372_pllc2_clk, 594000000); |
| 742 | if (rate < 0) { | 826 | if (rate < 0) { |
| 743 | pr_err("Cannot get suitable rate: %ld\n", rate); | 827 | pr_err("Cannot get suitable rate: %ld\n", rate); |
| 744 | ret = rate; | 828 | ret = rate; |
| 745 | goto out; | 829 | goto out; |
| 746 | } | 830 | } |
| 747 | 831 | ||
| 748 | ret = clk_set_rate(&pllc2_clk, rate); | 832 | ret = clk_set_rate(&sh7372_pllc2_clk, rate); |
| 749 | if (ret < 0) { | 833 | if (ret < 0) { |
| 750 | pr_err("Cannot set rate %ld: %d\n", rate, ret); | 834 | pr_err("Cannot set rate %ld: %d\n", rate, ret); |
| 751 | goto out; | 835 | goto out; |
| @@ -753,7 +837,7 @@ static int __init hdmi_init_pm_clock(void) | |||
| 753 | 837 | ||
| 754 | pr_debug("PLLC2 set frequency %lu\n", rate); | 838 | pr_debug("PLLC2 set frequency %lu\n", rate); |
| 755 | 839 | ||
| 756 | ret = clk_set_parent(hdmi_ick, &pllc2_clk); | 840 | ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); |
| 757 | if (ret < 0) { | 841 | if (ret < 0) { |
| 758 | pr_err("Cannot set HDMI parent: %d\n", ret); | 842 | pr_err("Cannot set HDMI parent: %d\n", ret); |
| 759 | goto out; | 843 | goto out; |
| @@ -767,11 +851,51 @@ out: | |||
| 767 | 851 | ||
| 768 | device_initcall(hdmi_init_pm_clock); | 852 | device_initcall(hdmi_init_pm_clock); |
| 769 | 853 | ||
| 854 | #define FSIACK_DUMMY_RATE 48000 | ||
| 855 | static int __init fsi_init_pm_clock(void) | ||
| 856 | { | ||
| 857 | struct clk *fsia_ick; | ||
| 858 | int ret; | ||
| 859 | |||
| 860 | /* | ||
| 861 | * FSIACK is connected to AK4642, | ||
| 862 | * and the rate is depend on playing sound rate. | ||
| 863 | * So, set dummy rate (= 48k) here | ||
| 864 | */ | ||
| 865 | ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE); | ||
| 866 | if (ret < 0) { | ||
| 867 | pr_err("Cannot set FSIACK dummy rate: %d\n", ret); | ||
| 868 | return ret; | ||
| 869 | } | ||
| 870 | |||
| 871 | fsia_ick = clk_get(&fsi_device.dev, "icka"); | ||
| 872 | if (IS_ERR(fsia_ick)) { | ||
| 873 | ret = PTR_ERR(fsia_ick); | ||
| 874 | pr_err("Cannot get FSI ICK: %d\n", ret); | ||
| 875 | return ret; | ||
| 876 | } | ||
| 877 | |||
| 878 | ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk); | ||
| 879 | if (ret < 0) { | ||
| 880 | pr_err("Cannot set FSI-A parent: %d\n", ret); | ||
| 881 | goto out; | ||
| 882 | } | ||
| 883 | |||
| 884 | ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE); | ||
| 885 | if (ret < 0) | ||
| 886 | pr_err("Cannot set FSI-A rate: %d\n", ret); | ||
| 887 | |||
| 888 | out: | ||
| 889 | clk_put(fsia_ick); | ||
| 890 | |||
| 891 | return ret; | ||
| 892 | } | ||
| 893 | device_initcall(fsi_init_pm_clock); | ||
| 894 | |||
| 770 | /* | 895 | /* |
| 771 | * FIXME !! | 896 | * FIXME !! |
| 772 | * | 897 | * |
| 773 | * gpio_no_direction | 898 | * gpio_no_direction |
| 774 | * gpio_pull_up | ||
| 775 | * are quick_hack. | 899 | * are quick_hack. |
| 776 | * | 900 | * |
| 777 | * current gpio frame work doesn't have | 901 | * current gpio frame work doesn't have |
| @@ -783,49 +907,37 @@ static void __init gpio_no_direction(u32 addr) | |||
| 783 | __raw_writeb(0x00, addr); | 907 | __raw_writeb(0x00, addr); |
| 784 | } | 908 | } |
| 785 | 909 | ||
| 786 | static void __init gpio_pull_up(u32 addr) | ||
| 787 | { | ||
| 788 | u8 data = __raw_readb(addr); | ||
| 789 | |||
| 790 | data &= 0x0F; | ||
| 791 | data |= 0xC0; | ||
| 792 | __raw_writeb(data, addr); | ||
| 793 | } | ||
| 794 | |||
| 795 | /* TouchScreen */ | 910 | /* TouchScreen */ |
| 911 | #ifdef CONFIG_AP4EVB_QHD | ||
| 912 | # define GPIO_TSC_IRQ GPIO_FN_IRQ28_123 | ||
| 913 | # define GPIO_TSC_PORT GPIO_PORT123 | ||
| 914 | #else /* WVGA */ | ||
| 915 | # define GPIO_TSC_IRQ GPIO_FN_IRQ7_40 | ||
| 916 | # define GPIO_TSC_PORT GPIO_PORT40 | ||
| 917 | #endif | ||
| 918 | |||
| 796 | #define IRQ28 evt2irq(0x3380) /* IRQ28A */ | 919 | #define IRQ28 evt2irq(0x3380) /* IRQ28A */ |
| 797 | #define IRQ7 evt2irq(0x02e0) /* IRQ7A */ | 920 | #define IRQ7 evt2irq(0x02e0) /* IRQ7A */ |
| 798 | static int ts_get_pendown_state(void) | 921 | static int ts_get_pendown_state(void) |
| 799 | { | 922 | { |
| 800 | int val1, val2; | 923 | int val; |
| 801 | 924 | ||
| 802 | gpio_free(GPIO_FN_IRQ28_123); | 925 | gpio_free(GPIO_TSC_IRQ); |
| 803 | gpio_free(GPIO_FN_IRQ7_40); | ||
| 804 | 926 | ||
| 805 | gpio_request(GPIO_PORT123, NULL); | 927 | gpio_request(GPIO_TSC_PORT, NULL); |
| 806 | gpio_request(GPIO_PORT40, NULL); | ||
| 807 | 928 | ||
| 808 | gpio_direction_input(GPIO_PORT123); | 929 | gpio_direction_input(GPIO_TSC_PORT); |
| 809 | gpio_direction_input(GPIO_PORT40); | ||
| 810 | 930 | ||
| 811 | val1 = gpio_get_value(GPIO_PORT123); | 931 | val = gpio_get_value(GPIO_TSC_PORT); |
| 812 | val2 = gpio_get_value(GPIO_PORT40); | ||
| 813 | 932 | ||
| 814 | gpio_request(GPIO_FN_IRQ28_123, NULL); /* for QHD */ | 933 | gpio_request(GPIO_TSC_IRQ, NULL); |
| 815 | gpio_request(GPIO_FN_IRQ7_40, NULL); /* for WVGA */ | ||
| 816 | 934 | ||
| 817 | return val1 ^ val2; | 935 | return !val; |
| 818 | } | 936 | } |
| 819 | 937 | ||
| 820 | #define PORT40CR 0xE6051028 | ||
| 821 | #define PORT123CR 0xE605007B | ||
| 822 | static int ts_init(void) | 938 | static int ts_init(void) |
| 823 | { | 939 | { |
| 824 | gpio_request(GPIO_FN_IRQ28_123, NULL); /* for QHD */ | 940 | gpio_request(GPIO_TSC_IRQ, NULL); |
| 825 | gpio_request(GPIO_FN_IRQ7_40, NULL); /* for WVGA */ | ||
| 826 | |||
| 827 | gpio_pull_up(PORT40CR); | ||
| 828 | gpio_pull_up(PORT123CR); | ||
| 829 | 941 | ||
| 830 | return 0; | 942 | return 0; |
| 831 | } | 943 | } |
| @@ -974,14 +1086,6 @@ static void __init ap4evb_init(void) | |||
| 974 | clk_put(clk); | 1086 | clk_put(clk); |
| 975 | } | 1087 | } |
| 976 | 1088 | ||
| 977 | /* change parent of FSI A */ | ||
| 978 | clk = clk_get(NULL, "fsia_clk"); | ||
| 979 | if (!IS_ERR(clk)) { | ||
| 980 | clk_register(&fsiackcr_clk); | ||
| 981 | clk_set_parent(clk, &fsiackcr_clk); | ||
| 982 | clk_put(clk); | ||
| 983 | } | ||
| 984 | |||
| 985 | /* | 1089 | /* |
| 986 | * set irq priority, to avoid sound chopping | 1090 | * set irq priority, to avoid sound chopping |
| 987 | * when NFS rootfs is used | 1091 | * when NFS rootfs is used |
| @@ -996,8 +1100,10 @@ static void __init ap4evb_init(void) | |||
| 996 | ARRAY_SIZE(i2c1_devices)); | 1100 | ARRAY_SIZE(i2c1_devices)); |
| 997 | 1101 | ||
| 998 | #ifdef CONFIG_AP4EVB_QHD | 1102 | #ifdef CONFIG_AP4EVB_QHD |
| 1103 | |||
| 999 | /* | 1104 | /* |
| 1000 | * QHD | 1105 | * For QHD Panel (MIPI-DSI, CONFIG_AP4EVB_QHD=y) and |
| 1106 | * IRQ28 for Touch Panel, set dip switches S3, S43 as OFF, ON. | ||
| 1001 | */ | 1107 | */ |
| 1002 | 1108 | ||
| 1003 | /* enable KEYSC */ | 1109 | /* enable KEYSC */ |
| @@ -1023,17 +1129,6 @@ static void __init ap4evb_init(void) | |||
| 1023 | lcdc_info.ch[0].interface_type = RGB24; | 1129 | lcdc_info.ch[0].interface_type = RGB24; |
| 1024 | lcdc_info.ch[0].clock_divider = 1; | 1130 | lcdc_info.ch[0].clock_divider = 1; |
| 1025 | lcdc_info.ch[0].flags = LCDC_FLAGS_DWPOL; | 1131 | lcdc_info.ch[0].flags = LCDC_FLAGS_DWPOL; |
| 1026 | lcdc_info.ch[0].lcd_cfg.name = "R63302(QHD)"; | ||
| 1027 | lcdc_info.ch[0].lcd_cfg.xres = 544; | ||
| 1028 | lcdc_info.ch[0].lcd_cfg.yres = 961; | ||
| 1029 | lcdc_info.ch[0].lcd_cfg.left_margin = 72; | ||
| 1030 | lcdc_info.ch[0].lcd_cfg.right_margin = 600; | ||
| 1031 | lcdc_info.ch[0].lcd_cfg.hsync_len = 16; | ||
| 1032 | lcdc_info.ch[0].lcd_cfg.upper_margin = 8; | ||
| 1033 | lcdc_info.ch[0].lcd_cfg.lower_margin = 8; | ||
| 1034 | lcdc_info.ch[0].lcd_cfg.vsync_len = 2; | ||
| 1035 | lcdc_info.ch[0].lcd_cfg.sync = FB_SYNC_VERT_HIGH_ACT | | ||
| 1036 | FB_SYNC_HOR_HIGH_ACT; | ||
| 1037 | lcdc_info.ch[0].lcd_size_cfg.width = 44; | 1132 | lcdc_info.ch[0].lcd_size_cfg.width = 44; |
| 1038 | lcdc_info.ch[0].lcd_size_cfg.height = 79; | 1133 | lcdc_info.ch[0].lcd_size_cfg.height = 79; |
| 1039 | 1134 | ||
| @@ -1041,8 +1136,10 @@ static void __init ap4evb_init(void) | |||
| 1041 | 1136 | ||
| 1042 | #else | 1137 | #else |
| 1043 | /* | 1138 | /* |
| 1044 | * WVGA | 1139 | * For WVGA Panel (18-bit RGB, CONFIG_AP4EVB_WVGA=y) and |
| 1140 | * IRQ7 for Touch Panel, set dip switches S3, S43 to ON, OFF. | ||
| 1045 | */ | 1141 | */ |
| 1142 | |||
| 1046 | gpio_request(GPIO_FN_LCDD17, NULL); | 1143 | gpio_request(GPIO_FN_LCDD17, NULL); |
| 1047 | gpio_request(GPIO_FN_LCDD16, NULL); | 1144 | gpio_request(GPIO_FN_LCDD16, NULL); |
| 1048 | gpio_request(GPIO_FN_LCDD15, NULL); | 1145 | gpio_request(GPIO_FN_LCDD15, NULL); |
| @@ -1074,16 +1171,6 @@ static void __init ap4evb_init(void) | |||
| 1074 | lcdc_info.ch[0].interface_type = RGB18; | 1171 | lcdc_info.ch[0].interface_type = RGB18; |
| 1075 | lcdc_info.ch[0].clock_divider = 2; | 1172 | lcdc_info.ch[0].clock_divider = 2; |
| 1076 | lcdc_info.ch[0].flags = 0; | 1173 | lcdc_info.ch[0].flags = 0; |
| 1077 | lcdc_info.ch[0].lcd_cfg.name = "WVGA Panel"; | ||
| 1078 | lcdc_info.ch[0].lcd_cfg.xres = 800; | ||
| 1079 | lcdc_info.ch[0].lcd_cfg.yres = 480; | ||
| 1080 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
| 1081 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
| 1082 | lcdc_info.ch[0].lcd_cfg.hsync_len = 70; | ||
| 1083 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
| 1084 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
| 1085 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
| 1086 | lcdc_info.ch[0].lcd_cfg.sync = 0; | ||
| 1087 | lcdc_info.ch[0].lcd_size_cfg.width = 152; | 1174 | lcdc_info.ch[0].lcd_size_cfg.width = 152; |
| 1088 | lcdc_info.ch[0].lcd_size_cfg.height = 91; | 1175 | lcdc_info.ch[0].lcd_size_cfg.height = 91; |
| 1089 | 1176 | ||
| @@ -1094,6 +1181,23 @@ static void __init ap4evb_init(void) | |||
| 1094 | i2c_register_board_info(0, &tsc_device, 1); | 1181 | i2c_register_board_info(0, &tsc_device, 1); |
| 1095 | #endif /* CONFIG_AP4EVB_QHD */ | 1182 | #endif /* CONFIG_AP4EVB_QHD */ |
| 1096 | 1183 | ||
| 1184 | /* CEU */ | ||
| 1185 | |||
| 1186 | /* | ||
| 1187 | * TODO: reserve memory for V4L2 DMA buffers, when a suitable API | ||
| 1188 | * becomes available | ||
| 1189 | */ | ||
| 1190 | |||
| 1191 | /* MIPI-CSI stuff */ | ||
| 1192 | gpio_request(GPIO_FN_VIO_CKO, NULL); | ||
| 1193 | |||
| 1194 | clk = clk_get(NULL, "vck1_clk"); | ||
| 1195 | if (!IS_ERR(clk)) { | ||
| 1196 | clk_set_rate(clk, clk_round_rate(clk, 13000000)); | ||
| 1197 | clk_enable(clk); | ||
| 1198 | clk_put(clk); | ||
| 1199 | } | ||
| 1200 | |||
| 1097 | sh7372_add_standard_devices(); | 1201 | sh7372_add_standard_devices(); |
| 1098 | 1202 | ||
| 1099 | /* HDMI */ | 1203 | /* HDMI */ |
| @@ -1116,7 +1220,7 @@ static void __init ap4evb_timer_init(void) | |||
| 1116 | shmobile_timer.init(); | 1220 | shmobile_timer.init(); |
| 1117 | 1221 | ||
| 1118 | /* External clock source */ | 1222 | /* External clock source */ |
| 1119 | clk_set_rate(&dv_clki_clk, 27000000); | 1223 | clk_set_rate(&sh7372_dv_clki_clk, 27000000); |
| 1120 | } | 1224 | } |
| 1121 | 1225 | ||
| 1122 | static struct sys_timer ap4evb_timer = { | 1226 | static struct sys_timer ap4evb_timer = { |
diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c index b6454c9f2abb..9f78729098f2 100644 --- a/arch/arm/mach-shmobile/clock-sh7367.c +++ b/arch/arm/mach-shmobile/clock-sh7367.c | |||
| @@ -321,7 +321,7 @@ static struct clk_lookup lookups[] = { | |||
| 321 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */ | 321 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */ |
| 322 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */ | 322 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */ |
| 323 | CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */ | 323 | CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */ |
| 324 | CLKDEV_CON_ID("cmt1", &mstp_clks[SYMSTP229]), /* CMT10 */ | 324 | CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[SYMSTP229]), /* CMT10 */ |
| 325 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */ | 325 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */ |
| 326 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */ | 326 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */ |
| 327 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */ | 327 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */ |
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 759468992ad2..8565aefa21fd 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c | |||
| @@ -51,7 +51,7 @@ | |||
| 51 | #define SMSTPCR4 0xe6150140 | 51 | #define SMSTPCR4 0xe6150140 |
| 52 | 52 | ||
| 53 | /* Platforms must set frequency on their DV_CLKI pin */ | 53 | /* Platforms must set frequency on their DV_CLKI pin */ |
| 54 | struct clk dv_clki_clk = { | 54 | struct clk sh7372_dv_clki_clk = { |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
| 57 | /* Fixed 32 KHz root clock from EXTALR pin */ | 57 | /* Fixed 32 KHz root clock from EXTALR pin */ |
| @@ -86,9 +86,9 @@ static struct clk_ops div2_clk_ops = { | |||
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| 88 | /* Divide dv_clki by two */ | 88 | /* Divide dv_clki by two */ |
| 89 | struct clk dv_clki_div2_clk = { | 89 | struct clk sh7372_dv_clki_div2_clk = { |
| 90 | .ops = &div2_clk_ops, | 90 | .ops = &div2_clk_ops, |
| 91 | .parent = &dv_clki_clk, | 91 | .parent = &sh7372_dv_clki_clk, |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | /* Divide extal1 by two */ | 94 | /* Divide extal1 by two */ |
| @@ -150,7 +150,7 @@ static struct clk pllc1_div2_clk = { | |||
| 150 | static struct clk *pllc2_parent[] = { | 150 | static struct clk *pllc2_parent[] = { |
| 151 | [0] = &extal1_div2_clk, | 151 | [0] = &extal1_div2_clk, |
| 152 | [1] = &extal2_div2_clk, | 152 | [1] = &extal2_div2_clk, |
| 153 | [2] = &dv_clki_div2_clk, | 153 | [2] = &sh7372_dv_clki_div2_clk, |
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | /* Only multipliers 20 * 2 to 46 * 2 are valid, last entry for CPUFREQ_TABLE_END */ | 156 | /* Only multipliers 20 * 2 to 46 * 2 are valid, last entry for CPUFREQ_TABLE_END */ |
| @@ -284,7 +284,7 @@ static struct clk_ops pllc2_clk_ops = { | |||
| 284 | .set_parent = pllc2_set_parent, | 284 | .set_parent = pllc2_set_parent, |
| 285 | }; | 285 | }; |
| 286 | 286 | ||
| 287 | struct clk pllc2_clk = { | 287 | struct clk sh7372_pllc2_clk = { |
| 288 | .ops = &pllc2_clk_ops, | 288 | .ops = &pllc2_clk_ops, |
| 289 | .parent = &extal1_div2_clk, | 289 | .parent = &extal1_div2_clk, |
| 290 | .freq_table = pllc2_freq_table, | 290 | .freq_table = pllc2_freq_table, |
| @@ -292,19 +292,28 @@ struct clk pllc2_clk = { | |||
| 292 | .parent_num = ARRAY_SIZE(pllc2_parent), | 292 | .parent_num = ARRAY_SIZE(pllc2_parent), |
| 293 | }; | 293 | }; |
| 294 | 294 | ||
| 295 | /* External input clock (pin name: FSIACK/FSIBCK ) */ | ||
| 296 | struct clk sh7372_fsiack_clk = { | ||
| 297 | }; | ||
| 298 | |||
| 299 | struct clk sh7372_fsibck_clk = { | ||
| 300 | }; | ||
| 301 | |||
| 295 | static struct clk *main_clks[] = { | 302 | static struct clk *main_clks[] = { |
| 296 | &dv_clki_clk, | 303 | &sh7372_dv_clki_clk, |
| 297 | &r_clk, | 304 | &r_clk, |
| 298 | &sh7372_extal1_clk, | 305 | &sh7372_extal1_clk, |
| 299 | &sh7372_extal2_clk, | 306 | &sh7372_extal2_clk, |
| 300 | &dv_clki_div2_clk, | 307 | &sh7372_dv_clki_div2_clk, |
| 301 | &extal1_div2_clk, | 308 | &extal1_div2_clk, |
| 302 | &extal2_div2_clk, | 309 | &extal2_div2_clk, |
| 303 | &extal2_div4_clk, | 310 | &extal2_div4_clk, |
| 304 | &pllc0_clk, | 311 | &pllc0_clk, |
| 305 | &pllc1_clk, | 312 | &pllc1_clk, |
| 306 | &pllc1_div2_clk, | 313 | &pllc1_div2_clk, |
| 307 | &pllc2_clk, | 314 | &sh7372_pllc2_clk, |
| 315 | &sh7372_fsiack_clk, | ||
| 316 | &sh7372_fsibck_clk, | ||
| 308 | }; | 317 | }; |
| 309 | 318 | ||
| 310 | static void div4_kick(struct clk *clk) | 319 | static void div4_kick(struct clk *clk) |
| @@ -357,7 +366,7 @@ static struct clk div4_clks[DIV4_NR] = { | |||
| 357 | }; | 366 | }; |
| 358 | 367 | ||
| 359 | enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, | 368 | enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, |
| 360 | DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU, | 369 | DIV6_SUB, DIV6_SPU, |
| 361 | DIV6_VOU, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P, | 370 | DIV6_VOU, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P, |
| 362 | DIV6_NR }; | 371 | DIV6_NR }; |
| 363 | 372 | ||
| @@ -367,8 +376,6 @@ static struct clk div6_clks[DIV6_NR] = { | |||
| 367 | [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), | 376 | [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), |
| 368 | [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0), | 377 | [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0), |
| 369 | [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0), | 378 | [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0), |
| 370 | [DIV6_FSIA] = SH_CLK_DIV6(&pllc1_div2_clk, FSIACKCR, 0), | ||
| 371 | [DIV6_FSIB] = SH_CLK_DIV6(&pllc1_div2_clk, FSIBCKCR, 0), | ||
| 372 | [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0), | 379 | [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0), |
| 373 | [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), | 380 | [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), |
| 374 | [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), | 381 | [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), |
| @@ -377,24 +384,42 @@ static struct clk div6_clks[DIV6_NR] = { | |||
| 377 | [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0), | 384 | [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0), |
| 378 | }; | 385 | }; |
| 379 | 386 | ||
| 380 | enum { DIV6_HDMI, DIV6_REPARENT_NR }; | 387 | enum { DIV6_HDMI, DIV6_FSIA, DIV6_FSIB, DIV6_REPARENT_NR }; |
| 381 | 388 | ||
| 382 | /* Indices are important - they are the actual src selecting values */ | 389 | /* Indices are important - they are the actual src selecting values */ |
| 383 | static struct clk *hdmi_parent[] = { | 390 | static struct clk *hdmi_parent[] = { |
| 384 | [0] = &pllc1_div2_clk, | 391 | [0] = &pllc1_div2_clk, |
| 385 | [1] = &pllc2_clk, | 392 | [1] = &sh7372_pllc2_clk, |
| 386 | [2] = &dv_clki_clk, | 393 | [2] = &sh7372_dv_clki_clk, |
| 387 | [3] = NULL, /* pllc2_div4 not implemented yet */ | 394 | [3] = NULL, /* pllc2_div4 not implemented yet */ |
| 388 | }; | 395 | }; |
| 389 | 396 | ||
| 397 | static struct clk *fsiackcr_parent[] = { | ||
| 398 | [0] = &pllc1_div2_clk, | ||
| 399 | [1] = &sh7372_pllc2_clk, | ||
| 400 | [2] = &sh7372_fsiack_clk, /* external input for FSI A */ | ||
| 401 | [3] = NULL, /* setting prohibited */ | ||
| 402 | }; | ||
| 403 | |||
| 404 | static struct clk *fsibckcr_parent[] = { | ||
| 405 | [0] = &pllc1_div2_clk, | ||
| 406 | [1] = &sh7372_pllc2_clk, | ||
| 407 | [2] = &sh7372_fsibck_clk, /* external input for FSI B */ | ||
| 408 | [3] = NULL, /* setting prohibited */ | ||
| 409 | }; | ||
| 410 | |||
| 390 | static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { | 411 | static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { |
| 391 | [DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0, | 412 | [DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0, |
| 392 | hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2), | 413 | hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2), |
| 414 | [DIV6_FSIA] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIACKCR, 0, | ||
| 415 | fsiackcr_parent, ARRAY_SIZE(fsiackcr_parent), 6, 2), | ||
| 416 | [DIV6_FSIB] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIBCKCR, 0, | ||
| 417 | fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2), | ||
| 393 | }; | 418 | }; |
| 394 | 419 | ||
| 395 | enum { MSTP001, | 420 | enum { MSTP001, |
| 396 | MSTP131, MSTP130, | 421 | MSTP131, MSTP130, |
| 397 | MSTP129, MSTP128, MSTP127, MSTP126, | 422 | MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, |
| 398 | MSTP118, MSTP117, MSTP116, | 423 | MSTP118, MSTP117, MSTP116, |
| 399 | MSTP106, MSTP101, MSTP100, | 424 | MSTP106, MSTP101, MSTP100, |
| 400 | MSTP223, | 425 | MSTP223, |
| @@ -414,6 +439,7 @@ static struct clk mstp_clks[MSTP_NR] = { | |||
| 414 | [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ | 439 | [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ |
| 415 | [MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU */ | 440 | [MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU */ |
| 416 | [MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2 */ | 441 | [MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2 */ |
| 442 | [MSTP125] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */ | ||
| 417 | [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */ | 443 | [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */ |
| 418 | [MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ | 444 | [MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ |
| 419 | [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ | 445 | [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ |
| @@ -429,7 +455,7 @@ static struct clk mstp_clks[MSTP_NR] = { | |||
| 429 | [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ | 455 | [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ |
| 430 | [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ | 456 | [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ |
| 431 | [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ | 457 | [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ |
| 432 | [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSIA */ | 458 | [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */ |
| 433 | [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ | 459 | [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ |
| 434 | [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ | 460 | [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ |
| 435 | [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ | 461 | [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ |
| @@ -445,10 +471,11 @@ static struct clk mstp_clks[MSTP_NR] = { | |||
| 445 | 471 | ||
| 446 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } | 472 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } |
| 447 | #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk } | 473 | #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk } |
| 474 | #define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk } | ||
| 448 | 475 | ||
| 449 | static struct clk_lookup lookups[] = { | 476 | static struct clk_lookup lookups[] = { |
| 450 | /* main clocks */ | 477 | /* main clocks */ |
| 451 | CLKDEV_CON_ID("dv_clki_div2_clk", &dv_clki_div2_clk), | 478 | CLKDEV_CON_ID("dv_clki_div2_clk", &sh7372_dv_clki_div2_clk), |
| 452 | CLKDEV_CON_ID("r_clk", &r_clk), | 479 | CLKDEV_CON_ID("r_clk", &r_clk), |
| 453 | CLKDEV_CON_ID("extal1", &sh7372_extal1_clk), | 480 | CLKDEV_CON_ID("extal1", &sh7372_extal1_clk), |
| 454 | CLKDEV_CON_ID("extal2", &sh7372_extal2_clk), | 481 | CLKDEV_CON_ID("extal2", &sh7372_extal2_clk), |
| @@ -458,7 +485,7 @@ static struct clk_lookup lookups[] = { | |||
| 458 | CLKDEV_CON_ID("pllc0_clk", &pllc0_clk), | 485 | CLKDEV_CON_ID("pllc0_clk", &pllc0_clk), |
| 459 | CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), | 486 | CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), |
| 460 | CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), | 487 | CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), |
| 461 | CLKDEV_CON_ID("pllc2_clk", &pllc2_clk), | 488 | CLKDEV_CON_ID("pllc2_clk", &sh7372_pllc2_clk), |
| 462 | 489 | ||
| 463 | /* DIV4 clocks */ | 490 | /* DIV4 clocks */ |
| 464 | CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), | 491 | CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), |
| @@ -483,8 +510,8 @@ static struct clk_lookup lookups[] = { | |||
| 483 | CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), | 510 | CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), |
| 484 | CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), | 511 | CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), |
| 485 | CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), | 512 | CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), |
| 486 | CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FSIA]), | 513 | CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FSIA]), |
| 487 | CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FSIB]), | 514 | CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FSIB]), |
| 488 | CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), | 515 | CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), |
| 489 | CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), | 516 | CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), |
| 490 | CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), | 517 | CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), |
| @@ -501,6 +528,8 @@ static struct clk_lookup lookups[] = { | |||
| 501 | CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ | 528 | CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ |
| 502 | CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU */ | 529 | CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU */ |
| 503 | CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2 */ | 530 | CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2 */ |
| 531 | CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), /* TMU00 */ | ||
| 532 | CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */ | ||
| 504 | CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */ | 533 | CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */ |
| 505 | CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */ | 534 | CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */ |
| 506 | CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ | 535 | CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ |
| @@ -516,7 +545,7 @@ static struct clk_lookup lookups[] = { | |||
| 516 | CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */ | 545 | CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */ |
| 517 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ | 546 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ |
| 518 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ | 547 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ |
| 519 | CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */ | 548 | CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ |
| 520 | CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ | 549 | CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ |
| 521 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ | 550 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ |
| 522 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ | 551 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ |
| @@ -531,7 +560,10 @@ static struct clk_lookup lookups[] = { | |||
| 531 | CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ | 560 | CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ |
| 532 | CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ | 561 | CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ |
| 533 | CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ | 562 | CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ |
| 534 | {.con_id = "ick", .dev_id = "sh-mobile-hdmi", .clk = &div6_reparent_clks[DIV6_HDMI]}, | 563 | |
| 564 | CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]), | ||
| 565 | CLKDEV_ICK_ID("icka", "sh_fsi2", &div6_reparent_clks[DIV6_FSIA]), | ||
| 566 | CLKDEV_ICK_ID("ickb", "sh_fsi2", &div6_reparent_clks[DIV6_FSIB]), | ||
| 535 | }; | 567 | }; |
| 536 | 568 | ||
| 537 | void __init sh7372_clock_init(void) | 569 | void __init sh7372_clock_init(void) |
| @@ -548,7 +580,7 @@ void __init sh7372_clock_init(void) | |||
| 548 | ret = sh_clk_div6_register(div6_clks, DIV6_NR); | 580 | ret = sh_clk_div6_register(div6_clks, DIV6_NR); |
| 549 | 581 | ||
| 550 | if (!ret) | 582 | if (!ret) |
| 551 | ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_NR); | 583 | ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR); |
| 552 | 584 | ||
| 553 | if (!ret) | 585 | if (!ret) |
| 554 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); | 586 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); |
diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c index e007c28cf0a8..f91395aeb9ab 100644 --- a/arch/arm/mach-shmobile/clock-sh7377.c +++ b/arch/arm/mach-shmobile/clock-sh7377.c | |||
| @@ -333,7 +333,7 @@ static struct clk_lookup lookups[] = { | |||
| 333 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ | 333 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ |
| 334 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ | 334 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ |
| 335 | CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */ | 335 | CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */ |
| 336 | CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */ | 336 | CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ |
| 337 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */ | 337 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */ |
| 338 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ | 338 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ |
| 339 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */ | 339 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */ |
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index 33e9700ded7e..147775a94bce 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h | |||
| @@ -457,8 +457,12 @@ enum { | |||
| 457 | SHDMA_SLAVE_SDHI2_TX, | 457 | SHDMA_SLAVE_SDHI2_TX, |
| 458 | }; | 458 | }; |
| 459 | 459 | ||
| 460 | extern struct clk dv_clki_clk; | 460 | extern struct clk sh7372_extal1_clk; |
| 461 | extern struct clk dv_clki_div2_clk; | 461 | extern struct clk sh7372_extal2_clk; |
| 462 | extern struct clk pllc2_clk; | 462 | extern struct clk sh7372_dv_clki_clk; |
| 463 | extern struct clk sh7372_dv_clki_div2_clk; | ||
| 464 | extern struct clk sh7372_pllc2_clk; | ||
| 465 | extern struct clk sh7372_fsiack_clk; | ||
| 466 | extern struct clk sh7372_fsibck_clk; | ||
| 463 | 467 | ||
| 464 | #endif /* __ASM_SH7372_H__ */ | 468 | #endif /* __ASM_SH7372_H__ */ |
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index e3551b56cd03..4cd3cae38e72 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c | |||
| @@ -369,9 +369,13 @@ enum { | |||
| 369 | INTCS, | 369 | INTCS, |
| 370 | 370 | ||
| 371 | /* interrupt sources INTCS */ | 371 | /* interrupt sources INTCS */ |
| 372 | |||
| 373 | /* IRQ0S - IRQ31S */ | ||
| 372 | VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3, | 374 | VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3, |
| 373 | RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3, | 375 | RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3, |
| 374 | CEU, BEU_BEU0, BEU_BEU1, BEU_BEU2, | 376 | CEU, BEU_BEU0, BEU_BEU1, BEU_BEU2, |
| 377 | /* MFI */ | ||
| 378 | /* BBIF2 */ | ||
| 375 | VPU, | 379 | VPU, |
| 376 | TSIF1, | 380 | TSIF1, |
| 377 | _3DG_SGX530, | 381 | _3DG_SGX530, |
| @@ -379,13 +383,17 @@ enum { | |||
| 379 | IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, | 383 | IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, |
| 380 | IPMMU_IPMMUR, IPMMU_IPMMUR2, | 384 | IPMMU_IPMMUR, IPMMU_IPMMUR2, |
| 381 | RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR, | 385 | RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR, |
| 386 | /* KEYSC */ | ||
| 387 | /* TTI20 */ | ||
| 382 | MSIOF, | 388 | MSIOF, |
| 383 | IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0, | 389 | IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0, |
| 384 | TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, | 390 | TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, |
| 385 | CMT0, | 391 | CMT0, |
| 386 | TSIF0, | 392 | TSIF0, |
| 393 | /* CMT2 */ | ||
| 387 | LMB, | 394 | LMB, |
| 388 | CTI, | 395 | CTI, |
| 396 | /* RWDT0 */ | ||
| 389 | ICB, | 397 | ICB, |
| 390 | JPU_JPEG, | 398 | JPU_JPEG, |
| 391 | LCDC, | 399 | LCDC, |
| @@ -397,11 +405,17 @@ enum { | |||
| 397 | CSIRX, | 405 | CSIRX, |
| 398 | DSITX_DSITX0, | 406 | DSITX_DSITX0, |
| 399 | DSITX_DSITX1, | 407 | DSITX_DSITX1, |
| 408 | /* SPU2 */ | ||
| 409 | /* FSI */ | ||
| 410 | /* FMSI */ | ||
| 411 | /* HDMI */ | ||
| 400 | TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2, | 412 | TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2, |
| 401 | CMT4, | 413 | CMT4, |
| 402 | DSITX1_DSITX1_0, | 414 | DSITX1_DSITX1_0, |
| 403 | DSITX1_DSITX1_1, | 415 | DSITX1_DSITX1_1, |
| 416 | /* MFIS2 */ | ||
| 404 | CPORTS2R, | 417 | CPORTS2R, |
| 418 | /* CEC */ | ||
| 405 | JPU6E, | 419 | JPU6E, |
| 406 | 420 | ||
| 407 | /* interrupt groups INTCS */ | 421 | /* interrupt groups INTCS */ |
| @@ -410,12 +424,15 @@ enum { | |||
| 410 | }; | 424 | }; |
| 411 | 425 | ||
| 412 | static struct intc_vect intcs_vectors[] = { | 426 | static struct intc_vect intcs_vectors[] = { |
| 427 | /* IRQ0S - IRQ31S */ | ||
| 413 | INTCS_VECT(VEU_VEU0, 0x700), INTCS_VECT(VEU_VEU1, 0x720), | 428 | INTCS_VECT(VEU_VEU0, 0x700), INTCS_VECT(VEU_VEU1, 0x720), |
| 414 | INTCS_VECT(VEU_VEU2, 0x740), INTCS_VECT(VEU_VEU3, 0x760), | 429 | INTCS_VECT(VEU_VEU2, 0x740), INTCS_VECT(VEU_VEU3, 0x760), |
| 415 | INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820), | 430 | INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820), |
| 416 | INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860), | 431 | INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860), |
| 417 | INTCS_VECT(CEU, 0x880), INTCS_VECT(BEU_BEU0, 0x8a0), | 432 | INTCS_VECT(CEU, 0x880), INTCS_VECT(BEU_BEU0, 0x8a0), |
| 418 | INTCS_VECT(BEU_BEU1, 0x8c0), INTCS_VECT(BEU_BEU2, 0x8e0), | 433 | INTCS_VECT(BEU_BEU1, 0x8c0), INTCS_VECT(BEU_BEU2, 0x8e0), |
| 434 | /* MFI */ | ||
| 435 | /* BBIF2 */ | ||
| 419 | INTCS_VECT(VPU, 0x980), | 436 | INTCS_VECT(VPU, 0x980), |
| 420 | INTCS_VECT(TSIF1, 0x9a0), | 437 | INTCS_VECT(TSIF1, 0x9a0), |
| 421 | INTCS_VECT(_3DG_SGX530, 0x9e0), | 438 | INTCS_VECT(_3DG_SGX530, 0x9e0), |
| @@ -425,14 +442,19 @@ static struct intc_vect intcs_vectors[] = { | |||
| 425 | INTCS_VECT(IPMMU_IPMMUR, 0xb00), INTCS_VECT(IPMMU_IPMMUR2, 0xb20), | 442 | INTCS_VECT(IPMMU_IPMMUR, 0xb00), INTCS_VECT(IPMMU_IPMMUR2, 0xb20), |
| 426 | INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0), | 443 | INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0), |
| 427 | INTCS_VECT(RTDMAC_2_DADERR, 0xbc0), | 444 | INTCS_VECT(RTDMAC_2_DADERR, 0xbc0), |
| 445 | /* KEYSC */ | ||
| 446 | /* TTI20 */ | ||
| 447 | INTCS_VECT(MSIOF, 0x0d20), | ||
| 428 | INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20), | 448 | INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20), |
| 429 | INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60), | 449 | INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60), |
| 430 | INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0), | 450 | INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0), |
| 431 | INTCS_VECT(TMU_TUNI2, 0xec0), | 451 | INTCS_VECT(TMU_TUNI2, 0xec0), |
| 432 | INTCS_VECT(CMT0, 0xf00), | 452 | INTCS_VECT(CMT0, 0xf00), |
| 433 | INTCS_VECT(TSIF0, 0xf20), | 453 | INTCS_VECT(TSIF0, 0xf20), |
| 454 | /* CMT2 */ | ||
| 434 | INTCS_VECT(LMB, 0xf60), | 455 | INTCS_VECT(LMB, 0xf60), |
| 435 | INTCS_VECT(CTI, 0x400), | 456 | INTCS_VECT(CTI, 0x400), |
| 457 | /* RWDT0 */ | ||
| 436 | INTCS_VECT(ICB, 0x480), | 458 | INTCS_VECT(ICB, 0x480), |
| 437 | INTCS_VECT(JPU_JPEG, 0x560), | 459 | INTCS_VECT(JPU_JPEG, 0x560), |
| 438 | INTCS_VECT(LCDC, 0x580), | 460 | INTCS_VECT(LCDC, 0x580), |
| @@ -446,12 +468,18 @@ static struct intc_vect intcs_vectors[] = { | |||
| 446 | INTCS_VECT(CSIRX, 0x17a0), | 468 | INTCS_VECT(CSIRX, 0x17a0), |
| 447 | INTCS_VECT(DSITX_DSITX0, 0x17c0), | 469 | INTCS_VECT(DSITX_DSITX0, 0x17c0), |
| 448 | INTCS_VECT(DSITX_DSITX1, 0x17e0), | 470 | INTCS_VECT(DSITX_DSITX1, 0x17e0), |
| 471 | /* SPU2 */ | ||
| 472 | /* FSI */ | ||
| 473 | /* FMSI */ | ||
| 474 | /* HDMI */ | ||
| 449 | INTCS_VECT(TMU1_TUNI0, 0x1900), INTCS_VECT(TMU1_TUNI1, 0x1920), | 475 | INTCS_VECT(TMU1_TUNI0, 0x1900), INTCS_VECT(TMU1_TUNI1, 0x1920), |
| 450 | INTCS_VECT(TMU1_TUNI2, 0x1940), | 476 | INTCS_VECT(TMU1_TUNI2, 0x1940), |
| 451 | INTCS_VECT(CMT4, 0x1980), | 477 | INTCS_VECT(CMT4, 0x1980), |
| 452 | INTCS_VECT(DSITX1_DSITX1_0, 0x19a0), | 478 | INTCS_VECT(DSITX1_DSITX1_0, 0x19a0), |
| 453 | INTCS_VECT(DSITX1_DSITX1_1, 0x19c0), | 479 | INTCS_VECT(DSITX1_DSITX1_1, 0x19c0), |
| 480 | /* MFIS2 */ | ||
| 454 | INTCS_VECT(CPORTS2R, 0x1a20), | 481 | INTCS_VECT(CPORTS2R, 0x1a20), |
| 482 | /* CEC */ | ||
| 455 | INTCS_VECT(JPU6E, 0x1a80), | 483 | INTCS_VECT(JPU6E, 0x1a80), |
| 456 | 484 | ||
| 457 | INTC_VECT(INTCS, 0xf80), | 485 | INTC_VECT(INTCS, 0xf80), |
diff --git a/arch/arm/mach-shmobile/pfc-sh7372.c b/arch/arm/mach-shmobile/pfc-sh7372.c index ec420353f8e3..9c265dae138a 100644 --- a/arch/arm/mach-shmobile/pfc-sh7372.c +++ b/arch/arm/mach-shmobile/pfc-sh7372.c | |||
| @@ -166,12 +166,12 @@ enum { | |||
| 166 | MSIOF2_TSYNC_MARK, MSIOF2_TSCK_MARK, MSIOF2_RXD_MARK, | 166 | MSIOF2_TSYNC_MARK, MSIOF2_TSCK_MARK, MSIOF2_RXD_MARK, |
| 167 | MSIOF2_TXD_MARK, | 167 | MSIOF2_TXD_MARK, |
| 168 | 168 | ||
| 169 | /* MSIOF3 */ | 169 | /* BBIF1 */ |
| 170 | BBIF1_RXD_MARK, BBIF1_TSYNC_MARK, BBIF1_TSCK_MARK, | 170 | BBIF1_RXD_MARK, BBIF1_TSYNC_MARK, BBIF1_TSCK_MARK, |
| 171 | BBIF1_TXD_MARK, BBIF1_RSCK_MARK, BBIF1_RSYNC_MARK, | 171 | BBIF1_TXD_MARK, BBIF1_RSCK_MARK, BBIF1_RSYNC_MARK, |
| 172 | BBIF1_FLOW_MARK, BB_RX_FLOW_N_MARK, | 172 | BBIF1_FLOW_MARK, BB_RX_FLOW_N_MARK, |
| 173 | 173 | ||
| 174 | /* MSIOF4 */ | 174 | /* BBIF2 */ |
| 175 | BBIF2_TSCK1_MARK, BBIF2_TSYNC1_MARK, | 175 | BBIF2_TSCK1_MARK, BBIF2_TSYNC1_MARK, |
| 176 | BBIF2_TXD1_MARK, BBIF2_RXD_MARK, | 176 | BBIF2_TXD1_MARK, BBIF2_RXD_MARK, |
| 177 | 177 | ||
| @@ -976,12 +976,12 @@ static struct pinmux_gpio pinmux_gpios[] = { | |||
| 976 | GPIO_FN(MSIOF2_TSYNC), GPIO_FN(MSIOF2_TSCK), GPIO_FN(MSIOF2_RXD), | 976 | GPIO_FN(MSIOF2_TSYNC), GPIO_FN(MSIOF2_TSCK), GPIO_FN(MSIOF2_RXD), |
| 977 | GPIO_FN(MSIOF2_TXD), | 977 | GPIO_FN(MSIOF2_TXD), |
| 978 | 978 | ||
| 979 | /* MSIOF3 */ | 979 | /* BBIF1 */ |
| 980 | GPIO_FN(BBIF1_RXD), GPIO_FN(BBIF1_TSYNC), GPIO_FN(BBIF1_TSCK), | 980 | GPIO_FN(BBIF1_RXD), GPIO_FN(BBIF1_TSYNC), GPIO_FN(BBIF1_TSCK), |
| 981 | GPIO_FN(BBIF1_TXD), GPIO_FN(BBIF1_RSCK), GPIO_FN(BBIF1_RSYNC), | 981 | GPIO_FN(BBIF1_TXD), GPIO_FN(BBIF1_RSCK), GPIO_FN(BBIF1_RSYNC), |
| 982 | GPIO_FN(BBIF1_FLOW), GPIO_FN(BB_RX_FLOW_N), | 982 | GPIO_FN(BBIF1_FLOW), GPIO_FN(BB_RX_FLOW_N), |
| 983 | 983 | ||
| 984 | /* MSIOF4 */ | 984 | /* BBIF2 */ |
| 985 | GPIO_FN(BBIF2_TSCK1), GPIO_FN(BBIF2_TSYNC1), | 985 | GPIO_FN(BBIF2_TSCK1), GPIO_FN(BBIF2_TSYNC1), |
| 986 | GPIO_FN(BBIF2_TXD1), GPIO_FN(BBIF2_RXD), | 986 | GPIO_FN(BBIF2_TXD1), GPIO_FN(BBIF2_RXD), |
| 987 | 987 | ||
diff --git a/arch/arm/mach-shmobile/setup-sh7367.c b/arch/arm/mach-shmobile/setup-sh7367.c index 3148c11a550e..003008c18360 100644 --- a/arch/arm/mach-shmobile/setup-sh7367.c +++ b/arch/arm/mach-shmobile/setup-sh7367.c | |||
| @@ -154,7 +154,6 @@ static struct sh_timer_config cmt10_platform_data = { | |||
| 154 | .name = "CMT10", | 154 | .name = "CMT10", |
| 155 | .channel_offset = 0x10, | 155 | .channel_offset = 0x10, |
| 156 | .timer_bit = 0, | 156 | .timer_bit = 0, |
| 157 | .clk = "r_clk", | ||
| 158 | .clockevent_rating = 125, | 157 | .clockevent_rating = 125, |
| 159 | .clocksource_rating = 125, | 158 | .clocksource_rating = 125, |
| 160 | }; | 159 | }; |
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index e26686c9d0b6..564a6d0be473 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c | |||
| @@ -158,7 +158,6 @@ static struct sh_timer_config cmt10_platform_data = { | |||
| 158 | .name = "CMT10", | 158 | .name = "CMT10", |
| 159 | .channel_offset = 0x10, | 159 | .channel_offset = 0x10, |
| 160 | .timer_bit = 0, | 160 | .timer_bit = 0, |
| 161 | .clk = "cmt1", | ||
| 162 | .clockevent_rating = 125, | 161 | .clockevent_rating = 125, |
| 163 | .clocksource_rating = 125, | 162 | .clocksource_rating = 125, |
| 164 | }; | 163 | }; |
| @@ -186,6 +185,67 @@ static struct platform_device cmt10_device = { | |||
| 186 | .num_resources = ARRAY_SIZE(cmt10_resources), | 185 | .num_resources = ARRAY_SIZE(cmt10_resources), |
| 187 | }; | 186 | }; |
| 188 | 187 | ||
| 188 | /* TMU */ | ||
| 189 | static struct sh_timer_config tmu00_platform_data = { | ||
| 190 | .name = "TMU00", | ||
| 191 | .channel_offset = 0x4, | ||
| 192 | .timer_bit = 0, | ||
| 193 | .clockevent_rating = 200, | ||
| 194 | }; | ||
| 195 | |||
| 196 | static struct resource tmu00_resources[] = { | ||
| 197 | [0] = { | ||
| 198 | .name = "TMU00", | ||
| 199 | .start = 0xfff60008, | ||
| 200 | .end = 0xfff60013, | ||
| 201 | .flags = IORESOURCE_MEM, | ||
| 202 | }, | ||
| 203 | [1] = { | ||
| 204 | .start = intcs_evt2irq(0xe80), /* TMU_TUNI0 */ | ||
| 205 | .flags = IORESOURCE_IRQ, | ||
| 206 | }, | ||
| 207 | }; | ||
| 208 | |||
| 209 | static struct platform_device tmu00_device = { | ||
| 210 | .name = "sh_tmu", | ||
| 211 | .id = 0, | ||
| 212 | .dev = { | ||
| 213 | .platform_data = &tmu00_platform_data, | ||
| 214 | }, | ||
| 215 | .resource = tmu00_resources, | ||
| 216 | .num_resources = ARRAY_SIZE(tmu00_resources), | ||
| 217 | }; | ||
| 218 | |||
| 219 | static struct sh_timer_config tmu01_platform_data = { | ||
| 220 | .name = "TMU01", | ||
| 221 | .channel_offset = 0x10, | ||
| 222 | .timer_bit = 1, | ||
| 223 | .clocksource_rating = 200, | ||
| 224 | }; | ||
| 225 | |||
| 226 | static struct resource tmu01_resources[] = { | ||
| 227 | [0] = { | ||
| 228 | .name = "TMU01", | ||
| 229 | .start = 0xfff60014, | ||
| 230 | .end = 0xfff6001f, | ||
| 231 | .flags = IORESOURCE_MEM, | ||
| 232 | }, | ||
| 233 | [1] = { | ||
| 234 | .start = intcs_evt2irq(0xea0), /* TMU_TUNI1 */ | ||
| 235 | .flags = IORESOURCE_IRQ, | ||
| 236 | }, | ||
| 237 | }; | ||
| 238 | |||
| 239 | static struct platform_device tmu01_device = { | ||
| 240 | .name = "sh_tmu", | ||
| 241 | .id = 1, | ||
| 242 | .dev = { | ||
| 243 | .platform_data = &tmu01_platform_data, | ||
| 244 | }, | ||
| 245 | .resource = tmu01_resources, | ||
| 246 | .num_resources = ARRAY_SIZE(tmu01_resources), | ||
| 247 | }; | ||
| 248 | |||
| 189 | /* I2C */ | 249 | /* I2C */ |
| 190 | static struct resource iic0_resources[] = { | 250 | static struct resource iic0_resources[] = { |
| 191 | [0] = { | 251 | [0] = { |
| @@ -419,14 +479,14 @@ static struct resource sh7372_dmae0_resources[] = { | |||
| 419 | }, | 479 | }, |
| 420 | { | 480 | { |
| 421 | /* DMA error IRQ */ | 481 | /* DMA error IRQ */ |
| 422 | .start = 246, | 482 | .start = evt2irq(0x20c0), |
| 423 | .end = 246, | 483 | .end = evt2irq(0x20c0), |
| 424 | .flags = IORESOURCE_IRQ, | 484 | .flags = IORESOURCE_IRQ, |
| 425 | }, | 485 | }, |
| 426 | { | 486 | { |
| 427 | /* IRQ for channels 0-5 */ | 487 | /* IRQ for channels 0-5 */ |
| 428 | .start = 240, | 488 | .start = evt2irq(0x2000), |
| 429 | .end = 245, | 489 | .end = evt2irq(0x20a0), |
| 430 | .flags = IORESOURCE_IRQ, | 490 | .flags = IORESOURCE_IRQ, |
| 431 | }, | 491 | }, |
| 432 | }; | 492 | }; |
| @@ -447,14 +507,14 @@ static struct resource sh7372_dmae1_resources[] = { | |||
| 447 | }, | 507 | }, |
| 448 | { | 508 | { |
| 449 | /* DMA error IRQ */ | 509 | /* DMA error IRQ */ |
| 450 | .start = 254, | 510 | .start = evt2irq(0x21c0), |
| 451 | .end = 254, | 511 | .end = evt2irq(0x21c0), |
| 452 | .flags = IORESOURCE_IRQ, | 512 | .flags = IORESOURCE_IRQ, |
| 453 | }, | 513 | }, |
| 454 | { | 514 | { |
| 455 | /* IRQ for channels 0-5 */ | 515 | /* IRQ for channels 0-5 */ |
| 456 | .start = 248, | 516 | .start = evt2irq(0x2100), |
| 457 | .end = 253, | 517 | .end = evt2irq(0x21a0), |
| 458 | .flags = IORESOURCE_IRQ, | 518 | .flags = IORESOURCE_IRQ, |
| 459 | }, | 519 | }, |
| 460 | }; | 520 | }; |
| @@ -475,14 +535,14 @@ static struct resource sh7372_dmae2_resources[] = { | |||
| 475 | }, | 535 | }, |
| 476 | { | 536 | { |
| 477 | /* DMA error IRQ */ | 537 | /* DMA error IRQ */ |
| 478 | .start = 262, | 538 | .start = evt2irq(0x22c0), |
| 479 | .end = 262, | 539 | .end = evt2irq(0x22c0), |
| 480 | .flags = IORESOURCE_IRQ, | 540 | .flags = IORESOURCE_IRQ, |
| 481 | }, | 541 | }, |
| 482 | { | 542 | { |
| 483 | /* IRQ for channels 0-5 */ | 543 | /* IRQ for channels 0-5 */ |
| 484 | .start = 256, | 544 | .start = evt2irq(0x2200), |
| 485 | .end = 261, | 545 | .end = evt2irq(0x22a0), |
| 486 | .flags = IORESOURCE_IRQ, | 546 | .flags = IORESOURCE_IRQ, |
| 487 | }, | 547 | }, |
| 488 | }; | 548 | }; |
| @@ -526,6 +586,11 @@ static struct platform_device *sh7372_early_devices[] __initdata = { | |||
| 526 | &scif5_device, | 586 | &scif5_device, |
| 527 | &scif6_device, | 587 | &scif6_device, |
| 528 | &cmt10_device, | 588 | &cmt10_device, |
| 589 | &tmu00_device, | ||
| 590 | &tmu01_device, | ||
| 591 | }; | ||
| 592 | |||
| 593 | static struct platform_device *sh7372_late_devices[] __initdata = { | ||
| 529 | &iic0_device, | 594 | &iic0_device, |
| 530 | &iic1_device, | 595 | &iic1_device, |
| 531 | &dma0_device, | 596 | &dma0_device, |
| @@ -537,6 +602,9 @@ void __init sh7372_add_standard_devices(void) | |||
| 537 | { | 602 | { |
| 538 | platform_add_devices(sh7372_early_devices, | 603 | platform_add_devices(sh7372_early_devices, |
| 539 | ARRAY_SIZE(sh7372_early_devices)); | 604 | ARRAY_SIZE(sh7372_early_devices)); |
| 605 | |||
| 606 | platform_add_devices(sh7372_late_devices, | ||
| 607 | ARRAY_SIZE(sh7372_late_devices)); | ||
| 540 | } | 608 | } |
| 541 | 609 | ||
| 542 | void __init sh7372_add_early_devices(void) | 610 | void __init sh7372_add_early_devices(void) |
diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c index bb4adf17dbf4..575dbd6c2f1d 100644 --- a/arch/arm/mach-shmobile/setup-sh7377.c +++ b/arch/arm/mach-shmobile/setup-sh7377.c | |||
| @@ -172,7 +172,6 @@ static struct sh_timer_config cmt10_platform_data = { | |||
| 172 | .name = "CMT10", | 172 | .name = "CMT10", |
| 173 | .channel_offset = 0x10, | 173 | .channel_offset = 0x10, |
| 174 | .timer_bit = 0, | 174 | .timer_bit = 0, |
| 175 | .clk = "r_clk", | ||
| 176 | .clockevent_rating = 125, | 175 | .clockevent_rating = 125, |
| 177 | .clocksource_rating = 125, | 176 | .clocksource_rating = 125, |
| 178 | }; | 177 | }; |
diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c index 60acf9e708ae..7458fc6df5c6 100644 --- a/arch/arm/mach-u300/clock.c +++ b/arch/arm/mach-u300/clock.c | |||
| @@ -66,7 +66,7 @@ static DEFINE_SPINLOCK(syscon_resetreg_lock); | |||
| 66 | * AMBA bus | 66 | * AMBA bus |
| 67 | * | | 67 | * | |
| 68 | * +- CPU | 68 | * +- CPU |
| 69 | * +- NANDIF NAND Flash interface | 69 | * +- FSMC NANDIF NAND Flash interface |
| 70 | * +- SEMI Shared Memory interface | 70 | * +- SEMI Shared Memory interface |
| 71 | * +- ISP Image Signal Processor (U335 only) | 71 | * +- ISP Image Signal Processor (U335 only) |
| 72 | * +- CDS (U335 only) | 72 | * +- CDS (U335 only) |
| @@ -726,7 +726,7 @@ static struct clk cpu_clk = { | |||
| 726 | }; | 726 | }; |
| 727 | 727 | ||
| 728 | static struct clk nandif_clk = { | 728 | static struct clk nandif_clk = { |
| 729 | .name = "NANDIF", | 729 | .name = "FSMC", |
| 730 | .parent = &amba_clk, | 730 | .parent = &amba_clk, |
| 731 | .hw_ctrld = false, | 731 | .hw_ctrld = false, |
| 732 | .reset = true, | 732 | .reset = true, |
| @@ -1259,7 +1259,7 @@ static struct clk_lookup lookups[] = { | |||
| 1259 | /* Connected directly to the AMBA bus */ | 1259 | /* Connected directly to the AMBA bus */ |
| 1260 | DEF_LOOKUP("amba", &amba_clk), | 1260 | DEF_LOOKUP("amba", &amba_clk), |
| 1261 | DEF_LOOKUP("cpu", &cpu_clk), | 1261 | DEF_LOOKUP("cpu", &cpu_clk), |
| 1262 | DEF_LOOKUP("fsmc", &nandif_clk), | 1262 | DEF_LOOKUP("fsmc-nand", &nandif_clk), |
| 1263 | DEF_LOOKUP("semi", &semi_clk), | 1263 | DEF_LOOKUP("semi", &semi_clk), |
| 1264 | #ifdef CONFIG_MACH_U300_BS335 | 1264 | #ifdef CONFIG_MACH_U300_BS335 |
| 1265 | DEF_LOOKUP("isp", &isp_clk), | 1265 | DEF_LOOKUP("isp", &isp_clk), |
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index ea41c236be0f..aa53ee22438f 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c | |||
| @@ -21,7 +21,8 @@ | |||
| 21 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
| 22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
| 23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
| 24 | #include <mach/coh901318.h> | 24 | #include <linux/mtd/nand.h> |
| 25 | #include <linux/mtd/fsmc.h> | ||
| 25 | 26 | ||
| 26 | #include <asm/types.h> | 27 | #include <asm/types.h> |
| 27 | #include <asm/setup.h> | 28 | #include <asm/setup.h> |
| @@ -30,6 +31,7 @@ | |||
| 30 | #include <asm/mach/map.h> | 31 | #include <asm/mach/map.h> |
| 31 | #include <asm/mach/irq.h> | 32 | #include <asm/mach/irq.h> |
| 32 | 33 | ||
| 34 | #include <mach/coh901318.h> | ||
| 33 | #include <mach/hardware.h> | 35 | #include <mach/hardware.h> |
| 34 | #include <mach/syscon.h> | 36 | #include <mach/syscon.h> |
| 35 | #include <mach/dma_channels.h> | 37 | #include <mach/dma_channels.h> |
| @@ -285,6 +287,13 @@ static struct resource rtc_resources[] = { | |||
| 285 | */ | 287 | */ |
| 286 | static struct resource fsmc_resources[] = { | 288 | static struct resource fsmc_resources[] = { |
| 287 | { | 289 | { |
| 290 | .name = "nand_data", | ||
| 291 | .start = U300_NAND_CS0_PHYS_BASE, | ||
| 292 | .end = U300_NAND_CS0_PHYS_BASE + SZ_16K - 1, | ||
| 293 | .flags = IORESOURCE_MEM, | ||
| 294 | }, | ||
| 295 | { | ||
| 296 | .name = "fsmc_regs", | ||
| 288 | .start = U300_NAND_IF_PHYS_BASE, | 297 | .start = U300_NAND_IF_PHYS_BASE, |
| 289 | .end = U300_NAND_IF_PHYS_BASE + SZ_4K - 1, | 298 | .end = U300_NAND_IF_PHYS_BASE + SZ_4K - 1, |
| 290 | .flags = IORESOURCE_MEM, | 299 | .flags = IORESOURCE_MEM, |
| @@ -1429,11 +1438,39 @@ static struct platform_device rtc_device = { | |||
| 1429 | .resource = rtc_resources, | 1438 | .resource = rtc_resources, |
| 1430 | }; | 1439 | }; |
| 1431 | 1440 | ||
| 1432 | static struct platform_device fsmc_device = { | 1441 | static struct mtd_partition u300_partitions[] = { |
| 1433 | .name = "nandif", | 1442 | { |
| 1443 | .name = "bootrecords", | ||
| 1444 | .offset = 0, | ||
| 1445 | .size = SZ_128K, | ||
| 1446 | }, | ||
| 1447 | { | ||
| 1448 | .name = "free", | ||
| 1449 | .offset = SZ_128K, | ||
| 1450 | .size = 8064 * SZ_1K, | ||
| 1451 | }, | ||
| 1452 | { | ||
| 1453 | .name = "platform", | ||
| 1454 | .offset = 8192 * SZ_1K, | ||
| 1455 | .size = 253952 * SZ_1K, | ||
| 1456 | }, | ||
| 1457 | }; | ||
| 1458 | |||
| 1459 | static struct fsmc_nand_platform_data nand_platform_data = { | ||
| 1460 | .partitions = u300_partitions, | ||
| 1461 | .nr_partitions = ARRAY_SIZE(u300_partitions), | ||
| 1462 | .options = NAND_SKIP_BBTSCAN, | ||
| 1463 | .width = FSMC_NAND_BW8, | ||
| 1464 | }; | ||
| 1465 | |||
| 1466 | static struct platform_device nand_device = { | ||
| 1467 | .name = "fsmc-nand", | ||
| 1434 | .id = -1, | 1468 | .id = -1, |
| 1435 | .num_resources = ARRAY_SIZE(fsmc_resources), | ||
| 1436 | .resource = fsmc_resources, | 1469 | .resource = fsmc_resources, |
| 1470 | .num_resources = ARRAY_SIZE(fsmc_resources), | ||
| 1471 | .dev = { | ||
| 1472 | .platform_data = &nand_platform_data, | ||
| 1473 | }, | ||
| 1437 | }; | 1474 | }; |
| 1438 | 1475 | ||
| 1439 | static struct platform_device ave_device = { | 1476 | static struct platform_device ave_device = { |
| @@ -1465,7 +1502,7 @@ static struct platform_device *platform_devs[] __initdata = { | |||
| 1465 | &keypad_device, | 1502 | &keypad_device, |
| 1466 | &rtc_device, | 1503 | &rtc_device, |
| 1467 | &gpio_device, | 1504 | &gpio_device, |
| 1468 | &fsmc_device, | 1505 | &nand_device, |
| 1469 | &wdog_device, | 1506 | &wdog_device, |
| 1470 | &ave_device | 1507 | &ave_device |
| 1471 | }; | 1508 | }; |
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h index 56721a0cd2af..8b85df4c8d8f 100644 --- a/arch/arm/mach-u300/include/mach/u300-regs.h +++ b/arch/arm/mach-u300/include/mach/u300-regs.h | |||
| @@ -20,11 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | /* NAND Flash CS0 */ | 21 | /* NAND Flash CS0 */ |
| 22 | #define U300_NAND_CS0_PHYS_BASE 0x80000000 | 22 | #define U300_NAND_CS0_PHYS_BASE 0x80000000 |
| 23 | #define U300_NAND_CS0_VIRT_BASE 0xff040000 | ||
| 24 | 23 | ||
| 25 | /* NFIF */ | 24 | /* NFIF */ |
| 26 | #define U300_NAND_IF_PHYS_BASE 0x9f800000 | 25 | #define U300_NAND_IF_PHYS_BASE 0x9f800000 |
| 27 | #define U300_NAND_IF_VIRT_BASE 0xff030000 | ||
| 28 | 26 | ||
| 29 | /* AHB Peripherals */ | 27 | /* AHB Peripherals */ |
| 30 | #define U300_AHB_PER_PHYS_BASE 0xa0000000 | 28 | #define U300_AHB_PER_PHYS_BASE 0xa0000000 |
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index e0fd747e447a..73fb1a551ec6 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/io.h> | 10 | #include <linux/io.h> |
| 11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
| 12 | 12 | ||
| 13 | #include <asm/cacheflush.h> | ||
| 13 | #include <asm/hardware/cache-l2x0.h> | 14 | #include <asm/hardware/cache-l2x0.h> |
| 14 | #include <asm/hardware/gic.h> | 15 | #include <asm/hardware/gic.h> |
| 15 | #include <asm/mach/map.h> | 16 | #include <asm/mach/map.h> |
| @@ -71,6 +72,46 @@ void __init ux500_init_irq(void) | |||
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | #ifdef CONFIG_CACHE_L2X0 | 74 | #ifdef CONFIG_CACHE_L2X0 |
| 75 | static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) | ||
| 76 | { | ||
| 77 | /* wait for the operation to complete */ | ||
| 78 | while (readl(reg) & mask) | ||
| 79 | ; | ||
| 80 | } | ||
| 81 | |||
| 82 | static inline void ux500_cache_sync(void) | ||
| 83 | { | ||
| 84 | void __iomem *base = __io_address(UX500_L2CC_BASE); | ||
| 85 | writel(0, base + L2X0_CACHE_SYNC); | ||
| 86 | ux500_cache_wait(base + L2X0_CACHE_SYNC, 1); | ||
| 87 | } | ||
| 88 | |||
| 89 | /* | ||
| 90 | * The L2 cache cannot be turned off in the non-secure world. | ||
| 91 | * Dummy until a secure service is in place. | ||
| 92 | */ | ||
| 93 | static void ux500_l2x0_disable(void) | ||
| 94 | { | ||
| 95 | } | ||
| 96 | |||
| 97 | /* | ||
| 98 | * This is only called when doing a kexec, just after turning off the L2 | ||
| 99 | * and L1 cache, and it is surrounded by a spinlock in the generic version. | ||
| 100 | * However, we're not really turning off the L2 cache right now and the | ||
| 101 | * PL310 does not support exclusive accesses (used to implement the spinlock). | ||
| 102 | * So, the invalidation needs to be done without the spinlock. | ||
| 103 | */ | ||
| 104 | static void ux500_l2x0_inv_all(void) | ||
| 105 | { | ||
| 106 | void __iomem *l2x0_base = __io_address(UX500_L2CC_BASE); | ||
| 107 | uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ | ||
| 108 | |||
| 109 | /* invalidate all ways */ | ||
| 110 | writel(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); | ||
| 111 | ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); | ||
| 112 | ux500_cache_sync(); | ||
| 113 | } | ||
| 114 | |||
| 74 | static int ux500_l2x0_init(void) | 115 | static int ux500_l2x0_init(void) |
| 75 | { | 116 | { |
| 76 | void __iomem *l2x0_base; | 117 | void __iomem *l2x0_base; |
| @@ -80,6 +121,10 @@ static int ux500_l2x0_init(void) | |||
| 80 | /* 64KB way size, 8 way associativity, force WA */ | 121 | /* 64KB way size, 8 way associativity, force WA */ |
| 81 | l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); | 122 | l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); |
| 82 | 123 | ||
| 124 | /* Override invalidate function */ | ||
| 125 | outer_cache.disable = ux500_l2x0_disable; | ||
| 126 | outer_cache.inv_all = ux500_l2x0_inv_all; | ||
| 127 | |||
| 83 | return 0; | 128 | return 0; |
| 84 | } | 129 | } |
| 85 | early_initcall(ux500_l2x0_init); | 130 | early_initcall(ux500_l2x0_init); |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index a0a2928ae4dd..4414a01e1e8a 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
| @@ -779,6 +779,14 @@ config CACHE_L2X0 | |||
| 779 | help | 779 | help |
| 780 | This option enables the L2x0 PrimeCell. | 780 | This option enables the L2x0 PrimeCell. |
| 781 | 781 | ||
| 782 | config CACHE_PL310 | ||
| 783 | bool | ||
| 784 | depends on CACHE_L2X0 | ||
| 785 | default y if CPU_V7 && !CPU_V6 | ||
| 786 | help | ||
| 787 | This option enables optimisations for the PL310 cache | ||
| 788 | controller. | ||
| 789 | |||
| 782 | config CACHE_TAUROS2 | 790 | config CACHE_TAUROS2 |
| 783 | bool "Enable the Tauros2 L2 cache controller" | 791 | bool "Enable the Tauros2 L2 cache controller" |
| 784 | depends on (ARCH_DOVE || ARCH_MMP) | 792 | depends on (ARCH_DOVE || ARCH_MMP) |
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S index 7148e53e6078..1fa6f71470de 100644 --- a/arch/arm/mm/cache-fa.S +++ b/arch/arm/mm/cache-fa.S | |||
| @@ -38,6 +38,17 @@ | |||
| 38 | #define CACHE_DLIMIT (CACHE_DSIZE * 2) | 38 | #define CACHE_DLIMIT (CACHE_DSIZE * 2) |
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| 41 | * flush_icache_all() | ||
| 42 | * | ||
| 43 | * Unconditionally clean and invalidate the entire icache. | ||
| 44 | */ | ||
| 45 | ENTRY(fa_flush_icache_all) | ||
| 46 | mov r0, #0 | ||
| 47 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 48 | mov pc, lr | ||
| 49 | ENDPROC(fa_flush_icache_all) | ||
| 50 | |||
| 51 | /* | ||
| 41 | * flush_user_cache_all() | 52 | * flush_user_cache_all() |
| 42 | * | 53 | * |
| 43 | * Clean and invalidate all cache entries in a particular address | 54 | * Clean and invalidate all cache entries in a particular address |
| @@ -233,6 +244,7 @@ ENDPROC(fa_dma_unmap_area) | |||
| 233 | 244 | ||
| 234 | .type fa_cache_fns, #object | 245 | .type fa_cache_fns, #object |
| 235 | ENTRY(fa_cache_fns) | 246 | ENTRY(fa_cache_fns) |
| 247 | .long fa_flush_icache_all | ||
| 236 | .long fa_flush_kern_cache_all | 248 | .long fa_flush_kern_cache_all |
| 237 | .long fa_flush_user_cache_all | 249 | .long fa_flush_user_cache_all |
| 238 | .long fa_flush_user_cache_range | 250 | .long fa_flush_user_cache_range |
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 9982eb385c0f..170c9bb95866 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
| @@ -28,14 +28,24 @@ | |||
| 28 | static void __iomem *l2x0_base; | 28 | static void __iomem *l2x0_base; |
| 29 | static DEFINE_SPINLOCK(l2x0_lock); | 29 | static DEFINE_SPINLOCK(l2x0_lock); |
| 30 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ | 30 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ |
| 31 | static uint32_t l2x0_size; | ||
| 31 | 32 | ||
| 32 | static inline void cache_wait(void __iomem *reg, unsigned long mask) | 33 | static inline void cache_wait_way(void __iomem *reg, unsigned long mask) |
| 33 | { | 34 | { |
| 34 | /* wait for the operation to complete */ | 35 | /* wait for cache operation by line or way to complete */ |
| 35 | while (readl_relaxed(reg) & mask) | 36 | while (readl_relaxed(reg) & mask) |
| 36 | ; | 37 | ; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 40 | #ifdef CONFIG_CACHE_PL310 | ||
| 41 | static inline void cache_wait(void __iomem *reg, unsigned long mask) | ||
| 42 | { | ||
| 43 | /* cache operations by line are atomic on PL310 */ | ||
| 44 | } | ||
| 45 | #else | ||
| 46 | #define cache_wait cache_wait_way | ||
| 47 | #endif | ||
| 48 | |||
| 39 | static inline void cache_sync(void) | 49 | static inline void cache_sync(void) |
| 40 | { | 50 | { |
| 41 | void __iomem *base = l2x0_base; | 51 | void __iomem *base = l2x0_base; |
| @@ -103,14 +113,40 @@ static void l2x0_cache_sync(void) | |||
| 103 | spin_unlock_irqrestore(&l2x0_lock, flags); | 113 | spin_unlock_irqrestore(&l2x0_lock, flags); |
| 104 | } | 114 | } |
| 105 | 115 | ||
| 106 | static inline void l2x0_inv_all(void) | 116 | static void l2x0_flush_all(void) |
| 117 | { | ||
| 118 | unsigned long flags; | ||
| 119 | |||
| 120 | /* clean all ways */ | ||
| 121 | spin_lock_irqsave(&l2x0_lock, flags); | ||
| 122 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); | ||
| 123 | cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); | ||
| 124 | cache_sync(); | ||
| 125 | spin_unlock_irqrestore(&l2x0_lock, flags); | ||
| 126 | } | ||
| 127 | |||
| 128 | static void l2x0_clean_all(void) | ||
| 129 | { | ||
| 130 | unsigned long flags; | ||
| 131 | |||
| 132 | /* clean all ways */ | ||
| 133 | spin_lock_irqsave(&l2x0_lock, flags); | ||
| 134 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); | ||
| 135 | cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); | ||
| 136 | cache_sync(); | ||
| 137 | spin_unlock_irqrestore(&l2x0_lock, flags); | ||
| 138 | } | ||
| 139 | |||
| 140 | static void l2x0_inv_all(void) | ||
| 107 | { | 141 | { |
| 108 | unsigned long flags; | 142 | unsigned long flags; |
| 109 | 143 | ||
| 110 | /* invalidate all ways */ | 144 | /* invalidate all ways */ |
| 111 | spin_lock_irqsave(&l2x0_lock, flags); | 145 | spin_lock_irqsave(&l2x0_lock, flags); |
| 146 | /* Invalidating when L2 is enabled is a nono */ | ||
| 147 | BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1); | ||
| 112 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); | 148 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); |
| 113 | cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); | 149 | cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); |
| 114 | cache_sync(); | 150 | cache_sync(); |
| 115 | spin_unlock_irqrestore(&l2x0_lock, flags); | 151 | spin_unlock_irqrestore(&l2x0_lock, flags); |
| 116 | } | 152 | } |
| @@ -159,6 +195,11 @@ static void l2x0_clean_range(unsigned long start, unsigned long end) | |||
| 159 | void __iomem *base = l2x0_base; | 195 | void __iomem *base = l2x0_base; |
| 160 | unsigned long flags; | 196 | unsigned long flags; |
| 161 | 197 | ||
| 198 | if ((end - start) >= l2x0_size) { | ||
| 199 | l2x0_clean_all(); | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | |||
| 162 | spin_lock_irqsave(&l2x0_lock, flags); | 203 | spin_lock_irqsave(&l2x0_lock, flags); |
| 163 | start &= ~(CACHE_LINE_SIZE - 1); | 204 | start &= ~(CACHE_LINE_SIZE - 1); |
| 164 | while (start < end) { | 205 | while (start < end) { |
| @@ -184,6 +225,11 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) | |||
| 184 | void __iomem *base = l2x0_base; | 225 | void __iomem *base = l2x0_base; |
| 185 | unsigned long flags; | 226 | unsigned long flags; |
| 186 | 227 | ||
| 228 | if ((end - start) >= l2x0_size) { | ||
| 229 | l2x0_flush_all(); | ||
| 230 | return; | ||
| 231 | } | ||
| 232 | |||
| 187 | spin_lock_irqsave(&l2x0_lock, flags); | 233 | spin_lock_irqsave(&l2x0_lock, flags); |
| 188 | start &= ~(CACHE_LINE_SIZE - 1); | 234 | start &= ~(CACHE_LINE_SIZE - 1); |
| 189 | while (start < end) { | 235 | while (start < end) { |
| @@ -206,10 +252,20 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) | |||
| 206 | spin_unlock_irqrestore(&l2x0_lock, flags); | 252 | spin_unlock_irqrestore(&l2x0_lock, flags); |
| 207 | } | 253 | } |
| 208 | 254 | ||
| 255 | static void l2x0_disable(void) | ||
| 256 | { | ||
| 257 | unsigned long flags; | ||
| 258 | |||
| 259 | spin_lock_irqsave(&l2x0_lock, flags); | ||
| 260 | writel(0, l2x0_base + L2X0_CTRL); | ||
| 261 | spin_unlock_irqrestore(&l2x0_lock, flags); | ||
| 262 | } | ||
| 263 | |||
| 209 | void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | 264 | void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) |
| 210 | { | 265 | { |
| 211 | __u32 aux; | 266 | __u32 aux; |
| 212 | __u32 cache_id; | 267 | __u32 cache_id; |
| 268 | __u32 way_size = 0; | ||
| 213 | int ways; | 269 | int ways; |
| 214 | const char *type; | 270 | const char *type; |
| 215 | 271 | ||
| @@ -244,6 +300,13 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | |||
| 244 | l2x0_way_mask = (1 << ways) - 1; | 300 | l2x0_way_mask = (1 << ways) - 1; |
| 245 | 301 | ||
| 246 | /* | 302 | /* |
| 303 | * L2 cache Size = Way size * Number of ways | ||
| 304 | */ | ||
| 305 | way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17; | ||
| 306 | way_size = 1 << (way_size + 3); | ||
| 307 | l2x0_size = ways * way_size * SZ_1K; | ||
| 308 | |||
| 309 | /* | ||
| 247 | * Check if l2x0 controller is already enabled. | 310 | * Check if l2x0 controller is already enabled. |
| 248 | * If you are booting from non-secure mode | 311 | * If you are booting from non-secure mode |
| 249 | * accessing the below registers will fault. | 312 | * accessing the below registers will fault. |
| @@ -263,8 +326,11 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | |||
| 263 | outer_cache.clean_range = l2x0_clean_range; | 326 | outer_cache.clean_range = l2x0_clean_range; |
| 264 | outer_cache.flush_range = l2x0_flush_range; | 327 | outer_cache.flush_range = l2x0_flush_range; |
| 265 | outer_cache.sync = l2x0_cache_sync; | 328 | outer_cache.sync = l2x0_cache_sync; |
| 329 | outer_cache.flush_all = l2x0_flush_all; | ||
| 330 | outer_cache.inv_all = l2x0_inv_all; | ||
| 331 | outer_cache.disable = l2x0_disable; | ||
| 266 | 332 | ||
| 267 | printk(KERN_INFO "%s cache controller enabled\n", type); | 333 | printk(KERN_INFO "%s cache controller enabled\n", type); |
| 268 | printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", | 334 | printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", |
| 269 | ways, cache_id, aux); | 335 | ways, cache_id, aux, l2x0_size); |
| 270 | } | 336 | } |
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S index c2ff3c599fee..2e2bc406a18d 100644 --- a/arch/arm/mm/cache-v3.S +++ b/arch/arm/mm/cache-v3.S | |||
| @@ -13,6 +13,15 @@ | |||
| 13 | #include "proc-macros.S" | 13 | #include "proc-macros.S" |
| 14 | 14 | ||
| 15 | /* | 15 | /* |
| 16 | * flush_icache_all() | ||
| 17 | * | ||
| 18 | * Unconditionally clean and invalidate the entire icache. | ||
| 19 | */ | ||
| 20 | ENTRY(v3_flush_icache_all) | ||
| 21 | mov pc, lr | ||
| 22 | ENDPROC(v3_flush_icache_all) | ||
| 23 | |||
| 24 | /* | ||
| 16 | * flush_user_cache_all() | 25 | * flush_user_cache_all() |
| 17 | * | 26 | * |
| 18 | * Invalidate all cache entries in a particular address | 27 | * Invalidate all cache entries in a particular address |
| @@ -122,6 +131,7 @@ ENDPROC(v3_dma_map_area) | |||
| 122 | 131 | ||
| 123 | .type v3_cache_fns, #object | 132 | .type v3_cache_fns, #object |
| 124 | ENTRY(v3_cache_fns) | 133 | ENTRY(v3_cache_fns) |
| 134 | .long v3_flush_icache_all | ||
| 125 | .long v3_flush_kern_cache_all | 135 | .long v3_flush_kern_cache_all |
| 126 | .long v3_flush_user_cache_all | 136 | .long v3_flush_user_cache_all |
| 127 | .long v3_flush_user_cache_range | 137 | .long v3_flush_user_cache_range |
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S index 4810f7e3e813..a8fefb523f19 100644 --- a/arch/arm/mm/cache-v4.S +++ b/arch/arm/mm/cache-v4.S | |||
| @@ -13,6 +13,15 @@ | |||
| 13 | #include "proc-macros.S" | 13 | #include "proc-macros.S" |
| 14 | 14 | ||
| 15 | /* | 15 | /* |
| 16 | * flush_icache_all() | ||
| 17 | * | ||
| 18 | * Unconditionally clean and invalidate the entire icache. | ||
| 19 | */ | ||
| 20 | ENTRY(v4_flush_icache_all) | ||
| 21 | mov pc, lr | ||
| 22 | ENDPROC(v4_flush_icache_all) | ||
| 23 | |||
| 24 | /* | ||
| 16 | * flush_user_cache_all() | 25 | * flush_user_cache_all() |
| 17 | * | 26 | * |
| 18 | * Invalidate all cache entries in a particular address | 27 | * Invalidate all cache entries in a particular address |
| @@ -134,6 +143,7 @@ ENDPROC(v4_dma_map_area) | |||
| 134 | 143 | ||
| 135 | .type v4_cache_fns, #object | 144 | .type v4_cache_fns, #object |
| 136 | ENTRY(v4_cache_fns) | 145 | ENTRY(v4_cache_fns) |
| 146 | .long v4_flush_icache_all | ||
| 137 | .long v4_flush_kern_cache_all | 147 | .long v4_flush_kern_cache_all |
| 138 | .long v4_flush_user_cache_all | 148 | .long v4_flush_user_cache_all |
| 139 | .long v4_flush_user_cache_range | 149 | .long v4_flush_user_cache_range |
diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S index df8368afa102..d3644db467b7 100644 --- a/arch/arm/mm/cache-v4wb.S +++ b/arch/arm/mm/cache-v4wb.S | |||
| @@ -51,6 +51,17 @@ flush_base: | |||
| 51 | .text | 51 | .text |
| 52 | 52 | ||
| 53 | /* | 53 | /* |
| 54 | * flush_icache_all() | ||
| 55 | * | ||
| 56 | * Unconditionally clean and invalidate the entire icache. | ||
| 57 | */ | ||
| 58 | ENTRY(v4wb_flush_icache_all) | ||
| 59 | mov r0, #0 | ||
| 60 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 61 | mov pc, lr | ||
| 62 | ENDPROC(v4wb_flush_icache_all) | ||
| 63 | |||
| 64 | /* | ||
| 54 | * flush_user_cache_all() | 65 | * flush_user_cache_all() |
| 55 | * | 66 | * |
| 56 | * Clean and invalidate all cache entries in a particular address | 67 | * Clean and invalidate all cache entries in a particular address |
| @@ -244,6 +255,7 @@ ENDPROC(v4wb_dma_unmap_area) | |||
| 244 | 255 | ||
| 245 | .type v4wb_cache_fns, #object | 256 | .type v4wb_cache_fns, #object |
| 246 | ENTRY(v4wb_cache_fns) | 257 | ENTRY(v4wb_cache_fns) |
| 258 | .long v4wb_flush_icache_all | ||
| 247 | .long v4wb_flush_kern_cache_all | 259 | .long v4wb_flush_kern_cache_all |
| 248 | .long v4wb_flush_user_cache_all | 260 | .long v4wb_flush_user_cache_all |
| 249 | .long v4wb_flush_user_cache_range | 261 | .long v4wb_flush_user_cache_range |
diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S index 45c70312f43b..49c2b66cf3dd 100644 --- a/arch/arm/mm/cache-v4wt.S +++ b/arch/arm/mm/cache-v4wt.S | |||
| @@ -41,6 +41,17 @@ | |||
| 41 | #define CACHE_DLIMIT 16384 | 41 | #define CACHE_DLIMIT 16384 |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| 44 | * flush_icache_all() | ||
| 45 | * | ||
| 46 | * Unconditionally clean and invalidate the entire icache. | ||
| 47 | */ | ||
| 48 | ENTRY(v4wt_flush_icache_all) | ||
| 49 | mov r0, #0 | ||
| 50 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 51 | mov pc, lr | ||
| 52 | ENDPROC(v4wt_flush_icache_all) | ||
| 53 | |||
| 54 | /* | ||
| 44 | * flush_user_cache_all() | 55 | * flush_user_cache_all() |
| 45 | * | 56 | * |
| 46 | * Invalidate all cache entries in a particular address | 57 | * Invalidate all cache entries in a particular address |
| @@ -188,6 +199,7 @@ ENDPROC(v4wt_dma_map_area) | |||
| 188 | 199 | ||
| 189 | .type v4wt_cache_fns, #object | 200 | .type v4wt_cache_fns, #object |
| 190 | ENTRY(v4wt_cache_fns) | 201 | ENTRY(v4wt_cache_fns) |
| 202 | .long v4wt_flush_icache_all | ||
| 191 | .long v4wt_flush_kern_cache_all | 203 | .long v4wt_flush_kern_cache_all |
| 192 | .long v4wt_flush_user_cache_all | 204 | .long v4wt_flush_user_cache_all |
| 193 | .long v4wt_flush_user_cache_range | 205 | .long v4wt_flush_user_cache_range |
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index c493d7244d3d..83e59f870426 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c | |||
| @@ -66,6 +66,30 @@ static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address, | |||
| 66 | return ret; | 66 | return ret; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | #if USE_SPLIT_PTLOCKS | ||
| 70 | /* | ||
| 71 | * If we are using split PTE locks, then we need to take the page | ||
| 72 | * lock here. Otherwise we are using shared mm->page_table_lock | ||
| 73 | * which is already locked, thus cannot take it. | ||
| 74 | */ | ||
| 75 | static inline void do_pte_lock(spinlock_t *ptl) | ||
| 76 | { | ||
| 77 | /* | ||
| 78 | * Use nested version here to indicate that we are already | ||
| 79 | * holding one similar spinlock. | ||
| 80 | */ | ||
| 81 | spin_lock_nested(ptl, SINGLE_DEPTH_NESTING); | ||
| 82 | } | ||
| 83 | |||
| 84 | static inline void do_pte_unlock(spinlock_t *ptl) | ||
| 85 | { | ||
| 86 | spin_unlock(ptl); | ||
| 87 | } | ||
| 88 | #else /* !USE_SPLIT_PTLOCKS */ | ||
| 89 | static inline void do_pte_lock(spinlock_t *ptl) {} | ||
| 90 | static inline void do_pte_unlock(spinlock_t *ptl) {} | ||
| 91 | #endif /* USE_SPLIT_PTLOCKS */ | ||
| 92 | |||
| 69 | static int adjust_pte(struct vm_area_struct *vma, unsigned long address, | 93 | static int adjust_pte(struct vm_area_struct *vma, unsigned long address, |
| 70 | unsigned long pfn) | 94 | unsigned long pfn) |
| 71 | { | 95 | { |
| @@ -90,11 +114,11 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address, | |||
| 90 | */ | 114 | */ |
| 91 | ptl = pte_lockptr(vma->vm_mm, pmd); | 115 | ptl = pte_lockptr(vma->vm_mm, pmd); |
| 92 | pte = pte_offset_map(pmd, address); | 116 | pte = pte_offset_map(pmd, address); |
| 93 | spin_lock(ptl); | 117 | do_pte_lock(ptl); |
| 94 | 118 | ||
| 95 | ret = do_adjust_pte(vma, address, pfn, pte); | 119 | ret = do_adjust_pte(vma, address, pfn, pte); |
| 96 | 120 | ||
| 97 | spin_unlock(ptl); | 121 | do_pte_unlock(ptl); |
| 98 | pte_unmap(pte); | 122 | pte_unmap(pte); |
| 99 | 123 | ||
| 100 | return ret; | 124 | return ret; |
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 7fd9b5eb177f..5164069ced42 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
| 19 | #include <linux/gfp.h> | 19 | #include <linux/gfp.h> |
| 20 | #include <linux/memblock.h> | 20 | #include <linux/memblock.h> |
| 21 | #include <linux/sort.h> | ||
| 21 | 22 | ||
| 22 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
| 23 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
| @@ -121,9 +122,10 @@ void show_mem(void) | |||
| 121 | printk("%d pages swap cached\n", cached); | 122 | printk("%d pages swap cached\n", cached); |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | static void __init find_limits(struct meminfo *mi, | 125 | static void __init find_limits(unsigned long *min, unsigned long *max_low, |
| 125 | unsigned long *min, unsigned long *max_low, unsigned long *max_high) | 126 | unsigned long *max_high) |
| 126 | { | 127 | { |
| 128 | struct meminfo *mi = &meminfo; | ||
| 127 | int i; | 129 | int i; |
| 128 | 130 | ||
| 129 | *min = -1UL; | 131 | *min = -1UL; |
| @@ -147,14 +149,13 @@ static void __init find_limits(struct meminfo *mi, | |||
| 147 | } | 149 | } |
| 148 | } | 150 | } |
| 149 | 151 | ||
| 150 | static void __init arm_bootmem_init(struct meminfo *mi, | 152 | static void __init arm_bootmem_init(unsigned long start_pfn, |
| 151 | unsigned long start_pfn, unsigned long end_pfn) | 153 | unsigned long end_pfn) |
| 152 | { | 154 | { |
| 153 | struct memblock_region *reg; | 155 | struct memblock_region *reg; |
| 154 | unsigned int boot_pages; | 156 | unsigned int boot_pages; |
| 155 | phys_addr_t bitmap; | 157 | phys_addr_t bitmap; |
| 156 | pg_data_t *pgdat; | 158 | pg_data_t *pgdat; |
| 157 | int i; | ||
| 158 | 159 | ||
| 159 | /* | 160 | /* |
| 160 | * Allocate the bootmem bitmap page. This must be in a region | 161 | * Allocate the bootmem bitmap page. This must be in a region |
| @@ -172,30 +173,39 @@ static void __init arm_bootmem_init(struct meminfo *mi, | |||
| 172 | pgdat = NODE_DATA(0); | 173 | pgdat = NODE_DATA(0); |
| 173 | init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn); | 174 | init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn); |
| 174 | 175 | ||
| 175 | for_each_bank(i, mi) { | 176 | /* Free the lowmem regions from memblock into bootmem. */ |
| 176 | struct membank *bank = &mi->bank[i]; | 177 | for_each_memblock(memory, reg) { |
| 177 | if (!bank->highmem) | 178 | unsigned long start = memblock_region_memory_base_pfn(reg); |
| 178 | free_bootmem(bank_phys_start(bank), bank_phys_size(bank)); | 179 | unsigned long end = memblock_region_memory_end_pfn(reg); |
| 180 | |||
| 181 | if (end >= end_pfn) | ||
| 182 | end = end_pfn; | ||
| 183 | if (start >= end) | ||
| 184 | break; | ||
| 185 | |||
| 186 | free_bootmem(__pfn_to_phys(start), (end - start) << PAGE_SHIFT); | ||
| 179 | } | 187 | } |
| 180 | 188 | ||
| 181 | /* | 189 | /* Reserve the lowmem memblock reserved regions in bootmem. */ |
| 182 | * Reserve the memblock reserved regions in bootmem. | ||
| 183 | */ | ||
| 184 | for_each_memblock(reserved, reg) { | 190 | for_each_memblock(reserved, reg) { |
| 185 | phys_addr_t start = memblock_region_reserved_base_pfn(reg); | 191 | unsigned long start = memblock_region_reserved_base_pfn(reg); |
| 186 | phys_addr_t end = memblock_region_reserved_end_pfn(reg); | 192 | unsigned long end = memblock_region_reserved_end_pfn(reg); |
| 187 | if (start >= start_pfn && end <= end_pfn) | 193 | |
| 188 | reserve_bootmem_node(pgdat, __pfn_to_phys(start), | 194 | if (end >= end_pfn) |
| 189 | (end - start) << PAGE_SHIFT, | 195 | end = end_pfn; |
| 190 | BOOTMEM_DEFAULT); | 196 | if (start >= end) |
| 197 | break; | ||
| 198 | |||
| 199 | reserve_bootmem(__pfn_to_phys(start), | ||
| 200 | (end - start) << PAGE_SHIFT, BOOTMEM_DEFAULT); | ||
| 191 | } | 201 | } |
| 192 | } | 202 | } |
| 193 | 203 | ||
| 194 | static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min, | 204 | static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, |
| 195 | unsigned long max_low, unsigned long max_high) | 205 | unsigned long max_high) |
| 196 | { | 206 | { |
| 197 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; | 207 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; |
| 198 | int i; | 208 | struct memblock_region *reg; |
| 199 | 209 | ||
| 200 | /* | 210 | /* |
| 201 | * initialise the zones. | 211 | * initialise the zones. |
| @@ -217,13 +227,20 @@ static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min, | |||
| 217 | * holes = node_size - sum(bank_sizes) | 227 | * holes = node_size - sum(bank_sizes) |
| 218 | */ | 228 | */ |
| 219 | memcpy(zhole_size, zone_size, sizeof(zhole_size)); | 229 | memcpy(zhole_size, zone_size, sizeof(zhole_size)); |
| 220 | for_each_bank(i, mi) { | 230 | for_each_memblock(memory, reg) { |
| 221 | int idx = 0; | 231 | unsigned long start = memblock_region_memory_base_pfn(reg); |
| 232 | unsigned long end = memblock_region_memory_end_pfn(reg); | ||
| 233 | |||
| 234 | if (start < max_low) { | ||
| 235 | unsigned long low_end = min(end, max_low); | ||
| 236 | zhole_size[0] -= low_end - start; | ||
| 237 | } | ||
| 222 | #ifdef CONFIG_HIGHMEM | 238 | #ifdef CONFIG_HIGHMEM |
| 223 | if (mi->bank[i].highmem) | 239 | if (end > max_low) { |
| 224 | idx = ZONE_HIGHMEM; | 240 | unsigned long high_start = max(start, max_low); |
| 241 | zhole_size[ZONE_HIGHMEM] -= end - high_start; | ||
| 242 | } | ||
| 225 | #endif | 243 | #endif |
| 226 | zhole_size[idx] -= bank_pfn_size(&mi->bank[i]); | ||
| 227 | } | 244 | } |
| 228 | 245 | ||
| 229 | /* | 246 | /* |
| @@ -256,10 +273,19 @@ static void arm_memory_present(void) | |||
| 256 | } | 273 | } |
| 257 | #endif | 274 | #endif |
| 258 | 275 | ||
| 276 | static int __init meminfo_cmp(const void *_a, const void *_b) | ||
| 277 | { | ||
| 278 | const struct membank *a = _a, *b = _b; | ||
| 279 | long cmp = bank_pfn_start(a) - bank_pfn_start(b); | ||
| 280 | return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; | ||
| 281 | } | ||
| 282 | |||
| 259 | void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) | 283 | void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) |
| 260 | { | 284 | { |
| 261 | int i; | 285 | int i; |
| 262 | 286 | ||
| 287 | sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); | ||
| 288 | |||
| 263 | memblock_init(); | 289 | memblock_init(); |
| 264 | for (i = 0; i < mi->nr_banks; i++) | 290 | for (i = 0; i < mi->nr_banks; i++) |
| 265 | memblock_add(mi->bank[i].start, mi->bank[i].size); | 291 | memblock_add(mi->bank[i].start, mi->bank[i].size); |
| @@ -292,14 +318,13 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) | |||
| 292 | 318 | ||
| 293 | void __init bootmem_init(void) | 319 | void __init bootmem_init(void) |
| 294 | { | 320 | { |
| 295 | struct meminfo *mi = &meminfo; | ||
| 296 | unsigned long min, max_low, max_high; | 321 | unsigned long min, max_low, max_high; |
| 297 | 322 | ||
| 298 | max_low = max_high = 0; | 323 | max_low = max_high = 0; |
| 299 | 324 | ||
| 300 | find_limits(mi, &min, &max_low, &max_high); | 325 | find_limits(&min, &max_low, &max_high); |
| 301 | 326 | ||
| 302 | arm_bootmem_init(mi, min, max_low); | 327 | arm_bootmem_init(min, max_low); |
| 303 | 328 | ||
| 304 | /* | 329 | /* |
| 305 | * Sparsemem tries to allocate bootmem in memory_present(), | 330 | * Sparsemem tries to allocate bootmem in memory_present(), |
| @@ -317,7 +342,7 @@ void __init bootmem_init(void) | |||
| 317 | * the sparse mem_map arrays initialized by sparse_init() | 342 | * the sparse mem_map arrays initialized by sparse_init() |
| 318 | * for memmap_init_zone(), otherwise all PFNs are invalid. | 343 | * for memmap_init_zone(), otherwise all PFNs are invalid. |
| 319 | */ | 344 | */ |
| 320 | arm_bootmem_free(mi, min, max_low, max_high); | 345 | arm_bootmem_free(min, max_low, max_high); |
| 321 | 346 | ||
| 322 | high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; | 347 | high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; |
| 323 | 348 | ||
| @@ -411,6 +436,56 @@ static void __init free_unused_memmap(struct meminfo *mi) | |||
| 411 | } | 436 | } |
| 412 | } | 437 | } |
| 413 | 438 | ||
| 439 | static void __init free_highpages(void) | ||
| 440 | { | ||
| 441 | #ifdef CONFIG_HIGHMEM | ||
| 442 | unsigned long max_low = max_low_pfn + PHYS_PFN_OFFSET; | ||
| 443 | struct memblock_region *mem, *res; | ||
| 444 | |||
| 445 | /* set highmem page free */ | ||
| 446 | for_each_memblock(memory, mem) { | ||
| 447 | unsigned long start = memblock_region_memory_base_pfn(mem); | ||
| 448 | unsigned long end = memblock_region_memory_end_pfn(mem); | ||
| 449 | |||
| 450 | /* Ignore complete lowmem entries */ | ||
| 451 | if (end <= max_low) | ||
| 452 | continue; | ||
| 453 | |||
| 454 | /* Truncate partial highmem entries */ | ||
| 455 | if (start < max_low) | ||
| 456 | start = max_low; | ||
| 457 | |||
| 458 | /* Find and exclude any reserved regions */ | ||
| 459 | for_each_memblock(reserved, res) { | ||
| 460 | unsigned long res_start, res_end; | ||
| 461 | |||
| 462 | res_start = memblock_region_reserved_base_pfn(res); | ||
| 463 | res_end = memblock_region_reserved_end_pfn(res); | ||
| 464 | |||
| 465 | if (res_end < start) | ||
| 466 | continue; | ||
| 467 | if (res_start < start) | ||
| 468 | res_start = start; | ||
| 469 | if (res_start > end) | ||
| 470 | res_start = end; | ||
| 471 | if (res_end > end) | ||
| 472 | res_end = end; | ||
| 473 | if (res_start != start) | ||
| 474 | totalhigh_pages += free_area(start, res_start, | ||
| 475 | NULL); | ||
| 476 | start = res_end; | ||
| 477 | if (start == end) | ||
| 478 | break; | ||
| 479 | } | ||
| 480 | |||
| 481 | /* And now free anything which remains */ | ||
| 482 | if (start < end) | ||
| 483 | totalhigh_pages += free_area(start, end, NULL); | ||
| 484 | } | ||
| 485 | totalram_pages += totalhigh_pages; | ||
| 486 | #endif | ||
| 487 | } | ||
| 488 | |||
| 414 | /* | 489 | /* |
| 415 | * mem_init() marks the free areas in the mem_map and tells us how much | 490 | * mem_init() marks the free areas in the mem_map and tells us how much |
| 416 | * memory is free. This is done after various parts of the system have | 491 | * memory is free. This is done after various parts of the system have |
| @@ -419,6 +494,7 @@ static void __init free_unused_memmap(struct meminfo *mi) | |||
| 419 | void __init mem_init(void) | 494 | void __init mem_init(void) |
| 420 | { | 495 | { |
| 421 | unsigned long reserved_pages, free_pages; | 496 | unsigned long reserved_pages, free_pages; |
| 497 | struct memblock_region *reg; | ||
| 422 | int i; | 498 | int i; |
| 423 | #ifdef CONFIG_HAVE_TCM | 499 | #ifdef CONFIG_HAVE_TCM |
| 424 | /* These pointers are filled in on TCM detection */ | 500 | /* These pointers are filled in on TCM detection */ |
| @@ -439,16 +515,7 @@ void __init mem_init(void) | |||
| 439 | __phys_to_pfn(__pa(swapper_pg_dir)), NULL); | 515 | __phys_to_pfn(__pa(swapper_pg_dir)), NULL); |
| 440 | #endif | 516 | #endif |
| 441 | 517 | ||
| 442 | #ifdef CONFIG_HIGHMEM | 518 | free_highpages(); |
| 443 | /* set highmem page free */ | ||
| 444 | for_each_bank (i, &meminfo) { | ||
| 445 | unsigned long start = bank_pfn_start(&meminfo.bank[i]); | ||
| 446 | unsigned long end = bank_pfn_end(&meminfo.bank[i]); | ||
| 447 | if (start >= max_low_pfn + PHYS_PFN_OFFSET) | ||
| 448 | totalhigh_pages += free_area(start, end, NULL); | ||
| 449 | } | ||
| 450 | totalram_pages += totalhigh_pages; | ||
| 451 | #endif | ||
| 452 | 519 | ||
| 453 | reserved_pages = free_pages = 0; | 520 | reserved_pages = free_pages = 0; |
| 454 | 521 | ||
| @@ -478,9 +545,11 @@ void __init mem_init(void) | |||
| 478 | */ | 545 | */ |
| 479 | printk(KERN_INFO "Memory:"); | 546 | printk(KERN_INFO "Memory:"); |
| 480 | num_physpages = 0; | 547 | num_physpages = 0; |
| 481 | for (i = 0; i < meminfo.nr_banks; i++) { | 548 | for_each_memblock(memory, reg) { |
| 482 | num_physpages += bank_pfn_size(&meminfo.bank[i]); | 549 | unsigned long pages = memblock_region_memory_end_pfn(reg) - |
| 483 | printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20); | 550 | memblock_region_memory_base_pfn(reg); |
| 551 | num_physpages += pages; | ||
| 552 | printk(" %ldMB", pages >> (20 - PAGE_SHIFT)); | ||
| 484 | } | 553 | } |
| 485 | printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); | 554 | printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); |
| 486 | 555 | ||
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index c32f731d56d3..72ad3e1f56cf 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include <linux/mman.h> | 14 | #include <linux/mman.h> |
| 15 | #include <linux/nodemask.h> | 15 | #include <linux/nodemask.h> |
| 16 | #include <linux/memblock.h> | 16 | #include <linux/memblock.h> |
| 17 | #include <linux/sort.h> | ||
| 18 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| 19 | 18 | ||
| 20 | #include <asm/cputype.h> | 19 | #include <asm/cputype.h> |
| @@ -265,17 +264,17 @@ static struct mem_type mem_types[] = { | |||
| 265 | .domain = DOMAIN_KERNEL, | 264 | .domain = DOMAIN_KERNEL, |
| 266 | }, | 265 | }, |
| 267 | [MT_MEMORY_DTCM] = { | 266 | [MT_MEMORY_DTCM] = { |
| 268 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | | 267 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | |
| 269 | L_PTE_DIRTY | L_PTE_WRITE, | 268 | L_PTE_WRITE, |
| 270 | .prot_l1 = PMD_TYPE_TABLE, | 269 | .prot_l1 = PMD_TYPE_TABLE, |
| 271 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, | 270 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, |
| 272 | .domain = DOMAIN_KERNEL, | 271 | .domain = DOMAIN_KERNEL, |
| 273 | }, | 272 | }, |
| 274 | [MT_MEMORY_ITCM] = { | 273 | [MT_MEMORY_ITCM] = { |
| 275 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | | 274 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | |
| 276 | L_PTE_USER | L_PTE_EXEC, | 275 | L_PTE_WRITE | L_PTE_EXEC, |
| 277 | .prot_l1 = PMD_TYPE_TABLE, | 276 | .prot_l1 = PMD_TYPE_TABLE, |
| 278 | .domain = DOMAIN_IO, | 277 | .domain = DOMAIN_KERNEL, |
| 279 | }, | 278 | }, |
| 280 | }; | 279 | }; |
| 281 | 280 | ||
| @@ -745,13 +744,14 @@ static int __init early_vmalloc(char *arg) | |||
| 745 | } | 744 | } |
| 746 | early_param("vmalloc", early_vmalloc); | 745 | early_param("vmalloc", early_vmalloc); |
| 747 | 746 | ||
| 748 | phys_addr_t lowmem_end_addr; | 747 | static phys_addr_t lowmem_limit __initdata = 0; |
| 749 | 748 | ||
| 750 | static void __init sanity_check_meminfo(void) | 749 | static void __init sanity_check_meminfo(void) |
| 751 | { | 750 | { |
| 752 | int i, j, highmem = 0; | 751 | int i, j, highmem = 0; |
| 753 | 752 | ||
| 754 | lowmem_end_addr = __pa(vmalloc_min - 1) + 1; | 753 | lowmem_limit = __pa(vmalloc_min - 1) + 1; |
| 754 | memblock_set_current_limit(lowmem_limit); | ||
| 755 | 755 | ||
| 756 | for (i = 0, j = 0; i < meminfo.nr_banks; i++) { | 756 | for (i = 0, j = 0; i < meminfo.nr_banks; i++) { |
| 757 | struct membank *bank = &meminfo.bank[j]; | 757 | struct membank *bank = &meminfo.bank[j]; |
| @@ -852,6 +852,7 @@ static void __init sanity_check_meminfo(void) | |||
| 852 | static inline void prepare_page_table(void) | 852 | static inline void prepare_page_table(void) |
| 853 | { | 853 | { |
| 854 | unsigned long addr; | 854 | unsigned long addr; |
| 855 | phys_addr_t end; | ||
| 855 | 856 | ||
| 856 | /* | 857 | /* |
| 857 | * Clear out all the mappings below the kernel image. | 858 | * Clear out all the mappings below the kernel image. |
| @@ -867,10 +868,17 @@ static inline void prepare_page_table(void) | |||
| 867 | pmd_clear(pmd_off_k(addr)); | 868 | pmd_clear(pmd_off_k(addr)); |
| 868 | 869 | ||
| 869 | /* | 870 | /* |
| 871 | * Find the end of the first block of lowmem. | ||
| 872 | */ | ||
| 873 | end = memblock.memory.regions[0].base + memblock.memory.regions[0].size; | ||
| 874 | if (end >= lowmem_limit) | ||
| 875 | end = lowmem_limit; | ||
| 876 | |||
| 877 | /* | ||
| 870 | * Clear out all the kernel space mappings, except for the first | 878 | * Clear out all the kernel space mappings, except for the first |
| 871 | * memory bank, up to the end of the vmalloc region. | 879 | * memory bank, up to the end of the vmalloc region. |
| 872 | */ | 880 | */ |
| 873 | for (addr = __phys_to_virt(bank_phys_end(&meminfo.bank[0])); | 881 | for (addr = __phys_to_virt(end); |
| 874 | addr < VMALLOC_END; addr += PGDIR_SIZE) | 882 | addr < VMALLOC_END; addr += PGDIR_SIZE) |
| 875 | pmd_clear(pmd_off_k(addr)); | 883 | pmd_clear(pmd_off_k(addr)); |
| 876 | } | 884 | } |
| @@ -987,37 +995,28 @@ static void __init kmap_init(void) | |||
| 987 | #endif | 995 | #endif |
| 988 | } | 996 | } |
| 989 | 997 | ||
| 990 | static inline void map_memory_bank(struct membank *bank) | ||
| 991 | { | ||
| 992 | struct map_desc map; | ||
| 993 | |||
| 994 | map.pfn = bank_pfn_start(bank); | ||
| 995 | map.virtual = __phys_to_virt(bank_phys_start(bank)); | ||
| 996 | map.length = bank_phys_size(bank); | ||
| 997 | map.type = MT_MEMORY; | ||
| 998 | |||
| 999 | create_mapping(&map); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | static void __init map_lowmem(void) | 998 | static void __init map_lowmem(void) |
| 1003 | { | 999 | { |
| 1004 | struct meminfo *mi = &meminfo; | 1000 | struct memblock_region *reg; |
| 1005 | int i; | ||
| 1006 | 1001 | ||
| 1007 | /* Map all the lowmem memory banks. */ | 1002 | /* Map all the lowmem memory banks. */ |
| 1008 | for (i = 0; i < mi->nr_banks; i++) { | 1003 | for_each_memblock(memory, reg) { |
| 1009 | struct membank *bank = &mi->bank[i]; | 1004 | phys_addr_t start = reg->base; |
| 1005 | phys_addr_t end = start + reg->size; | ||
| 1006 | struct map_desc map; | ||
| 1007 | |||
| 1008 | if (end > lowmem_limit) | ||
| 1009 | end = lowmem_limit; | ||
| 1010 | if (start >= end) | ||
| 1011 | break; | ||
| 1010 | 1012 | ||
| 1011 | if (!bank->highmem) | 1013 | map.pfn = __phys_to_pfn(start); |
| 1012 | map_memory_bank(bank); | 1014 | map.virtual = __phys_to_virt(start); |
| 1013 | } | 1015 | map.length = end - start; |
| 1014 | } | 1016 | map.type = MT_MEMORY; |
| 1015 | 1017 | ||
| 1016 | static int __init meminfo_cmp(const void *_a, const void *_b) | 1018 | create_mapping(&map); |
| 1017 | { | 1019 | } |
| 1018 | const struct membank *a = _a, *b = _b; | ||
| 1019 | long cmp = bank_pfn_start(a) - bank_pfn_start(b); | ||
| 1020 | return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; | ||
| 1021 | } | 1020 | } |
| 1022 | 1021 | ||
| 1023 | /* | 1022 | /* |
| @@ -1028,8 +1027,6 @@ void __init paging_init(struct machine_desc *mdesc) | |||
| 1028 | { | 1027 | { |
| 1029 | void *zero_page; | 1028 | void *zero_page; |
| 1030 | 1029 | ||
| 1031 | sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); | ||
| 1032 | |||
| 1033 | build_mem_type_table(); | 1030 | build_mem_type_table(); |
| 1034 | sanity_check_meminfo(); | 1031 | sanity_check_meminfo(); |
| 1035 | prepare_page_table(); | 1032 | prepare_page_table(); |
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index a6f5f8475b96..bcf748d9f4e2 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S | |||
| @@ -119,6 +119,20 @@ ENTRY(cpu_arm1020_do_idle) | |||
| 119 | /* ================================= CACHE ================================ */ | 119 | /* ================================= CACHE ================================ */ |
| 120 | 120 | ||
| 121 | .align 5 | 121 | .align 5 |
| 122 | |||
| 123 | /* | ||
| 124 | * flush_icache_all() | ||
| 125 | * | ||
| 126 | * Unconditionally clean and invalidate the entire icache. | ||
| 127 | */ | ||
| 128 | ENTRY(arm1020_flush_icache_all) | ||
| 129 | #ifndef CONFIG_CPU_ICACHE_DISABLE | ||
| 130 | mov r0, #0 | ||
| 131 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 132 | #endif | ||
| 133 | mov pc, lr | ||
| 134 | ENDPROC(arm1020_flush_icache_all) | ||
| 135 | |||
| 122 | /* | 136 | /* |
| 123 | * flush_user_cache_all() | 137 | * flush_user_cache_all() |
| 124 | * | 138 | * |
| @@ -351,6 +365,7 @@ ENTRY(arm1020_dma_unmap_area) | |||
| 351 | ENDPROC(arm1020_dma_unmap_area) | 365 | ENDPROC(arm1020_dma_unmap_area) |
| 352 | 366 | ||
| 353 | ENTRY(arm1020_cache_fns) | 367 | ENTRY(arm1020_cache_fns) |
| 368 | .long arm1020_flush_icache_all | ||
| 354 | .long arm1020_flush_kern_cache_all | 369 | .long arm1020_flush_kern_cache_all |
| 355 | .long arm1020_flush_user_cache_all | 370 | .long arm1020_flush_user_cache_all |
| 356 | .long arm1020_flush_user_cache_range | 371 | .long arm1020_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index afc06b9c3133..ab7ec26657ea 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S | |||
| @@ -119,6 +119,20 @@ ENTRY(cpu_arm1020e_do_idle) | |||
| 119 | /* ================================= CACHE ================================ */ | 119 | /* ================================= CACHE ================================ */ |
| 120 | 120 | ||
| 121 | .align 5 | 121 | .align 5 |
| 122 | |||
| 123 | /* | ||
| 124 | * flush_icache_all() | ||
| 125 | * | ||
| 126 | * Unconditionally clean and invalidate the entire icache. | ||
| 127 | */ | ||
| 128 | ENTRY(arm1020e_flush_icache_all) | ||
| 129 | #ifndef CONFIG_CPU_ICACHE_DISABLE | ||
| 130 | mov r0, #0 | ||
| 131 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 132 | #endif | ||
| 133 | mov pc, lr | ||
| 134 | ENDPROC(arm1020e_flush_icache_all) | ||
| 135 | |||
| 122 | /* | 136 | /* |
| 123 | * flush_user_cache_all() | 137 | * flush_user_cache_all() |
| 124 | * | 138 | * |
| @@ -337,6 +351,7 @@ ENTRY(arm1020e_dma_unmap_area) | |||
| 337 | ENDPROC(arm1020e_dma_unmap_area) | 351 | ENDPROC(arm1020e_dma_unmap_area) |
| 338 | 352 | ||
| 339 | ENTRY(arm1020e_cache_fns) | 353 | ENTRY(arm1020e_cache_fns) |
| 354 | .long arm1020e_flush_icache_all | ||
| 340 | .long arm1020e_flush_kern_cache_all | 355 | .long arm1020e_flush_kern_cache_all |
| 341 | .long arm1020e_flush_user_cache_all | 356 | .long arm1020e_flush_user_cache_all |
| 342 | .long arm1020e_flush_user_cache_range | 357 | .long arm1020e_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index 8915e0ba3fe5..831c5e54e22f 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S | |||
| @@ -108,6 +108,20 @@ ENTRY(cpu_arm1022_do_idle) | |||
| 108 | /* ================================= CACHE ================================ */ | 108 | /* ================================= CACHE ================================ */ |
| 109 | 109 | ||
| 110 | .align 5 | 110 | .align 5 |
| 111 | |||
| 112 | /* | ||
| 113 | * flush_icache_all() | ||
| 114 | * | ||
| 115 | * Unconditionally clean and invalidate the entire icache. | ||
| 116 | */ | ||
| 117 | ENTRY(arm1022_flush_icache_all) | ||
| 118 | #ifndef CONFIG_CPU_ICACHE_DISABLE | ||
| 119 | mov r0, #0 | ||
| 120 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 121 | #endif | ||
| 122 | mov pc, lr | ||
| 123 | ENDPROC(arm1022_flush_icache_all) | ||
| 124 | |||
| 111 | /* | 125 | /* |
| 112 | * flush_user_cache_all() | 126 | * flush_user_cache_all() |
| 113 | * | 127 | * |
| @@ -326,6 +340,7 @@ ENTRY(arm1022_dma_unmap_area) | |||
| 326 | ENDPROC(arm1022_dma_unmap_area) | 340 | ENDPROC(arm1022_dma_unmap_area) |
| 327 | 341 | ||
| 328 | ENTRY(arm1022_cache_fns) | 342 | ENTRY(arm1022_cache_fns) |
| 343 | .long arm1022_flush_icache_all | ||
| 329 | .long arm1022_flush_kern_cache_all | 344 | .long arm1022_flush_kern_cache_all |
| 330 | .long arm1022_flush_user_cache_all | 345 | .long arm1022_flush_user_cache_all |
| 331 | .long arm1022_flush_user_cache_range | 346 | .long arm1022_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index ff446c5d476f..e3f7e9a166bf 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S | |||
| @@ -108,6 +108,20 @@ ENTRY(cpu_arm1026_do_idle) | |||
| 108 | /* ================================= CACHE ================================ */ | 108 | /* ================================= CACHE ================================ */ |
| 109 | 109 | ||
| 110 | .align 5 | 110 | .align 5 |
| 111 | |||
| 112 | /* | ||
| 113 | * flush_icache_all() | ||
| 114 | * | ||
| 115 | * Unconditionally clean and invalidate the entire icache. | ||
| 116 | */ | ||
| 117 | ENTRY(arm1026_flush_icache_all) | ||
| 118 | #ifndef CONFIG_CPU_ICACHE_DISABLE | ||
| 119 | mov r0, #0 | ||
| 120 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 121 | #endif | ||
| 122 | mov pc, lr | ||
| 123 | ENDPROC(arm1026_flush_icache_all) | ||
| 124 | |||
| 111 | /* | 125 | /* |
| 112 | * flush_user_cache_all() | 126 | * flush_user_cache_all() |
| 113 | * | 127 | * |
| @@ -320,6 +334,7 @@ ENTRY(arm1026_dma_unmap_area) | |||
| 320 | ENDPROC(arm1026_dma_unmap_area) | 334 | ENDPROC(arm1026_dma_unmap_area) |
| 321 | 335 | ||
| 322 | ENTRY(arm1026_cache_fns) | 336 | ENTRY(arm1026_cache_fns) |
| 337 | .long arm1026_flush_icache_all | ||
| 323 | .long arm1026_flush_kern_cache_all | 338 | .long arm1026_flush_kern_cache_all |
| 324 | .long arm1026_flush_user_cache_all | 339 | .long arm1026_flush_user_cache_all |
| 325 | .long arm1026_flush_user_cache_range | 340 | .long arm1026_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index fecf570939f3..6109f278a904 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S | |||
| @@ -110,6 +110,17 @@ ENTRY(cpu_arm920_do_idle) | |||
| 110 | #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH | 110 | #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH |
| 111 | 111 | ||
| 112 | /* | 112 | /* |
| 113 | * flush_icache_all() | ||
| 114 | * | ||
| 115 | * Unconditionally clean and invalidate the entire icache. | ||
| 116 | */ | ||
| 117 | ENTRY(arm920_flush_icache_all) | ||
| 118 | mov r0, #0 | ||
| 119 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 120 | mov pc, lr | ||
| 121 | ENDPROC(arm920_flush_icache_all) | ||
| 122 | |||
| 123 | /* | ||
| 113 | * flush_user_cache_all() | 124 | * flush_user_cache_all() |
| 114 | * | 125 | * |
| 115 | * Invalidate all cache entries in a particular address | 126 | * Invalidate all cache entries in a particular address |
| @@ -305,6 +316,7 @@ ENTRY(arm920_dma_unmap_area) | |||
| 305 | ENDPROC(arm920_dma_unmap_area) | 316 | ENDPROC(arm920_dma_unmap_area) |
| 306 | 317 | ||
| 307 | ENTRY(arm920_cache_fns) | 318 | ENTRY(arm920_cache_fns) |
| 319 | .long arm920_flush_icache_all | ||
| 308 | .long arm920_flush_kern_cache_all | 320 | .long arm920_flush_kern_cache_all |
| 309 | .long arm920_flush_user_cache_all | 321 | .long arm920_flush_user_cache_all |
| 310 | .long arm920_flush_user_cache_range | 322 | .long arm920_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index e3cbf87c9480..bb2f0f46a5e6 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S | |||
| @@ -112,6 +112,17 @@ ENTRY(cpu_arm922_do_idle) | |||
| 112 | #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH | 112 | #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH |
| 113 | 113 | ||
| 114 | /* | 114 | /* |
| 115 | * flush_icache_all() | ||
| 116 | * | ||
| 117 | * Unconditionally clean and invalidate the entire icache. | ||
| 118 | */ | ||
| 119 | ENTRY(arm922_flush_icache_all) | ||
| 120 | mov r0, #0 | ||
| 121 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 122 | mov pc, lr | ||
| 123 | ENDPROC(arm922_flush_icache_all) | ||
| 124 | |||
| 125 | /* | ||
| 115 | * flush_user_cache_all() | 126 | * flush_user_cache_all() |
| 116 | * | 127 | * |
| 117 | * Clean and invalidate all cache entries in a particular | 128 | * Clean and invalidate all cache entries in a particular |
| @@ -307,6 +318,7 @@ ENTRY(arm922_dma_unmap_area) | |||
| 307 | ENDPROC(arm922_dma_unmap_area) | 318 | ENDPROC(arm922_dma_unmap_area) |
| 308 | 319 | ||
| 309 | ENTRY(arm922_cache_fns) | 320 | ENTRY(arm922_cache_fns) |
| 321 | .long arm922_flush_icache_all | ||
| 310 | .long arm922_flush_kern_cache_all | 322 | .long arm922_flush_kern_cache_all |
| 311 | .long arm922_flush_user_cache_all | 323 | .long arm922_flush_user_cache_all |
| 312 | .long arm922_flush_user_cache_range | 324 | .long arm922_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index 572424c867b5..c13e01accfe2 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S | |||
| @@ -145,6 +145,17 @@ ENTRY(cpu_arm925_do_idle) | |||
| 145 | mov pc, lr | 145 | mov pc, lr |
| 146 | 146 | ||
| 147 | /* | 147 | /* |
| 148 | * flush_icache_all() | ||
| 149 | * | ||
| 150 | * Unconditionally clean and invalidate the entire icache. | ||
| 151 | */ | ||
| 152 | ENTRY(arm925_flush_icache_all) | ||
| 153 | mov r0, #0 | ||
| 154 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 155 | mov pc, lr | ||
| 156 | ENDPROC(arm925_flush_icache_all) | ||
| 157 | |||
| 158 | /* | ||
| 148 | * flush_user_cache_all() | 159 | * flush_user_cache_all() |
| 149 | * | 160 | * |
| 150 | * Clean and invalidate all cache entries in a particular | 161 | * Clean and invalidate all cache entries in a particular |
| @@ -362,6 +373,7 @@ ENTRY(arm925_dma_unmap_area) | |||
| 362 | ENDPROC(arm925_dma_unmap_area) | 373 | ENDPROC(arm925_dma_unmap_area) |
| 363 | 374 | ||
| 364 | ENTRY(arm925_cache_fns) | 375 | ENTRY(arm925_cache_fns) |
| 376 | .long arm925_flush_icache_all | ||
| 365 | .long arm925_flush_kern_cache_all | 377 | .long arm925_flush_kern_cache_all |
| 366 | .long arm925_flush_user_cache_all | 378 | .long arm925_flush_user_cache_all |
| 367 | .long arm925_flush_user_cache_range | 379 | .long arm925_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index 63d168b4ebe6..42eb4315740b 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S | |||
| @@ -111,6 +111,17 @@ ENTRY(cpu_arm926_do_idle) | |||
| 111 | mov pc, lr | 111 | mov pc, lr |
| 112 | 112 | ||
| 113 | /* | 113 | /* |
| 114 | * flush_icache_all() | ||
| 115 | * | ||
| 116 | * Unconditionally clean and invalidate the entire icache. | ||
| 117 | */ | ||
| 118 | ENTRY(arm926_flush_icache_all) | ||
| 119 | mov r0, #0 | ||
| 120 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 121 | mov pc, lr | ||
| 122 | ENDPROC(arm926_flush_icache_all) | ||
| 123 | |||
| 124 | /* | ||
| 114 | * flush_user_cache_all() | 125 | * flush_user_cache_all() |
| 115 | * | 126 | * |
| 116 | * Clean and invalidate all cache entries in a particular | 127 | * Clean and invalidate all cache entries in a particular |
| @@ -325,6 +336,7 @@ ENTRY(arm926_dma_unmap_area) | |||
| 325 | ENDPROC(arm926_dma_unmap_area) | 336 | ENDPROC(arm926_dma_unmap_area) |
| 326 | 337 | ||
| 327 | ENTRY(arm926_cache_fns) | 338 | ENTRY(arm926_cache_fns) |
| 339 | .long arm926_flush_icache_all | ||
| 328 | .long arm926_flush_kern_cache_all | 340 | .long arm926_flush_kern_cache_all |
| 329 | .long arm926_flush_user_cache_all | 341 | .long arm926_flush_user_cache_all |
| 330 | .long arm926_flush_user_cache_range | 342 | .long arm926_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S index f6a62822418e..7b11cdb9935f 100644 --- a/arch/arm/mm/proc-arm940.S +++ b/arch/arm/mm/proc-arm940.S | |||
| @@ -68,6 +68,17 @@ ENTRY(cpu_arm940_do_idle) | |||
| 68 | mov pc, lr | 68 | mov pc, lr |
| 69 | 69 | ||
| 70 | /* | 70 | /* |
| 71 | * flush_icache_all() | ||
| 72 | * | ||
| 73 | * Unconditionally clean and invalidate the entire icache. | ||
| 74 | */ | ||
| 75 | ENTRY(arm940_flush_icache_all) | ||
| 76 | mov r0, #0 | ||
| 77 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 78 | mov pc, lr | ||
| 79 | ENDPROC(arm940_flush_icache_all) | ||
| 80 | |||
| 81 | /* | ||
| 71 | * flush_user_cache_all() | 82 | * flush_user_cache_all() |
| 72 | */ | 83 | */ |
| 73 | ENTRY(arm940_flush_user_cache_all) | 84 | ENTRY(arm940_flush_user_cache_all) |
| @@ -254,6 +265,7 @@ ENTRY(arm940_dma_unmap_area) | |||
| 254 | ENDPROC(arm940_dma_unmap_area) | 265 | ENDPROC(arm940_dma_unmap_area) |
| 255 | 266 | ||
| 256 | ENTRY(arm940_cache_fns) | 267 | ENTRY(arm940_cache_fns) |
| 268 | .long arm940_flush_icache_all | ||
| 257 | .long arm940_flush_kern_cache_all | 269 | .long arm940_flush_kern_cache_all |
| 258 | .long arm940_flush_user_cache_all | 270 | .long arm940_flush_user_cache_all |
| 259 | .long arm940_flush_user_cache_range | 271 | .long arm940_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S index ea2e7f2eb95b..1a5bbf080342 100644 --- a/arch/arm/mm/proc-arm946.S +++ b/arch/arm/mm/proc-arm946.S | |||
| @@ -75,6 +75,17 @@ ENTRY(cpu_arm946_do_idle) | |||
| 75 | mov pc, lr | 75 | mov pc, lr |
| 76 | 76 | ||
| 77 | /* | 77 | /* |
| 78 | * flush_icache_all() | ||
| 79 | * | ||
| 80 | * Unconditionally clean and invalidate the entire icache. | ||
| 81 | */ | ||
| 82 | ENTRY(arm946_flush_icache_all) | ||
| 83 | mov r0, #0 | ||
| 84 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 85 | mov pc, lr | ||
| 86 | ENDPROC(arm946_flush_icache_all) | ||
| 87 | |||
| 88 | /* | ||
| 78 | * flush_user_cache_all() | 89 | * flush_user_cache_all() |
| 79 | */ | 90 | */ |
| 80 | ENTRY(arm946_flush_user_cache_all) | 91 | ENTRY(arm946_flush_user_cache_all) |
| @@ -296,6 +307,7 @@ ENTRY(arm946_dma_unmap_area) | |||
| 296 | ENDPROC(arm946_dma_unmap_area) | 307 | ENDPROC(arm946_dma_unmap_area) |
| 297 | 308 | ||
| 298 | ENTRY(arm946_cache_fns) | 309 | ENTRY(arm946_cache_fns) |
| 310 | .long arm946_flush_icache_all | ||
| 299 | .long arm946_flush_kern_cache_all | 311 | .long arm946_flush_kern_cache_all |
| 300 | .long arm946_flush_user_cache_all | 312 | .long arm946_flush_user_cache_all |
| 301 | .long arm946_flush_user_cache_range | 313 | .long arm946_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S index 578da69200cf..b4597edbff97 100644 --- a/arch/arm/mm/proc-feroceon.S +++ b/arch/arm/mm/proc-feroceon.S | |||
| @@ -124,6 +124,17 @@ ENTRY(cpu_feroceon_do_idle) | |||
| 124 | mov pc, lr | 124 | mov pc, lr |
| 125 | 125 | ||
| 126 | /* | 126 | /* |
| 127 | * flush_icache_all() | ||
| 128 | * | ||
| 129 | * Unconditionally clean and invalidate the entire icache. | ||
| 130 | */ | ||
| 131 | ENTRY(feroceon_flush_icache_all) | ||
| 132 | mov r0, #0 | ||
| 133 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 134 | mov pc, lr | ||
| 135 | ENDPROC(feroceon_flush_icache_all) | ||
| 136 | |||
| 137 | /* | ||
| 127 | * flush_user_cache_all() | 138 | * flush_user_cache_all() |
| 128 | * | 139 | * |
| 129 | * Clean and invalidate all cache entries in a particular | 140 | * Clean and invalidate all cache entries in a particular |
| @@ -401,6 +412,7 @@ ENTRY(feroceon_dma_unmap_area) | |||
| 401 | ENDPROC(feroceon_dma_unmap_area) | 412 | ENDPROC(feroceon_dma_unmap_area) |
| 402 | 413 | ||
| 403 | ENTRY(feroceon_cache_fns) | 414 | ENTRY(feroceon_cache_fns) |
| 415 | .long feroceon_flush_icache_all | ||
| 404 | .long feroceon_flush_kern_cache_all | 416 | .long feroceon_flush_kern_cache_all |
| 405 | .long feroceon_flush_user_cache_all | 417 | .long feroceon_flush_user_cache_all |
| 406 | .long feroceon_flush_user_cache_range | 418 | .long feroceon_flush_user_cache_range |
| @@ -412,6 +424,7 @@ ENTRY(feroceon_cache_fns) | |||
| 412 | .long feroceon_dma_flush_range | 424 | .long feroceon_dma_flush_range |
| 413 | 425 | ||
| 414 | ENTRY(feroceon_range_cache_fns) | 426 | ENTRY(feroceon_range_cache_fns) |
| 427 | .long feroceon_flush_icache_all | ||
| 415 | .long feroceon_flush_kern_cache_all | 428 | .long feroceon_flush_kern_cache_all |
| 416 | .long feroceon_flush_user_cache_all | 429 | .long feroceon_flush_user_cache_all |
| 417 | .long feroceon_flush_user_cache_range | 430 | .long feroceon_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index cad07e403044..ec26355cb7c2 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S | |||
| @@ -141,6 +141,17 @@ ENTRY(cpu_xsc3_do_idle) | |||
| 141 | /* ================================= CACHE ================================ */ | 141 | /* ================================= CACHE ================================ */ |
| 142 | 142 | ||
| 143 | /* | 143 | /* |
| 144 | * flush_icache_all() | ||
| 145 | * | ||
| 146 | * Unconditionally clean and invalidate the entire icache. | ||
| 147 | */ | ||
| 148 | ENTRY(xsc3_flush_icache_all) | ||
| 149 | mov r0, #0 | ||
| 150 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 151 | mov pc, lr | ||
| 152 | ENDPROC(xsc3_flush_icache_all) | ||
| 153 | |||
| 154 | /* | ||
| 144 | * flush_user_cache_all() | 155 | * flush_user_cache_all() |
| 145 | * | 156 | * |
| 146 | * Invalidate all cache entries in a particular address | 157 | * Invalidate all cache entries in a particular address |
| @@ -325,6 +336,7 @@ ENTRY(xsc3_dma_unmap_area) | |||
| 325 | ENDPROC(xsc3_dma_unmap_area) | 336 | ENDPROC(xsc3_dma_unmap_area) |
| 326 | 337 | ||
| 327 | ENTRY(xsc3_cache_fns) | 338 | ENTRY(xsc3_cache_fns) |
| 339 | .long xsc3_flush_icache_all | ||
| 328 | .long xsc3_flush_kern_cache_all | 340 | .long xsc3_flush_kern_cache_all |
| 329 | .long xsc3_flush_user_cache_all | 341 | .long xsc3_flush_user_cache_all |
| 330 | .long xsc3_flush_user_cache_range | 342 | .long xsc3_flush_user_cache_range |
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index cb245edb2c2b..523408c0bb38 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S | |||
| @@ -181,6 +181,17 @@ ENTRY(cpu_xscale_do_idle) | |||
| 181 | /* ================================= CACHE ================================ */ | 181 | /* ================================= CACHE ================================ */ |
| 182 | 182 | ||
| 183 | /* | 183 | /* |
| 184 | * flush_icache_all() | ||
| 185 | * | ||
| 186 | * Unconditionally clean and invalidate the entire icache. | ||
| 187 | */ | ||
| 188 | ENTRY(xscale_flush_icache_all) | ||
| 189 | mov r0, #0 | ||
| 190 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 191 | mov pc, lr | ||
| 192 | ENDPROC(xscale_flush_icache_all) | ||
| 193 | |||
| 194 | /* | ||
| 184 | * flush_user_cache_all() | 195 | * flush_user_cache_all() |
| 185 | * | 196 | * |
| 186 | * Invalidate all cache entries in a particular address | 197 | * Invalidate all cache entries in a particular address |
| @@ -397,6 +408,7 @@ ENTRY(xscale_dma_unmap_area) | |||
| 397 | ENDPROC(xscale_dma_unmap_area) | 408 | ENDPROC(xscale_dma_unmap_area) |
| 398 | 409 | ||
| 399 | ENTRY(xscale_cache_fns) | 410 | ENTRY(xscale_cache_fns) |
| 411 | .long xscale_flush_icache_all | ||
| 400 | .long xscale_flush_kern_cache_all | 412 | .long xscale_flush_kern_cache_all |
| 401 | .long xscale_flush_user_cache_all | 413 | .long xscale_flush_user_cache_all |
| 402 | .long xscale_flush_user_cache_range | 414 | .long xscale_flush_user_cache_range |
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 06875b4dd70f..372670952789 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile | |||
| @@ -18,6 +18,7 @@ obj-$(CONFIG_MXC_USE_EPIT) += epit.o | |||
| 18 | obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o | 18 | obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o |
| 19 | obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o | 19 | obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o |
| 20 | obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o | 20 | obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o |
| 21 | obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o | ||
| 21 | ifdef CONFIG_SND_IMX_SOC | 22 | ifdef CONFIG_SND_IMX_SOC |
| 22 | obj-y += ssi-fiq.o | 23 | obj-y += ssi-fiq.o |
| 23 | obj-y += ssi-fiq-ksym.o | 24 | obj-y += ssi-fiq-ksym.o |
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c new file mode 100644 index 000000000000..039538e68793 --- /dev/null +++ b/arch/arm/plat-mxc/cpufreq.c | |||
| @@ -0,0 +1,206 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* | ||
| 6 | * The code contained herein is licensed under the GNU General Public | ||
| 7 | * License. You may obtain a copy of the GNU General Public License | ||
| 8 | * Version 2 or later at the following locations: | ||
| 9 | * | ||
| 10 | * http://www.opensource.org/licenses/gpl-license.html | ||
| 11 | * http://www.gnu.org/copyleft/gpl.html | ||
| 12 | */ | ||
| 13 | |||
| 14 | /* | ||
| 15 | * A driver for the Freescale Semiconductor i.MXC CPUfreq module. | ||
| 16 | * The CPUFREQ driver is for controling CPU frequency. It allows you to change | ||
| 17 | * the CPU clock speed on the fly. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/cpufreq.h> | ||
| 21 | #include <linux/clk.h> | ||
| 22 | #include <linux/err.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <mach/hardware.h> | ||
| 25 | #include <mach/clock.h> | ||
| 26 | |||
| 27 | #define CLK32_FREQ 32768 | ||
| 28 | #define NANOSECOND (1000 * 1000 * 1000) | ||
| 29 | |||
| 30 | struct cpu_op *(*get_cpu_op)(int *op); | ||
| 31 | |||
| 32 | static int cpu_freq_khz_min; | ||
| 33 | static int cpu_freq_khz_max; | ||
| 34 | |||
| 35 | static struct clk *cpu_clk; | ||
| 36 | static struct cpufreq_frequency_table *imx_freq_table; | ||
| 37 | |||
| 38 | static int cpu_op_nr; | ||
| 39 | static struct cpu_op *cpu_op_tbl; | ||
| 40 | |||
| 41 | static int set_cpu_freq(int freq) | ||
| 42 | { | ||
| 43 | int ret = 0; | ||
| 44 | int org_cpu_rate; | ||
| 45 | |||
| 46 | org_cpu_rate = clk_get_rate(cpu_clk); | ||
| 47 | if (org_cpu_rate == freq) | ||
| 48 | return ret; | ||
| 49 | |||
| 50 | ret = clk_set_rate(cpu_clk, freq); | ||
| 51 | if (ret != 0) { | ||
| 52 | printk(KERN_DEBUG "cannot set CPU clock rate\n"); | ||
| 53 | return ret; | ||
| 54 | } | ||
| 55 | |||
| 56 | return ret; | ||
| 57 | } | ||
| 58 | |||
| 59 | static int mxc_verify_speed(struct cpufreq_policy *policy) | ||
| 60 | { | ||
| 61 | if (policy->cpu != 0) | ||
| 62 | return -EINVAL; | ||
| 63 | |||
| 64 | return cpufreq_frequency_table_verify(policy, imx_freq_table); | ||
| 65 | } | ||
| 66 | |||
| 67 | static unsigned int mxc_get_speed(unsigned int cpu) | ||
| 68 | { | ||
| 69 | if (cpu) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | return clk_get_rate(cpu_clk) / 1000; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int mxc_set_target(struct cpufreq_policy *policy, | ||
| 76 | unsigned int target_freq, unsigned int relation) | ||
| 77 | { | ||
| 78 | struct cpufreq_freqs freqs; | ||
| 79 | int freq_Hz; | ||
| 80 | int ret = 0; | ||
| 81 | unsigned int index; | ||
| 82 | |||
| 83 | cpufreq_frequency_table_target(policy, imx_freq_table, | ||
| 84 | target_freq, relation, &index); | ||
| 85 | freq_Hz = imx_freq_table[index].frequency * 1000; | ||
| 86 | |||
| 87 | freqs.old = clk_get_rate(cpu_clk) / 1000; | ||
| 88 | freqs.new = freq_Hz / 1000; | ||
| 89 | freqs.cpu = 0; | ||
| 90 | freqs.flags = 0; | ||
| 91 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
| 92 | |||
| 93 | ret = set_cpu_freq(freq_Hz); | ||
| 94 | |||
| 95 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
| 96 | |||
| 97 | return ret; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int __init mxc_cpufreq_init(struct cpufreq_policy *policy) | ||
| 101 | { | ||
| 102 | int ret; | ||
| 103 | int i; | ||
| 104 | |||
| 105 | printk(KERN_INFO "i.MXC CPU frequency driver\n"); | ||
| 106 | |||
| 107 | if (policy->cpu != 0) | ||
| 108 | return -EINVAL; | ||
| 109 | |||
| 110 | if (!get_cpu_op) | ||
| 111 | return -EINVAL; | ||
| 112 | |||
| 113 | cpu_clk = clk_get(NULL, "cpu_clk"); | ||
| 114 | if (IS_ERR(cpu_clk)) { | ||
| 115 | printk(KERN_ERR "%s: failed to get cpu clock\n", __func__); | ||
| 116 | return PTR_ERR(cpu_clk); | ||
| 117 | } | ||
| 118 | |||
| 119 | cpu_op_tbl = get_cpu_op(&cpu_op_nr); | ||
| 120 | |||
| 121 | cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000; | ||
| 122 | cpu_freq_khz_max = cpu_op_tbl[0].cpu_rate / 1000; | ||
| 123 | |||
| 124 | imx_freq_table = kmalloc( | ||
| 125 | sizeof(struct cpufreq_frequency_table) * (cpu_op_nr + 1), | ||
| 126 | GFP_KERNEL); | ||
| 127 | if (!imx_freq_table) { | ||
| 128 | ret = -ENOMEM; | ||
| 129 | goto err1; | ||
| 130 | } | ||
| 131 | |||
| 132 | for (i = 0; i < cpu_op_nr; i++) { | ||
| 133 | imx_freq_table[i].index = i; | ||
| 134 | imx_freq_table[i].frequency = cpu_op_tbl[i].cpu_rate / 1000; | ||
| 135 | |||
| 136 | if ((cpu_op_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min) | ||
| 137 | cpu_freq_khz_min = cpu_op_tbl[i].cpu_rate / 1000; | ||
| 138 | |||
| 139 | if ((cpu_op_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max) | ||
| 140 | cpu_freq_khz_max = cpu_op_tbl[i].cpu_rate / 1000; | ||
| 141 | } | ||
| 142 | |||
| 143 | imx_freq_table[i].index = i; | ||
| 144 | imx_freq_table[i].frequency = CPUFREQ_TABLE_END; | ||
| 145 | |||
| 146 | policy->cur = clk_get_rate(cpu_clk) / 1000; | ||
| 147 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | ||
| 148 | policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min; | ||
| 149 | policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max; | ||
| 150 | |||
| 151 | /* Manual states, that PLL stabilizes in two CLK32 periods */ | ||
| 152 | policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ; | ||
| 153 | |||
| 154 | ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table); | ||
| 155 | |||
| 156 | if (ret < 0) { | ||
| 157 | printk(KERN_ERR "%s: failed to register i.MXC CPUfreq \ | ||
| 158 | with error code %d\n", __func__, ret); | ||
| 159 | goto err; | ||
| 160 | } | ||
| 161 | |||
| 162 | cpufreq_frequency_table_get_attr(imx_freq_table, policy->cpu); | ||
| 163 | return 0; | ||
| 164 | err: | ||
| 165 | kfree(imx_freq_table); | ||
| 166 | err1: | ||
| 167 | clk_put(cpu_clk); | ||
| 168 | return ret; | ||
| 169 | } | ||
| 170 | |||
| 171 | static int mxc_cpufreq_exit(struct cpufreq_policy *policy) | ||
| 172 | { | ||
| 173 | cpufreq_frequency_table_put_attr(policy->cpu); | ||
| 174 | |||
| 175 | set_cpu_freq(cpu_freq_khz_max * 1000); | ||
| 176 | clk_put(cpu_clk); | ||
| 177 | kfree(imx_freq_table); | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | static struct cpufreq_driver mxc_driver = { | ||
| 182 | .flags = CPUFREQ_STICKY, | ||
| 183 | .verify = mxc_verify_speed, | ||
| 184 | .target = mxc_set_target, | ||
| 185 | .get = mxc_get_speed, | ||
| 186 | .init = mxc_cpufreq_init, | ||
| 187 | .exit = mxc_cpufreq_exit, | ||
| 188 | .name = "imx", | ||
| 189 | }; | ||
| 190 | |||
| 191 | static int __devinit mxc_cpufreq_driver_init(void) | ||
| 192 | { | ||
| 193 | return cpufreq_register_driver(&mxc_driver); | ||
| 194 | } | ||
| 195 | |||
| 196 | static void mxc_cpufreq_driver_exit(void) | ||
| 197 | { | ||
| 198 | cpufreq_unregister_driver(&mxc_driver); | ||
| 199 | } | ||
| 200 | |||
| 201 | module_init(mxc_cpufreq_driver_init); | ||
| 202 | module_exit(mxc_cpufreq_driver_exit); | ||
| 203 | |||
| 204 | MODULE_AUTHOR("Freescale Semiconductor Inc. Yong Shen <yong.shen@linaro.org>"); | ||
| 205 | MODULE_DESCRIPTION("CPUfreq driver for i.MX"); | ||
| 206 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index 404799487f17..9aa6f3ea9012 100644 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig | |||
| @@ -6,9 +6,13 @@ config IMX_HAVE_PLATFORM_FEC | |||
| 6 | default y if ARCH_MX25 || SOC_IMX27 || ARCH_MX35 || ARCH_MX51 | 6 | default y if ARCH_MX25 || SOC_IMX27 || ARCH_MX35 || ARCH_MX51 |
| 7 | 7 | ||
| 8 | config IMX_HAVE_PLATFORM_FLEXCAN | 8 | config IMX_HAVE_PLATFORM_FLEXCAN |
| 9 | select HAVE_CAN_FLEXCAN | 9 | select HAVE_CAN_FLEXCAN if CAN |
| 10 | bool | 10 | bool |
| 11 | 11 | ||
| 12 | config IMX_HAVE_PLATFORM_GPIO_KEYS | ||
| 13 | bool | ||
| 14 | default y if ARCH_MX51 | ||
| 15 | |||
| 12 | config IMX_HAVE_PLATFORM_IMX_I2C | 16 | config IMX_HAVE_PLATFORM_IMX_I2C |
| 13 | bool | 17 | bool |
| 14 | 18 | ||
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index 0a3c1f089413..45aefeb283ba 100644 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | obj-$(CONFIG_IMX_HAVE_PLATFORM_ESDHC) += platform-esdhc.o | 1 | obj-$(CONFIG_IMX_HAVE_PLATFORM_ESDHC) += platform-esdhc.o |
| 2 | obj-$(CONFIG_IMX_HAVE_PLATFORM_FEC) += platform-fec.o | 2 | obj-$(CONFIG_IMX_HAVE_PLATFORM_FEC) += platform-fec.o |
| 3 | obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o | 3 | obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o |
| 4 | obj-$(CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS) += platform-gpio_keys.o | ||
| 4 | obj-y += platform-imx-dma.o | 5 | obj-y += platform-imx-dma.o |
| 5 | obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o | 6 | obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o |
| 6 | obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SSI) += platform-imx-ssi.o | 7 | obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SSI) += platform-imx-ssi.o |
diff --git a/arch/arm/plat-mxc/devices/platform-gpio_keys.c b/arch/arm/plat-mxc/devices/platform-gpio_keys.c new file mode 100644 index 000000000000..1c53a532ea0e --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-gpio_keys.c | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version 2 | ||
| 7 | * of the License, or (at your option) any later version. | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program; if not, write to the Free Software | ||
| 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 16 | * Boston, MA 02110-1301, USA. | ||
| 17 | */ | ||
| 18 | #include <asm/sizes.h> | ||
| 19 | #include <mach/hardware.h> | ||
| 20 | #include <mach/devices-common.h> | ||
| 21 | |||
| 22 | struct platform_device *__init imx_add_gpio_keys( | ||
| 23 | const struct gpio_keys_platform_data *pdata) | ||
| 24 | { | ||
| 25 | return imx_add_platform_device("gpio-keys", -1, NULL, | ||
| 26 | 0, pdata, sizeof(*pdata)); | ||
| 27 | } | ||
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 9d38da077edb..9c3e36232b5b 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 23 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/io.h> | 24 | #include <linux/io.h> |
| 24 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
| 25 | #include <linux/gpio.h> | 26 | #include <linux/gpio.h> |
| @@ -201,11 +202,42 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) | |||
| 201 | } | 202 | } |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 205 | /* | ||
| 206 | * Set interrupt number "irq" in the GPIO as a wake-up source. | ||
| 207 | * While system is running, all registered GPIO interrupts need to have | ||
| 208 | * wake-up enabled. When system is suspended, only selected GPIO interrupts | ||
| 209 | * need to have wake-up enabled. | ||
| 210 | * @param irq interrupt source number | ||
| 211 | * @param enable enable as wake-up if equal to non-zero | ||
| 212 | * @return This function returns 0 on success. | ||
| 213 | */ | ||
| 214 | static int gpio_set_wake_irq(u32 irq, u32 enable) | ||
| 215 | { | ||
| 216 | u32 gpio = irq_to_gpio(irq); | ||
| 217 | u32 gpio_idx = gpio & 0x1F; | ||
| 218 | struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32]; | ||
| 219 | |||
| 220 | if (enable) { | ||
| 221 | if (port->irq_high && (gpio_idx >= 16)) | ||
| 222 | enable_irq_wake(port->irq_high); | ||
| 223 | else | ||
| 224 | enable_irq_wake(port->irq); | ||
| 225 | } else { | ||
| 226 | if (port->irq_high && (gpio_idx >= 16)) | ||
| 227 | disable_irq_wake(port->irq_high); | ||
| 228 | else | ||
| 229 | disable_irq_wake(port->irq); | ||
| 230 | } | ||
| 231 | |||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 204 | static struct irq_chip gpio_irq_chip = { | 235 | static struct irq_chip gpio_irq_chip = { |
| 205 | .ack = gpio_ack_irq, | 236 | .ack = gpio_ack_irq, |
| 206 | .mask = gpio_mask_irq, | 237 | .mask = gpio_mask_irq, |
| 207 | .unmask = gpio_unmask_irq, | 238 | .unmask = gpio_unmask_irq, |
| 208 | .set_type = gpio_set_irq_type, | 239 | .set_type = gpio_set_irq_type, |
| 240 | .set_wake = gpio_set_wake_irq, | ||
| 209 | }; | 241 | }; |
| 210 | 242 | ||
| 211 | static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, | 243 | static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, |
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index 86d7575a564d..8c6896fd1e5f 100644 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h | |||
| @@ -29,6 +29,10 @@ struct platform_device *__init imx_add_flexcan(int id, | |||
| 29 | resource_size_t irq, | 29 | resource_size_t irq, |
| 30 | const struct flexcan_platform_data *pdata); | 30 | const struct flexcan_platform_data *pdata); |
| 31 | 31 | ||
| 32 | #include <linux/gpio_keys.h> | ||
| 33 | struct platform_device *__init imx_add_gpio_keys( | ||
| 34 | const struct gpio_keys_platform_data *pdata); | ||
| 35 | |||
| 32 | #include <mach/i2c.h> | 36 | #include <mach/i2c.h> |
| 33 | struct imx_imx_i2c_data { | 37 | struct imx_imx_i2c_data { |
| 34 | int id; | 38 | int id; |
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h index e46b1c2836d4..d7a41e9a2605 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h +++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h | |||
| @@ -45,6 +45,8 @@ typedef enum iomux_config { | |||
| 45 | PAD_CTL_PKE | PAD_CTL_HYS) | 45 | PAD_CTL_PKE | PAD_CTL_HYS) |
| 46 | #define MX51_GPIO_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \ | 46 | #define MX51_GPIO_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \ |
| 47 | PAD_CTL_SRE_FAST) | 47 | PAD_CTL_SRE_FAST) |
| 48 | #define MX51_GPIO_PAD_CTRL_2 (PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | \ | ||
| 49 | PAD_CTL_PUS_100K_UP) | ||
| 48 | #define MX51_ECSPI_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_DSE_HIGH | \ | 50 | #define MX51_ECSPI_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_DSE_HIGH | \ |
| 49 | PAD_CTL_SRE_FAST) | 51 | PAD_CTL_SRE_FAST) |
| 50 | #define MX51_SDHCI_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP | \ | 52 | #define MX51_SDHCI_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP | \ |
diff --git a/arch/arm/plat-mxc/include/mach/mx31.h b/arch/arm/plat-mxc/include/mach/mx31.h index 03e2afabc9fc..61cfe827498b 100644 --- a/arch/arm/plat-mxc/include/mach/mx31.h +++ b/arch/arm/plat-mxc/include/mach/mx31.h | |||
| @@ -240,7 +240,6 @@ static inline void mx31_setup_weimcs(size_t cs, | |||
| 240 | #define MPEG4_ENC_BASE_ADDR MX31_MPEG4_ENC_BASE_ADDR | 240 | #define MPEG4_ENC_BASE_ADDR MX31_MPEG4_ENC_BASE_ADDR |
| 241 | #define MXC_INT_MPEG4_ENCODER MX31_INT_MPEG4_ENCODER | 241 | #define MXC_INT_MPEG4_ENCODER MX31_INT_MPEG4_ENCODER |
| 242 | #define MXC_INT_FIRI MX31_INT_FIRI | 242 | #define MXC_INT_FIRI MX31_INT_FIRI |
| 243 | #define MXC_INT_MMC_SDHC1 MX31_INT_MMC_SDHC1 | ||
| 244 | #define MXC_INT_MBX MX31_INT_MBX | 243 | #define MXC_INT_MBX MX31_INT_MBX |
| 245 | #define MXC_INT_CSPI3 MX31_INT_CSPI3 | 244 | #define MXC_INT_CSPI3 MX31_INT_CSPI3 |
| 246 | #define MXC_INT_SIM2 MX31_INT_SIM2 | 245 | #define MXC_INT_SIM2 MX31_INT_SIM2 |
diff --git a/arch/arm/plat-mxc/include/mach/mx35.h b/arch/arm/plat-mxc/include/mach/mx35.h index ff905cb32458..6267cff6035d 100644 --- a/arch/arm/plat-mxc/include/mach/mx35.h +++ b/arch/arm/plat-mxc/include/mach/mx35.h | |||
| @@ -197,8 +197,6 @@ | |||
| 197 | /* these should go away */ | 197 | /* these should go away */ |
| 198 | #define MXC_FEC_BASE_ADDR MX35_FEC_BASE_ADDR | 198 | #define MXC_FEC_BASE_ADDR MX35_FEC_BASE_ADDR |
| 199 | #define MXC_INT_OWIRE MX35_INT_OWIRE | 199 | #define MXC_INT_OWIRE MX35_INT_OWIRE |
| 200 | #define MXC_INT_MMC_SDHC2 MX35_INT_MMC_SDHC2 | ||
| 201 | #define MXC_INT_MMC_SDHC3 MX35_INT_MMC_SDHC3 | ||
| 202 | #define MXC_INT_GPU2D MX35_INT_GPU2D | 200 | #define MXC_INT_GPU2D MX35_INT_GPU2D |
| 203 | #define MXC_INT_ASRC MX35_INT_ASRC | 201 | #define MXC_INT_ASRC MX35_INT_ASRC |
| 204 | #define MXC_INT_USBHS MX35_INT_USBHS | 202 | #define MXC_INT_USBHS MX35_INT_USBHS |
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h index a790bf212972..a42c7207082d 100644 --- a/arch/arm/plat-mxc/include/mach/mxc.h +++ b/arch/arm/plat-mxc/include/mach/mxc.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. | 2 | * Copyright 2004-2007, 2010 Freescale Semiconductor, Inc. All Rights Reserved. |
| 3 | * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) | 3 | * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -20,6 +20,8 @@ | |||
| 20 | #ifndef __ASM_ARCH_MXC_H__ | 20 | #ifndef __ASM_ARCH_MXC_H__ |
| 21 | #define __ASM_ARCH_MXC_H__ | 21 | #define __ASM_ARCH_MXC_H__ |
| 22 | 22 | ||
| 23 | #include <linux/types.h> | ||
| 24 | |||
| 23 | #ifndef __ASM_ARCH_MXC_HARDWARE_H__ | 25 | #ifndef __ASM_ARCH_MXC_HARDWARE_H__ |
| 24 | #error "Do not include directly." | 26 | #error "Do not include directly." |
| 25 | #endif | 27 | #endif |
| @@ -133,6 +135,15 @@ extern unsigned int __mxc_cpu_type; | |||
| 133 | # define cpu_is_mxc91231() (0) | 135 | # define cpu_is_mxc91231() (0) |
| 134 | #endif | 136 | #endif |
| 135 | 137 | ||
| 138 | #ifndef __ASSEMBLY__ | ||
| 139 | |||
| 140 | struct cpu_op { | ||
| 141 | u32 cpu_rate; | ||
| 142 | }; | ||
| 143 | |||
| 144 | extern struct cpu_op *(*get_cpu_op)(int *op); | ||
| 145 | #endif | ||
| 146 | |||
| 136 | #if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX2) | 147 | #if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX2) |
| 137 | /* These are deprecated, use mx[23][157]_setup_weimcs instead. */ | 148 | /* These are deprecated, use mx[23][157]_setup_weimcs instead. */ |
| 138 | #define CSCR_U(n) (IO_ADDRESS(WEIM_BASE_ADDR + n * 0x10)) | 149 | #define CSCR_U(n) (IO_ADDRESS(WEIM_BASE_ADDR + n * 0x10)) |
diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h index 3478eae32d8a..01a8448e471c 100644 --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | |||
| @@ -30,15 +30,15 @@ struct pxa3xx_nand_cmdset { | |||
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | struct pxa3xx_nand_flash { | 32 | struct pxa3xx_nand_flash { |
| 33 | const struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ | 33 | uint32_t chip_id; |
| 34 | const struct pxa3xx_nand_cmdset *cmdset; | 34 | unsigned int page_per_block; /* Pages per block (PG_PER_BLK) */ |
| 35 | 35 | unsigned int page_size; /* Page size in bytes (PAGE_SZ) */ | |
| 36 | uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */ | 36 | unsigned int flash_width; /* Width of Flash memory (DWIDTH_M) */ |
| 37 | uint32_t page_size; /* Page size in bytes (PAGE_SZ) */ | 37 | unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */ |
| 38 | uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */ | 38 | unsigned int num_blocks; /* Number of physical blocks in Flash */ |
| 39 | uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */ | 39 | |
| 40 | uint32_t num_blocks; /* Number of physical blocks in Flash */ | 40 | struct pxa3xx_nand_cmdset *cmdset; /* NAND command set */ |
| 41 | uint32_t chip_id; | 41 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | struct pxa3xx_nand_platform_data { | 44 | struct pxa3xx_nand_platform_data { |
diff --git a/arch/arm/plat-s3c24xx/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c index 7b44d0c592b5..bcc43f346272 100644 --- a/arch/arm/plat-s3c24xx/common-smdk.c +++ b/arch/arm/plat-s3c24xx/common-smdk.c | |||
| @@ -147,7 +147,7 @@ static struct mtd_partition smdk_default_nand_part[] = { | |||
| 147 | [7] = { | 147 | [7] = { |
| 148 | .name = "S3C2410 flash partition 7", | 148 | .name = "S3C2410 flash partition 7", |
| 149 | .offset = SZ_1M * 48, | 149 | .offset = SZ_1M * 48, |
| 150 | .size = SZ_16M, | 150 | .size = MTDPART_SIZ_FULL, |
| 151 | } | 151 | } |
| 152 | }; | 152 | }; |
| 153 | 153 | ||
diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c index ae9d3c2403f0..24c6f5a30596 100644 --- a/arch/arm/plat-s3c24xx/gpiolib.c +++ b/arch/arm/plat-s3c24xx/gpiolib.c | |||
| @@ -74,11 +74,6 @@ static int s3c24xx_gpiolib_bankf_toirq(struct gpio_chip *chip, unsigned offset) | |||
| 74 | return -EINVAL; | 74 | return -EINVAL; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | static int s3c24xx_gpiolib_bankg_toirq(struct gpio_chip *chip, unsigned offset) | ||
| 78 | { | ||
| 79 | return IRQ_EINT8 + offset; | ||
| 80 | } | ||
| 81 | |||
| 82 | static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = { | 77 | static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = { |
| 83 | .set_config = s3c_gpio_setcfg_s3c24xx_a, | 78 | .set_config = s3c_gpio_setcfg_s3c24xx_a, |
| 84 | .get_config = s3c_gpio_getcfg_s3c24xx_a, | 79 | .get_config = s3c_gpio_getcfg_s3c24xx_a, |
| @@ -159,12 +154,13 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { | |||
| 159 | [6] = { | 154 | [6] = { |
| 160 | .base = S3C2410_GPGCON, | 155 | .base = S3C2410_GPGCON, |
| 161 | .pm = __gpio_pm(&s3c_gpio_pm_2bit), | 156 | .pm = __gpio_pm(&s3c_gpio_pm_2bit), |
| 157 | .irq_base = IRQ_EINT8, | ||
| 162 | .chip = { | 158 | .chip = { |
| 163 | .base = S3C2410_GPG(0), | 159 | .base = S3C2410_GPG(0), |
| 164 | .owner = THIS_MODULE, | 160 | .owner = THIS_MODULE, |
| 165 | .label = "GPIOG", | 161 | .label = "GPIOG", |
| 166 | .ngpio = 16, | 162 | .ngpio = 16, |
| 167 | .to_irq = s3c24xx_gpiolib_bankg_toirq, | 163 | .to_irq = samsung_gpiolib_to_irq, |
| 168 | }, | 164 | }, |
| 169 | }, { | 165 | }, { |
| 170 | .base = S3C2410_GPHCON, | 166 | .base = S3C2410_GPHCON, |
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 25960966af7c..65dbfa8e0a86 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig | |||
| @@ -32,6 +32,11 @@ config S5P_EXT_INT | |||
| 32 | Use the external interrupts (other than GPIO interrupts.) | 32 | Use the external interrupts (other than GPIO interrupts.) |
| 33 | Note: Do not choose this for S5P6440 and S5P6450. | 33 | Note: Do not choose this for S5P6440 and S5P6450. |
| 34 | 34 | ||
| 35 | config S5P_GPIO_INT | ||
| 36 | bool | ||
| 37 | help | ||
| 38 | Common code for the GPIO interrupts (other than external interrupts.) | ||
| 39 | |||
| 35 | config S5P_DEV_FIMC0 | 40 | config S5P_DEV_FIMC0 |
| 36 | bool | 41 | bool |
| 37 | help | 42 | help |
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile index f3e917e27da8..de65238a7aef 100644 --- a/arch/arm/plat-s5p/Makefile +++ b/arch/arm/plat-s5p/Makefile | |||
| @@ -18,6 +18,9 @@ obj-y += cpu.o | |||
| 18 | obj-y += clock.o | 18 | obj-y += clock.o |
| 19 | obj-y += irq.o | 19 | obj-y += irq.o |
| 20 | obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o | 20 | obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o |
| 21 | obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o | ||
| 22 | obj-$(CONFIG_PM) += pm.o | ||
| 23 | obj-$(CONFIG_PM) += irq-pm.o | ||
| 21 | 24 | ||
| 22 | # devices | 25 | # devices |
| 23 | 26 | ||
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c index 8aaf4e6b60c3..8d081d968c58 100644 --- a/arch/arm/plat-s5p/clock.c +++ b/arch/arm/plat-s5p/clock.c | |||
| @@ -21,6 +21,8 @@ | |||
| 21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
| 22 | #include <asm/div64.h> | 22 | #include <asm/div64.h> |
| 23 | 23 | ||
| 24 | #include <mach/regs-clock.h> | ||
| 25 | |||
| 24 | #include <plat/clock.h> | 26 | #include <plat/clock.h> |
| 25 | #include <plat/clock-clksrc.h> | 27 | #include <plat/clock-clksrc.h> |
| 26 | #include <plat/s5p-clock.h> | 28 | #include <plat/s5p-clock.h> |
| @@ -88,14 +90,6 @@ struct clk clk_fout_vpll = { | |||
| 88 | .ctrlbit = (1 << 31), | 90 | .ctrlbit = (1 << 31), |
| 89 | }; | 91 | }; |
| 90 | 92 | ||
| 91 | /* ARM clock */ | ||
| 92 | struct clk clk_arm = { | ||
| 93 | .name = "armclk", | ||
| 94 | .id = -1, | ||
| 95 | .rate = 0, | ||
| 96 | .ctrlbit = 0, | ||
| 97 | }; | ||
| 98 | |||
| 99 | /* Possible clock sources for APLL Mux */ | 93 | /* Possible clock sources for APLL Mux */ |
| 100 | static struct clk *clk_src_apll_list[] = { | 94 | static struct clk *clk_src_apll_list[] = { |
| 101 | [0] = &clk_fin_apll, | 95 | [0] = &clk_fin_apll, |
| @@ -156,6 +150,24 @@ int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable) | |||
| 156 | return 0; | 150 | return 0; |
| 157 | } | 151 | } |
| 158 | 152 | ||
| 153 | int s5p_epll_enable(struct clk *clk, int enable) | ||
| 154 | { | ||
| 155 | unsigned int ctrlbit = clk->ctrlbit; | ||
| 156 | unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit; | ||
| 157 | |||
| 158 | if (enable) | ||
| 159 | __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON); | ||
| 160 | else | ||
| 161 | __raw_writel(epll_con, S5P_EPLL_CON); | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | unsigned long s5p_epll_get_rate(struct clk *clk) | ||
| 167 | { | ||
| 168 | return clk->rate; | ||
| 169 | } | ||
| 170 | |||
| 159 | static struct clk *s5p_clks[] __initdata = { | 171 | static struct clk *s5p_clks[] __initdata = { |
| 160 | &clk_ext_xtal_mux, | 172 | &clk_ext_xtal_mux, |
| 161 | &clk_48m, | 173 | &clk_48m, |
| @@ -165,7 +177,6 @@ static struct clk *s5p_clks[] __initdata = { | |||
| 165 | &clk_fout_epll, | 177 | &clk_fout_epll, |
| 166 | &clk_fout_dpll, | 178 | &clk_fout_dpll, |
| 167 | &clk_fout_vpll, | 179 | &clk_fout_vpll, |
| 168 | &clk_arm, | ||
| 169 | &clk_vpll, | 180 | &clk_vpll, |
| 170 | &clk_xusbxti, | 181 | &clk_xusbxti, |
| 171 | }; | 182 | }; |
diff --git a/arch/arm/plat-s5p/include/plat/irqs.h b/arch/arm/plat-s5p/include/plat/irqs.h index 3fb3a3a17465..ba9121c60a2a 100644 --- a/arch/arm/plat-s5p/include/plat/irqs.h +++ b/arch/arm/plat-s5p/include/plat/irqs.h | |||
| @@ -94,4 +94,22 @@ | |||
| 94 | ((irq) - S5P_EINT_BASE1) : \ | 94 | ((irq) - S5P_EINT_BASE1) : \ |
| 95 | ((irq) + 16 - S5P_EINT_BASE2)) | 95 | ((irq) + 16 - S5P_EINT_BASE2)) |
| 96 | 96 | ||
| 97 | #define IRQ_EINT_BIT(x) EINT_OFFSET(x) | ||
| 98 | |||
| 99 | /* Typically only a few gpio chips require gpio interrupt support. | ||
| 100 | To avoid memory waste irq descriptors are allocated only for | ||
| 101 | S5P_GPIOINT_GROUP_COUNT chips, each with total number of | ||
| 102 | S5P_GPIOINT_GROUP_SIZE pins/irqs. Each GPIOINT group can be assiged | ||
| 103 | to any gpio chip with the s5p_register_gpio_interrupt() function */ | ||
| 104 | #define S5P_GPIOINT_GROUP_COUNT 4 | ||
| 105 | #define S5P_GPIOINT_GROUP_SIZE 8 | ||
| 106 | #define S5P_GPIOINT_COUNT (S5P_GPIOINT_GROUP_COUNT * S5P_GPIOINT_GROUP_SIZE) | ||
| 107 | |||
| 108 | /* IRQ types common for all s5p platforms */ | ||
| 109 | #define S5P_IRQ_TYPE_LEVEL_LOW (0x00) | ||
| 110 | #define S5P_IRQ_TYPE_LEVEL_HIGH (0x01) | ||
| 111 | #define S5P_IRQ_TYPE_EDGE_FALLING (0x02) | ||
| 112 | #define S5P_IRQ_TYPE_EDGE_RISING (0x03) | ||
| 113 | #define S5P_IRQ_TYPE_EDGE_BOTH (0x04) | ||
| 114 | |||
| 97 | #endif /* __ASM_PLAT_S5P_IRQS_H */ | 115 | #endif /* __ASM_PLAT_S5P_IRQS_H */ |
diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h index c4ff88bf6477..fef353d44513 100644 --- a/arch/arm/plat-s5p/include/plat/map-s5p.h +++ b/arch/arm/plat-s5p/include/plat/map-s5p.h | |||
| @@ -13,24 +13,38 @@ | |||
| 13 | #ifndef __ASM_PLAT_MAP_S5P_H | 13 | #ifndef __ASM_PLAT_MAP_S5P_H |
| 14 | #define __ASM_PLAT_MAP_S5P_H __FILE__ | 14 | #define __ASM_PLAT_MAP_S5P_H __FILE__ |
| 15 | 15 | ||
| 16 | #define S5P_VA_CHIPID S3C_ADDR(0x00700000) | 16 | #define S5P_VA_CHIPID S3C_ADDR(0x02000000) |
| 17 | #define S5P_VA_GPIO S3C_ADDR(0x00500000) | 17 | #define S5P_VA_CMU S3C_ADDR(0x02100000) |
| 18 | #define S5P_VA_SYSTIMER S3C_ADDR(0x01200000) | 18 | #define S5P_VA_GPIO S3C_ADDR(0x02200000) |
| 19 | #define S5P_VA_SROMC S3C_ADDR(0x01100000) | 19 | #define S5P_VA_GPIO1 S5P_VA_GPIO |
| 20 | #define S5P_VA_SYSRAM S3C_ADDR(0x01180000) | 20 | #define S5P_VA_GPIO2 S3C_ADDR(0x02240000) |
| 21 | 21 | #define S5P_VA_GPIO3 S3C_ADDR(0x02280000) | |
| 22 | #define S5P_VA_COMBINER_BASE S3C_ADDR(0x00600000) | 22 | |
| 23 | #define S5P_VA_SYSRAM S3C_ADDR(0x02400000) | ||
| 24 | #define S5P_VA_DMC0 S3C_ADDR(0x02440000) | ||
| 25 | #define S5P_VA_DMC1 S3C_ADDR(0x02480000) | ||
| 26 | #define S5P_VA_SROMC S3C_ADDR(0x024C0000) | ||
| 27 | |||
| 28 | #define S5P_VA_SYSTIMER S3C_ADDR(0x02500000) | ||
| 29 | #define S5P_VA_L2CC S3C_ADDR(0x02600000) | ||
| 30 | |||
| 31 | #define S5P_VA_COMBINER_BASE S3C_ADDR(0x02700000) | ||
| 23 | #define S5P_VA_COMBINER(x) (S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10) | 32 | #define S5P_VA_COMBINER(x) (S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10) |
| 24 | 33 | ||
| 25 | #define S5P_VA_COREPERI_BASE S3C_ADDR(0x00800000) | 34 | #define S5P_VA_COREPERI_BASE S3C_ADDR(0x02800000) |
| 26 | #define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x)) | 35 | #define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x)) |
| 27 | #define S5P_VA_SCU S5P_VA_COREPERI(0x0) | 36 | #define S5P_VA_SCU S5P_VA_COREPERI(0x0) |
| 28 | #define S5P_VA_GIC_CPU S5P_VA_COREPERI(0x100) | 37 | #define S5P_VA_GIC_CPU S5P_VA_COREPERI(0x100) |
| 29 | #define S5P_VA_TWD S5P_VA_COREPERI(0x600) | 38 | #define S5P_VA_TWD S5P_VA_COREPERI(0x600) |
| 30 | #define S5P_VA_GIC_DIST S5P_VA_COREPERI(0x1000) | 39 | #define S5P_VA_GIC_DIST S5P_VA_COREPERI(0x1000) |
| 31 | 40 | ||
| 32 | #define S5P_VA_L2CC S3C_ADDR(0x00900000) | 41 | #define S3C_VA_USB_HSPHY S3C_ADDR(0x02900000) |
| 33 | #define S5P_VA_CMU S3C_ADDR(0x00920000) | 42 | |
| 43 | #define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000)) | ||
| 44 | #define VA_VIC0 VA_VIC(0) | ||
| 45 | #define VA_VIC1 VA_VIC(1) | ||
| 46 | #define VA_VIC2 VA_VIC(2) | ||
| 47 | #define VA_VIC3 VA_VIC(3) | ||
| 34 | 48 | ||
| 35 | #define S5P_VA_UART(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) | 49 | #define S5P_VA_UART(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) |
| 36 | #define S5P_VA_UART0 S5P_VA_UART(0) | 50 | #define S5P_VA_UART0 S5P_VA_UART(0) |
| @@ -42,10 +56,4 @@ | |||
| 42 | #define S3C_UART_OFFSET (0x400) | 56 | #define S3C_UART_OFFSET (0x400) |
| 43 | #endif | 57 | #endif |
| 44 | 58 | ||
| 45 | #define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000)) | ||
| 46 | #define VA_VIC0 VA_VIC(0) | ||
| 47 | #define VA_VIC1 VA_VIC(1) | ||
| 48 | #define VA_VIC2 VA_VIC(2) | ||
| 49 | #define VA_VIC3 VA_VIC(3) | ||
| 50 | |||
| 51 | #endif /* __ASM_PLAT_MAP_S5P_H */ | 59 | #endif /* __ASM_PLAT_MAP_S5P_H */ |
diff --git a/arch/arm/plat-s5p/include/plat/s5p-clock.h b/arch/arm/plat-s5p/include/plat/s5p-clock.h index 17036c898409..2b6dcff8ab2b 100644 --- a/arch/arm/plat-s5p/include/plat/s5p-clock.h +++ b/arch/arm/plat-s5p/include/plat/s5p-clock.h | |||
| @@ -43,4 +43,8 @@ extern struct clksrc_sources clk_src_dpll; | |||
| 43 | 43 | ||
| 44 | extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable); | 44 | extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable); |
| 45 | 45 | ||
| 46 | /* Common EPLL operations for S5P platform */ | ||
| 47 | extern int s5p_epll_enable(struct clk *clk, int enable); | ||
| 48 | extern unsigned long s5p_epll_get_rate(struct clk *clk); | ||
| 49 | |||
| 46 | #endif /* __ASM_PLAT_S5P_CLOCK_H */ | 50 | #endif /* __ASM_PLAT_S5P_CLOCK_H */ |
diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c index f36cd3327025..752f1a645f9d 100644 --- a/arch/arm/plat-s5p/irq-eint.c +++ b/arch/arm/plat-s5p/irq-eint.c | |||
| @@ -67,23 +67,23 @@ static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type) | |||
| 67 | 67 | ||
| 68 | switch (type) { | 68 | switch (type) { |
| 69 | case IRQ_TYPE_EDGE_RISING: | 69 | case IRQ_TYPE_EDGE_RISING: |
| 70 | newvalue = S5P_EXTINT_RISEEDGE; | 70 | newvalue = S5P_IRQ_TYPE_EDGE_RISING; |
| 71 | break; | 71 | break; |
| 72 | 72 | ||
| 73 | case IRQ_TYPE_EDGE_FALLING: | 73 | case IRQ_TYPE_EDGE_FALLING: |
| 74 | newvalue = S5P_EXTINT_FALLEDGE; | 74 | newvalue = S5P_IRQ_TYPE_EDGE_FALLING; |
| 75 | break; | 75 | break; |
| 76 | 76 | ||
| 77 | case IRQ_TYPE_EDGE_BOTH: | 77 | case IRQ_TYPE_EDGE_BOTH: |
| 78 | newvalue = S5P_EXTINT_BOTHEDGE; | 78 | newvalue = S5P_IRQ_TYPE_EDGE_BOTH; |
| 79 | break; | 79 | break; |
| 80 | 80 | ||
| 81 | case IRQ_TYPE_LEVEL_LOW: | 81 | case IRQ_TYPE_LEVEL_LOW: |
| 82 | newvalue = S5P_EXTINT_LOWLEV; | 82 | newvalue = S5P_IRQ_TYPE_LEVEL_LOW; |
| 83 | break; | 83 | break; |
| 84 | 84 | ||
| 85 | case IRQ_TYPE_LEVEL_HIGH: | 85 | case IRQ_TYPE_LEVEL_HIGH: |
| 86 | newvalue = S5P_EXTINT_HILEV; | 86 | newvalue = S5P_IRQ_TYPE_LEVEL_HIGH; |
| 87 | break; | 87 | break; |
| 88 | 88 | ||
| 89 | default: | 89 | default: |
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c new file mode 100644 index 000000000000..0e5dc8cbf5e3 --- /dev/null +++ b/arch/arm/plat-s5p/irq-gpioint.c | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | /* linux/arch/arm/plat-s5p/irq-gpioint.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * Author: Kyungmin Park <kyungmin.park@samsung.com> | ||
| 5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
| 6 | * Author: Marek Szyprowski <m.szyprowski@samsung.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/irq.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/gpio.h> | ||
| 20 | |||
| 21 | #include <mach/map.h> | ||
| 22 | #include <plat/gpio-core.h> | ||
| 23 | #include <plat/gpio-cfg.h> | ||
| 24 | |||
| 25 | #define S5P_GPIOREG(x) (S5P_VA_GPIO + (x)) | ||
| 26 | |||
| 27 | #define GPIOINT_CON_OFFSET 0x700 | ||
| 28 | #define GPIOINT_MASK_OFFSET 0x900 | ||
| 29 | #define GPIOINT_PEND_OFFSET 0xA00 | ||
| 30 | |||
| 31 | static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR]; | ||
| 32 | |||
| 33 | static int s5p_gpioint_get_group(unsigned int irq) | ||
| 34 | { | ||
| 35 | struct gpio_chip *chip = get_irq_data(irq); | ||
| 36 | struct s3c_gpio_chip *s3c_chip = container_of(chip, | ||
| 37 | struct s3c_gpio_chip, chip); | ||
| 38 | int group; | ||
| 39 | |||
| 40 | for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) | ||
| 41 | if (s3c_chip == irq_chips[group]) | ||
| 42 | break; | ||
| 43 | |||
| 44 | return group; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int s5p_gpioint_get_offset(unsigned int irq) | ||
| 48 | { | ||
| 49 | struct gpio_chip *chip = get_irq_data(irq); | ||
| 50 | struct s3c_gpio_chip *s3c_chip = container_of(chip, | ||
| 51 | struct s3c_gpio_chip, chip); | ||
| 52 | |||
| 53 | return irq - s3c_chip->irq_base; | ||
| 54 | } | ||
| 55 | |||
| 56 | static void s5p_gpioint_ack(unsigned int irq) | ||
| 57 | { | ||
| 58 | int group, offset, pend_offset; | ||
| 59 | unsigned int value; | ||
| 60 | |||
| 61 | group = s5p_gpioint_get_group(irq); | ||
| 62 | offset = s5p_gpioint_get_offset(irq); | ||
| 63 | pend_offset = group << 2; | ||
| 64 | |||
| 65 | value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); | ||
| 66 | value |= 1 << offset; | ||
| 67 | __raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); | ||
| 68 | } | ||
| 69 | |||
| 70 | static void s5p_gpioint_mask(unsigned int irq) | ||
| 71 | { | ||
| 72 | int group, offset, mask_offset; | ||
| 73 | unsigned int value; | ||
| 74 | |||
| 75 | group = s5p_gpioint_get_group(irq); | ||
| 76 | offset = s5p_gpioint_get_offset(irq); | ||
| 77 | mask_offset = group << 2; | ||
| 78 | |||
| 79 | value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); | ||
| 80 | value |= 1 << offset; | ||
| 81 | __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); | ||
| 82 | } | ||
| 83 | |||
| 84 | static void s5p_gpioint_unmask(unsigned int irq) | ||
| 85 | { | ||
| 86 | int group, offset, mask_offset; | ||
| 87 | unsigned int value; | ||
| 88 | |||
| 89 | group = s5p_gpioint_get_group(irq); | ||
| 90 | offset = s5p_gpioint_get_offset(irq); | ||
| 91 | mask_offset = group << 2; | ||
| 92 | |||
| 93 | value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); | ||
| 94 | value &= ~(1 << offset); | ||
| 95 | __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); | ||
| 96 | } | ||
| 97 | |||
| 98 | static void s5p_gpioint_mask_ack(unsigned int irq) | ||
| 99 | { | ||
| 100 | s5p_gpioint_mask(irq); | ||
| 101 | s5p_gpioint_ack(irq); | ||
| 102 | } | ||
| 103 | |||
| 104 | static int s5p_gpioint_set_type(unsigned int irq, unsigned int type) | ||
| 105 | { | ||
| 106 | int group, offset, con_offset; | ||
| 107 | unsigned int value; | ||
| 108 | |||
| 109 | group = s5p_gpioint_get_group(irq); | ||
| 110 | offset = s5p_gpioint_get_offset(irq); | ||
| 111 | con_offset = group << 2; | ||
| 112 | |||
| 113 | switch (type) { | ||
| 114 | case IRQ_TYPE_EDGE_RISING: | ||
| 115 | type = S5P_IRQ_TYPE_EDGE_RISING; | ||
| 116 | break; | ||
| 117 | case IRQ_TYPE_EDGE_FALLING: | ||
| 118 | type = S5P_IRQ_TYPE_EDGE_FALLING; | ||
| 119 | break; | ||
| 120 | case IRQ_TYPE_EDGE_BOTH: | ||
| 121 | type = S5P_IRQ_TYPE_EDGE_BOTH; | ||
| 122 | break; | ||
| 123 | case IRQ_TYPE_LEVEL_HIGH: | ||
| 124 | type = S5P_IRQ_TYPE_LEVEL_HIGH; | ||
| 125 | break; | ||
| 126 | case IRQ_TYPE_LEVEL_LOW: | ||
| 127 | type = S5P_IRQ_TYPE_LEVEL_LOW; | ||
| 128 | break; | ||
| 129 | case IRQ_TYPE_NONE: | ||
| 130 | default: | ||
| 131 | printk(KERN_WARNING "No irq type\n"); | ||
| 132 | return -EINVAL; | ||
| 133 | } | ||
| 134 | |||
| 135 | value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); | ||
| 136 | value &= ~(0x7 << (offset * 0x4)); | ||
| 137 | value |= (type << (offset * 0x4)); | ||
| 138 | __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | struct irq_chip s5p_gpioint = { | ||
| 144 | .name = "s5p_gpioint", | ||
| 145 | .ack = s5p_gpioint_ack, | ||
| 146 | .mask = s5p_gpioint_mask, | ||
| 147 | .mask_ack = s5p_gpioint_mask_ack, | ||
| 148 | .unmask = s5p_gpioint_unmask, | ||
| 149 | .set_type = s5p_gpioint_set_type, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) | ||
| 153 | { | ||
| 154 | int group, offset, pend_offset, mask_offset; | ||
| 155 | int real_irq; | ||
| 156 | unsigned int pend, mask; | ||
| 157 | |||
| 158 | for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) { | ||
| 159 | pend_offset = group << 2; | ||
| 160 | pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + | ||
| 161 | pend_offset); | ||
| 162 | if (!pend) | ||
| 163 | continue; | ||
| 164 | |||
| 165 | mask_offset = group << 2; | ||
| 166 | mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + | ||
| 167 | mask_offset); | ||
| 168 | pend &= ~mask; | ||
| 169 | |||
| 170 | for (offset = 0; offset < 8; offset++) { | ||
| 171 | if (pend & (1 << offset)) { | ||
| 172 | struct s3c_gpio_chip *chip = irq_chips[group]; | ||
| 173 | if (chip) { | ||
| 174 | real_irq = chip->irq_base + offset; | ||
| 175 | generic_handle_irq(real_irq); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) | ||
| 183 | { | ||
| 184 | static int used_gpioint_groups = 0; | ||
| 185 | static bool handler_registered = 0; | ||
| 186 | int irq, group = chip->group; | ||
| 187 | int i; | ||
| 188 | |||
| 189 | if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) | ||
| 190 | return -ENOMEM; | ||
| 191 | |||
| 192 | chip->irq_base = S5P_GPIOINT_BASE + | ||
| 193 | used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; | ||
| 194 | used_gpioint_groups++; | ||
| 195 | |||
| 196 | if (!handler_registered) { | ||
| 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++) { | ||
| 203 | irq = chip->irq_base + i; | ||
| 204 | set_irq_chip(irq, &s5p_gpioint); | ||
| 205 | set_irq_data(irq, &chip->chip); | ||
| 206 | set_irq_handler(irq, handle_level_irq); | ||
| 207 | set_irq_flags(irq, IRQF_VALID); | ||
| 208 | } | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | int __init s5p_register_gpio_interrupt(int pin) | ||
| 213 | { | ||
| 214 | struct s3c_gpio_chip *my_chip = s3c_gpiolib_getchip(pin); | ||
| 215 | int offset, group; | ||
| 216 | int ret; | ||
| 217 | |||
| 218 | if (!my_chip) | ||
| 219 | return -EINVAL; | ||
| 220 | |||
| 221 | offset = pin - my_chip->chip.base; | ||
| 222 | group = my_chip->group; | ||
| 223 | |||
| 224 | /* check if the group has been already registered */ | ||
| 225 | if (my_chip->irq_base) | ||
| 226 | return my_chip->irq_base + offset; | ||
| 227 | |||
| 228 | /* register gpio group */ | ||
| 229 | ret = s5p_gpioint_add(my_chip); | ||
| 230 | if (ret == 0) { | ||
| 231 | my_chip->chip.to_irq = samsung_gpiolib_to_irq; | ||
| 232 | printk(KERN_INFO "Registered interrupt support for gpio group %d.\n", | ||
| 233 | group); | ||
| 234 | return my_chip->irq_base + offset; | ||
| 235 | } | ||
| 236 | return ret; | ||
| 237 | } | ||
diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-s5p/irq-pm.c new file mode 100644 index 000000000000..dc33b9ecda45 --- /dev/null +++ b/arch/arm/plat-s5p/irq-pm.c | |||
| @@ -0,0 +1,93 @@ | |||
| 1 | /* linux/arch/arm/plat-s5p/irq-pm.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * Based on arch/arm/plat-s3c24xx/irq-pm.c, | ||
| 7 | * Copyright (c) 2003,2004 Simtec Electronics | ||
| 8 | * Ben Dooks <ben@simtec.co.uk> | ||
| 9 | * http://armlinux.simtec.co.uk/ | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License version 2 as | ||
| 13 | * published by the Free Software Foundation. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/interrupt.h> | ||
| 19 | #include <linux/sysdev.h> | ||
| 20 | |||
| 21 | #include <plat/cpu.h> | ||
| 22 | #include <plat/irqs.h> | ||
| 23 | #include <plat/pm.h> | ||
| 24 | #include <mach/map.h> | ||
| 25 | |||
| 26 | #include <mach/regs-gpio.h> | ||
| 27 | #include <mach/regs-irq.h> | ||
| 28 | |||
| 29 | /* state for IRQs over sleep */ | ||
| 30 | |||
| 31 | /* default is to allow for EINT0..EINT31, and IRQ_RTC_TIC, IRQ_RTC_ALARM, | ||
| 32 | * as wakeup sources | ||
| 33 | * | ||
| 34 | * set bit to 1 in allow bitfield to enable the wakeup settings on it | ||
| 35 | */ | ||
| 36 | |||
| 37 | unsigned long s3c_irqwake_intallow = 0x00000006L; | ||
| 38 | unsigned long s3c_irqwake_eintallow = 0xffffffffL; | ||
| 39 | |||
| 40 | int s3c_irq_wake(unsigned int irqno, unsigned int state) | ||
| 41 | { | ||
| 42 | unsigned long irqbit; | ||
| 43 | |||
| 44 | switch (irqno) { | ||
| 45 | case IRQ_RTC_TIC: | ||
| 46 | case IRQ_RTC_ALARM: | ||
| 47 | irqbit = 1 << (irqno + 1 - IRQ_RTC_ALARM); | ||
| 48 | if (!state) | ||
| 49 | s3c_irqwake_intmask |= irqbit; | ||
| 50 | else | ||
| 51 | s3c_irqwake_intmask &= ~irqbit; | ||
| 52 | break; | ||
| 53 | default: | ||
| 54 | return -ENOENT; | ||
| 55 | } | ||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static struct sleep_save eint_save[] = { | ||
| 60 | SAVE_ITEM(S5P_EINT_CON(0)), | ||
| 61 | SAVE_ITEM(S5P_EINT_CON(1)), | ||
| 62 | SAVE_ITEM(S5P_EINT_CON(2)), | ||
| 63 | SAVE_ITEM(S5P_EINT_CON(3)), | ||
| 64 | |||
| 65 | SAVE_ITEM(S5P_EINT_FLTCON(0)), | ||
| 66 | SAVE_ITEM(S5P_EINT_FLTCON(1)), | ||
| 67 | SAVE_ITEM(S5P_EINT_FLTCON(2)), | ||
| 68 | SAVE_ITEM(S5P_EINT_FLTCON(3)), | ||
| 69 | SAVE_ITEM(S5P_EINT_FLTCON(4)), | ||
| 70 | SAVE_ITEM(S5P_EINT_FLTCON(5)), | ||
| 71 | SAVE_ITEM(S5P_EINT_FLTCON(6)), | ||
| 72 | SAVE_ITEM(S5P_EINT_FLTCON(7)), | ||
| 73 | |||
| 74 | SAVE_ITEM(S5P_EINT_MASK(0)), | ||
| 75 | SAVE_ITEM(S5P_EINT_MASK(1)), | ||
| 76 | SAVE_ITEM(S5P_EINT_MASK(2)), | ||
| 77 | SAVE_ITEM(S5P_EINT_MASK(3)), | ||
| 78 | }; | ||
| 79 | |||
| 80 | int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) | ||
| 81 | { | ||
| 82 | s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save)); | ||
| 83 | |||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | int s3c24xx_irq_resume(struct sys_device *dev) | ||
| 88 | { | ||
| 89 | s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save)); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
diff --git a/arch/arm/plat-s5p/pm.c b/arch/arm/plat-s5p/pm.c new file mode 100644 index 000000000000..d592b6304b48 --- /dev/null +++ b/arch/arm/plat-s5p/pm.c | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* linux/arch/arm/plat-s5p/pm.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com | ||
| 5 | * | ||
| 6 | * S5P Power Manager (Suspend-To-RAM) support | ||
| 7 | * | ||
| 8 | * Based on arch/arm/plat-s3c24xx/pm.c | ||
| 9 | * Copyright (c) 2004,2006 Simtec Electronics | ||
| 10 | * Ben Dooks <ben@simtec.co.uk> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License version 2 as | ||
| 14 | * published by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/suspend.h> | ||
| 18 | #include <plat/pm.h> | ||
| 19 | |||
| 20 | #define PFX "s5p pm: " | ||
| 21 | |||
| 22 | /* s3c_pm_check_resume_pin | ||
| 23 | * | ||
| 24 | * check to see if the pin is configured correctly for sleep mode, and | ||
| 25 | * make any necessary adjustments if it is not | ||
| 26 | */ | ||
| 27 | |||
| 28 | static void s3c_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) | ||
| 29 | { | ||
| 30 | /* nothing here yet */ | ||
| 31 | } | ||
| 32 | |||
| 33 | /* s3c_pm_configure_extint | ||
| 34 | * | ||
| 35 | * configure all external interrupt pins | ||
| 36 | */ | ||
| 37 | |||
| 38 | void s3c_pm_configure_extint(void) | ||
| 39 | { | ||
| 40 | /* nothing here yet */ | ||
| 41 | } | ||
| 42 | |||
| 43 | void s3c_pm_restore_core(void) | ||
| 44 | { | ||
| 45 | /* nothing here yet */ | ||
| 46 | } | ||
| 47 | |||
| 48 | void s3c_pm_save_core(void) | ||
| 49 | { | ||
| 50 | /* nothing here yet */ | ||
| 51 | } | ||
| 52 | |||
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index 7c0bde781167..dcd6eff4ee53 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig | |||
| @@ -180,6 +180,31 @@ config S3C_DEV_I2C2 | |||
| 180 | help | 180 | help |
| 181 | Compile in platform device definitions for I2C channel 2 | 181 | Compile in platform device definitions for I2C channel 2 |
| 182 | 182 | ||
| 183 | config S3C_DEV_I2C3 | ||
| 184 | bool | ||
| 185 | help | ||
| 186 | Compile in platform device definition for I2C controller 3 | ||
| 187 | |||
| 188 | config S3C_DEV_I2C4 | ||
| 189 | bool | ||
| 190 | help | ||
| 191 | Compile in platform device definition for I2C controller 4 | ||
| 192 | |||
| 193 | config S3C_DEV_I2C5 | ||
| 194 | bool | ||
| 195 | help | ||
| 196 | Compile in platform device definition for I2C controller 5 | ||
| 197 | |||
| 198 | config S3C_DEV_I2C6 | ||
| 199 | bool | ||
| 200 | help | ||
| 201 | Compile in platform device definition for I2C controller 6 | ||
| 202 | |||
| 203 | config S3C_DEV_I2C7 | ||
| 204 | bool | ||
| 205 | help | ||
| 206 | Compile in platform device definition for I2C controller 7 | ||
| 207 | |||
| 183 | config S3C_DEV_FB | 208 | config S3C_DEV_FB |
| 184 | bool | 209 | bool |
| 185 | help | 210 | help |
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 4d8ff923207a..afcce474af8e 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile | |||
| @@ -40,6 +40,11 @@ obj-$(CONFIG_S3C_DEV_HWMON) += dev-hwmon.o | |||
| 40 | obj-y += dev-i2c0.o | 40 | obj-y += dev-i2c0.o |
| 41 | obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o | 41 | obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o |
| 42 | obj-$(CONFIG_S3C_DEV_I2C2) += dev-i2c2.o | 42 | obj-$(CONFIG_S3C_DEV_I2C2) += dev-i2c2.o |
| 43 | obj-$(CONFIG_S3C_DEV_I2C3) += dev-i2c3.o | ||
| 44 | obj-$(CONFIG_S3C_DEV_I2C4) += dev-i2c4.o | ||
| 45 | obj-$(CONFIG_S3C_DEV_I2C5) += dev-i2c5.o | ||
| 46 | obj-$(CONFIG_S3C_DEV_I2C6) += dev-i2c6.o | ||
| 47 | obj-$(CONFIG_S3C_DEV_I2C7) += dev-i2c7.o | ||
| 43 | obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o | 48 | obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o |
| 44 | obj-y += dev-uart.o | 49 | obj-y += dev-uart.o |
| 45 | obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o | 50 | obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o |
diff --git a/arch/arm/plat-samsung/dev-hsmmc.c b/arch/arm/plat-samsung/dev-hsmmc.c index 9d2be0941410..db7a65c7f127 100644 --- a/arch/arm/plat-samsung/dev-hsmmc.c +++ b/arch/arm/plat-samsung/dev-hsmmc.c | |||
| @@ -41,6 +41,7 @@ struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata = { | |||
| 41 | .max_width = 4, | 41 | .max_width = 4, |
| 42 | .host_caps = (MMC_CAP_4_BIT_DATA | | 42 | .host_caps = (MMC_CAP_4_BIT_DATA | |
| 43 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), | 43 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), |
| 44 | .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL, | ||
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | struct platform_device s3c_device_hsmmc0 = { | 47 | struct platform_device s3c_device_hsmmc0 = { |
| @@ -59,17 +60,20 @@ void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd) | |||
| 59 | { | 60 | { |
| 60 | struct s3c_sdhci_platdata *set = &s3c_hsmmc0_def_platdata; | 61 | struct s3c_sdhci_platdata *set = &s3c_hsmmc0_def_platdata; |
| 61 | 62 | ||
| 62 | set->max_width = pd->max_width; | ||
| 63 | set->cd_type = pd->cd_type; | 63 | set->cd_type = pd->cd_type; |
| 64 | set->ext_cd_init = pd->ext_cd_init; | 64 | set->ext_cd_init = pd->ext_cd_init; |
| 65 | set->ext_cd_cleanup = pd->ext_cd_cleanup; | 65 | set->ext_cd_cleanup = pd->ext_cd_cleanup; |
| 66 | set->ext_cd_gpio = pd->ext_cd_gpio; | 66 | set->ext_cd_gpio = pd->ext_cd_gpio; |
| 67 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; | 67 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; |
| 68 | 68 | ||
| 69 | if (pd->max_width) | ||
| 70 | set->max_width = pd->max_width; | ||
| 69 | if (pd->cfg_gpio) | 71 | if (pd->cfg_gpio) |
| 70 | set->cfg_gpio = pd->cfg_gpio; | 72 | set->cfg_gpio = pd->cfg_gpio; |
| 71 | if (pd->cfg_card) | 73 | if (pd->cfg_card) |
| 72 | set->cfg_card = pd->cfg_card; | 74 | set->cfg_card = pd->cfg_card; |
| 73 | if (pd->host_caps) | 75 | if (pd->host_caps) |
| 74 | set->host_caps = pd->host_caps; | 76 | set->host_caps |= pd->host_caps; |
| 77 | if (pd->clk_type) | ||
| 78 | set->clk_type = pd->clk_type; | ||
| 75 | } | 79 | } |
diff --git a/arch/arm/plat-samsung/dev-hsmmc1.c b/arch/arm/plat-samsung/dev-hsmmc1.c index a6c8295840af..2497321f08d7 100644 --- a/arch/arm/plat-samsung/dev-hsmmc1.c +++ b/arch/arm/plat-samsung/dev-hsmmc1.c | |||
| @@ -41,6 +41,7 @@ struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata = { | |||
| 41 | .max_width = 4, | 41 | .max_width = 4, |
| 42 | .host_caps = (MMC_CAP_4_BIT_DATA | | 42 | .host_caps = (MMC_CAP_4_BIT_DATA | |
| 43 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), | 43 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), |
| 44 | .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL, | ||
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | struct platform_device s3c_device_hsmmc1 = { | 47 | struct platform_device s3c_device_hsmmc1 = { |
| @@ -59,17 +60,20 @@ void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd) | |||
| 59 | { | 60 | { |
| 60 | struct s3c_sdhci_platdata *set = &s3c_hsmmc1_def_platdata; | 61 | struct s3c_sdhci_platdata *set = &s3c_hsmmc1_def_platdata; |
| 61 | 62 | ||
| 62 | set->max_width = pd->max_width; | ||
| 63 | set->cd_type = pd->cd_type; | 63 | set->cd_type = pd->cd_type; |
| 64 | set->ext_cd_init = pd->ext_cd_init; | 64 | set->ext_cd_init = pd->ext_cd_init; |
| 65 | set->ext_cd_cleanup = pd->ext_cd_cleanup; | 65 | set->ext_cd_cleanup = pd->ext_cd_cleanup; |
| 66 | set->ext_cd_gpio = pd->ext_cd_gpio; | 66 | set->ext_cd_gpio = pd->ext_cd_gpio; |
| 67 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; | 67 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; |
| 68 | 68 | ||
| 69 | if (pd->max_width) | ||
| 70 | set->max_width = pd->max_width; | ||
| 69 | if (pd->cfg_gpio) | 71 | if (pd->cfg_gpio) |
| 70 | set->cfg_gpio = pd->cfg_gpio; | 72 | set->cfg_gpio = pd->cfg_gpio; |
| 71 | if (pd->cfg_card) | 73 | if (pd->cfg_card) |
| 72 | set->cfg_card = pd->cfg_card; | 74 | set->cfg_card = pd->cfg_card; |
| 73 | if (pd->host_caps) | 75 | if (pd->host_caps) |
| 74 | set->host_caps = pd->host_caps; | 76 | set->host_caps |= pd->host_caps; |
| 77 | if (pd->clk_type) | ||
| 78 | set->clk_type = pd->clk_type; | ||
| 75 | } | 79 | } |
diff --git a/arch/arm/plat-samsung/dev-hsmmc2.c b/arch/arm/plat-samsung/dev-hsmmc2.c index cb0d7143381a..f60aedba417c 100644 --- a/arch/arm/plat-samsung/dev-hsmmc2.c +++ b/arch/arm/plat-samsung/dev-hsmmc2.c | |||
| @@ -42,6 +42,7 @@ struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata = { | |||
| 42 | .max_width = 4, | 42 | .max_width = 4, |
| 43 | .host_caps = (MMC_CAP_4_BIT_DATA | | 43 | .host_caps = (MMC_CAP_4_BIT_DATA | |
| 44 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), | 44 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), |
| 45 | .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL, | ||
| 45 | }; | 46 | }; |
| 46 | 47 | ||
| 47 | struct platform_device s3c_device_hsmmc2 = { | 48 | struct platform_device s3c_device_hsmmc2 = { |
| @@ -60,17 +61,20 @@ void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd) | |||
| 60 | { | 61 | { |
| 61 | struct s3c_sdhci_platdata *set = &s3c_hsmmc2_def_platdata; | 62 | struct s3c_sdhci_platdata *set = &s3c_hsmmc2_def_platdata; |
| 62 | 63 | ||
| 63 | set->max_width = pd->max_width; | ||
| 64 | set->cd_type = pd->cd_type; | 64 | set->cd_type = pd->cd_type; |
| 65 | set->ext_cd_init = pd->ext_cd_init; | 65 | set->ext_cd_init = pd->ext_cd_init; |
| 66 | set->ext_cd_cleanup = pd->ext_cd_cleanup; | 66 | set->ext_cd_cleanup = pd->ext_cd_cleanup; |
| 67 | set->ext_cd_gpio = pd->ext_cd_gpio; | 67 | set->ext_cd_gpio = pd->ext_cd_gpio; |
| 68 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; | 68 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; |
| 69 | 69 | ||
| 70 | if (pd->max_width) | ||
| 71 | set->max_width = pd->max_width; | ||
| 70 | if (pd->cfg_gpio) | 72 | if (pd->cfg_gpio) |
| 71 | set->cfg_gpio = pd->cfg_gpio; | 73 | set->cfg_gpio = pd->cfg_gpio; |
| 72 | if (pd->cfg_card) | 74 | if (pd->cfg_card) |
| 73 | set->cfg_card = pd->cfg_card; | 75 | set->cfg_card = pd->cfg_card; |
| 74 | if (pd->host_caps) | 76 | if (pd->host_caps) |
| 75 | set->host_caps = pd->host_caps; | 77 | set->host_caps |= pd->host_caps; |
| 78 | if (pd->clk_type) | ||
| 79 | set->clk_type = pd->clk_type; | ||
| 76 | } | 80 | } |
diff --git a/arch/arm/plat-samsung/dev-hsmmc3.c b/arch/arm/plat-samsung/dev-hsmmc3.c index 85aaf0f2842f..ede776f20e62 100644 --- a/arch/arm/plat-samsung/dev-hsmmc3.c +++ b/arch/arm/plat-samsung/dev-hsmmc3.c | |||
| @@ -33,8 +33,8 @@ static struct resource s3c_hsmmc3_resource[] = { | |||
| 33 | .flags = IORESOURCE_MEM, | 33 | .flags = IORESOURCE_MEM, |
| 34 | }, | 34 | }, |
| 35 | [1] = { | 35 | [1] = { |
| 36 | .start = IRQ_MMC3, | 36 | .start = IRQ_HSMMC3, |
| 37 | .end = IRQ_MMC3, | 37 | .end = IRQ_HSMMC3, |
| 38 | .flags = IORESOURCE_IRQ, | 38 | .flags = IORESOURCE_IRQ, |
| 39 | } | 39 | } |
| 40 | }; | 40 | }; |
| @@ -45,6 +45,7 @@ struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata = { | |||
| 45 | .max_width = 4, | 45 | .max_width = 4, |
| 46 | .host_caps = (MMC_CAP_4_BIT_DATA | | 46 | .host_caps = (MMC_CAP_4_BIT_DATA | |
| 47 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), | 47 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), |
| 48 | .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL, | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | struct platform_device s3c_device_hsmmc3 = { | 51 | struct platform_device s3c_device_hsmmc3 = { |
| @@ -63,15 +64,20 @@ void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd) | |||
| 63 | { | 64 | { |
| 64 | struct s3c_sdhci_platdata *set = &s3c_hsmmc3_def_platdata; | 65 | struct s3c_sdhci_platdata *set = &s3c_hsmmc3_def_platdata; |
| 65 | 66 | ||
| 66 | set->max_width = pd->max_width; | ||
| 67 | set->cd_type = pd->cd_type; | 67 | set->cd_type = pd->cd_type; |
| 68 | set->ext_cd_init = pd->ext_cd_init; | 68 | set->ext_cd_init = pd->ext_cd_init; |
| 69 | set->ext_cd_cleanup = pd->ext_cd_cleanup; | 69 | set->ext_cd_cleanup = pd->ext_cd_cleanup; |
| 70 | set->ext_cd_gpio = pd->ext_cd_gpio; | 70 | set->ext_cd_gpio = pd->ext_cd_gpio; |
| 71 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; | 71 | set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; |
| 72 | 72 | ||
| 73 | if (pd->max_width) | ||
| 74 | set->max_width = pd->max_width; | ||
| 73 | if (pd->cfg_gpio) | 75 | if (pd->cfg_gpio) |
| 74 | set->cfg_gpio = pd->cfg_gpio; | 76 | set->cfg_gpio = pd->cfg_gpio; |
| 75 | if (pd->cfg_card) | 77 | if (pd->cfg_card) |
| 76 | set->cfg_card = pd->cfg_card; | 78 | set->cfg_card = pd->cfg_card; |
| 79 | if (pd->host_caps) | ||
| 80 | set->host_caps |= pd->host_caps; | ||
| 81 | if (pd->clk_type) | ||
| 82 | set->clk_type = pd->clk_type; | ||
| 77 | } | 83 | } |
diff --git a/arch/arm/plat-samsung/dev-i2c2.c b/arch/arm/plat-samsung/dev-i2c2.c index 07036dee09e7..ff4ba69b6830 100644 --- a/arch/arm/plat-samsung/dev-i2c2.c +++ b/arch/arm/plat-samsung/dev-i2c2.c | |||
| @@ -32,8 +32,8 @@ static struct resource s3c_i2c_resource[] = { | |||
| 32 | .flags = IORESOURCE_MEM, | 32 | .flags = IORESOURCE_MEM, |
| 33 | }, | 33 | }, |
| 34 | [1] = { | 34 | [1] = { |
| 35 | .start = IRQ_CAN0, | 35 | .start = IRQ_IIC2, |
| 36 | .end = IRQ_CAN0, | 36 | .end = IRQ_IIC2, |
| 37 | .flags = IORESOURCE_IRQ, | 37 | .flags = IORESOURCE_IRQ, |
| 38 | }, | 38 | }, |
| 39 | }; | 39 | }; |
diff --git a/arch/arm/plat-samsung/dev-i2c3.c b/arch/arm/plat-samsung/dev-i2c3.c new file mode 100644 index 000000000000..8586a10014b7 --- /dev/null +++ b/arch/arm/plat-samsung/dev-i2c3.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* linux/arch/arm/plat-samsung/dev-i2c3.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5P series device definition for i2c device 3 | ||
| 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/gfp.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | #include <mach/irqs.h> | ||
| 19 | #include <mach/map.h> | ||
| 20 | |||
| 21 | #include <plat/regs-iic.h> | ||
| 22 | #include <plat/iic.h> | ||
| 23 | #include <plat/devs.h> | ||
| 24 | #include <plat/cpu.h> | ||
| 25 | |||
| 26 | static struct resource s3c_i2c_resource[] = { | ||
| 27 | [0] = { | ||
| 28 | .start = S3C_PA_IIC3, | ||
| 29 | .end = S3C_PA_IIC3 + SZ_4K - 1, | ||
| 30 | .flags = IORESOURCE_MEM, | ||
| 31 | }, | ||
| 32 | [1] = { | ||
| 33 | .start = IRQ_IIC3, | ||
| 34 | .end = IRQ_IIC3, | ||
| 35 | .flags = IORESOURCE_IRQ, | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct platform_device s3c_device_i2c3 = { | ||
| 40 | .name = "s3c2440-i2c", | ||
| 41 | .id = 3, | ||
| 42 | .num_resources = ARRAY_SIZE(s3c_i2c_resource), | ||
| 43 | .resource = s3c_i2c_resource, | ||
| 44 | }; | ||
| 45 | |||
| 46 | static struct s3c2410_platform_i2c default_i2c_data3 __initdata = { | ||
| 47 | .flags = 0, | ||
| 48 | .bus_num = 3, | ||
| 49 | .slave_addr = 0x10, | ||
| 50 | .frequency = 100*1000, | ||
| 51 | .sda_delay = 100, | ||
| 52 | }; | ||
| 53 | |||
| 54 | void __init s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *pd) | ||
| 55 | { | ||
| 56 | struct s3c2410_platform_i2c *npd; | ||
| 57 | |||
| 58 | if (!pd) | ||
| 59 | pd = &default_i2c_data3; | ||
| 60 | |||
| 61 | npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL); | ||
| 62 | if (!npd) | ||
| 63 | printk(KERN_ERR "%s: no memory for platform data\n", __func__); | ||
| 64 | else if (!npd->cfg_gpio) | ||
| 65 | npd->cfg_gpio = s3c_i2c3_cfg_gpio; | ||
| 66 | |||
| 67 | s3c_device_i2c3.dev.platform_data = npd; | ||
| 68 | } | ||
diff --git a/arch/arm/plat-samsung/dev-i2c4.c b/arch/arm/plat-samsung/dev-i2c4.c new file mode 100644 index 000000000000..df2159e2daa6 --- /dev/null +++ b/arch/arm/plat-samsung/dev-i2c4.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* linux/arch/arm/plat-samsung/dev-i2c4.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5P series device definition for i2c device 3 | ||
| 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/gfp.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | #include <mach/irqs.h> | ||
| 19 | #include <mach/map.h> | ||
| 20 | |||
| 21 | #include <plat/regs-iic.h> | ||
| 22 | #include <plat/iic.h> | ||
| 23 | #include <plat/devs.h> | ||
| 24 | #include <plat/cpu.h> | ||
| 25 | |||
| 26 | static struct resource s3c_i2c_resource[] = { | ||
| 27 | [0] = { | ||
| 28 | .start = S3C_PA_IIC4, | ||
| 29 | .end = S3C_PA_IIC4 + SZ_4K - 1, | ||
| 30 | .flags = IORESOURCE_MEM, | ||
| 31 | }, | ||
| 32 | [1] = { | ||
| 33 | .start = IRQ_IIC4, | ||
| 34 | .end = IRQ_IIC4, | ||
| 35 | .flags = IORESOURCE_IRQ, | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct platform_device s3c_device_i2c4 = { | ||
| 40 | .name = "s3c2440-i2c", | ||
| 41 | .id = 4, | ||
| 42 | .num_resources = ARRAY_SIZE(s3c_i2c_resource), | ||
| 43 | .resource = s3c_i2c_resource, | ||
| 44 | }; | ||
| 45 | |||
| 46 | static struct s3c2410_platform_i2c default_i2c_data4 __initdata = { | ||
| 47 | .flags = 0, | ||
| 48 | .bus_num = 4, | ||
| 49 | .slave_addr = 0x10, | ||
| 50 | .frequency = 100*1000, | ||
| 51 | .sda_delay = 100, | ||
| 52 | }; | ||
| 53 | |||
| 54 | void __init s3c_i2c4_set_platdata(struct s3c2410_platform_i2c *pd) | ||
| 55 | { | ||
| 56 | struct s3c2410_platform_i2c *npd; | ||
| 57 | |||
| 58 | if (!pd) | ||
| 59 | pd = &default_i2c_data4; | ||
| 60 | |||
| 61 | npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL); | ||
| 62 | if (!npd) | ||
| 63 | printk(KERN_ERR "%s: no memory for platform data\n", __func__); | ||
| 64 | else if (!npd->cfg_gpio) | ||
| 65 | npd->cfg_gpio = s3c_i2c4_cfg_gpio; | ||
| 66 | |||
| 67 | s3c_device_i2c4.dev.platform_data = npd; | ||
| 68 | } | ||
diff --git a/arch/arm/plat-samsung/dev-i2c5.c b/arch/arm/plat-samsung/dev-i2c5.c new file mode 100644 index 000000000000..0499c2c3877b --- /dev/null +++ b/arch/arm/plat-samsung/dev-i2c5.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* linux/arch/arm/plat-samsung/dev-i2c3.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5P series device definition for i2c device 3 | ||
| 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/gfp.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | #include <mach/irqs.h> | ||
| 19 | #include <mach/map.h> | ||
| 20 | |||
| 21 | #include <plat/regs-iic.h> | ||
| 22 | #include <plat/iic.h> | ||
| 23 | #include <plat/devs.h> | ||
| 24 | #include <plat/cpu.h> | ||
| 25 | |||
| 26 | static struct resource s3c_i2c_resource[] = { | ||
| 27 | [0] = { | ||
| 28 | .start = S3C_PA_IIC5, | ||
| 29 | .end = S3C_PA_IIC5 + SZ_4K - 1, | ||
| 30 | .flags = IORESOURCE_MEM, | ||
| 31 | }, | ||
| 32 | [1] = { | ||
| 33 | .start = IRQ_IIC5, | ||
| 34 | .end = IRQ_IIC5, | ||
| 35 | .flags = IORESOURCE_IRQ, | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct platform_device s3c_device_i2c5 = { | ||
| 40 | .name = "s3c2440-i2c", | ||
| 41 | .id = 5, | ||
| 42 | .num_resources = ARRAY_SIZE(s3c_i2c_resource), | ||
| 43 | .resource = s3c_i2c_resource, | ||
| 44 | }; | ||
| 45 | |||
| 46 | static struct s3c2410_platform_i2c default_i2c_data5 __initdata = { | ||
| 47 | .flags = 0, | ||
| 48 | .bus_num = 5, | ||
| 49 | .slave_addr = 0x10, | ||
| 50 | .frequency = 100*1000, | ||
| 51 | .sda_delay = 100, | ||
| 52 | }; | ||
| 53 | |||
| 54 | void __init s3c_i2c5_set_platdata(struct s3c2410_platform_i2c *pd) | ||
| 55 | { | ||
| 56 | struct s3c2410_platform_i2c *npd; | ||
| 57 | |||
| 58 | if (!pd) | ||
| 59 | pd = &default_i2c_data5; | ||
| 60 | |||
| 61 | npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL); | ||
| 62 | if (!npd) | ||
| 63 | printk(KERN_ERR "%s: no memory for platform data\n", __func__); | ||
| 64 | else if (!npd->cfg_gpio) | ||
| 65 | npd->cfg_gpio = s3c_i2c5_cfg_gpio; | ||
| 66 | |||
| 67 | s3c_device_i2c5.dev.platform_data = npd; | ||
| 68 | } | ||
diff --git a/arch/arm/plat-samsung/dev-i2c6.c b/arch/arm/plat-samsung/dev-i2c6.c new file mode 100644 index 000000000000..4083108908a8 --- /dev/null +++ b/arch/arm/plat-samsung/dev-i2c6.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* linux/arch/arm/plat-samsung/dev-i2c6.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5P series device definition for i2c device 6 | ||
| 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/gfp.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | #include <mach/irqs.h> | ||
| 19 | #include <mach/map.h> | ||
| 20 | |||
| 21 | #include <plat/regs-iic.h> | ||
| 22 | #include <plat/iic.h> | ||
| 23 | #include <plat/devs.h> | ||
| 24 | #include <plat/cpu.h> | ||
| 25 | |||
| 26 | static struct resource s3c_i2c_resource[] = { | ||
| 27 | [0] = { | ||
| 28 | .start = S3C_PA_IIC6, | ||
| 29 | .end = S3C_PA_IIC6 + SZ_4K - 1, | ||
| 30 | .flags = IORESOURCE_MEM, | ||
| 31 | }, | ||
| 32 | [1] = { | ||
| 33 | .start = IRQ_IIC6, | ||
| 34 | .end = IRQ_IIC6, | ||
| 35 | .flags = IORESOURCE_IRQ, | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct platform_device s3c_device_i2c6 = { | ||
| 40 | .name = "s3c2440-i2c", | ||
| 41 | .id = 6, | ||
| 42 | .num_resources = ARRAY_SIZE(s3c_i2c_resource), | ||
| 43 | .resource = s3c_i2c_resource, | ||
| 44 | }; | ||
| 45 | |||
| 46 | static struct s3c2410_platform_i2c default_i2c_data6 __initdata = { | ||
| 47 | .flags = 0, | ||
| 48 | .bus_num = 6, | ||
| 49 | .slave_addr = 0x10, | ||
| 50 | .frequency = 100*1000, | ||
| 51 | .sda_delay = 100, | ||
| 52 | }; | ||
| 53 | |||
| 54 | void __init s3c_i2c6_set_platdata(struct s3c2410_platform_i2c *pd) | ||
| 55 | { | ||
| 56 | struct s3c2410_platform_i2c *npd; | ||
| 57 | |||
| 58 | if (!pd) | ||
| 59 | pd = &default_i2c_data6; | ||
| 60 | |||
| 61 | npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL); | ||
| 62 | if (!npd) | ||
| 63 | printk(KERN_ERR "%s: no memory for platform data\n", __func__); | ||
| 64 | else if (!npd->cfg_gpio) | ||
| 65 | npd->cfg_gpio = s3c_i2c6_cfg_gpio; | ||
| 66 | |||
| 67 | s3c_device_i2c6.dev.platform_data = npd; | ||
| 68 | } | ||
diff --git a/arch/arm/plat-samsung/dev-i2c7.c b/arch/arm/plat-samsung/dev-i2c7.c new file mode 100644 index 000000000000..1182451d7dce --- /dev/null +++ b/arch/arm/plat-samsung/dev-i2c7.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* linux/arch/arm/plat-samsung/dev-i2c7.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S5P series device definition for i2c device 7 | ||
| 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/gfp.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | #include <mach/irqs.h> | ||
| 19 | #include <mach/map.h> | ||
| 20 | |||
| 21 | #include <plat/regs-iic.h> | ||
| 22 | #include <plat/iic.h> | ||
| 23 | #include <plat/devs.h> | ||
| 24 | #include <plat/cpu.h> | ||
| 25 | |||
| 26 | static struct resource s3c_i2c_resource[] = { | ||
| 27 | [0] = { | ||
| 28 | .start = S3C_PA_IIC7, | ||
| 29 | .end = S3C_PA_IIC7 + SZ_4K - 1, | ||
| 30 | .flags = IORESOURCE_MEM, | ||
| 31 | }, | ||
| 32 | [1] = { | ||
| 33 | .start = IRQ_IIC7, | ||
| 34 | .end = IRQ_IIC7, | ||
| 35 | .flags = IORESOURCE_IRQ, | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct platform_device s3c_device_i2c7 = { | ||
| 40 | .name = "s3c2440-i2c", | ||
| 41 | .id = 7, | ||
| 42 | .num_resources = ARRAY_SIZE(s3c_i2c_resource), | ||
| 43 | .resource = s3c_i2c_resource, | ||
| 44 | }; | ||
| 45 | |||
| 46 | static struct s3c2410_platform_i2c default_i2c_data7 __initdata = { | ||
| 47 | .flags = 0, | ||
| 48 | .bus_num = 7, | ||
| 49 | .slave_addr = 0x10, | ||
| 50 | .frequency = 100*1000, | ||
| 51 | .sda_delay = 100, | ||
| 52 | }; | ||
| 53 | |||
| 54 | void __init s3c_i2c7_set_platdata(struct s3c2410_platform_i2c *pd) | ||
| 55 | { | ||
| 56 | struct s3c2410_platform_i2c *npd; | ||
| 57 | |||
| 58 | if (!pd) | ||
| 59 | pd = &default_i2c_data7; | ||
| 60 | |||
| 61 | npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL); | ||
| 62 | if (!npd) | ||
| 63 | printk(KERN_ERR "%s: no memory for platform data\n", __func__); | ||
| 64 | else if (!npd->cfg_gpio) | ||
| 65 | npd->cfg_gpio = s3c_i2c7_cfg_gpio; | ||
| 66 | |||
| 67 | s3c_device_i2c7.dev.platform_data = npd; | ||
| 68 | } | ||
diff --git a/arch/arm/plat-samsung/gpio-config.c b/arch/arm/plat-samsung/gpio-config.c index e3d41eaed1ff..b732b773b9af 100644 --- a/arch/arm/plat-samsung/gpio-config.c +++ b/arch/arm/plat-samsung/gpio-config.c | |||
| @@ -41,6 +41,37 @@ int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) | |||
| 41 | } | 41 | } |
| 42 | EXPORT_SYMBOL(s3c_gpio_cfgpin); | 42 | EXPORT_SYMBOL(s3c_gpio_cfgpin); |
| 43 | 43 | ||
| 44 | int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, | ||
| 45 | unsigned int cfg) | ||
| 46 | { | ||
| 47 | int ret; | ||
| 48 | |||
| 49 | for (; nr > 0; nr--, start++) { | ||
| 50 | ret = s3c_gpio_cfgpin(start, cfg); | ||
| 51 | if (ret != 0) | ||
| 52 | return ret; | ||
| 53 | } | ||
| 54 | |||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range); | ||
| 58 | |||
| 59 | int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, | ||
| 60 | unsigned int cfg, s3c_gpio_pull_t pull) | ||
| 61 | { | ||
| 62 | int ret; | ||
| 63 | |||
| 64 | for (; nr > 0; nr--, start++) { | ||
| 65 | s3c_gpio_setpull(start, pull); | ||
| 66 | ret = s3c_gpio_cfgpin(start, cfg); | ||
| 67 | if (ret != 0) | ||
| 68 | return ret; | ||
| 69 | } | ||
| 70 | |||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range); | ||
| 74 | |||
| 44 | unsigned s3c_gpio_getcfg(unsigned int pin) | 75 | unsigned s3c_gpio_getcfg(unsigned int pin) |
| 45 | { | 76 | { |
| 46 | struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); | 77 | struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); |
| @@ -80,6 +111,25 @@ int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull) | |||
| 80 | } | 111 | } |
| 81 | EXPORT_SYMBOL(s3c_gpio_setpull); | 112 | EXPORT_SYMBOL(s3c_gpio_setpull); |
| 82 | 113 | ||
| 114 | s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin) | ||
| 115 | { | ||
| 116 | struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); | ||
| 117 | unsigned long flags; | ||
| 118 | int offset; | ||
| 119 | u32 pup = 0; | ||
| 120 | |||
| 121 | if (chip) { | ||
| 122 | offset = pin - chip->chip.base; | ||
| 123 | |||
| 124 | s3c_gpio_lock(chip, flags); | ||
| 125 | pup = s3c_gpio_do_getpull(chip, offset); | ||
| 126 | s3c_gpio_unlock(chip, flags); | ||
| 127 | } | ||
| 128 | |||
| 129 | return (__force s3c_gpio_pull_t)pup; | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL(s3c_gpio_getpull); | ||
| 132 | |||
| 83 | #ifdef CONFIG_S3C_GPIO_CFG_S3C24XX | 133 | #ifdef CONFIG_S3C_GPIO_CFG_S3C24XX |
| 84 | int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip, | 134 | int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip, |
| 85 | unsigned int off, unsigned int cfg) | 135 | unsigned int off, unsigned int cfg) |
diff --git a/arch/arm/plat-samsung/gpio.c b/arch/arm/plat-samsung/gpio.c index b83a83351cea..7743c4b8b2fb 100644 --- a/arch/arm/plat-samsung/gpio.c +++ b/arch/arm/plat-samsung/gpio.c | |||
| @@ -157,3 +157,11 @@ __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip) | |||
| 157 | if (ret >= 0) | 157 | if (ret >= 0) |
| 158 | s3c_gpiolib_track(chip); | 158 | s3c_gpiolib_track(chip); |
| 159 | } | 159 | } |
| 160 | |||
| 161 | int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) | ||
| 162 | { | ||
| 163 | struct s3c_gpio_chip *s3c_chip = container_of(chip, | ||
| 164 | struct s3c_gpio_chip, chip); | ||
| 165 | |||
| 166 | return s3c_chip->irq_base + offset; | ||
| 167 | } | ||
diff --git a/arch/arm/plat-samsung/include/plat/audio.h b/arch/arm/plat-samsung/include/plat/audio.h index e32f9edfd4b7..7712ff6336f4 100644 --- a/arch/arm/plat-samsung/include/plat/audio.h +++ b/arch/arm/plat-samsung/include/plat/audio.h | |||
| @@ -16,6 +16,15 @@ | |||
| 16 | #define S3C64XX_AC97_GPE 1 | 16 | #define S3C64XX_AC97_GPE 1 |
| 17 | extern void s3c64xx_ac97_setup_gpio(int); | 17 | extern void s3c64xx_ac97_setup_gpio(int); |
| 18 | 18 | ||
| 19 | /* | ||
| 20 | * The machine init code calls s5p*_spdif_setup_gpio with | ||
| 21 | * one of these defines in order to select appropriate bank | ||
| 22 | * of GPIO for S/PDIF pins | ||
| 23 | */ | ||
| 24 | #define S5PC100_SPDIF_GPD 0 | ||
| 25 | #define S5PC100_SPDIF_GPG3 1 | ||
| 26 | extern void s5pc100_spdif_setup_gpio(int); | ||
| 27 | |||
| 19 | /** | 28 | /** |
| 20 | * struct s3c_audio_pdata - common platform data for audio device drivers | 29 | * struct s3c_audio_pdata - common platform data for audio device drivers |
| 21 | * @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode | 30 | * @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode |
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index c8b94279bad1..2d82a6cb1444 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h | |||
| @@ -48,6 +48,11 @@ extern struct platform_device s3c_device_wdt; | |||
| 48 | extern struct platform_device s3c_device_i2c0; | 48 | extern struct platform_device s3c_device_i2c0; |
| 49 | extern struct platform_device s3c_device_i2c1; | 49 | extern struct platform_device s3c_device_i2c1; |
| 50 | extern struct platform_device s3c_device_i2c2; | 50 | extern struct platform_device s3c_device_i2c2; |
| 51 | extern struct platform_device s3c_device_i2c3; | ||
| 52 | extern struct platform_device s3c_device_i2c4; | ||
| 53 | extern struct platform_device s3c_device_i2c5; | ||
| 54 | extern struct platform_device s3c_device_i2c6; | ||
| 55 | extern struct platform_device s3c_device_i2c7; | ||
| 51 | extern struct platform_device s3c_device_rtc; | 56 | extern struct platform_device s3c_device_rtc; |
| 52 | extern struct platform_device s3c_device_adc; | 57 | extern struct platform_device s3c_device_adc; |
| 53 | extern struct platform_device s3c_device_sdi; | 58 | extern struct platform_device s3c_device_sdi; |
| @@ -89,6 +94,7 @@ extern struct platform_device s5pv210_device_pcm2; | |||
| 89 | extern struct platform_device s5pv210_device_iis0; | 94 | extern struct platform_device s5pv210_device_iis0; |
| 90 | extern struct platform_device s5pv210_device_iis1; | 95 | extern struct platform_device s5pv210_device_iis1; |
| 91 | extern struct platform_device s5pv210_device_iis2; | 96 | extern struct platform_device s5pv210_device_iis2; |
| 97 | extern struct platform_device s5pv210_device_spdif; | ||
| 92 | 98 | ||
| 93 | extern struct platform_device s5p6442_device_pcm0; | 99 | extern struct platform_device s5p6442_device_pcm0; |
| 94 | extern struct platform_device s5p6442_device_pcm1; | 100 | extern struct platform_device s5p6442_device_pcm1; |
| @@ -108,6 +114,7 @@ extern struct platform_device s5pc100_device_pcm1; | |||
| 108 | extern struct platform_device s5pc100_device_iis0; | 114 | extern struct platform_device s5pc100_device_iis0; |
| 109 | extern struct platform_device s5pc100_device_iis1; | 115 | extern struct platform_device s5pc100_device_iis1; |
| 110 | extern struct platform_device s5pc100_device_iis2; | 116 | extern struct platform_device s5pc100_device_iis2; |
| 117 | extern struct platform_device s5pc100_device_spdif; | ||
| 111 | 118 | ||
| 112 | extern struct platform_device samsung_device_keypad; | 119 | extern struct platform_device samsung_device_keypad; |
| 113 | 120 | ||
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h index 3e21c75feefa..8fd65d8b5863 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h | |||
| @@ -42,6 +42,12 @@ static inline int s3c_gpio_do_setpull(struct s3c_gpio_chip *chip, | |||
| 42 | return (chip->config->set_pull)(chip, off, pull); | 42 | return (chip->config->set_pull)(chip, off, pull); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static inline s3c_gpio_pull_t s3c_gpio_do_getpull(struct s3c_gpio_chip *chip, | ||
| 46 | unsigned int off) | ||
| 47 | { | ||
| 48 | return chip->config->get_pull(chip, off); | ||
| 49 | } | ||
| 50 | |||
| 45 | /** | 51 | /** |
| 46 | * s3c_gpio_setcfg_s3c24xx - S3C24XX style GPIO configuration. | 52 | * s3c_gpio_setcfg_s3c24xx - S3C24XX style GPIO configuration. |
| 47 | * @chip: The gpio chip that is being configured. | 53 | * @chip: The gpio chip that is being configured. |
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h index 1c6b92947c5d..e4b5cf126fa9 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h | |||
| @@ -108,6 +108,19 @@ extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to); | |||
| 108 | */ | 108 | */ |
| 109 | extern unsigned s3c_gpio_getcfg(unsigned int pin); | 109 | extern unsigned s3c_gpio_getcfg(unsigned int pin); |
| 110 | 110 | ||
| 111 | /** | ||
| 112 | * s3c_gpio_cfgpin_range() - Change the GPIO function for configuring pin range | ||
| 113 | * @start: The pin number to start at | ||
| 114 | * @nr: The number of pins to configure from @start. | ||
| 115 | * @cfg: The configuration for the pin's function | ||
| 116 | * | ||
| 117 | * Call s3c_gpio_cfgpin() for the @nr pins starting at @start. | ||
| 118 | * | ||
| 119 | * @sa s3c_gpio_cfgpin. | ||
| 120 | */ | ||
| 121 | extern int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, | ||
| 122 | unsigned int cfg); | ||
| 123 | |||
| 111 | /* Define values for the pull-{up,down} available for each gpio pin. | 124 | /* Define values for the pull-{up,down} available for each gpio pin. |
| 112 | * | 125 | * |
| 113 | * These values control the state of the weak pull-{up,down} resistors | 126 | * These values control the state of the weak pull-{up,down} resistors |
| @@ -140,6 +153,31 @@ extern int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull); | |||
| 140 | */ | 153 | */ |
| 141 | extern s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin); | 154 | extern s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin); |
| 142 | 155 | ||
| 156 | /* configure `all` aspects of an gpio */ | ||
| 157 | |||
| 158 | /** | ||
| 159 | * s3c_gpio_cfgall_range() - configure range of gpio functtion and pull. | ||
| 160 | * @start: The gpio number to start at. | ||
| 161 | * @nr: The number of gpio to configure from @start. | ||
| 162 | * @cfg: The configuration to use | ||
| 163 | * @pull: The pull setting to use. | ||
| 164 | * | ||
| 165 | * Run s3c_gpio_cfgpin() and s3c_gpio_setpull() over the gpio range starting | ||
| 166 | * @gpio and running for @size. | ||
| 167 | * | ||
| 168 | * @sa s3c_gpio_cfgpin | ||
| 169 | * @sa s3c_gpio_setpull | ||
| 170 | * @sa s3c_gpio_cfgpin_range | ||
| 171 | */ | ||
| 172 | extern int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, | ||
| 173 | unsigned int cfg, s3c_gpio_pull_t pull); | ||
| 174 | |||
| 175 | static inline int s3c_gpio_cfgrange_nopull(unsigned int pin, unsigned int size, | ||
| 176 | unsigned int cfg) | ||
| 177 | { | ||
| 178 | return s3c_gpio_cfgall_range(pin, size, cfg, S3C_GPIO_PULL_NONE); | ||
| 179 | } | ||
| 180 | |||
| 143 | /* Define values for the drvstr available for each gpio pin. | 181 | /* Define values for the drvstr available for each gpio pin. |
| 144 | * | 182 | * |
| 145 | * These values control the value of the output signal driver strength, | 183 | * These values control the value of the output signal driver strength, |
| @@ -169,4 +207,22 @@ extern s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin); | |||
| 169 | */ | 207 | */ |
| 170 | extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr); | 208 | extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr); |
| 171 | 209 | ||
| 210 | /** | ||
| 211 | * s5p_register_gpio_interrupt() - register interrupt support for a gpio group | ||
| 212 | * @pin: The pin number from the group to be registered | ||
| 213 | * | ||
| 214 | * This function registers gpio interrupt support for the group that the | ||
| 215 | * specified pin belongs to. | ||
| 216 | * | ||
| 217 | * The total number of gpio pins is quite large ob s5p series. Registering | ||
| 218 | * irq support for all of them would be a resource waste. Because of that the | ||
| 219 | * interrupt support for standard gpio pins is registered dynamically. | ||
| 220 | * | ||
| 221 | * It will return the irq number of the interrupt that has been registered | ||
| 222 | * or -ENOMEM if no more gpio interrupts can be registered. It is allowed | ||
| 223 | * to call this function more than once for the same gpio group (the group | ||
| 224 | * will be registered only once). | ||
| 225 | */ | ||
| 226 | extern int s5p_register_gpio_interrupt(int pin); | ||
| 227 | |||
| 172 | #endif /* __PLAT_GPIO_CFG_H */ | 228 | #endif /* __PLAT_GPIO_CFG_H */ |
diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h index e358c7da8480..13a22b8861ef 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-core.h +++ b/arch/arm/plat-samsung/include/plat/gpio-core.h | |||
| @@ -43,6 +43,8 @@ struct s3c_gpio_cfg; | |||
| 43 | * struct s3c_gpio_chip - wrapper for specific implementation of gpio | 43 | * struct s3c_gpio_chip - wrapper for specific implementation of gpio |
| 44 | * @chip: The chip structure to be exported via gpiolib. | 44 | * @chip: The chip structure to be exported via gpiolib. |
| 45 | * @base: The base pointer to the gpio configuration registers. | 45 | * @base: The base pointer to the gpio configuration registers. |
| 46 | * @group: The group register number for gpio interrupt support. | ||
| 47 | * @irq_base: The base irq number. | ||
| 46 | * @config: special function and pull-resistor control information. | 48 | * @config: special function and pull-resistor control information. |
| 47 | * @lock: Lock for exclusive access to this gpio bank. | 49 | * @lock: Lock for exclusive access to this gpio bank. |
| 48 | * @pm_save: Save information for suspend/resume support. | 50 | * @pm_save: Save information for suspend/resume support. |
| @@ -63,6 +65,8 @@ struct s3c_gpio_chip { | |||
| 63 | struct s3c_gpio_cfg *config; | 65 | struct s3c_gpio_cfg *config; |
| 64 | struct s3c_gpio_pm *pm; | 66 | struct s3c_gpio_pm *pm; |
| 65 | void __iomem *base; | 67 | void __iomem *base; |
| 68 | int irq_base; | ||
| 69 | int group; | ||
| 66 | spinlock_t lock; | 70 | spinlock_t lock; |
| 67 | #ifdef CONFIG_PM | 71 | #ifdef CONFIG_PM |
| 68 | u32 pm_save[4]; | 72 | u32 pm_save[4]; |
| @@ -118,6 +122,17 @@ extern void samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip, | |||
| 118 | extern void samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip); | 122 | extern void samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip); |
| 119 | extern void samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip); | 123 | extern void samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip); |
| 120 | 124 | ||
| 125 | |||
| 126 | /** | ||
| 127 | * samsung_gpiolib_to_irq - convert gpio pin to irq number | ||
| 128 | * @chip: The gpio chip that the pin belongs to. | ||
| 129 | * @offset: The offset of the pin in the chip. | ||
| 130 | * | ||
| 131 | * This helper returns the irq number calculated from the chip->irq_base and | ||
| 132 | * the provided offset. | ||
| 133 | */ | ||
| 134 | extern int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset); | ||
| 135 | |||
| 121 | /* exported for core SoC support to change */ | 136 | /* exported for core SoC support to change */ |
| 122 | extern struct s3c_gpio_cfg s3c24xx_gpiocfg_default; | 137 | extern struct s3c_gpio_cfg s3c24xx_gpiocfg_default; |
| 123 | 138 | ||
diff --git a/arch/arm/plat-samsung/include/plat/iic.h b/arch/arm/plat-samsung/include/plat/iic.h index 133308bf595d..1543da8f85c1 100644 --- a/arch/arm/plat-samsung/include/plat/iic.h +++ b/arch/arm/plat-samsung/include/plat/iic.h | |||
| @@ -55,10 +55,20 @@ struct s3c2410_platform_i2c { | |||
| 55 | extern void s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *i2c); | 55 | extern void s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *i2c); |
| 56 | extern void s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *i2c); | 56 | extern void s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *i2c); |
| 57 | extern void s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *i2c); | 57 | extern void s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *i2c); |
| 58 | extern void s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *i2c); | ||
| 59 | extern void s3c_i2c4_set_platdata(struct s3c2410_platform_i2c *i2c); | ||
| 60 | extern void s3c_i2c5_set_platdata(struct s3c2410_platform_i2c *i2c); | ||
| 61 | extern void s3c_i2c6_set_platdata(struct s3c2410_platform_i2c *i2c); | ||
| 62 | extern void s3c_i2c7_set_platdata(struct s3c2410_platform_i2c *i2c); | ||
| 58 | 63 | ||
| 59 | /* defined by architecture to configure gpio */ | 64 | /* defined by architecture to configure gpio */ |
| 60 | extern void s3c_i2c0_cfg_gpio(struct platform_device *dev); | 65 | extern void s3c_i2c0_cfg_gpio(struct platform_device *dev); |
| 61 | extern void s3c_i2c1_cfg_gpio(struct platform_device *dev); | 66 | extern void s3c_i2c1_cfg_gpio(struct platform_device *dev); |
| 62 | extern void s3c_i2c2_cfg_gpio(struct platform_device *dev); | 67 | extern void s3c_i2c2_cfg_gpio(struct platform_device *dev); |
| 68 | extern void s3c_i2c3_cfg_gpio(struct platform_device *dev); | ||
| 69 | extern void s3c_i2c4_cfg_gpio(struct platform_device *dev); | ||
| 70 | extern void s3c_i2c5_cfg_gpio(struct platform_device *dev); | ||
| 71 | extern void s3c_i2c6_cfg_gpio(struct platform_device *dev); | ||
| 72 | extern void s3c_i2c7_cfg_gpio(struct platform_device *dev); | ||
| 63 | 73 | ||
| 64 | #endif /* __ASM_ARCH_IIC_H */ | 74 | #endif /* __ASM_ARCH_IIC_H */ |
diff --git a/arch/arm/plat-samsung/include/plat/map-base.h b/arch/arm/plat-samsung/include/plat/map-base.h index 250be311c85b..3ffac4d2e4f0 100644 --- a/arch/arm/plat-samsung/include/plat/map-base.h +++ b/arch/arm/plat-samsung/include/plat/map-base.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | #ifndef __ASM_PLAT_MAP_H | 14 | #ifndef __ASM_PLAT_MAP_H |
| 15 | #define __ASM_PLAT_MAP_H __FILE__ | 15 | #define __ASM_PLAT_MAP_H __FILE__ |
| 16 | 16 | ||
| 17 | /* Fit all our registers in at 0xF4000000 upwards, trying to use as | 17 | /* Fit all our registers in at 0xF6000000 upwards, trying to use as |
| 18 | * little of the VA space as possible so vmalloc and friends have a | 18 | * little of the VA space as possible so vmalloc and friends have a |
| 19 | * better chance of getting memory. | 19 | * better chance of getting memory. |
| 20 | * | 20 | * |
| @@ -22,7 +22,7 @@ | |||
| 22 | * an single MOVS instruction (ie, only 8 bits of set data) | 22 | * an single MOVS instruction (ie, only 8 bits of set data) |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #define S3C_ADDR_BASE (0xF4000000) | 25 | #define S3C_ADDR_BASE 0xF6000000 |
| 26 | 26 | ||
| 27 | #ifndef __ASSEMBLY__ | 27 | #ifndef __ASSEMBLY__ |
| 28 | #define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x)) | 28 | #define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x)) |
diff --git a/arch/arm/plat-samsung/include/plat/nand-core.h b/arch/arm/plat-samsung/include/plat/nand-core.h new file mode 100644 index 000000000000..6de20789a95e --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/nand-core.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* arch/arm/plat-samsung/include/plat/nand-core.h | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 4 | * http://www.samsung.com/ | ||
| 5 | * | ||
| 6 | * S3C - Nand Controller core functions | ||
| 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_ARCH_NAND_CORE_H | ||
| 14 | #define __ASM_ARCH_NAND_CORE_H __FILE__ | ||
| 15 | |||
| 16 | /* These functions are only for use with the core support code, such as | ||
| 17 | * the cpu specific initialisation code | ||
| 18 | */ | ||
| 19 | |||
| 20 | /* re-define device name depending on support. */ | ||
| 21 | static inline void s3c_nand_setname(char *name) | ||
| 22 | { | ||
| 23 | #ifdef CONFIG_S3C_DEV_NAND | ||
| 24 | s3c_device_nand.name = name; | ||
| 25 | #endif | ||
| 26 | } | ||
| 27 | |||
| 28 | #endif /* __ASM_ARCH_NAND_CORE_H */ | ||
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h index 30844c263d03..85853f8c4c5d 100644 --- a/arch/arm/plat-samsung/include/plat/sdhci.h +++ b/arch/arm/plat-samsung/include/plat/sdhci.h | |||
| @@ -28,11 +28,17 @@ enum cd_types { | |||
| 28 | S3C_SDHCI_CD_PERMANENT, /* no CD line, card permanently wired to host */ | 28 | S3C_SDHCI_CD_PERMANENT, /* no CD line, card permanently wired to host */ |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | enum clk_types { | ||
| 32 | S3C_SDHCI_CLK_DIV_INTERNAL, /* use mmc internal clock divider */ | ||
| 33 | S3C_SDHCI_CLK_DIV_EXTERNAL, /* use external clock divider */ | ||
| 34 | }; | ||
| 35 | |||
| 31 | /** | 36 | /** |
| 32 | * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI | 37 | * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI |
| 33 | * @max_width: The maximum number of data bits supported. | 38 | * @max_width: The maximum number of data bits supported. |
| 34 | * @host_caps: Standard MMC host capabilities bit field. | 39 | * @host_caps: Standard MMC host capabilities bit field. |
| 35 | * @cd_type: Type of Card Detection method (see cd_types enum above) | 40 | * @cd_type: Type of Card Detection method (see cd_types enum above) |
| 41 | * @clk_type: Type of clock divider method (see clk_types enum above) | ||
| 36 | * @ext_cd_init: Initialize external card detect subsystem. Called on | 42 | * @ext_cd_init: Initialize external card detect subsystem. Called on |
| 37 | * sdhci-s3c driver probe when cd_type == S3C_SDHCI_CD_EXTERNAL. | 43 | * sdhci-s3c driver probe when cd_type == S3C_SDHCI_CD_EXTERNAL. |
| 38 | * notify_func argument is a callback to the sdhci-s3c driver | 44 | * notify_func argument is a callback to the sdhci-s3c driver |
| @@ -59,6 +65,7 @@ struct s3c_sdhci_platdata { | |||
| 59 | unsigned int max_width; | 65 | unsigned int max_width; |
| 60 | unsigned int host_caps; | 66 | unsigned int host_caps; |
| 61 | enum cd_types cd_type; | 67 | enum cd_types cd_type; |
| 68 | enum clk_types clk_type; | ||
| 62 | 69 | ||
| 63 | char **clocks; /* set of clock sources */ | 70 | char **clocks; /* set of clock sources */ |
| 64 | 71 | ||
| @@ -110,6 +117,10 @@ extern void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *, int w); | |||
| 110 | extern void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *, int w); | 117 | extern void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *, int w); |
| 111 | extern void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *, int w); | 118 | extern void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *, int w); |
| 112 | extern void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *, int w); | 119 | extern void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *, int w); |
| 120 | extern void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *, int w); | ||
| 121 | extern void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *, int w); | ||
| 122 | extern void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *, int w); | ||
| 123 | extern void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *, int w); | ||
| 113 | 124 | ||
| 114 | /* S3C64XX SDHCI setup */ | 125 | /* S3C64XX SDHCI setup */ |
| 115 | 126 | ||
| @@ -288,4 +299,57 @@ static inline void s5pv210_default_sdhci3(void) { } | |||
| 288 | 299 | ||
| 289 | #endif /* CONFIG_S5PV210_SETUP_SDHCI */ | 300 | #endif /* CONFIG_S5PV210_SETUP_SDHCI */ |
| 290 | 301 | ||
| 302 | /* S5PV310 SDHCI setup */ | ||
| 303 | #ifdef CONFIG_S5PV310_SETUP_SDHCI | ||
| 304 | extern char *s5pv310_hsmmc_clksrcs[4]; | ||
| 305 | |||
| 306 | extern void s5pv310_setup_sdhci_cfg_card(struct platform_device *dev, | ||
| 307 | void __iomem *r, | ||
| 308 | struct mmc_ios *ios, | ||
| 309 | struct mmc_card *card); | ||
| 310 | |||
| 311 | static inline void s5pv310_default_sdhci0(void) | ||
| 312 | { | ||
| 313 | #ifdef CONFIG_S3C_DEV_HSMMC | ||
| 314 | s3c_hsmmc0_def_platdata.clocks = s5pv310_hsmmc_clksrcs; | ||
| 315 | s3c_hsmmc0_def_platdata.cfg_gpio = s5pv310_setup_sdhci0_cfg_gpio; | ||
| 316 | s3c_hsmmc0_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card; | ||
| 317 | #endif | ||
| 318 | } | ||
| 319 | |||
| 320 | static inline void s5pv310_default_sdhci1(void) | ||
| 321 | { | ||
| 322 | #ifdef CONFIG_S3C_DEV_HSMMC1 | ||
| 323 | s3c_hsmmc1_def_platdata.clocks = s5pv310_hsmmc_clksrcs; | ||
| 324 | s3c_hsmmc1_def_platdata.cfg_gpio = s5pv310_setup_sdhci1_cfg_gpio; | ||
| 325 | s3c_hsmmc1_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card; | ||
| 326 | #endif | ||
| 327 | } | ||
| 328 | |||
| 329 | static inline void s5pv310_default_sdhci2(void) | ||
| 330 | { | ||
| 331 | #ifdef CONFIG_S3C_DEV_HSMMC2 | ||
| 332 | s3c_hsmmc2_def_platdata.clocks = s5pv310_hsmmc_clksrcs; | ||
| 333 | s3c_hsmmc2_def_platdata.cfg_gpio = s5pv310_setup_sdhci2_cfg_gpio; | ||
| 334 | s3c_hsmmc2_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card; | ||
| 335 | #endif | ||
| 336 | } | ||
| 337 | |||
| 338 | static inline void s5pv310_default_sdhci3(void) | ||
| 339 | { | ||
| 340 | #ifdef CONFIG_S3C_DEV_HSMMC3 | ||
| 341 | s3c_hsmmc3_def_platdata.clocks = s5pv310_hsmmc_clksrcs; | ||
| 342 | s3c_hsmmc3_def_platdata.cfg_gpio = s5pv310_setup_sdhci3_cfg_gpio; | ||
| 343 | s3c_hsmmc3_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card; | ||
| 344 | #endif | ||
| 345 | } | ||
| 346 | |||
| 347 | #else | ||
| 348 | static inline void s5pv310_default_sdhci0(void) { } | ||
| 349 | static inline void s5pv310_default_sdhci1(void) { } | ||
| 350 | static inline void s5pv310_default_sdhci2(void) { } | ||
| 351 | static inline void s5pv310_default_sdhci3(void) { } | ||
| 352 | |||
| 353 | #endif /* CONFIG_S5PV310_SETUP_SDHCI */ | ||
| 354 | |||
| 291 | #endif /* __PLAT_S3C_SDHCI_H */ | 355 | #endif /* __PLAT_S3C_SDHCI_H */ |
diff --git a/arch/arm/plat-samsung/pm-gpio.c b/arch/arm/plat-samsung/pm-gpio.c index 7df03f87fbfa..96528200eb79 100644 --- a/arch/arm/plat-samsung/pm-gpio.c +++ b/arch/arm/plat-samsung/pm-gpio.c | |||
| @@ -192,7 +192,7 @@ struct s3c_gpio_pm s3c_gpio_pm_2bit = { | |||
| 192 | .resume = s3c_gpio_pm_2bit_resume, | 192 | .resume = s3c_gpio_pm_2bit_resume, |
| 193 | }; | 193 | }; |
| 194 | 194 | ||
| 195 | #ifdef CONFIG_ARCH_S3C64XX | 195 | #if defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_PLAT_S5P) |
| 196 | static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip) | 196 | static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip) |
| 197 | { | 197 | { |
| 198 | chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON); | 198 | chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON); |
| @@ -302,7 +302,7 @@ struct s3c_gpio_pm s3c_gpio_pm_4bit = { | |||
| 302 | .save = s3c_gpio_pm_4bit_save, | 302 | .save = s3c_gpio_pm_4bit_save, |
| 303 | .resume = s3c_gpio_pm_4bit_resume, | 303 | .resume = s3c_gpio_pm_4bit_resume, |
| 304 | }; | 304 | }; |
| 305 | #endif /* CONFIG_ARCH_S3C64XX */ | 305 | #endif /* CONFIG_ARCH_S3C64XX || CONFIG_PLAT_S5P */ |
| 306 | 306 | ||
| 307 | /** | 307 | /** |
| 308 | * s3c_pm_save_gpio() - save gpio chip data for suspend | 308 | * s3c_pm_save_gpio() - save gpio chip data for suspend |
diff --git a/arch/arm/plat-samsung/s3c-pl330.c b/arch/arm/plat-samsung/s3c-pl330.c index a91305a60aed..b4ff8d74ac40 100644 --- a/arch/arm/plat-samsung/s3c-pl330.c +++ b/arch/arm/plat-samsung/s3c-pl330.c | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 18 | #include <linux/clk.h> | ||
| 19 | #include <linux/err.h> | ||
| 18 | 20 | ||
| 19 | #include <asm/hardware/pl330.h> | 21 | #include <asm/hardware/pl330.h> |
| 20 | 22 | ||
| @@ -27,6 +29,7 @@ | |||
| 27 | * @node: To attach to the global list of DMACs. | 29 | * @node: To attach to the global list of DMACs. |
| 28 | * @pi: PL330 configuration info for the DMAC. | 30 | * @pi: PL330 configuration info for the DMAC. |
| 29 | * @kmcache: Pool to quickly allocate xfers for all channels in the dmac. | 31 | * @kmcache: Pool to quickly allocate xfers for all channels in the dmac. |
| 32 | * @clk: Pointer of DMAC operation clock. | ||
| 30 | */ | 33 | */ |
| 31 | struct s3c_pl330_dmac { | 34 | struct s3c_pl330_dmac { |
| 32 | unsigned busy_chan; | 35 | unsigned busy_chan; |
| @@ -34,6 +37,7 @@ struct s3c_pl330_dmac { | |||
| 34 | struct list_head node; | 37 | struct list_head node; |
| 35 | struct pl330_info *pi; | 38 | struct pl330_info *pi; |
| 36 | struct kmem_cache *kmcache; | 39 | struct kmem_cache *kmcache; |
| 40 | struct clk *clk; | ||
| 37 | }; | 41 | }; |
| 38 | 42 | ||
| 39 | /** | 43 | /** |
| @@ -1072,16 +1076,25 @@ static int pl330_probe(struct platform_device *pdev) | |||
| 1072 | if (ret) | 1076 | if (ret) |
| 1073 | goto probe_err4; | 1077 | goto probe_err4; |
| 1074 | 1078 | ||
| 1075 | ret = pl330_add(pl330_info); | ||
| 1076 | if (ret) | ||
| 1077 | goto probe_err5; | ||
| 1078 | |||
| 1079 | /* Allocate a new DMAC */ | 1079 | /* Allocate a new DMAC */ |
| 1080 | s3c_pl330_dmac = kmalloc(sizeof(*s3c_pl330_dmac), GFP_KERNEL); | 1080 | s3c_pl330_dmac = kmalloc(sizeof(*s3c_pl330_dmac), GFP_KERNEL); |
| 1081 | if (!s3c_pl330_dmac) { | 1081 | if (!s3c_pl330_dmac) { |
| 1082 | ret = -ENOMEM; | 1082 | ret = -ENOMEM; |
| 1083 | goto probe_err5; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | /* Get operation clock and enable it */ | ||
| 1087 | s3c_pl330_dmac->clk = clk_get(&pdev->dev, "pdma"); | ||
| 1088 | if (IS_ERR(s3c_pl330_dmac->clk)) { | ||
| 1089 | dev_err(&pdev->dev, "Cannot get operation clock.\n"); | ||
| 1090 | ret = -EINVAL; | ||
| 1083 | goto probe_err6; | 1091 | goto probe_err6; |
| 1084 | } | 1092 | } |
| 1093 | clk_enable(s3c_pl330_dmac->clk); | ||
| 1094 | |||
| 1095 | ret = pl330_add(pl330_info); | ||
| 1096 | if (ret) | ||
| 1097 | goto probe_err7; | ||
| 1085 | 1098 | ||
| 1086 | /* Hook the info */ | 1099 | /* Hook the info */ |
| 1087 | s3c_pl330_dmac->pi = pl330_info; | 1100 | s3c_pl330_dmac->pi = pl330_info; |
| @@ -1094,7 +1107,7 @@ static int pl330_probe(struct platform_device *pdev) | |||
| 1094 | 1107 | ||
| 1095 | if (!s3c_pl330_dmac->kmcache) { | 1108 | if (!s3c_pl330_dmac->kmcache) { |
| 1096 | ret = -ENOMEM; | 1109 | ret = -ENOMEM; |
| 1097 | goto probe_err7; | 1110 | goto probe_err8; |
| 1098 | } | 1111 | } |
| 1099 | 1112 | ||
| 1100 | /* Get the list of peripherals */ | 1113 | /* Get the list of peripherals */ |
| @@ -1120,10 +1133,13 @@ static int pl330_probe(struct platform_device *pdev) | |||
| 1120 | 1133 | ||
| 1121 | return 0; | 1134 | return 0; |
| 1122 | 1135 | ||
| 1136 | probe_err8: | ||
| 1137 | pl330_del(pl330_info); | ||
| 1123 | probe_err7: | 1138 | probe_err7: |
| 1124 | kfree(s3c_pl330_dmac); | 1139 | clk_disable(s3c_pl330_dmac->clk); |
| 1140 | clk_put(s3c_pl330_dmac->clk); | ||
| 1125 | probe_err6: | 1141 | probe_err6: |
| 1126 | pl330_del(pl330_info); | 1142 | kfree(s3c_pl330_dmac); |
| 1127 | probe_err5: | 1143 | probe_err5: |
| 1128 | free_irq(irq, pl330_info); | 1144 | free_irq(irq, pl330_info); |
| 1129 | probe_err4: | 1145 | probe_err4: |
| @@ -1188,6 +1204,10 @@ static int pl330_remove(struct platform_device *pdev) | |||
| 1188 | } | 1204 | } |
| 1189 | } | 1205 | } |
| 1190 | 1206 | ||
| 1207 | /* Disable operation clock */ | ||
| 1208 | clk_disable(dmac->clk); | ||
| 1209 | clk_put(dmac->clk); | ||
| 1210 | |||
| 1191 | /* Remove the DMAC */ | 1211 | /* Remove the DMAC */ |
| 1192 | list_del(&dmac->node); | 1212 | list_del(&dmac->node); |
| 1193 | kfree(dmac); | 1213 | kfree(dmac); |
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h new file mode 100644 index 000000000000..5325084d5c48 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | #ifndef __BCM963XX_TAG_H | ||
| 2 | #define __BCM963XX_TAG_H | ||
| 3 | |||
| 4 | #define TAGVER_LEN 4 /* Length of Tag Version */ | ||
| 5 | #define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */ | ||
| 6 | #define SIG1_LEN 20 /* Company Signature 1 Length */ | ||
| 7 | #define SIG2_LEN 14 /* Company Signature 2 Lenght */ | ||
| 8 | #define BOARDID_LEN 16 /* Length of BoardId */ | ||
| 9 | #define ENDIANFLAG_LEN 2 /* Endian Flag Length */ | ||
| 10 | #define CHIPID_LEN 6 /* Chip Id Length */ | ||
| 11 | #define IMAGE_LEN 10 /* Length of Length Field */ | ||
| 12 | #define ADDRESS_LEN 12 /* Length of Address field */ | ||
| 13 | #define DUALFLAG_LEN 2 /* Dual Image flag Length */ | ||
| 14 | #define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */ | ||
| 15 | #define RSASIG_LEN 20 /* Length of RSA Signature in tag */ | ||
| 16 | #define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */ | ||
| 17 | #define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */ | ||
| 18 | #define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */ | ||
| 19 | #define CRC_LEN 4 /* Length of CRC in bytes */ | ||
| 20 | #define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */ | ||
| 21 | |||
| 22 | #define NUM_PIRELLI 2 | ||
| 23 | #define IMAGETAG_CRC_START 0xFFFFFFFF | ||
| 24 | |||
| 25 | #define PIRELLI_BOARDS { \ | ||
| 26 | "AGPF-S0", \ | ||
| 27 | "DWV-S0", \ | ||
| 28 | } | ||
| 29 | |||
| 30 | /* | ||
| 31 | * The broadcom firmware assumes the rootfs starts the image, | ||
| 32 | * therefore uses the rootfs start (flash_image_address) | ||
| 33 | * to determine where to flash the image. Since we have the kernel first | ||
| 34 | * we have to give it the kernel address, but the crc uses the length | ||
| 35 | * associated with this address (root_length), which is added to the kernel | ||
| 36 | * length (kernel_length) to determine the length of image to flash and thus | ||
| 37 | * needs to be rootfs + deadcode (jffs2 EOF marker) | ||
| 38 | */ | ||
| 39 | |||
| 40 | struct bcm_tag { | ||
| 41 | /* 0-3: Version of the image tag */ | ||
| 42 | char tag_version[TAGVER_LEN]; | ||
| 43 | /* 4-23: Company Line 1 */ | ||
| 44 | char sig_1[SIG1_LEN]; | ||
| 45 | /* 24-37: Company Line 2 */ | ||
| 46 | char sig_2[SIG2_LEN]; | ||
| 47 | /* 38-43: Chip this image is for */ | ||
| 48 | char chip_id[CHIPID_LEN]; | ||
| 49 | /* 44-59: Board name */ | ||
| 50 | char board_id[BOARDID_LEN]; | ||
| 51 | /* 60-61: Map endianness -- 1 BE 0 LE */ | ||
| 52 | char big_endian[ENDIANFLAG_LEN]; | ||
| 53 | /* 62-71: Total length of image */ | ||
| 54 | char total_length[IMAGE_LEN]; | ||
| 55 | /* 72-83: Address in memory of CFE */ | ||
| 56 | char cfe__address[ADDRESS_LEN]; | ||
| 57 | /* 84-93: Size of CFE */ | ||
| 58 | char cfe_length[IMAGE_LEN]; | ||
| 59 | /* 94-105: Address in memory of image start | ||
| 60 | * (kernel for OpenWRT, rootfs for stock firmware) | ||
| 61 | */ | ||
| 62 | char flash_image_start[ADDRESS_LEN]; | ||
| 63 | /* 106-115: Size of rootfs */ | ||
| 64 | char root_length[IMAGE_LEN]; | ||
| 65 | /* 116-127: Address in memory of kernel */ | ||
| 66 | char kernel_address[ADDRESS_LEN]; | ||
| 67 | /* 128-137: Size of kernel */ | ||
| 68 | char kernel_length[IMAGE_LEN]; | ||
| 69 | /* 138-139: Unused at the moment */ | ||
| 70 | char dual_image[DUALFLAG_LEN]; | ||
| 71 | /* 140-141: Unused at the moment */ | ||
| 72 | char inactive_flag[INACTIVEFLAG_LEN]; | ||
| 73 | /* 142-161: RSA Signature (not used; some vendors may use this) */ | ||
| 74 | char rsa_signature[RSASIG_LEN]; | ||
| 75 | /* 162-191: Compilation and related information (not used in OpenWrt) */ | ||
| 76 | char information1[TAGINFO1_LEN]; | ||
| 77 | /* 192-195: Version flash layout */ | ||
| 78 | char flash_layout_ver[FLASHLAYOUTVER_LEN]; | ||
| 79 | /* 196-199: kernel+rootfs CRC32 */ | ||
| 80 | char fskernel_crc[CRC_LEN]; | ||
| 81 | /* 200-215: Unused except on Alice Gate where is is information */ | ||
| 82 | char information2[TAGINFO2_LEN]; | ||
| 83 | /* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */ | ||
| 84 | char image_crc[CRC_LEN]; | ||
| 85 | /* 220-223: CRC32 of rootfs partition */ | ||
| 86 | char rootfs_crc[CRC_LEN]; | ||
| 87 | /* 224-227: CRC32 of kernel partition */ | ||
| 88 | char kernel_crc[CRC_LEN]; | ||
| 89 | /* 228-235: Unused at present */ | ||
| 90 | char reserved1[8]; | ||
| 91 | /* 236-239: CRC32 of header excluding tagVersion */ | ||
| 92 | char header_crc[CRC_LEN]; | ||
| 93 | /* 240-255: Unused at present */ | ||
| 94 | char reserved2[16]; | ||
| 95 | }; | ||
| 96 | |||
| 97 | #endif /* __BCM63XX_TAG_H */ | ||
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c7e40b37aa65..b6447190e1a2 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
| @@ -682,9 +682,12 @@ config 4xx_SOC | |||
| 682 | bool | 682 | bool |
| 683 | 683 | ||
| 684 | config FSL_LBC | 684 | config FSL_LBC |
| 685 | bool | 685 | bool "Freescale Local Bus support" |
| 686 | depends on FSL_SOC | ||
| 686 | help | 687 | help |
| 687 | Freescale Localbus support | 688 | Enables reporting of errors from the Freescale local bus |
| 689 | controller. Also contains some common code used by | ||
| 690 | drivers for specific local bus peripherals. | ||
| 688 | 691 | ||
| 689 | config FSL_GTM | 692 | config FSL_GTM |
| 690 | bool | 693 | bool |
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h index 1b5a21041f9b..5c1bf3466749 100644 --- a/arch/powerpc/include/asm/fsl_lbc.h +++ b/arch/powerpc/include/asm/fsl_lbc.h | |||
| @@ -1,9 +1,10 @@ | |||
| 1 | /* Freescale Local Bus Controller | 1 | /* Freescale Local Bus Controller |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2006-2007 Freescale Semiconductor | 3 | * Copyright © 2006-2007, 2010 Freescale Semiconductor |
| 4 | * | 4 | * |
| 5 | * Authors: Nick Spence <nick.spence@freescale.com>, | 5 | * Authors: Nick Spence <nick.spence@freescale.com>, |
| 6 | * Scott Wood <scottwood@freescale.com> | 6 | * Scott Wood <scottwood@freescale.com> |
| 7 | * Jack Lan <jack.lan@freescale.com> | ||
| 7 | * | 8 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
| @@ -26,6 +27,8 @@ | |||
| 26 | #include <linux/compiler.h> | 27 | #include <linux/compiler.h> |
| 27 | #include <linux/types.h> | 28 | #include <linux/types.h> |
| 28 | #include <linux/io.h> | 29 | #include <linux/io.h> |
| 30 | #include <linux/device.h> | ||
| 31 | #include <linux/spinlock.h> | ||
| 29 | 32 | ||
| 30 | struct fsl_lbc_bank { | 33 | struct fsl_lbc_bank { |
| 31 | __be32 br; /**< Base Register */ | 34 | __be32 br; /**< Base Register */ |
| @@ -125,13 +128,23 @@ struct fsl_lbc_regs { | |||
| 125 | #define LTESR_ATMW 0x00800000 | 128 | #define LTESR_ATMW 0x00800000 |
| 126 | #define LTESR_ATMR 0x00400000 | 129 | #define LTESR_ATMR 0x00400000 |
| 127 | #define LTESR_CS 0x00080000 | 130 | #define LTESR_CS 0x00080000 |
| 131 | #define LTESR_UPM 0x00000002 | ||
| 128 | #define LTESR_CC 0x00000001 | 132 | #define LTESR_CC 0x00000001 |
| 129 | #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) | 133 | #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) |
| 134 | #define LTESR_MASK (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \ | ||
| 135 | | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \ | ||
| 136 | | LTESR_CC) | ||
| 137 | #define LTESR_CLEAR 0xFFFFFFFF | ||
| 138 | #define LTECCR_CLEAR 0xFFFFFFFF | ||
| 139 | #define LTESR_STATUS LTESR_MASK | ||
| 140 | #define LTEIR_ENABLE LTESR_MASK | ||
| 141 | #define LTEDR_ENABLE 0x00000000 | ||
| 130 | __be32 ltedr; /**< Transfer Error Disable Register */ | 142 | __be32 ltedr; /**< Transfer Error Disable Register */ |
| 131 | __be32 lteir; /**< Transfer Error Interrupt Register */ | 143 | __be32 lteir; /**< Transfer Error Interrupt Register */ |
| 132 | __be32 lteatr; /**< Transfer Error Attributes Register */ | 144 | __be32 lteatr; /**< Transfer Error Attributes Register */ |
| 133 | __be32 ltear; /**< Transfer Error Address Register */ | 145 | __be32 ltear; /**< Transfer Error Address Register */ |
| 134 | u8 res6[0xC]; | 146 | __be32 lteccr; /**< Transfer Error ECC Register */ |
| 147 | u8 res6[0x8]; | ||
| 135 | __be32 lbcr; /**< Configuration Register */ | 148 | __be32 lbcr; /**< Configuration Register */ |
| 136 | #define LBCR_LDIS 0x80000000 | 149 | #define LBCR_LDIS 0x80000000 |
| 137 | #define LBCR_LDIS_SHIFT 31 | 150 | #define LBCR_LDIS_SHIFT 31 |
| @@ -235,6 +248,7 @@ struct fsl_upm { | |||
| 235 | int width; | 248 | int width; |
| 236 | }; | 249 | }; |
| 237 | 250 | ||
| 251 | extern u32 fsl_lbc_addr(phys_addr_t addr_base); | ||
| 238 | extern int fsl_lbc_find(phys_addr_t addr_base); | 252 | extern int fsl_lbc_find(phys_addr_t addr_base); |
| 239 | extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm); | 253 | extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm); |
| 240 | 254 | ||
| @@ -265,7 +279,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm) | |||
| 265 | cpu_relax(); | 279 | cpu_relax(); |
| 266 | } | 280 | } |
| 267 | 281 | ||
| 282 | /* overview of the fsl lbc controller */ | ||
| 283 | |||
| 284 | struct fsl_lbc_ctrl { | ||
| 285 | /* device info */ | ||
| 286 | struct device *dev; | ||
| 287 | struct fsl_lbc_regs __iomem *regs; | ||
| 288 | int irq; | ||
| 289 | wait_queue_head_t irq_wait; | ||
| 290 | spinlock_t lock; | ||
| 291 | void *nand; | ||
| 292 | |||
| 293 | /* status read from LTESR by irq handler */ | ||
| 294 | unsigned int irq_status; | ||
| 295 | }; | ||
| 296 | |||
| 268 | extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, | 297 | extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, |
| 269 | u32 mar); | 298 | u32 mar); |
| 299 | extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev; | ||
| 270 | 300 | ||
| 271 | #endif /* __ASM_FSL_LBC_H */ | 301 | #endif /* __ASM_FSL_LBC_H */ |
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index dceb8d1a843d..4fcb5a4e60dd 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Freescale LBC and UPM routines. | 2 | * Freescale LBC and UPM routines. |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2007-2008 MontaVista Software, Inc. | 4 | * Copyright © 2007-2008 MontaVista Software, Inc. |
| 5 | * Copyright © 2010 Freescale Semiconductor | ||
| 5 | * | 6 | * |
| 6 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> | 7 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> |
| 8 | * Author: Jack Lan <Jack.Lan@freescale.com> | ||
| 9 | * Author: Roy Zang <tie-fei.zang@freescale.com> | ||
| 7 | * | 10 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
| @@ -19,39 +22,37 @@ | |||
| 19 | #include <linux/types.h> | 22 | #include <linux/types.h> |
| 20 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 21 | #include <linux/of.h> | 24 | #include <linux/of.h> |
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <linux/mod_devicetable.h> | ||
| 22 | #include <asm/prom.h> | 29 | #include <asm/prom.h> |
| 23 | #include <asm/fsl_lbc.h> | 30 | #include <asm/fsl_lbc.h> |
| 24 | 31 | ||
| 25 | static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); | 32 | static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); |
| 26 | static struct fsl_lbc_regs __iomem *fsl_lbc_regs; | 33 | struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev; |
| 34 | EXPORT_SYMBOL(fsl_lbc_ctrl_dev); | ||
| 27 | 35 | ||
| 28 | static char __initdata *compat_lbc[] = { | 36 | /** |
| 29 | "fsl,pq2-localbus", | 37 | * fsl_lbc_addr - convert the base address |
| 30 | "fsl,pq2pro-localbus", | 38 | * @addr_base: base address of the memory bank |
| 31 | "fsl,pq3-localbus", | 39 | * |
| 32 | "fsl,elbc", | 40 | * This function converts a base address of lbc into the right format for the |
| 33 | }; | 41 | * BR register. If the SOC has eLBC then it returns 32bit physical address |
| 34 | 42 | * else it convers a 34bit local bus physical address to correct format of | |
| 35 | static int __init fsl_lbc_init(void) | 43 | * 32bit address for BR register (Example: MPC8641). |
| 44 | */ | ||
| 45 | u32 fsl_lbc_addr(phys_addr_t addr_base) | ||
| 36 | { | 46 | { |
| 37 | struct device_node *lbus; | 47 | struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node; |
| 38 | int i; | 48 | u32 addr = addr_base & 0xffff8000; |
| 39 | 49 | ||
| 40 | for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) { | 50 | if (of_device_is_compatible(np, "fsl,elbc")) |
| 41 | lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]); | 51 | return addr; |
| 42 | if (lbus) | ||
| 43 | goto found; | ||
| 44 | } | ||
| 45 | return -ENODEV; | ||
| 46 | 52 | ||
| 47 | found: | 53 | return addr | ((addr_base & 0x300000000ull) >> 19); |
| 48 | fsl_lbc_regs = of_iomap(lbus, 0); | ||
| 49 | of_node_put(lbus); | ||
| 50 | if (!fsl_lbc_regs) | ||
| 51 | return -ENOMEM; | ||
| 52 | return 0; | ||
| 53 | } | 54 | } |
| 54 | arch_initcall(fsl_lbc_init); | 55 | EXPORT_SYMBOL(fsl_lbc_addr); |
| 55 | 56 | ||
| 56 | /** | 57 | /** |
| 57 | * fsl_lbc_find - find Localbus bank | 58 | * fsl_lbc_find - find Localbus bank |
| @@ -65,15 +66,17 @@ arch_initcall(fsl_lbc_init); | |||
| 65 | int fsl_lbc_find(phys_addr_t addr_base) | 66 | int fsl_lbc_find(phys_addr_t addr_base) |
| 66 | { | 67 | { |
| 67 | int i; | 68 | int i; |
| 69 | struct fsl_lbc_regs __iomem *lbc; | ||
| 68 | 70 | ||
| 69 | if (!fsl_lbc_regs) | 71 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
| 70 | return -ENODEV; | 72 | return -ENODEV; |
| 71 | 73 | ||
| 72 | for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) { | 74 | lbc = fsl_lbc_ctrl_dev->regs; |
| 73 | __be32 br = in_be32(&fsl_lbc_regs->bank[i].br); | 75 | for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) { |
| 74 | __be32 or = in_be32(&fsl_lbc_regs->bank[i].or); | 76 | __be32 br = in_be32(&lbc->bank[i].br); |
| 77 | __be32 or = in_be32(&lbc->bank[i].or); | ||
| 75 | 78 | ||
| 76 | if (br & BR_V && (br & or & BR_BA) == addr_base) | 79 | if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base)) |
| 77 | return i; | 80 | return i; |
| 78 | } | 81 | } |
| 79 | 82 | ||
| @@ -94,22 +97,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm) | |||
| 94 | { | 97 | { |
| 95 | int bank; | 98 | int bank; |
| 96 | __be32 br; | 99 | __be32 br; |
| 100 | struct fsl_lbc_regs __iomem *lbc; | ||
| 97 | 101 | ||
| 98 | bank = fsl_lbc_find(addr_base); | 102 | bank = fsl_lbc_find(addr_base); |
| 99 | if (bank < 0) | 103 | if (bank < 0) |
| 100 | return bank; | 104 | return bank; |
| 101 | 105 | ||
| 102 | br = in_be32(&fsl_lbc_regs->bank[bank].br); | 106 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
| 107 | return -ENODEV; | ||
| 108 | |||
| 109 | lbc = fsl_lbc_ctrl_dev->regs; | ||
| 110 | br = in_be32(&lbc->bank[bank].br); | ||
| 103 | 111 | ||
| 104 | switch (br & BR_MSEL) { | 112 | switch (br & BR_MSEL) { |
| 105 | case BR_MS_UPMA: | 113 | case BR_MS_UPMA: |
| 106 | upm->mxmr = &fsl_lbc_regs->mamr; | 114 | upm->mxmr = &lbc->mamr; |
| 107 | break; | 115 | break; |
| 108 | case BR_MS_UPMB: | 116 | case BR_MS_UPMB: |
| 109 | upm->mxmr = &fsl_lbc_regs->mbmr; | 117 | upm->mxmr = &lbc->mbmr; |
| 110 | break; | 118 | break; |
| 111 | case BR_MS_UPMC: | 119 | case BR_MS_UPMC: |
| 112 | upm->mxmr = &fsl_lbc_regs->mcmr; | 120 | upm->mxmr = &lbc->mcmr; |
| 113 | break; | 121 | break; |
| 114 | default: | 122 | default: |
| 115 | return -EINVAL; | 123 | return -EINVAL; |
| @@ -148,9 +156,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) | |||
| 148 | int ret = 0; | 156 | int ret = 0; |
| 149 | unsigned long flags; | 157 | unsigned long flags; |
| 150 | 158 | ||
| 159 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) | ||
| 160 | return -ENODEV; | ||
| 161 | |||
| 151 | spin_lock_irqsave(&fsl_lbc_lock, flags); | 162 | spin_lock_irqsave(&fsl_lbc_lock, flags); |
| 152 | 163 | ||
| 153 | out_be32(&fsl_lbc_regs->mar, mar); | 164 | out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar); |
| 154 | 165 | ||
| 155 | switch (upm->width) { | 166 | switch (upm->width) { |
| 156 | case 8: | 167 | case 8: |
| @@ -172,3 +183,166 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) | |||
| 172 | return ret; | 183 | return ret; |
| 173 | } | 184 | } |
| 174 | EXPORT_SYMBOL(fsl_upm_run_pattern); | 185 | EXPORT_SYMBOL(fsl_upm_run_pattern); |
| 186 | |||
| 187 | static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl) | ||
| 188 | { | ||
| 189 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
| 190 | |||
| 191 | /* clear event registers */ | ||
| 192 | setbits32(&lbc->ltesr, LTESR_CLEAR); | ||
| 193 | out_be32(&lbc->lteatr, 0); | ||
| 194 | out_be32(&lbc->ltear, 0); | ||
| 195 | out_be32(&lbc->lteccr, LTECCR_CLEAR); | ||
| 196 | out_be32(&lbc->ltedr, LTEDR_ENABLE); | ||
| 197 | |||
| 198 | /* Enable interrupts for any detected events */ | ||
| 199 | out_be32(&lbc->lteir, LTEIR_ENABLE); | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* | ||
| 205 | * NOTE: This interrupt is used to report localbus events of various kinds, | ||
| 206 | * such as transaction errors on the chipselects. | ||
| 207 | */ | ||
| 208 | |||
| 209 | static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) | ||
| 210 | { | ||
| 211 | struct fsl_lbc_ctrl *ctrl = data; | ||
| 212 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
| 213 | u32 status; | ||
| 214 | |||
| 215 | status = in_be32(&lbc->ltesr); | ||
| 216 | if (!status) | ||
| 217 | return IRQ_NONE; | ||
| 218 | |||
| 219 | out_be32(&lbc->ltesr, LTESR_CLEAR); | ||
| 220 | out_be32(&lbc->lteatr, 0); | ||
| 221 | out_be32(&lbc->ltear, 0); | ||
| 222 | ctrl->irq_status = status; | ||
| 223 | |||
| 224 | if (status & LTESR_BM) | ||
| 225 | dev_err(ctrl->dev, "Local bus monitor time-out: " | ||
| 226 | "LTESR 0x%08X\n", status); | ||
| 227 | if (status & LTESR_WP) | ||
| 228 | dev_err(ctrl->dev, "Write protect error: " | ||
| 229 | "LTESR 0x%08X\n", status); | ||
| 230 | if (status & LTESR_ATMW) | ||
| 231 | dev_err(ctrl->dev, "Atomic write error: " | ||
| 232 | "LTESR 0x%08X\n", status); | ||
| 233 | if (status & LTESR_ATMR) | ||
| 234 | dev_err(ctrl->dev, "Atomic read error: " | ||
| 235 | "LTESR 0x%08X\n", status); | ||
| 236 | if (status & LTESR_CS) | ||
| 237 | dev_err(ctrl->dev, "Chip select error: " | ||
| 238 | "LTESR 0x%08X\n", status); | ||
| 239 | if (status & LTESR_UPM) | ||
| 240 | ; | ||
| 241 | if (status & LTESR_FCT) { | ||
| 242 | dev_err(ctrl->dev, "FCM command time-out: " | ||
| 243 | "LTESR 0x%08X\n", status); | ||
| 244 | smp_wmb(); | ||
| 245 | wake_up(&ctrl->irq_wait); | ||
| 246 | } | ||
| 247 | if (status & LTESR_PAR) { | ||
| 248 | dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: " | ||
| 249 | "LTESR 0x%08X\n", status); | ||
| 250 | smp_wmb(); | ||
| 251 | wake_up(&ctrl->irq_wait); | ||
| 252 | } | ||
| 253 | if (status & LTESR_CC) { | ||
| 254 | smp_wmb(); | ||
| 255 | wake_up(&ctrl->irq_wait); | ||
| 256 | } | ||
| 257 | if (status & ~LTESR_MASK) | ||
| 258 | dev_err(ctrl->dev, "Unknown error: " | ||
| 259 | "LTESR 0x%08X\n", status); | ||
| 260 | return IRQ_HANDLED; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* | ||
| 264 | * fsl_lbc_ctrl_probe | ||
| 265 | * | ||
| 266 | * called by device layer when it finds a device matching | ||
| 267 | * one our driver can handled. This code allocates all of | ||
| 268 | * the resources needed for the controller only. The | ||
| 269 | * resources for the NAND banks themselves are allocated | ||
| 270 | * in the chip probe function. | ||
| 271 | */ | ||
| 272 | |||
| 273 | static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev) | ||
| 274 | { | ||
| 275 | int ret; | ||
| 276 | |||
| 277 | if (!dev->dev.of_node) { | ||
| 278 | dev_err(&dev->dev, "Device OF-Node is NULL"); | ||
| 279 | return -EFAULT; | ||
| 280 | } | ||
| 281 | |||
| 282 | fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL); | ||
| 283 | if (!fsl_lbc_ctrl_dev) | ||
| 284 | return -ENOMEM; | ||
| 285 | |||
| 286 | dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev); | ||
| 287 | |||
| 288 | spin_lock_init(&fsl_lbc_ctrl_dev->lock); | ||
| 289 | init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait); | ||
| 290 | |||
| 291 | fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0); | ||
| 292 | if (!fsl_lbc_ctrl_dev->regs) { | ||
| 293 | dev_err(&dev->dev, "failed to get memory region\n"); | ||
| 294 | ret = -ENODEV; | ||
| 295 | goto err; | ||
| 296 | } | ||
| 297 | |||
| 298 | fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); | ||
| 299 | if (fsl_lbc_ctrl_dev->irq == NO_IRQ) { | ||
| 300 | dev_err(&dev->dev, "failed to get irq resource\n"); | ||
| 301 | ret = -ENODEV; | ||
| 302 | goto err; | ||
| 303 | } | ||
| 304 | |||
| 305 | fsl_lbc_ctrl_dev->dev = &dev->dev; | ||
| 306 | |||
| 307 | ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev); | ||
| 308 | if (ret < 0) | ||
| 309 | goto err; | ||
| 310 | |||
| 311 | ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0, | ||
| 312 | "fsl-lbc", fsl_lbc_ctrl_dev); | ||
| 313 | if (ret != 0) { | ||
| 314 | dev_err(&dev->dev, "failed to install irq (%d)\n", | ||
| 315 | fsl_lbc_ctrl_dev->irq); | ||
| 316 | ret = fsl_lbc_ctrl_dev->irq; | ||
| 317 | goto err; | ||
| 318 | } | ||
| 319 | |||
| 320 | return 0; | ||
| 321 | |||
| 322 | err: | ||
| 323 | iounmap(fsl_lbc_ctrl_dev->regs); | ||
| 324 | kfree(fsl_lbc_ctrl_dev); | ||
| 325 | return ret; | ||
| 326 | } | ||
| 327 | |||
| 328 | static const struct of_device_id fsl_lbc_match[] = { | ||
| 329 | { .compatible = "fsl,elbc", }, | ||
| 330 | { .compatible = "fsl,pq3-localbus", }, | ||
| 331 | { .compatible = "fsl,pq2-localbus", }, | ||
| 332 | { .compatible = "fsl,pq2pro-localbus", }, | ||
| 333 | {}, | ||
| 334 | }; | ||
| 335 | |||
| 336 | static struct platform_driver fsl_lbc_ctrl_driver = { | ||
| 337 | .driver = { | ||
| 338 | .name = "fsl-lbc", | ||
| 339 | .of_match_table = fsl_lbc_match, | ||
| 340 | }, | ||
| 341 | .probe = fsl_lbc_ctrl_probe, | ||
| 342 | }; | ||
| 343 | |||
| 344 | static int __init fsl_lbc_init(void) | ||
| 345 | { | ||
| 346 | return platform_driver_register(&fsl_lbc_ctrl_driver); | ||
| 347 | } | ||
| 348 | module_init(fsl_lbc_init); | ||
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 881a3a5f5647..07ea908c510d 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c | |||
| @@ -176,6 +176,21 @@ static void ap320_wvga_power_off(void *board_data) | |||
| 176 | __raw_writew(0, FPGA_LCDREG); | 176 | __raw_writew(0, FPGA_LCDREG); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | const static struct fb_videomode ap325rxa_lcdc_modes[] = { | ||
| 180 | { | ||
| 181 | .name = "LB070WV1", | ||
| 182 | .xres = 800, | ||
| 183 | .yres = 480, | ||
| 184 | .left_margin = 32, | ||
| 185 | .right_margin = 160, | ||
| 186 | .hsync_len = 8, | ||
| 187 | .upper_margin = 63, | ||
| 188 | .lower_margin = 80, | ||
| 189 | .vsync_len = 1, | ||
| 190 | .sync = 0, /* hsync and vsync are active low */ | ||
| 191 | }, | ||
| 192 | }; | ||
| 193 | |||
| 179 | static struct sh_mobile_lcdc_info lcdc_info = { | 194 | static struct sh_mobile_lcdc_info lcdc_info = { |
| 180 | .clock_source = LCDC_CLK_EXTERNAL, | 195 | .clock_source = LCDC_CLK_EXTERNAL, |
| 181 | .ch[0] = { | 196 | .ch[0] = { |
| @@ -183,18 +198,8 @@ static struct sh_mobile_lcdc_info lcdc_info = { | |||
| 183 | .bpp = 16, | 198 | .bpp = 16, |
| 184 | .interface_type = RGB18, | 199 | .interface_type = RGB18, |
| 185 | .clock_divider = 1, | 200 | .clock_divider = 1, |
| 186 | .lcd_cfg = { | 201 | .lcd_cfg = ap325rxa_lcdc_modes, |
| 187 | .name = "LB070WV1", | 202 | .num_cfg = ARRAY_SIZE(ap325rxa_lcdc_modes), |
| 188 | .xres = 800, | ||
| 189 | .yres = 480, | ||
| 190 | .left_margin = 32, | ||
| 191 | .right_margin = 160, | ||
| 192 | .hsync_len = 8, | ||
| 193 | .upper_margin = 63, | ||
| 194 | .lower_margin = 80, | ||
| 195 | .vsync_len = 1, | ||
| 196 | .sync = 0, /* hsync and vsync are active low */ | ||
| 197 | }, | ||
| 198 | .lcd_size_cfg = { /* 7.0 inch */ | 203 | .lcd_size_cfg = { /* 7.0 inch */ |
| 199 | .width = 152, | 204 | .width = 152, |
| 200 | .height = 91, | 205 | .height = 91, |
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index ddc7e4e4d2a0..2eaeb9e59585 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c | |||
| @@ -231,14 +231,41 @@ static struct platform_device usb1_common_device = { | |||
| 231 | }; | 231 | }; |
| 232 | 232 | ||
| 233 | /* LCDC */ | 233 | /* LCDC */ |
| 234 | const static struct fb_videomode ecovec_lcd_modes[] = { | ||
| 235 | { | ||
| 236 | .name = "Panel", | ||
| 237 | .xres = 800, | ||
| 238 | .yres = 480, | ||
| 239 | .left_margin = 220, | ||
| 240 | .right_margin = 110, | ||
| 241 | .hsync_len = 70, | ||
| 242 | .upper_margin = 20, | ||
| 243 | .lower_margin = 5, | ||
| 244 | .vsync_len = 5, | ||
| 245 | .sync = 0, /* hsync and vsync are active low */ | ||
| 246 | }, | ||
| 247 | }; | ||
| 248 | |||
| 249 | const static struct fb_videomode ecovec_dvi_modes[] = { | ||
| 250 | { | ||
| 251 | .name = "DVI", | ||
| 252 | .xres = 1280, | ||
| 253 | .yres = 720, | ||
| 254 | .left_margin = 220, | ||
| 255 | .right_margin = 110, | ||
| 256 | .hsync_len = 40, | ||
| 257 | .upper_margin = 20, | ||
| 258 | .lower_margin = 5, | ||
| 259 | .vsync_len = 5, | ||
| 260 | .sync = 0, /* hsync and vsync are active low */ | ||
| 261 | }, | ||
| 262 | }; | ||
| 263 | |||
| 234 | static struct sh_mobile_lcdc_info lcdc_info = { | 264 | static struct sh_mobile_lcdc_info lcdc_info = { |
| 235 | .ch[0] = { | 265 | .ch[0] = { |
| 236 | .interface_type = RGB18, | 266 | .interface_type = RGB18, |
| 237 | .chan = LCDC_CHAN_MAINLCD, | 267 | .chan = LCDC_CHAN_MAINLCD, |
| 238 | .bpp = 16, | 268 | .bpp = 16, |
| 239 | .lcd_cfg = { | ||
| 240 | .sync = 0, /* hsync and vsync are active low */ | ||
| 241 | }, | ||
| 242 | .lcd_size_cfg = { /* 7.0 inch */ | 269 | .lcd_size_cfg = { /* 7.0 inch */ |
| 243 | .width = 152, | 270 | .width = 152, |
| 244 | .height = 91, | 271 | .height = 91, |
| @@ -1075,33 +1102,18 @@ static int __init arch_setup(void) | |||
| 1075 | if (gpio_get_value(GPIO_PTE6)) { | 1102 | if (gpio_get_value(GPIO_PTE6)) { |
| 1076 | /* DVI */ | 1103 | /* DVI */ |
| 1077 | lcdc_info.clock_source = LCDC_CLK_EXTERNAL; | 1104 | lcdc_info.clock_source = LCDC_CLK_EXTERNAL; |
| 1078 | lcdc_info.ch[0].clock_divider = 1, | 1105 | lcdc_info.ch[0].clock_divider = 1; |
| 1079 | lcdc_info.ch[0].lcd_cfg.name = "DVI"; | 1106 | lcdc_info.ch[0].lcd_cfg = ecovec_dvi_modes; |
| 1080 | lcdc_info.ch[0].lcd_cfg.xres = 1280; | 1107 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(ecovec_dvi_modes); |
| 1081 | lcdc_info.ch[0].lcd_cfg.yres = 720; | ||
| 1082 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
| 1083 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
| 1084 | lcdc_info.ch[0].lcd_cfg.hsync_len = 40; | ||
| 1085 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
| 1086 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
| 1087 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
| 1088 | 1108 | ||
| 1089 | gpio_set_value(GPIO_PTA2, 1); | 1109 | gpio_set_value(GPIO_PTA2, 1); |
| 1090 | gpio_set_value(GPIO_PTU1, 1); | 1110 | gpio_set_value(GPIO_PTU1, 1); |
| 1091 | } else { | 1111 | } else { |
| 1092 | /* Panel */ | 1112 | /* Panel */ |
| 1093 | |||
| 1094 | lcdc_info.clock_source = LCDC_CLK_PERIPHERAL; | 1113 | lcdc_info.clock_source = LCDC_CLK_PERIPHERAL; |
| 1095 | lcdc_info.ch[0].clock_divider = 2, | 1114 | lcdc_info.ch[0].clock_divider = 2; |
| 1096 | lcdc_info.ch[0].lcd_cfg.name = "Panel"; | 1115 | lcdc_info.ch[0].lcd_cfg = ecovec_lcd_modes; |
| 1097 | lcdc_info.ch[0].lcd_cfg.xres = 800; | 1116 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(ecovec_lcd_modes); |
| 1098 | lcdc_info.ch[0].lcd_cfg.yres = 480; | ||
| 1099 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
| 1100 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
| 1101 | lcdc_info.ch[0].lcd_cfg.hsync_len = 70; | ||
| 1102 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
| 1103 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
| 1104 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
| 1105 | 1117 | ||
| 1106 | gpio_set_value(GPIO_PTR1, 1); | 1118 | gpio_set_value(GPIO_PTR1, 1); |
| 1107 | 1119 | ||
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 1742849db648..9b60eaabf8f3 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c | |||
| @@ -126,6 +126,21 @@ static struct platform_device kfr2r09_sh_keysc_device = { | |||
| 126 | }, | 126 | }, |
| 127 | }; | 127 | }; |
| 128 | 128 | ||
| 129 | const static struct fb_videomode kfr2r09_lcdc_modes[] = { | ||
| 130 | { | ||
| 131 | .name = "TX07D34VM0AAA", | ||
| 132 | .xres = 240, | ||
| 133 | .yres = 400, | ||
| 134 | .left_margin = 0, | ||
| 135 | .right_margin = 16, | ||
| 136 | .hsync_len = 8, | ||
| 137 | .upper_margin = 0, | ||
| 138 | .lower_margin = 1, | ||
| 139 | .vsync_len = 1, | ||
| 140 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
| 141 | }, | ||
| 142 | }; | ||
| 143 | |||
| 129 | static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { | 144 | static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { |
| 130 | .clock_source = LCDC_CLK_BUS, | 145 | .clock_source = LCDC_CLK_BUS, |
| 131 | .ch[0] = { | 146 | .ch[0] = { |
| @@ -134,18 +149,8 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { | |||
| 134 | .interface_type = SYS18, | 149 | .interface_type = SYS18, |
| 135 | .clock_divider = 6, | 150 | .clock_divider = 6, |
| 136 | .flags = LCDC_FLAGS_DWPOL, | 151 | .flags = LCDC_FLAGS_DWPOL, |
| 137 | .lcd_cfg = { | 152 | .lcd_cfg = kfr2r09_lcdc_modes, |
| 138 | .name = "TX07D34VM0AAA", | 153 | .num_cfg = ARRAY_SIZE(kfr2r09_lcdc_modes), |
| 139 | .xres = 240, | ||
| 140 | .yres = 400, | ||
| 141 | .left_margin = 0, | ||
| 142 | .right_margin = 16, | ||
| 143 | .hsync_len = 8, | ||
| 144 | .upper_margin = 0, | ||
| 145 | .lower_margin = 1, | ||
| 146 | .vsync_len = 1, | ||
| 147 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
| 148 | }, | ||
| 149 | .lcd_size_cfg = { | 154 | .lcd_size_cfg = { |
| 150 | .width = 35, | 155 | .width = 35, |
| 151 | .height = 58, | 156 | .height = 58, |
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 03af84842559..c8acfec98695 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
| @@ -213,51 +213,55 @@ static struct platform_device migor_nand_flash_device = { | |||
| 213 | } | 213 | } |
| 214 | }; | 214 | }; |
| 215 | 215 | ||
| 216 | const static struct fb_videomode migor_lcd_modes[] = { | ||
| 217 | { | ||
| 218 | #if defined(CONFIG_SH_MIGOR_RTA_WVGA) | ||
| 219 | .name = "LB070WV1", | ||
| 220 | .xres = 800, | ||
| 221 | .yres = 480, | ||
| 222 | .left_margin = 64, | ||
| 223 | .right_margin = 16, | ||
| 224 | .hsync_len = 120, | ||
| 225 | .sync = 0, | ||
| 226 | #elif defined(CONFIG_SH_MIGOR_QVGA) | ||
| 227 | .name = "PH240320T", | ||
| 228 | .xres = 320, | ||
| 229 | .yres = 240, | ||
| 230 | .left_margin = 0, | ||
| 231 | .right_margin = 16, | ||
| 232 | .hsync_len = 8, | ||
| 233 | .sync = FB_SYNC_HOR_HIGH_ACT, | ||
| 234 | #endif | ||
| 235 | .upper_margin = 1, | ||
| 236 | .lower_margin = 17, | ||
| 237 | .vsync_len = 2, | ||
| 238 | }, | ||
| 239 | }; | ||
| 240 | |||
| 216 | static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { | 241 | static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { |
| 217 | #ifdef CONFIG_SH_MIGOR_RTA_WVGA | 242 | #if defined(CONFIG_SH_MIGOR_RTA_WVGA) |
| 218 | .clock_source = LCDC_CLK_BUS, | 243 | .clock_source = LCDC_CLK_BUS, |
| 219 | .ch[0] = { | 244 | .ch[0] = { |
| 220 | .chan = LCDC_CHAN_MAINLCD, | 245 | .chan = LCDC_CHAN_MAINLCD, |
| 221 | .bpp = 16, | 246 | .bpp = 16, |
| 222 | .interface_type = RGB16, | 247 | .interface_type = RGB16, |
| 223 | .clock_divider = 2, | 248 | .clock_divider = 2, |
| 224 | .lcd_cfg = { | 249 | .lcd_cfg = migor_lcd_modes, |
| 225 | .name = "LB070WV1", | 250 | .num_cfg = ARRAY_SIZE(migor_lcd_modes), |
| 226 | .xres = 800, | ||
| 227 | .yres = 480, | ||
| 228 | .left_margin = 64, | ||
| 229 | .right_margin = 16, | ||
| 230 | .hsync_len = 120, | ||
| 231 | .upper_margin = 1, | ||
| 232 | .lower_margin = 17, | ||
| 233 | .vsync_len = 2, | ||
| 234 | .sync = 0, | ||
| 235 | }, | ||
| 236 | .lcd_size_cfg = { /* 7.0 inch */ | 251 | .lcd_size_cfg = { /* 7.0 inch */ |
| 237 | .width = 152, | 252 | .width = 152, |
| 238 | .height = 91, | 253 | .height = 91, |
| 239 | }, | 254 | }, |
| 240 | } | 255 | } |
| 241 | #endif | 256 | #elif defined(CONFIG_SH_MIGOR_QVGA) |
| 242 | #ifdef CONFIG_SH_MIGOR_QVGA | ||
| 243 | .clock_source = LCDC_CLK_PERIPHERAL, | 257 | .clock_source = LCDC_CLK_PERIPHERAL, |
| 244 | .ch[0] = { | 258 | .ch[0] = { |
| 245 | .chan = LCDC_CHAN_MAINLCD, | 259 | .chan = LCDC_CHAN_MAINLCD, |
| 246 | .bpp = 16, | 260 | .bpp = 16, |
| 247 | .interface_type = SYS16A, | 261 | .interface_type = SYS16A, |
| 248 | .clock_divider = 10, | 262 | .clock_divider = 10, |
| 249 | .lcd_cfg = { | 263 | .lcd_cfg = migor_lcd_modes, |
| 250 | .name = "PH240320T", | 264 | .num_cfg = ARRAY_SIZE(migor_lcd_modes), |
| 251 | .xres = 320, | ||
| 252 | .yres = 240, | ||
| 253 | .left_margin = 0, | ||
| 254 | .right_margin = 16, | ||
| 255 | .hsync_len = 8, | ||
| 256 | .upper_margin = 1, | ||
| 257 | .lower_margin = 17, | ||
| 258 | .vsync_len = 2, | ||
| 259 | .sync = FB_SYNC_HOR_HIGH_ACT, | ||
| 260 | }, | ||
| 261 | .lcd_size_cfg = { /* 2.4 inch */ | 265 | .lcd_size_cfg = { /* 2.4 inch */ |
| 262 | .width = 49, | 266 | .width = 49, |
| 263 | .height = 37, | 267 | .height = 37, |
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 8cc1d7295d85..c31d228fdfc6 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c | |||
| @@ -144,16 +144,42 @@ static struct platform_device nor_flash_device = { | |||
| 144 | }; | 144 | }; |
| 145 | 145 | ||
| 146 | /* LCDC */ | 146 | /* LCDC */ |
| 147 | const static struct fb_videomode lcdc_720p_modes[] = { | ||
| 148 | { | ||
| 149 | .name = "LB070WV1", | ||
| 150 | .sync = 0, /* hsync and vsync are active low */ | ||
| 151 | .xres = 1280, | ||
| 152 | .yres = 720, | ||
| 153 | .left_margin = 220, | ||
| 154 | .right_margin = 110, | ||
| 155 | .hsync_len = 40, | ||
| 156 | .upper_margin = 20, | ||
| 157 | .lower_margin = 5, | ||
| 158 | .vsync_len = 5, | ||
| 159 | }, | ||
| 160 | }; | ||
| 161 | |||
| 162 | const static struct fb_videomode lcdc_vga_modes[] = { | ||
| 163 | { | ||
| 164 | .name = "LB070WV1", | ||
| 165 | .sync = 0, /* hsync and vsync are active low */ | ||
| 166 | .xres = 640, | ||
| 167 | .yres = 480, | ||
| 168 | .left_margin = 105, | ||
| 169 | .right_margin = 50, | ||
| 170 | .hsync_len = 96, | ||
| 171 | .upper_margin = 33, | ||
| 172 | .lower_margin = 10, | ||
| 173 | .vsync_len = 2, | ||
| 174 | }, | ||
| 175 | }; | ||
| 176 | |||
| 147 | static struct sh_mobile_lcdc_info lcdc_info = { | 177 | static struct sh_mobile_lcdc_info lcdc_info = { |
| 148 | .clock_source = LCDC_CLK_EXTERNAL, | 178 | .clock_source = LCDC_CLK_EXTERNAL, |
| 149 | .ch[0] = { | 179 | .ch[0] = { |
| 150 | .chan = LCDC_CHAN_MAINLCD, | 180 | .chan = LCDC_CHAN_MAINLCD, |
| 151 | .bpp = 16, | 181 | .bpp = 16, |
| 152 | .clock_divider = 1, | 182 | .clock_divider = 1, |
| 153 | .lcd_cfg = { | ||
| 154 | .name = "LB070WV1", | ||
| 155 | .sync = 0, /* hsync and vsync are active low */ | ||
| 156 | }, | ||
| 157 | .lcd_size_cfg = { /* 7.0 inch */ | 183 | .lcd_size_cfg = { /* 7.0 inch */ |
| 158 | .width = 152, | 184 | .width = 152, |
| 159 | .height = 91, | 185 | .height = 91, |
| @@ -908,24 +934,12 @@ static int __init devices_setup(void) | |||
| 908 | 934 | ||
| 909 | if (sw & SW41_B) { | 935 | if (sw & SW41_B) { |
| 910 | /* 720p */ | 936 | /* 720p */ |
| 911 | lcdc_info.ch[0].lcd_cfg.xres = 1280; | 937 | lcdc_info.ch[0].lcd_cfg = lcdc_720p_modes; |
| 912 | lcdc_info.ch[0].lcd_cfg.yres = 720; | 938 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(lcdc_720p_modes); |
| 913 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
| 914 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
| 915 | lcdc_info.ch[0].lcd_cfg.hsync_len = 40; | ||
| 916 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
| 917 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
| 918 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
| 919 | } else { | 939 | } else { |
| 920 | /* VGA */ | 940 | /* VGA */ |
| 921 | lcdc_info.ch[0].lcd_cfg.xres = 640; | 941 | lcdc_info.ch[0].lcd_cfg = lcdc_vga_modes; |
| 922 | lcdc_info.ch[0].lcd_cfg.yres = 480; | 942 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(lcdc_vga_modes); |
| 923 | lcdc_info.ch[0].lcd_cfg.left_margin = 105; | ||
| 924 | lcdc_info.ch[0].lcd_cfg.right_margin = 50; | ||
| 925 | lcdc_info.ch[0].lcd_cfg.hsync_len = 96; | ||
| 926 | lcdc_info.ch[0].lcd_cfg.upper_margin = 33; | ||
| 927 | lcdc_info.ch[0].lcd_cfg.lower_margin = 10; | ||
| 928 | lcdc_info.ch[0].lcd_cfg.vsync_len = 2; | ||
| 929 | } | 943 | } |
| 930 | 944 | ||
| 931 | if (sw & SW41_A) { | 945 | if (sw & SW41_A) { |
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h index 65c0d3029796..427d4684e0d2 100644 --- a/arch/sparc/include/asm/jump_label.h +++ b/arch/sparc/include/asm/jump_label.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | "nop\n\t" \ | 13 | "nop\n\t" \ |
| 14 | "nop\n\t" \ | 14 | "nop\n\t" \ |
| 15 | ".pushsection __jump_table, \"a\"\n\t"\ | 15 | ".pushsection __jump_table, \"a\"\n\t"\ |
| 16 | ".align 4\n\t" \ | ||
| 16 | ".word 1b, %l[" #label "], %c0\n\t" \ | 17 | ".word 1b, %l[" #label "], %c0\n\t" \ |
| 17 | ".popsection \n\t" \ | 18 | ".popsection \n\t" \ |
| 18 | : : "i" (key) : : label);\ | 19 | : : "i" (key) : : label);\ |
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index 1255d953c65d..f2ee1abb1df9 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu | |||
| @@ -51,7 +51,18 @@ cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686)) | |||
| 51 | # prologue (push %ebp, mov %esp, %ebp) which breaks the function graph | 51 | # prologue (push %ebp, mov %esp, %ebp) which breaks the function graph |
| 52 | # tracer assumptions. For i686, generic, core2 this is set by the | 52 | # tracer assumptions. For i686, generic, core2 this is set by the |
| 53 | # compiler anyway | 53 | # compiler anyway |
| 54 | cflags-$(CONFIG_FUNCTION_GRAPH_TRACER) += $(call cc-option,-maccumulate-outgoing-args) | 54 | ifeq ($(CONFIG_FUNCTION_GRAPH_TRACER), y) |
| 55 | ADD_ACCUMULATE_OUTGOING_ARGS := y | ||
| 56 | endif | ||
| 57 | |||
| 58 | # Work around to a bug with asm goto with first implementations of it | ||
| 59 | # in gcc causing gcc to mess up the push and pop of the stack in some | ||
| 60 | # uses of asm goto. | ||
| 61 | ifeq ($(CONFIG_JUMP_LABEL), y) | ||
| 62 | ADD_ACCUMULATE_OUTGOING_ARGS := y | ||
| 63 | endif | ||
| 64 | |||
| 65 | cflags-$(ADD_ACCUMULATE_OUTGOING_ARGS) += $(call cc-option,-maccumulate-outgoing-args) | ||
| 55 | 66 | ||
| 56 | # Bug fix for binutils: this option is required in order to keep | 67 | # Bug fix for binutils: this option is required in order to keep |
| 57 | # binutils from generating NOPL instructions against our will. | 68 | # binutils from generating NOPL instructions against our will. |
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 5ceeca382820..5079f24c955a 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
| @@ -644,65 +644,26 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) | |||
| 644 | 644 | ||
| 645 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) | 645 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) |
| 646 | 646 | ||
| 647 | unsigned char ideal_nop5[IDEAL_NOP_SIZE_5]; | 647 | #ifdef CONFIG_X86_64 |
| 648 | unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 }; | ||
| 649 | #else | ||
| 650 | unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; | ||
| 651 | #endif | ||
| 648 | 652 | ||
| 649 | void __init arch_init_ideal_nop5(void) | 653 | void __init arch_init_ideal_nop5(void) |
| 650 | { | 654 | { |
| 651 | extern const unsigned char ftrace_test_p6nop[]; | ||
| 652 | extern const unsigned char ftrace_test_nop5[]; | ||
| 653 | extern const unsigned char ftrace_test_jmp[]; | ||
| 654 | int faulted = 0; | ||
| 655 | |||
| 656 | /* | 655 | /* |
| 657 | * There is no good nop for all x86 archs. | 656 | * There is no good nop for all x86 archs. This selection |
| 658 | * We will default to using the P6_NOP5, but first we | 657 | * algorithm should be unified with the one in find_nop_table(), |
| 659 | * will test to make sure that the nop will actually | 658 | * but this should be good enough for now. |
| 660 | * work on this CPU. If it faults, we will then | ||
| 661 | * go to a lesser efficient 5 byte nop. If that fails | ||
| 662 | * we then just use a jmp as our nop. This isn't the most | ||
| 663 | * efficient nop, but we can not use a multi part nop | ||
| 664 | * since we would then risk being preempted in the middle | ||
| 665 | * of that nop, and if we enabled tracing then, it might | ||
| 666 | * cause a system crash. | ||
| 667 | * | 659 | * |
| 668 | * TODO: check the cpuid to determine the best nop. | 660 | * For cases other than the ones below, use the safe (as in |
| 661 | * always functional) defaults above. | ||
| 669 | */ | 662 | */ |
| 670 | asm volatile ( | 663 | #ifdef CONFIG_X86_64 |
| 671 | "ftrace_test_jmp:" | 664 | /* Don't use these on 32 bits due to broken virtualizers */ |
| 672 | "jmp ftrace_test_p6nop\n" | 665 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) |
| 673 | "nop\n" | 666 | memcpy(ideal_nop5, p6_nops[5], 5); |
| 674 | "nop\n" | 667 | #endif |
| 675 | "nop\n" /* 2 byte jmp + 3 bytes */ | ||
| 676 | "ftrace_test_p6nop:" | ||
| 677 | P6_NOP5 | ||
| 678 | "jmp 1f\n" | ||
| 679 | "ftrace_test_nop5:" | ||
| 680 | ".byte 0x66,0x66,0x66,0x66,0x90\n" | ||
| 681 | "1:" | ||
| 682 | ".section .fixup, \"ax\"\n" | ||
| 683 | "2: movl $1, %0\n" | ||
| 684 | " jmp ftrace_test_nop5\n" | ||
| 685 | "3: movl $2, %0\n" | ||
| 686 | " jmp 1b\n" | ||
| 687 | ".previous\n" | ||
| 688 | _ASM_EXTABLE(ftrace_test_p6nop, 2b) | ||
| 689 | _ASM_EXTABLE(ftrace_test_nop5, 3b) | ||
| 690 | : "=r"(faulted) : "0" (faulted)); | ||
| 691 | |||
| 692 | switch (faulted) { | ||
| 693 | case 0: | ||
| 694 | pr_info("converting mcount calls to 0f 1f 44 00 00\n"); | ||
| 695 | memcpy(ideal_nop5, ftrace_test_p6nop, IDEAL_NOP_SIZE_5); | ||
| 696 | break; | ||
| 697 | case 1: | ||
| 698 | pr_info("converting mcount calls to 66 66 66 66 90\n"); | ||
| 699 | memcpy(ideal_nop5, ftrace_test_nop5, IDEAL_NOP_SIZE_5); | ||
| 700 | break; | ||
| 701 | case 2: | ||
| 702 | pr_info("converting mcount calls to jmp . + 5\n"); | ||
| 703 | memcpy(ideal_nop5, ftrace_test_jmp, IDEAL_NOP_SIZE_5); | ||
| 704 | break; | ||
| 705 | } | ||
| 706 | |||
| 707 | } | 668 | } |
| 708 | #endif | 669 | #endif |
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 1b8ee590b4ca..f64582b0f623 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c | |||
| @@ -188,25 +188,43 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) | |||
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | /** | 190 | /** |
| 191 | * tty_audit_push_task - Flush task's pending audit data | 191 | * tty_audit_push_task - Flush task's pending audit data |
| 192 | * @tsk: task pointer | ||
| 193 | * @loginuid: sender login uid | ||
| 194 | * @sessionid: sender session id | ||
| 195 | * | ||
| 196 | * Called with a ref on @tsk held. Try to lock sighand and get a | ||
| 197 | * reference to the tty audit buffer if available. | ||
| 198 | * Flush the buffer or return an appropriate error code. | ||
| 192 | */ | 199 | */ |
| 193 | void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) | 200 | int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) |
| 194 | { | 201 | { |
| 195 | struct tty_audit_buf *buf; | 202 | struct tty_audit_buf *buf = ERR_PTR(-EPERM); |
| 203 | unsigned long flags; | ||
| 196 | 204 | ||
| 197 | spin_lock_irq(&tsk->sighand->siglock); | 205 | if (!lock_task_sighand(tsk, &flags)) |
| 198 | buf = tsk->signal->tty_audit_buf; | 206 | return -ESRCH; |
| 199 | if (buf) | 207 | |
| 200 | atomic_inc(&buf->count); | 208 | if (tsk->signal->audit_tty) { |
| 201 | spin_unlock_irq(&tsk->sighand->siglock); | 209 | buf = tsk->signal->tty_audit_buf; |
| 202 | if (!buf) | 210 | if (buf) |
| 203 | return; | 211 | atomic_inc(&buf->count); |
| 212 | } | ||
| 213 | unlock_task_sighand(tsk, &flags); | ||
| 214 | |||
| 215 | /* | ||
| 216 | * Return 0 when signal->audit_tty set | ||
| 217 | * but tsk->signal->tty_audit_buf == NULL. | ||
| 218 | */ | ||
| 219 | if (!buf || IS_ERR(buf)) | ||
| 220 | return PTR_ERR(buf); | ||
| 204 | 221 | ||
| 205 | mutex_lock(&buf->mutex); | 222 | mutex_lock(&buf->mutex); |
| 206 | tty_audit_buf_push(tsk, loginuid, sessionid, buf); | 223 | tty_audit_buf_push(tsk, loginuid, sessionid, buf); |
| 207 | mutex_unlock(&buf->mutex); | 224 | mutex_unlock(&buf->mutex); |
| 208 | 225 | ||
| 209 | tty_audit_buf_put(buf); | 226 | tty_audit_buf_put(buf); |
| 227 | return 0; | ||
| 210 | } | 228 | } |
| 211 | 229 | ||
| 212 | /** | 230 | /** |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 9e2b7e9e0ad9..ad9268b44416 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
| @@ -1496,7 +1496,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
| 1496 | 1496 | ||
| 1497 | switch (mode) { | 1497 | switch (mode) { |
| 1498 | case FL_WRITING: | 1498 | case FL_WRITING: |
| 1499 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); | 1499 | write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0x40) : CMD(0x41); |
| 1500 | break; | 1500 | break; |
| 1501 | case FL_OTP_WRITE: | 1501 | case FL_OTP_WRITE: |
| 1502 | write_cmd = CMD(0xc0); | 1502 | write_cmd = CMD(0xc0); |
| @@ -1661,7 +1661,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
| 1661 | cmd_adr = adr & ~(wbufsize-1); | 1661 | cmd_adr = adr & ~(wbufsize-1); |
| 1662 | 1662 | ||
| 1663 | /* Let's determine this according to the interleave only once */ | 1663 | /* Let's determine this according to the interleave only once */ |
| 1664 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); | 1664 | write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0xe8) : CMD(0xe9); |
| 1665 | 1665 | ||
| 1666 | mutex_lock(&chip->mutex); | 1666 | mutex_lock(&chip->mutex); |
| 1667 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); | 1667 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index ba29d2f0ffd7..3b8e32d87977 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
| @@ -291,6 +291,23 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) | |||
| 291 | 291 | ||
| 292 | cfi->addr_unlock1 = 0x555; | 292 | cfi->addr_unlock1 = 0x555; |
| 293 | cfi->addr_unlock2 = 0x2AA; | 293 | cfi->addr_unlock2 = 0x2AA; |
| 294 | |||
| 295 | cfi->sector_erase_cmd = CMD(0x50); | ||
| 296 | } | ||
| 297 | |||
| 298 | static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) | ||
| 299 | { | ||
| 300 | struct map_info *map = mtd->priv; | ||
| 301 | struct cfi_private *cfi = map->fldrv_priv; | ||
| 302 | |||
| 303 | fixup_sst39vf_rev_b(mtd, param); | ||
| 304 | |||
| 305 | /* | ||
| 306 | * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where | ||
| 307 | * it should report a size of 8KBytes (0x0020*256). | ||
| 308 | */ | ||
| 309 | cfi->cfiq->EraseRegionInfo[0] = 0x002003ff; | ||
| 310 | pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name); | ||
| 294 | } | 311 | } |
| 295 | 312 | ||
| 296 | static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) | 313 | static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) |
| @@ -317,14 +334,14 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) | |||
| 317 | 334 | ||
| 318 | /* Used to fix CFI-Tables of chips without Extended Query Tables */ | 335 | /* Used to fix CFI-Tables of chips without Extended Query Tables */ |
| 319 | static struct cfi_fixup cfi_nopri_fixup_table[] = { | 336 | static struct cfi_fixup cfi_nopri_fixup_table[] = { |
| 320 | { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, // SST39VF1602 | 337 | { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */ |
| 321 | { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, // SST39VF1601 | 338 | { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */ |
| 322 | { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, // SST39VF3202 | 339 | { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */ |
| 323 | { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, // SST39VF3201 | 340 | { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */ |
| 324 | { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, // SST39VF3202B | 341 | { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */ |
| 325 | { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, // SST39VF3201B | 342 | { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */ |
| 326 | { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, // SST39VF6402B | 343 | { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */ |
| 327 | { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, // SST39VF6401B | 344 | { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */ |
| 328 | { 0, 0, NULL, NULL } | 345 | { 0, 0, NULL, NULL } |
| 329 | }; | 346 | }; |
| 330 | 347 | ||
| @@ -344,6 +361,10 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
| 344 | { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, | 361 | { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, |
| 345 | { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, | 362 | { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, |
| 346 | { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, | 363 | { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, |
| 364 | { CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */ | ||
| 365 | { CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */ | ||
| 366 | { CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */ | ||
| 367 | { CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */ | ||
| 347 | #if !FORCE_WORD_WRITE | 368 | #if !FORCE_WORD_WRITE |
| 348 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, | 369 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, |
| 349 | #endif | 370 | #endif |
| @@ -374,6 +395,13 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, | |||
| 374 | if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && | 395 | if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && |
| 375 | extp->MajorVersion == '0') | 396 | extp->MajorVersion == '0') |
| 376 | extp->MajorVersion = '1'; | 397 | extp->MajorVersion = '1'; |
| 398 | /* | ||
| 399 | * SST 38VF640x chips report major=0xFF / minor=0xFF. | ||
| 400 | */ | ||
| 401 | if (cfi->mfr == CFI_MFR_SST && (cfi->id >> 4) == 0x0536) { | ||
| 402 | extp->MajorVersion = '1'; | ||
| 403 | extp->MinorVersion = '0'; | ||
| 404 | } | ||
| 377 | } | 405 | } |
| 378 | 406 | ||
| 379 | struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | 407 | struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) |
| @@ -545,15 +573,6 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) | |||
| 545 | printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); | 573 | printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); |
| 546 | goto setup_err; | 574 | goto setup_err; |
| 547 | } | 575 | } |
| 548 | #if 0 | ||
| 549 | // debug | ||
| 550 | for (i=0; i<mtd->numeraseregions;i++){ | ||
| 551 | printk("%d: offset=0x%x,size=0x%x,blocks=%d\n", | ||
| 552 | i,mtd->eraseregions[i].offset, | ||
| 553 | mtd->eraseregions[i].erasesize, | ||
| 554 | mtd->eraseregions[i].numblocks); | ||
| 555 | } | ||
| 556 | #endif | ||
| 557 | 576 | ||
| 558 | __module_get(THIS_MODULE); | 577 | __module_get(THIS_MODULE); |
| 559 | register_reboot_notifier(&mtd->reboot_notifier); | 578 | register_reboot_notifier(&mtd->reboot_notifier); |
| @@ -674,7 +693,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
| 674 | * there was an error (so leave the erase | 693 | * there was an error (so leave the erase |
| 675 | * routine to recover from it) or we trying to | 694 | * routine to recover from it) or we trying to |
| 676 | * use the erase-in-progress sector. */ | 695 | * use the erase-in-progress sector. */ |
| 677 | map_write(map, CMD(0x30), chip->in_progress_block_addr); | 696 | map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); |
| 678 | chip->state = FL_ERASING; | 697 | chip->state = FL_ERASING; |
| 679 | chip->oldstate = FL_READY; | 698 | chip->oldstate = FL_READY; |
| 680 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); | 699 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); |
| @@ -727,7 +746,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad | |||
| 727 | switch(chip->oldstate) { | 746 | switch(chip->oldstate) { |
| 728 | case FL_ERASING: | 747 | case FL_ERASING: |
| 729 | chip->state = chip->oldstate; | 748 | chip->state = chip->oldstate; |
| 730 | map_write(map, CMD(0x30), chip->in_progress_block_addr); | 749 | map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); |
| 731 | chip->oldstate = FL_READY; | 750 | chip->oldstate = FL_READY; |
| 732 | chip->state = FL_ERASING; | 751 | chip->state = FL_ERASING; |
| 733 | break; | 752 | break; |
| @@ -870,7 +889,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, | |||
| 870 | local_irq_disable(); | 889 | local_irq_disable(); |
| 871 | 890 | ||
| 872 | /* Resume the write or erase operation */ | 891 | /* Resume the write or erase operation */ |
| 873 | map_write(map, CMD(0x30), adr); | 892 | map_write(map, cfi->sector_erase_cmd, adr); |
| 874 | chip->state = oldstate; | 893 | chip->state = oldstate; |
| 875 | start = xip_currtime(); | 894 | start = xip_currtime(); |
| 876 | } else if (usec >= 1000000/HZ) { | 895 | } else if (usec >= 1000000/HZ) { |
| @@ -1025,9 +1044,6 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
| 1025 | mutex_lock(&chip->mutex); | 1044 | mutex_lock(&chip->mutex); |
| 1026 | 1045 | ||
| 1027 | if (chip->state != FL_READY){ | 1046 | if (chip->state != FL_READY){ |
| 1028 | #if 0 | ||
| 1029 | printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state); | ||
| 1030 | #endif | ||
| 1031 | set_current_state(TASK_UNINTERRUPTIBLE); | 1047 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 1032 | add_wait_queue(&chip->wq, &wait); | 1048 | add_wait_queue(&chip->wq, &wait); |
| 1033 | 1049 | ||
| @@ -1035,10 +1051,6 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
| 1035 | 1051 | ||
| 1036 | schedule(); | 1052 | schedule(); |
| 1037 | remove_wait_queue(&chip->wq, &wait); | 1053 | remove_wait_queue(&chip->wq, &wait); |
| 1038 | #if 0 | ||
| 1039 | if(signal_pending(current)) | ||
| 1040 | return -EINTR; | ||
| 1041 | #endif | ||
| 1042 | timeo = jiffies + HZ; | 1054 | timeo = jiffies + HZ; |
| 1043 | 1055 | ||
| 1044 | goto retry; | 1056 | goto retry; |
| @@ -1246,9 +1258,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 1246 | mutex_lock(&cfi->chips[chipnum].mutex); | 1258 | mutex_lock(&cfi->chips[chipnum].mutex); |
| 1247 | 1259 | ||
| 1248 | if (cfi->chips[chipnum].state != FL_READY) { | 1260 | if (cfi->chips[chipnum].state != FL_READY) { |
| 1249 | #if 0 | ||
| 1250 | printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); | ||
| 1251 | #endif | ||
| 1252 | set_current_state(TASK_UNINTERRUPTIBLE); | 1261 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 1253 | add_wait_queue(&cfi->chips[chipnum].wq, &wait); | 1262 | add_wait_queue(&cfi->chips[chipnum].wq, &wait); |
| 1254 | 1263 | ||
| @@ -1256,10 +1265,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 1256 | 1265 | ||
| 1257 | schedule(); | 1266 | schedule(); |
| 1258 | remove_wait_queue(&cfi->chips[chipnum].wq, &wait); | 1267 | remove_wait_queue(&cfi->chips[chipnum].wq, &wait); |
| 1259 | #if 0 | ||
| 1260 | if(signal_pending(current)) | ||
| 1261 | return -EINTR; | ||
| 1262 | #endif | ||
| 1263 | goto retry; | 1268 | goto retry; |
| 1264 | } | 1269 | } |
| 1265 | 1270 | ||
| @@ -1324,9 +1329,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 1324 | mutex_lock(&cfi->chips[chipnum].mutex); | 1329 | mutex_lock(&cfi->chips[chipnum].mutex); |
| 1325 | 1330 | ||
| 1326 | if (cfi->chips[chipnum].state != FL_READY) { | 1331 | if (cfi->chips[chipnum].state != FL_READY) { |
| 1327 | #if 0 | ||
| 1328 | printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); | ||
| 1329 | #endif | ||
| 1330 | set_current_state(TASK_UNINTERRUPTIBLE); | 1332 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 1331 | add_wait_queue(&cfi->chips[chipnum].wq, &wait); | 1333 | add_wait_queue(&cfi->chips[chipnum].wq, &wait); |
| 1332 | 1334 | ||
| @@ -1334,10 +1336,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 1334 | 1336 | ||
| 1335 | schedule(); | 1337 | schedule(); |
| 1336 | remove_wait_queue(&cfi->chips[chipnum].wq, &wait); | 1338 | remove_wait_queue(&cfi->chips[chipnum].wq, &wait); |
| 1337 | #if 0 | ||
| 1338 | if(signal_pending(current)) | ||
| 1339 | return -EINTR; | ||
| 1340 | #endif | ||
| 1341 | goto retry1; | 1339 | goto retry1; |
| 1342 | } | 1340 | } |
| 1343 | 1341 | ||
| @@ -1396,7 +1394,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
| 1396 | 1394 | ||
| 1397 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1395 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
| 1398 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 1396 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
| 1399 | //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | ||
| 1400 | 1397 | ||
| 1401 | /* Write Buffer Load */ | 1398 | /* Write Buffer Load */ |
| 1402 | map_write(map, CMD(0x25), cmd_adr); | 1399 | map_write(map, CMD(0x25), cmd_adr); |
| @@ -1675,7 +1672,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | |||
| 1675 | cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1672 | cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
| 1676 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1673 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
| 1677 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 1674 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
| 1678 | map_write(map, CMD(0x30), adr); | 1675 | map_write(map, cfi->sector_erase_cmd, adr); |
| 1679 | 1676 | ||
| 1680 | chip->state = FL_ERASING; | 1677 | chip->state = FL_ERASING; |
| 1681 | chip->erase_suspended = 0; | 1678 | chip->erase_suspended = 0; |
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index 8f5b96aa87a0..d25535279404 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
| @@ -177,6 +177,8 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
| 177 | 177 | ||
| 178 | cfi->cfi_mode = CFI_MODE_CFI; | 178 | cfi->cfi_mode = CFI_MODE_CFI; |
| 179 | 179 | ||
| 180 | cfi->sector_erase_cmd = CMD(0x30); | ||
| 181 | |||
| 180 | /* Read the CFI info structure */ | 182 | /* Read the CFI info structure */ |
| 181 | xip_disable_qry(base, map, cfi); | 183 | xip_disable_qry(base, map, cfi); |
| 182 | for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) | 184 | for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) |
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index e503b2ca894d..360525c637d2 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
| @@ -77,6 +77,13 @@ int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, | |||
| 77 | cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); | 77 | cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); |
| 78 | if (cfi_qry_present(map, base, cfi)) | 78 | if (cfi_qry_present(map, base, cfi)) |
| 79 | return 1; | 79 | return 1; |
| 80 | /* SST 39VF640xB */ | ||
| 81 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
| 82 | cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL); | ||
| 83 | cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL); | ||
| 84 | cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); | ||
| 85 | if (cfi_qry_present(map, base, cfi)) | ||
| 86 | return 1; | ||
| 80 | /* QRY not found */ | 87 | /* QRY not found */ |
| 81 | return 0; | 88 | return 0; |
| 82 | } | 89 | } |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 93651865ddbe..2cf0cc6a4189 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
| @@ -91,7 +91,6 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
| 91 | } else | 91 | } else |
| 92 | instr->state = MTD_ERASE_DONE; | 92 | instr->state = MTD_ERASE_DONE; |
| 93 | 93 | ||
| 94 | instr->state = MTD_ERASE_DONE; | ||
| 95 | mtd_erase_callback(instr); | 94 | mtd_erase_callback(instr); |
| 96 | return err; | 95 | return err; |
| 97 | } | 96 | } |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ea22520c0406..bf5a002209bd 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
| @@ -661,11 +661,14 @@ static const struct spi_device_id m25p_ids[] = { | |||
| 661 | { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, | 661 | { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, |
| 662 | { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, | 662 | { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, |
| 663 | { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, | 663 | { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, |
| 664 | { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SECT_4K) }, | ||
| 664 | { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, | 665 | { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, |
| 665 | { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, | 666 | { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, |
| 666 | { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, | 667 | { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, |
| 667 | { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, | 668 | { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, |
| 668 | { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, | 669 | { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, |
| 670 | { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, | ||
| 671 | { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, | ||
| 669 | 672 | ||
| 670 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ | 673 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ |
| 671 | { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K) }, | 674 | { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K) }, |
| @@ -714,6 +717,7 @@ static const struct spi_device_id m25p_ids[] = { | |||
| 714 | { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, | 717 | { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, |
| 715 | { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, | 718 | { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, |
| 716 | { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, | 719 | { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, |
| 720 | { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, | ||
| 717 | 721 | ||
| 718 | /* Catalyst / On Semiconductor -- non-JEDEC */ | 722 | /* Catalyst / On Semiconductor -- non-JEDEC */ |
| 719 | { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, | 723 | { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, |
| @@ -924,7 +928,7 @@ static int __devinit m25p_probe(struct spi_device *spi) | |||
| 924 | nr_parts = data->nr_parts; | 928 | nr_parts = data->nr_parts; |
| 925 | } | 929 | } |
| 926 | 930 | ||
| 927 | #ifdef CONFIG_OF | 931 | #ifdef CONFIG_MTD_OF_PARTS |
| 928 | if (nr_parts <= 0 && spi->dev.of_node) { | 932 | if (nr_parts <= 0 && spi->dev.of_node) { |
| 929 | nr_parts = of_mtd_parse_partitions(&spi->dev, | 933 | nr_parts = of_mtd_parse_partitions(&spi->dev, |
| 930 | spi->dev.of_node, &parts); | 934 | spi->dev.of_node, &parts); |
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 1696bbecaa7e..52393282eaf1 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi | 15 | * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #define pr_fmt(fmt) "phram: " fmt | 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 19 | 19 | ||
| 20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 962212628f6e..a0dd7bba9481 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
| @@ -251,6 +251,15 @@ config MTD_NETtel | |||
| 251 | help | 251 | help |
| 252 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. | 252 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. |
| 253 | 253 | ||
| 254 | config MTD_BCM963XX | ||
| 255 | tristate "Map driver for Broadcom BCM963xx boards" | ||
| 256 | depends on BCM63XX | ||
| 257 | select MTD_MAP_BANK_WIDTH_2 | ||
| 258 | select MTD_CFI_I1 | ||
| 259 | help | ||
| 260 | Support for parsing CFE image tag and creating MTD partitions on | ||
| 261 | Broadcom BCM63xx boards. | ||
| 262 | |||
| 254 | config MTD_DILNETPC | 263 | config MTD_DILNETPC |
| 255 | tristate "CFI Flash device mapped on DIL/Net PC" | 264 | tristate "CFI Flash device mapped on DIL/Net PC" |
| 256 | depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN | 265 | depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index f216bb573713..c7869c7a6b18 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
| @@ -58,3 +58,4 @@ obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o | |||
| 58 | obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o | 58 | obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o |
| 59 | obj-$(CONFIG_MTD_VMU) += vmu-flash.o | 59 | obj-$(CONFIG_MTD_VMU) += vmu-flash.o |
| 60 | obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o | 60 | obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o |
| 61 | obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o | ||
diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c new file mode 100644 index 000000000000..d175c120ee84 --- /dev/null +++ b/drivers/mtd/maps/bcm963xx-flash.c | |||
| @@ -0,0 +1,271 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> | ||
| 3 | * Mike Albon <malbon@openwrt.org> | ||
| 4 | * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> | ||
| 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 as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/mtd/map.h> | ||
| 25 | #include <linux/mtd/mtd.h> | ||
| 26 | #include <linux/mtd/partitions.h> | ||
| 27 | #include <linux/vmalloc.h> | ||
| 28 | #include <linux/platform_device.h> | ||
| 29 | #include <linux/io.h> | ||
| 30 | |||
| 31 | #include <asm/mach-bcm63xx/bcm963xx_tag.h> | ||
| 32 | |||
| 33 | #define BCM63XX_BUSWIDTH 2 /* Buswidth */ | ||
| 34 | #define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ | ||
| 35 | |||
| 36 | #define PFX KBUILD_MODNAME ": " | ||
| 37 | |||
| 38 | static struct mtd_partition *parsed_parts; | ||
| 39 | |||
| 40 | static struct mtd_info *bcm963xx_mtd_info; | ||
| 41 | |||
| 42 | static struct map_info bcm963xx_map = { | ||
| 43 | .name = "bcm963xx", | ||
| 44 | .bankwidth = BCM63XX_BUSWIDTH, | ||
| 45 | }; | ||
| 46 | |||
| 47 | static int parse_cfe_partitions(struct mtd_info *master, | ||
| 48 | struct mtd_partition **pparts) | ||
| 49 | { | ||
| 50 | /* CFE, NVRAM and global Linux are always present */ | ||
| 51 | int nrparts = 3, curpart = 0; | ||
| 52 | struct bcm_tag *buf; | ||
| 53 | struct mtd_partition *parts; | ||
| 54 | int ret; | ||
| 55 | size_t retlen; | ||
| 56 | unsigned int rootfsaddr, kerneladdr, spareaddr; | ||
| 57 | unsigned int rootfslen, kernellen, sparelen, totallen; | ||
| 58 | int namelen = 0; | ||
| 59 | int i; | ||
| 60 | char *boardid; | ||
| 61 | char *tagversion; | ||
| 62 | |||
| 63 | /* Allocate memory for buffer */ | ||
| 64 | buf = vmalloc(sizeof(struct bcm_tag)); | ||
| 65 | if (!buf) | ||
| 66 | return -ENOMEM; | ||
| 67 | |||
| 68 | /* Get the tag */ | ||
| 69 | ret = master->read(master, master->erasesize, sizeof(struct bcm_tag), | ||
| 70 | &retlen, (void *)buf); | ||
| 71 | if (retlen != sizeof(struct bcm_tag)) { | ||
| 72 | vfree(buf); | ||
| 73 | return -EIO; | ||
| 74 | } | ||
| 75 | |||
| 76 | sscanf(buf->kernel_address, "%u", &kerneladdr); | ||
| 77 | sscanf(buf->kernel_length, "%u", &kernellen); | ||
| 78 | sscanf(buf->total_length, "%u", &totallen); | ||
| 79 | tagversion = &(buf->tag_version[0]); | ||
| 80 | boardid = &(buf->board_id[0]); | ||
| 81 | |||
| 82 | printk(KERN_INFO PFX "CFE boot tag found with version %s " | ||
| 83 | "and board type %s\n", tagversion, boardid); | ||
| 84 | |||
| 85 | kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; | ||
| 86 | rootfsaddr = kerneladdr + kernellen; | ||
| 87 | spareaddr = roundup(totallen, master->erasesize) + master->erasesize; | ||
| 88 | sparelen = master->size - spareaddr - master->erasesize; | ||
| 89 | rootfslen = spareaddr - rootfsaddr; | ||
| 90 | |||
| 91 | /* Determine number of partitions */ | ||
| 92 | namelen = 8; | ||
| 93 | if (rootfslen > 0) { | ||
| 94 | nrparts++; | ||
| 95 | namelen += 6; | ||
| 96 | }; | ||
| 97 | if (kernellen > 0) { | ||
| 98 | nrparts++; | ||
| 99 | namelen += 6; | ||
| 100 | }; | ||
| 101 | |||
| 102 | /* Ask kernel for more memory */ | ||
| 103 | parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); | ||
| 104 | if (!parts) { | ||
| 105 | vfree(buf); | ||
| 106 | return -ENOMEM; | ||
| 107 | }; | ||
| 108 | |||
| 109 | /* Start building partition list */ | ||
| 110 | parts[curpart].name = "CFE"; | ||
| 111 | parts[curpart].offset = 0; | ||
| 112 | parts[curpart].size = master->erasesize; | ||
| 113 | curpart++; | ||
| 114 | |||
| 115 | if (kernellen > 0) { | ||
| 116 | parts[curpart].name = "kernel"; | ||
| 117 | parts[curpart].offset = kerneladdr; | ||
| 118 | parts[curpart].size = kernellen; | ||
| 119 | curpart++; | ||
| 120 | }; | ||
| 121 | |||
| 122 | if (rootfslen > 0) { | ||
| 123 | parts[curpart].name = "rootfs"; | ||
| 124 | parts[curpart].offset = rootfsaddr; | ||
| 125 | parts[curpart].size = rootfslen; | ||
| 126 | if (sparelen > 0) | ||
| 127 | parts[curpart].size += sparelen; | ||
| 128 | curpart++; | ||
| 129 | }; | ||
| 130 | |||
| 131 | parts[curpart].name = "nvram"; | ||
| 132 | parts[curpart].offset = master->size - master->erasesize; | ||
| 133 | parts[curpart].size = master->erasesize; | ||
| 134 | |||
| 135 | /* Global partition "linux" to make easy firmware upgrade */ | ||
| 136 | curpart++; | ||
| 137 | parts[curpart].name = "linux"; | ||
| 138 | parts[curpart].offset = parts[0].size; | ||
| 139 | parts[curpart].size = master->size - parts[0].size - parts[3].size; | ||
| 140 | |||
| 141 | for (i = 0; i < nrparts; i++) | ||
| 142 | printk(KERN_INFO PFX "Partition %d is %s offset %lx and " | ||
| 143 | "length %lx\n", i, parts[i].name, | ||
| 144 | (long unsigned int)(parts[i].offset), | ||
| 145 | (long unsigned int)(parts[i].size)); | ||
| 146 | |||
| 147 | printk(KERN_INFO PFX "Spare partition is %x offset and length %x\n", | ||
| 148 | spareaddr, sparelen); | ||
| 149 | *pparts = parts; | ||
| 150 | vfree(buf); | ||
| 151 | |||
| 152 | return nrparts; | ||
| 153 | }; | ||
| 154 | |||
| 155 | static int bcm963xx_detect_cfe(struct mtd_info *master) | ||
| 156 | { | ||
| 157 | int idoffset = 0x4e0; | ||
| 158 | static char idstring[8] = "CFE1CFE1"; | ||
| 159 | char buf[9]; | ||
| 160 | int ret; | ||
| 161 | size_t retlen; | ||
| 162 | |||
| 163 | ret = master->read(master, idoffset, 8, &retlen, (void *)buf); | ||
| 164 | buf[retlen] = 0; | ||
| 165 | printk(KERN_INFO PFX "Read Signature value of %s\n", buf); | ||
| 166 | |||
| 167 | return strncmp(idstring, buf, 8); | ||
| 168 | } | ||
| 169 | |||
| 170 | static int bcm963xx_probe(struct platform_device *pdev) | ||
| 171 | { | ||
| 172 | int err = 0; | ||
| 173 | int parsed_nr_parts = 0; | ||
| 174 | char *part_type; | ||
| 175 | struct resource *r; | ||
| 176 | |||
| 177 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 178 | if (!r) { | ||
| 179 | dev_err(&pdev->dev, "no resource supplied\n"); | ||
| 180 | return -ENODEV; | ||
| 181 | } | ||
| 182 | |||
| 183 | bcm963xx_map.phys = r->start; | ||
| 184 | bcm963xx_map.size = resource_size(r); | ||
| 185 | bcm963xx_map.virt = ioremap(r->start, resource_size(r)); | ||
| 186 | if (!bcm963xx_map.virt) { | ||
| 187 | dev_err(&pdev->dev, "failed to ioremap\n"); | ||
| 188 | return -EIO; | ||
| 189 | } | ||
| 190 | |||
| 191 | dev_info(&pdev->dev, "0x%08lx at 0x%08x\n", | ||
| 192 | bcm963xx_map.size, bcm963xx_map.phys); | ||
| 193 | |||
| 194 | simple_map_init(&bcm963xx_map); | ||
| 195 | |||
| 196 | bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); | ||
| 197 | if (!bcm963xx_mtd_info) { | ||
| 198 | dev_err(&pdev->dev, "failed to probe using CFI\n"); | ||
| 199 | err = -EIO; | ||
| 200 | goto err_probe; | ||
| 201 | } | ||
| 202 | |||
| 203 | bcm963xx_mtd_info->owner = THIS_MODULE; | ||
| 204 | |||
| 205 | /* This is mutually exclusive */ | ||
| 206 | if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) { | ||
| 207 | dev_info(&pdev->dev, "CFE bootloader detected\n"); | ||
| 208 | if (parsed_nr_parts == 0) { | ||
| 209 | int ret = parse_cfe_partitions(bcm963xx_mtd_info, | ||
| 210 | &parsed_parts); | ||
| 211 | if (ret > 0) { | ||
| 212 | part_type = "CFE"; | ||
| 213 | parsed_nr_parts = ret; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | } else { | ||
| 217 | dev_info(&pdev->dev, "unsupported bootloader\n"); | ||
| 218 | err = -ENODEV; | ||
| 219 | goto err_probe; | ||
| 220 | } | ||
| 221 | |||
| 222 | return add_mtd_partitions(bcm963xx_mtd_info, parsed_parts, | ||
| 223 | parsed_nr_parts); | ||
| 224 | |||
| 225 | err_probe: | ||
| 226 | iounmap(bcm963xx_map.virt); | ||
| 227 | return err; | ||
| 228 | } | ||
| 229 | |||
| 230 | static int bcm963xx_remove(struct platform_device *pdev) | ||
| 231 | { | ||
| 232 | if (bcm963xx_mtd_info) { | ||
| 233 | del_mtd_partitions(bcm963xx_mtd_info); | ||
| 234 | map_destroy(bcm963xx_mtd_info); | ||
| 235 | } | ||
| 236 | |||
| 237 | if (bcm963xx_map.virt) { | ||
| 238 | iounmap(bcm963xx_map.virt); | ||
| 239 | bcm963xx_map.virt = 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | static struct platform_driver bcm63xx_mtd_dev = { | ||
| 246 | .probe = bcm963xx_probe, | ||
| 247 | .remove = bcm963xx_remove, | ||
| 248 | .driver = { | ||
| 249 | .name = "bcm963xx-flash", | ||
| 250 | .owner = THIS_MODULE, | ||
| 251 | }, | ||
| 252 | }; | ||
| 253 | |||
| 254 | static int __init bcm963xx_mtd_init(void) | ||
| 255 | { | ||
| 256 | return platform_driver_register(&bcm63xx_mtd_dev); | ||
| 257 | } | ||
| 258 | |||
| 259 | static void __exit bcm963xx_mtd_exit(void) | ||
| 260 | { | ||
| 261 | platform_driver_unregister(&bcm63xx_mtd_dev); | ||
| 262 | } | ||
| 263 | |||
| 264 | module_init(bcm963xx_mtd_init); | ||
| 265 | module_exit(bcm963xx_mtd_exit); | ||
| 266 | |||
| 267 | MODULE_LICENSE("GPL"); | ||
| 268 | MODULE_DESCRIPTION("Broadcom BCM63xx MTD driver for CFE and RedBoot"); | ||
| 269 | MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>"); | ||
| 270 | MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); | ||
| 271 | MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>"); | ||
diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 32e89d773b4e..af5707a80205 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c | |||
| @@ -208,10 +208,14 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) | |||
| 208 | if (!state) | 208 | if (!state) |
| 209 | return -ENOMEM; | 209 | return -ENOMEM; |
| 210 | 210 | ||
| 211 | /* | ||
| 212 | * We cast start/end to known types in the boards file, so cast | ||
| 213 | * away their pointer types here to the known types (gpios->xxx). | ||
| 214 | */ | ||
| 211 | state->gpio_count = gpios->end; | 215 | state->gpio_count = gpios->end; |
| 212 | state->gpio_addrs = (void *)gpios->start; | 216 | state->gpio_addrs = (void *)(unsigned long)gpios->start; |
| 213 | state->gpio_values = (void *)(state + 1); | 217 | state->gpio_values = (void *)(state + 1); |
| 214 | state->win_size = memory->end - memory->start + 1; | 218 | state->win_size = resource_size(memory); |
| 215 | memset(state->gpio_values, 0xff, arr_size); | 219 | memset(state->gpio_values, 0xff, arr_size); |
| 216 | 220 | ||
| 217 | state->map.name = DRIVER_NAME; | 221 | state->map.name = DRIVER_NAME; |
| @@ -221,7 +225,7 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) | |||
| 221 | state->map.copy_to = gf_copy_to; | 225 | state->map.copy_to = gf_copy_to; |
| 222 | state->map.bankwidth = pdata->width; | 226 | state->map.bankwidth = pdata->width; |
| 223 | state->map.size = state->win_size * (1 << state->gpio_count); | 227 | state->map.size = state->win_size * (1 << state->gpio_count); |
| 224 | state->map.virt = (void __iomem *)memory->start; | 228 | state->map.virt = ioremap_nocache(memory->start, state->map.size); |
| 225 | state->map.phys = NO_XIP; | 229 | state->map.phys = NO_XIP; |
| 226 | state->map.map_priv_1 = (unsigned long)state; | 230 | state->map.map_priv_1 = (unsigned long)state; |
| 227 | 231 | ||
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 57a1acfe22c4..917022948399 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c | |||
| @@ -640,10 +640,6 @@ static int pcmciamtd_config(struct pcmcia_device *link) | |||
| 640 | } | 640 | } |
| 641 | dev_info(&dev->p_dev->dev, "mtd%d: %s\n", mtd->index, mtd->name); | 641 | dev_info(&dev->p_dev->dev, "mtd%d: %s\n", mtd->index, mtd->name); |
| 642 | return 0; | 642 | return 0; |
| 643 | |||
| 644 | dev_err(&dev->p_dev->dev, "CS Error, exiting\n"); | ||
| 645 | pcmciamtd_release(link); | ||
| 646 | return -ENODEV; | ||
| 647 | } | 643 | } |
| 648 | 644 | ||
| 649 | 645 | ||
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index ec3edf6e68b4..9861814aa027 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c | |||
| @@ -50,7 +50,7 @@ static int parse_obsolete_partitions(struct platform_device *dev, | |||
| 50 | { | 50 | { |
| 51 | int i, plen, nr_parts; | 51 | int i, plen, nr_parts; |
| 52 | const struct { | 52 | const struct { |
| 53 | u32 offset, len; | 53 | __be32 offset, len; |
| 54 | } *part; | 54 | } *part; |
| 55 | const char *names; | 55 | const char *names; |
| 56 | 56 | ||
| @@ -69,9 +69,9 @@ static int parse_obsolete_partitions(struct platform_device *dev, | |||
| 69 | names = of_get_property(dp, "partition-names", &plen); | 69 | names = of_get_property(dp, "partition-names", &plen); |
| 70 | 70 | ||
| 71 | for (i = 0; i < nr_parts; i++) { | 71 | for (i = 0; i < nr_parts; i++) { |
| 72 | info->parts[i].offset = part->offset; | 72 | info->parts[i].offset = be32_to_cpu(part->offset); |
| 73 | info->parts[i].size = part->len & ~1; | 73 | info->parts[i].size = be32_to_cpu(part->len) & ~1; |
| 74 | if (part->len & 1) /* bit 0 set signifies read only partition */ | 74 | if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */ |
| 75 | info->parts[i].mask_flags = MTD_WRITEABLE; | 75 | info->parts[i].mask_flags = MTD_WRITEABLE; |
| 76 | 76 | ||
| 77 | if (names && (plen > 0)) { | 77 | if (names && (plen > 0)) { |
| @@ -226,11 +226,11 @@ static int __devinit of_flash_probe(struct platform_device *dev, | |||
| 226 | struct resource res; | 226 | struct resource res; |
| 227 | struct of_flash *info; | 227 | struct of_flash *info; |
| 228 | const char *probe_type = match->data; | 228 | const char *probe_type = match->data; |
| 229 | const u32 *width; | 229 | const __be32 *width; |
| 230 | int err; | 230 | int err; |
| 231 | int i; | 231 | int i; |
| 232 | int count; | 232 | int count; |
| 233 | const u32 *p; | 233 | const __be32 *p; |
| 234 | int reg_tuple_size; | 234 | int reg_tuple_size; |
| 235 | struct mtd_info **mtd_list = NULL; | 235 | struct mtd_info **mtd_list = NULL; |
| 236 | resource_size_t res_size; | 236 | resource_size_t res_size; |
| @@ -267,9 +267,11 @@ static int __devinit of_flash_probe(struct platform_device *dev, | |||
| 267 | for (i = 0; i < count; i++) { | 267 | for (i = 0; i < count; i++) { |
| 268 | err = -ENXIO; | 268 | err = -ENXIO; |
| 269 | if (of_address_to_resource(dp, i, &res)) { | 269 | if (of_address_to_resource(dp, i, &res)) { |
| 270 | dev_err(&dev->dev, "Can't get IO address from device" | 270 | /* |
| 271 | " tree\n"); | 271 | * Continue with next register tuple if this |
| 272 | goto err_out; | 272 | * one is not mappable |
| 273 | */ | ||
| 274 | continue; | ||
| 273 | } | 275 | } |
| 274 | 276 | ||
| 275 | dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", | 277 | dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", |
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 50ab431b24eb..cb20c67995d8 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
| @@ -37,7 +37,6 @@ | |||
| 37 | 37 | ||
| 38 | #include "mtdcore.h" | 38 | #include "mtdcore.h" |
| 39 | 39 | ||
| 40 | static DEFINE_MUTEX(mtd_blkdevs_mutex); | ||
| 41 | static LIST_HEAD(blktrans_majors); | 40 | static LIST_HEAD(blktrans_majors); |
| 42 | static DEFINE_MUTEX(blktrans_ref_mutex); | 41 | static DEFINE_MUTEX(blktrans_ref_mutex); |
| 43 | 42 | ||
| @@ -133,6 +132,10 @@ static int mtd_blktrans_thread(void *arg) | |||
| 133 | 132 | ||
| 134 | if (!req && !(req = blk_fetch_request(rq))) { | 133 | if (!req && !(req = blk_fetch_request(rq))) { |
| 135 | set_current_state(TASK_INTERRUPTIBLE); | 134 | set_current_state(TASK_INTERRUPTIBLE); |
| 135 | |||
| 136 | if (kthread_should_stop()) | ||
| 137 | set_current_state(TASK_RUNNING); | ||
| 138 | |||
| 136 | spin_unlock_irq(rq->queue_lock); | 139 | spin_unlock_irq(rq->queue_lock); |
| 137 | schedule(); | 140 | schedule(); |
| 138 | spin_lock_irq(rq->queue_lock); | 141 | spin_lock_irq(rq->queue_lock); |
| @@ -176,54 +179,53 @@ static void mtd_blktrans_request(struct request_queue *rq) | |||
| 176 | static int blktrans_open(struct block_device *bdev, fmode_t mode) | 179 | static int blktrans_open(struct block_device *bdev, fmode_t mode) |
| 177 | { | 180 | { |
| 178 | struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); | 181 | struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); |
| 179 | int ret; | 182 | int ret = 0; |
| 180 | 183 | ||
| 181 | if (!dev) | 184 | if (!dev) |
| 182 | return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ | 185 | return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ |
| 183 | 186 | ||
| 184 | mutex_lock(&mtd_blkdevs_mutex); | ||
| 185 | mutex_lock(&dev->lock); | 187 | mutex_lock(&dev->lock); |
| 186 | 188 | ||
| 187 | if (!dev->mtd) { | 189 | if (dev->open++) |
| 188 | ret = -ENXIO; | ||
| 189 | goto unlock; | 190 | goto unlock; |
| 190 | } | ||
| 191 | 191 | ||
| 192 | ret = !dev->open++ && dev->tr->open ? dev->tr->open(dev) : 0; | 192 | kref_get(&dev->ref); |
| 193 | __module_get(dev->tr->owner); | ||
| 194 | |||
| 195 | if (dev->mtd) { | ||
| 196 | ret = dev->tr->open ? dev->tr->open(dev) : 0; | ||
| 197 | __get_mtd_device(dev->mtd); | ||
| 198 | } | ||
| 193 | 199 | ||
| 194 | /* Take another reference on the device so it won't go away till | ||
| 195 | last release */ | ||
| 196 | if (!ret) | ||
| 197 | kref_get(&dev->ref); | ||
| 198 | unlock: | 200 | unlock: |
| 199 | mutex_unlock(&dev->lock); | 201 | mutex_unlock(&dev->lock); |
| 200 | blktrans_dev_put(dev); | 202 | blktrans_dev_put(dev); |
| 201 | mutex_unlock(&mtd_blkdevs_mutex); | ||
| 202 | return ret; | 203 | return ret; |
| 203 | } | 204 | } |
| 204 | 205 | ||
| 205 | static int blktrans_release(struct gendisk *disk, fmode_t mode) | 206 | static int blktrans_release(struct gendisk *disk, fmode_t mode) |
| 206 | { | 207 | { |
| 207 | struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); | 208 | struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); |
| 208 | int ret = -ENXIO; | 209 | int ret = 0; |
| 209 | 210 | ||
| 210 | if (!dev) | 211 | if (!dev) |
| 211 | return ret; | 212 | return ret; |
| 212 | 213 | ||
| 213 | mutex_lock(&mtd_blkdevs_mutex); | ||
| 214 | mutex_lock(&dev->lock); | 214 | mutex_lock(&dev->lock); |
| 215 | 215 | ||
| 216 | /* Release one reference, we sure its not the last one here*/ | 216 | if (--dev->open) |
| 217 | kref_put(&dev->ref, blktrans_dev_release); | ||
| 218 | |||
| 219 | if (!dev->mtd) | ||
| 220 | goto unlock; | 217 | goto unlock; |
| 221 | 218 | ||
| 222 | ret = !--dev->open && dev->tr->release ? dev->tr->release(dev) : 0; | 219 | kref_put(&dev->ref, blktrans_dev_release); |
| 220 | module_put(dev->tr->owner); | ||
| 221 | |||
| 222 | if (dev->mtd) { | ||
| 223 | ret = dev->tr->release ? dev->tr->release(dev) : 0; | ||
| 224 | __put_mtd_device(dev->mtd); | ||
| 225 | } | ||
| 223 | unlock: | 226 | unlock: |
| 224 | mutex_unlock(&dev->lock); | 227 | mutex_unlock(&dev->lock); |
| 225 | blktrans_dev_put(dev); | 228 | blktrans_dev_put(dev); |
| 226 | mutex_unlock(&mtd_blkdevs_mutex); | ||
| 227 | return ret; | 229 | return ret; |
| 228 | } | 230 | } |
| 229 | 231 | ||
| @@ -256,7 +258,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 256 | if (!dev) | 258 | if (!dev) |
| 257 | return ret; | 259 | return ret; |
| 258 | 260 | ||
| 259 | mutex_lock(&mtd_blkdevs_mutex); | ||
| 260 | mutex_lock(&dev->lock); | 261 | mutex_lock(&dev->lock); |
| 261 | 262 | ||
| 262 | if (!dev->mtd) | 263 | if (!dev->mtd) |
| @@ -271,7 +272,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 271 | } | 272 | } |
| 272 | unlock: | 273 | unlock: |
| 273 | mutex_unlock(&dev->lock); | 274 | mutex_unlock(&dev->lock); |
| 274 | mutex_unlock(&mtd_blkdevs_mutex); | ||
| 275 | blktrans_dev_put(dev); | 275 | blktrans_dev_put(dev); |
| 276 | return ret; | 276 | return ret; |
| 277 | } | 277 | } |
| @@ -385,9 +385,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
| 385 | 385 | ||
| 386 | gd->queue = new->rq; | 386 | gd->queue = new->rq; |
| 387 | 387 | ||
| 388 | __get_mtd_device(new->mtd); | ||
| 389 | __module_get(tr->owner); | ||
| 390 | |||
| 391 | /* Create processing thread */ | 388 | /* Create processing thread */ |
| 392 | /* TODO: workqueue ? */ | 389 | /* TODO: workqueue ? */ |
| 393 | new->thread = kthread_run(mtd_blktrans_thread, new, | 390 | new->thread = kthread_run(mtd_blktrans_thread, new, |
| @@ -410,8 +407,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
| 410 | } | 407 | } |
| 411 | return 0; | 408 | return 0; |
| 412 | error4: | 409 | error4: |
| 413 | module_put(tr->owner); | ||
| 414 | __put_mtd_device(new->mtd); | ||
| 415 | blk_cleanup_queue(new->rq); | 410 | blk_cleanup_queue(new->rq); |
| 416 | error3: | 411 | error3: |
| 417 | put_disk(new->disk); | 412 | put_disk(new->disk); |
| @@ -448,17 +443,15 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | |||
| 448 | blk_start_queue(old->rq); | 443 | blk_start_queue(old->rq); |
| 449 | spin_unlock_irqrestore(&old->queue_lock, flags); | 444 | spin_unlock_irqrestore(&old->queue_lock, flags); |
| 450 | 445 | ||
| 451 | /* Ask trans driver for release to the mtd device */ | 446 | /* If the device is currently open, tell trans driver to close it, |
| 447 | then put mtd device, and don't touch it again */ | ||
| 452 | mutex_lock(&old->lock); | 448 | mutex_lock(&old->lock); |
| 453 | if (old->open && old->tr->release) { | 449 | if (old->open) { |
| 454 | old->tr->release(old); | 450 | if (old->tr->release) |
| 455 | old->open = 0; | 451 | old->tr->release(old); |
| 452 | __put_mtd_device(old->mtd); | ||
| 456 | } | 453 | } |
| 457 | 454 | ||
| 458 | __put_mtd_device(old->mtd); | ||
| 459 | module_put(old->tr->owner); | ||
| 460 | |||
| 461 | /* At that point, we don't touch the mtd anymore */ | ||
| 462 | old->mtd = NULL; | 455 | old->mtd = NULL; |
| 463 | 456 | ||
| 464 | mutex_unlock(&old->lock); | 457 | mutex_unlock(&old->lock); |
| @@ -508,13 +501,16 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
| 508 | mutex_lock(&mtd_table_mutex); | 501 | mutex_lock(&mtd_table_mutex); |
| 509 | 502 | ||
| 510 | ret = register_blkdev(tr->major, tr->name); | 503 | ret = register_blkdev(tr->major, tr->name); |
| 511 | if (ret) { | 504 | if (ret < 0) { |
| 512 | printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", | 505 | printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", |
| 513 | tr->name, tr->major, ret); | 506 | tr->name, tr->major, ret); |
| 514 | mutex_unlock(&mtd_table_mutex); | 507 | mutex_unlock(&mtd_table_mutex); |
| 515 | return ret; | 508 | return ret; |
| 516 | } | 509 | } |
| 517 | 510 | ||
| 511 | if (ret) | ||
| 512 | tr->major = ret; | ||
| 513 | |||
| 518 | tr->blkshift = ffs(tr->blksize) - 1; | 514 | tr->blkshift = ffs(tr->blksize) - 1; |
| 519 | 515 | ||
| 520 | INIT_LIST_HEAD(&tr->devs); | 516 | INIT_LIST_HEAD(&tr->devs); |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a34a0fe14884..4759d827e8c7 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
| @@ -30,8 +30,9 @@ | |||
| 30 | #include <linux/backing-dev.h> | 30 | #include <linux/backing-dev.h> |
| 31 | #include <linux/compat.h> | 31 | #include <linux/compat.h> |
| 32 | #include <linux/mount.h> | 32 | #include <linux/mount.h> |
| 33 | 33 | #include <linux/blkpg.h> | |
| 34 | #include <linux/mtd/mtd.h> | 34 | #include <linux/mtd/mtd.h> |
| 35 | #include <linux/mtd/partitions.h> | ||
| 35 | #include <linux/mtd/map.h> | 36 | #include <linux/mtd/map.h> |
| 36 | 37 | ||
| 37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
| @@ -478,6 +479,78 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, | |||
| 478 | return ret; | 479 | return ret; |
| 479 | } | 480 | } |
| 480 | 481 | ||
| 482 | /* | ||
| 483 | * Copies (and truncates, if necessary) data from the larger struct, | ||
| 484 | * nand_ecclayout, to the smaller, deprecated layout struct, | ||
| 485 | * nand_ecclayout_user. This is necessary only to suppport the deprecated | ||
| 486 | * API ioctl ECCGETLAYOUT while allowing all new functionality to use | ||
| 487 | * nand_ecclayout flexibly (i.e. the struct may change size in new | ||
| 488 | * releases without requiring major rewrites). | ||
| 489 | */ | ||
| 490 | static int shrink_ecclayout(const struct nand_ecclayout *from, | ||
| 491 | struct nand_ecclayout_user *to) | ||
| 492 | { | ||
| 493 | int i; | ||
| 494 | |||
| 495 | if (!from || !to) | ||
| 496 | return -EINVAL; | ||
| 497 | |||
| 498 | memset(to, 0, sizeof(*to)); | ||
| 499 | |||
| 500 | to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES); | ||
| 501 | for (i = 0; i < to->eccbytes; i++) | ||
| 502 | to->eccpos[i] = from->eccpos[i]; | ||
| 503 | |||
| 504 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) { | ||
| 505 | if (from->oobfree[i].length == 0 && | ||
| 506 | from->oobfree[i].offset == 0) | ||
| 507 | break; | ||
| 508 | to->oobavail += from->oobfree[i].length; | ||
| 509 | to->oobfree[i] = from->oobfree[i]; | ||
| 510 | } | ||
| 511 | |||
| 512 | return 0; | ||
| 513 | } | ||
| 514 | |||
| 515 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 516 | static int mtd_blkpg_ioctl(struct mtd_info *mtd, | ||
| 517 | struct blkpg_ioctl_arg __user *arg) | ||
| 518 | { | ||
| 519 | struct blkpg_ioctl_arg a; | ||
| 520 | struct blkpg_partition p; | ||
| 521 | |||
| 522 | if (!capable(CAP_SYS_ADMIN)) | ||
| 523 | return -EPERM; | ||
| 524 | |||
| 525 | /* Only master mtd device must be used to control partitions */ | ||
| 526 | if (!mtd_is_master(mtd)) | ||
| 527 | return -EINVAL; | ||
| 528 | |||
| 529 | if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) | ||
| 530 | return -EFAULT; | ||
| 531 | |||
| 532 | if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) | ||
| 533 | return -EFAULT; | ||
| 534 | |||
| 535 | switch (a.op) { | ||
| 536 | case BLKPG_ADD_PARTITION: | ||
| 537 | |||
| 538 | return mtd_add_partition(mtd, p.devname, p.start, p.length); | ||
| 539 | |||
| 540 | case BLKPG_DEL_PARTITION: | ||
| 541 | |||
| 542 | if (p.pno < 0) | ||
| 543 | return -EINVAL; | ||
| 544 | |||
| 545 | return mtd_del_partition(mtd, p.pno); | ||
| 546 | |||
| 547 | default: | ||
| 548 | return -EINVAL; | ||
| 549 | } | ||
| 550 | } | ||
| 551 | #endif | ||
| 552 | |||
| 553 | |||
| 481 | static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | 554 | static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) |
| 482 | { | 555 | { |
| 483 | struct mtd_file_info *mfi = file->private_data; | 556 | struct mtd_file_info *mfi = file->private_data; |
| @@ -514,6 +587,9 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
| 514 | if (get_user(ur_idx, &(ur->regionindex))) | 587 | if (get_user(ur_idx, &(ur->regionindex))) |
| 515 | return -EFAULT; | 588 | return -EFAULT; |
| 516 | 589 | ||
| 590 | if (ur_idx >= mtd->numeraseregions) | ||
| 591 | return -EINVAL; | ||
| 592 | |||
| 517 | kr = &(mtd->eraseregions[ur_idx]); | 593 | kr = &(mtd->eraseregions[ur_idx]); |
| 518 | 594 | ||
| 519 | if (put_user(kr->offset, &(ur->offset)) | 595 | if (put_user(kr->offset, &(ur->offset)) |
| @@ -813,14 +889,23 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
| 813 | } | 889 | } |
| 814 | #endif | 890 | #endif |
| 815 | 891 | ||
| 892 | /* This ioctl is being deprecated - it truncates the ecc layout */ | ||
| 816 | case ECCGETLAYOUT: | 893 | case ECCGETLAYOUT: |
| 817 | { | 894 | { |
| 895 | struct nand_ecclayout_user *usrlay; | ||
| 896 | |||
| 818 | if (!mtd->ecclayout) | 897 | if (!mtd->ecclayout) |
| 819 | return -EOPNOTSUPP; | 898 | return -EOPNOTSUPP; |
| 820 | 899 | ||
| 821 | if (copy_to_user(argp, mtd->ecclayout, | 900 | usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL); |
| 822 | sizeof(struct nand_ecclayout))) | 901 | if (!usrlay) |
| 823 | return -EFAULT; | 902 | return -ENOMEM; |
| 903 | |||
| 904 | shrink_ecclayout(mtd->ecclayout, usrlay); | ||
| 905 | |||
| 906 | if (copy_to_user(argp, usrlay, sizeof(*usrlay))) | ||
| 907 | ret = -EFAULT; | ||
| 908 | kfree(usrlay); | ||
| 824 | break; | 909 | break; |
| 825 | } | 910 | } |
| 826 | 911 | ||
| @@ -856,6 +941,22 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
| 856 | break; | 941 | break; |
| 857 | } | 942 | } |
| 858 | 943 | ||
| 944 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 945 | case BLKPG: | ||
| 946 | { | ||
| 947 | ret = mtd_blkpg_ioctl(mtd, | ||
| 948 | (struct blkpg_ioctl_arg __user *)arg); | ||
| 949 | break; | ||
| 950 | } | ||
| 951 | |||
| 952 | case BLKRRPART: | ||
| 953 | { | ||
| 954 | /* No reread partition feature. Just return ok */ | ||
| 955 | ret = 0; | ||
| 956 | break; | ||
| 957 | } | ||
| 958 | #endif | ||
| 959 | |||
| 859 | default: | 960 | default: |
| 860 | ret = -ENOTTY; | 961 | ret = -ENOTTY; |
| 861 | } | 962 | } |
| @@ -1033,7 +1134,7 @@ static const struct file_operations mtd_fops = { | |||
| 1033 | static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, | 1134 | static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, |
| 1034 | int flags, const char *dev_name, void *data) | 1135 | int flags, const char *dev_name, void *data) |
| 1035 | { | 1136 | { |
| 1036 | return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); | 1137 | return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); |
| 1037 | } | 1138 | } |
| 1038 | 1139 | ||
| 1039 | static struct file_system_type mtd_inodefs_type = { | 1140 | static struct file_system_type mtd_inodefs_type = { |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index dc6558568876..79e3689f1e16 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
| @@ -29,9 +29,11 @@ | |||
| 29 | #include <linux/kmod.h> | 29 | #include <linux/kmod.h> |
| 30 | #include <linux/mtd/mtd.h> | 30 | #include <linux/mtd/mtd.h> |
| 31 | #include <linux/mtd/partitions.h> | 31 | #include <linux/mtd/partitions.h> |
| 32 | #include <linux/err.h> | ||
| 32 | 33 | ||
| 33 | /* Our partition linked list */ | 34 | /* Our partition linked list */ |
| 34 | static LIST_HEAD(mtd_partitions); | 35 | static LIST_HEAD(mtd_partitions); |
| 36 | static DEFINE_MUTEX(mtd_partitions_mutex); | ||
| 35 | 37 | ||
| 36 | /* Our partition node structure */ | 38 | /* Our partition node structure */ |
| 37 | struct mtd_part { | 39 | struct mtd_part { |
| @@ -326,6 +328,12 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
| 326 | return res; | 328 | return res; |
| 327 | } | 329 | } |
| 328 | 330 | ||
| 331 | static inline void free_partition(struct mtd_part *p) | ||
| 332 | { | ||
| 333 | kfree(p->mtd.name); | ||
| 334 | kfree(p); | ||
| 335 | } | ||
| 336 | |||
| 329 | /* | 337 | /* |
| 330 | * This function unregisters and destroy all slave MTD objects which are | 338 | * This function unregisters and destroy all slave MTD objects which are |
| 331 | * attached to the given master MTD object. | 339 | * attached to the given master MTD object. |
| @@ -334,33 +342,42 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
| 334 | int del_mtd_partitions(struct mtd_info *master) | 342 | int del_mtd_partitions(struct mtd_info *master) |
| 335 | { | 343 | { |
| 336 | struct mtd_part *slave, *next; | 344 | struct mtd_part *slave, *next; |
| 345 | int ret, err = 0; | ||
| 337 | 346 | ||
| 347 | mutex_lock(&mtd_partitions_mutex); | ||
| 338 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) | 348 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) |
| 339 | if (slave->master == master) { | 349 | if (slave->master == master) { |
| 350 | ret = del_mtd_device(&slave->mtd); | ||
| 351 | if (ret < 0) { | ||
| 352 | err = ret; | ||
| 353 | continue; | ||
| 354 | } | ||
| 340 | list_del(&slave->list); | 355 | list_del(&slave->list); |
| 341 | del_mtd_device(&slave->mtd); | 356 | free_partition(slave); |
| 342 | kfree(slave); | ||
| 343 | } | 357 | } |
| 358 | mutex_unlock(&mtd_partitions_mutex); | ||
| 344 | 359 | ||
| 345 | return 0; | 360 | return err; |
| 346 | } | 361 | } |
| 347 | EXPORT_SYMBOL(del_mtd_partitions); | 362 | EXPORT_SYMBOL(del_mtd_partitions); |
| 348 | 363 | ||
| 349 | static struct mtd_part *add_one_partition(struct mtd_info *master, | 364 | static struct mtd_part *allocate_partition(struct mtd_info *master, |
| 350 | const struct mtd_partition *part, int partno, | 365 | const struct mtd_partition *part, int partno, |
| 351 | uint64_t cur_offset) | 366 | uint64_t cur_offset) |
| 352 | { | 367 | { |
| 353 | struct mtd_part *slave; | 368 | struct mtd_part *slave; |
| 369 | char *name; | ||
| 354 | 370 | ||
| 355 | /* allocate the partition structure */ | 371 | /* allocate the partition structure */ |
| 356 | slave = kzalloc(sizeof(*slave), GFP_KERNEL); | 372 | slave = kzalloc(sizeof(*slave), GFP_KERNEL); |
| 357 | if (!slave) { | 373 | name = kstrdup(part->name, GFP_KERNEL); |
| 374 | if (!name || !slave) { | ||
| 358 | printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", | 375 | printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", |
| 359 | master->name); | 376 | master->name); |
| 360 | del_mtd_partitions(master); | 377 | kfree(name); |
| 361 | return NULL; | 378 | kfree(slave); |
| 379 | return ERR_PTR(-ENOMEM); | ||
| 362 | } | 380 | } |
| 363 | list_add(&slave->list, &mtd_partitions); | ||
| 364 | 381 | ||
| 365 | /* set up the MTD object for this partition */ | 382 | /* set up the MTD object for this partition */ |
| 366 | slave->mtd.type = master->type; | 383 | slave->mtd.type = master->type; |
| @@ -371,7 +388,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, | |||
| 371 | slave->mtd.oobavail = master->oobavail; | 388 | slave->mtd.oobavail = master->oobavail; |
| 372 | slave->mtd.subpage_sft = master->subpage_sft; | 389 | slave->mtd.subpage_sft = master->subpage_sft; |
| 373 | 390 | ||
| 374 | slave->mtd.name = part->name; | 391 | slave->mtd.name = name; |
| 375 | slave->mtd.owner = master->owner; | 392 | slave->mtd.owner = master->owner; |
| 376 | slave->mtd.backing_dev_info = master->backing_dev_info; | 393 | slave->mtd.backing_dev_info = master->backing_dev_info; |
| 377 | 394 | ||
| @@ -518,12 +535,89 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, | |||
| 518 | } | 535 | } |
| 519 | 536 | ||
| 520 | out_register: | 537 | out_register: |
| 521 | /* register our partition */ | ||
| 522 | add_mtd_device(&slave->mtd); | ||
| 523 | |||
| 524 | return slave; | 538 | return slave; |
| 525 | } | 539 | } |
| 526 | 540 | ||
| 541 | int mtd_add_partition(struct mtd_info *master, char *name, | ||
| 542 | long long offset, long long length) | ||
| 543 | { | ||
| 544 | struct mtd_partition part; | ||
| 545 | struct mtd_part *p, *new; | ||
| 546 | uint64_t start, end; | ||
| 547 | int ret = 0; | ||
| 548 | |||
| 549 | /* the direct offset is expected */ | ||
| 550 | if (offset == MTDPART_OFS_APPEND || | ||
| 551 | offset == MTDPART_OFS_NXTBLK) | ||
| 552 | return -EINVAL; | ||
| 553 | |||
| 554 | if (length == MTDPART_SIZ_FULL) | ||
| 555 | length = master->size - offset; | ||
| 556 | |||
| 557 | if (length <= 0) | ||
| 558 | return -EINVAL; | ||
| 559 | |||
| 560 | part.name = name; | ||
| 561 | part.size = length; | ||
| 562 | part.offset = offset; | ||
| 563 | part.mask_flags = 0; | ||
| 564 | part.ecclayout = NULL; | ||
| 565 | |||
| 566 | new = allocate_partition(master, &part, -1, offset); | ||
| 567 | if (IS_ERR(new)) | ||
| 568 | return PTR_ERR(new); | ||
| 569 | |||
| 570 | start = offset; | ||
| 571 | end = offset + length; | ||
| 572 | |||
| 573 | mutex_lock(&mtd_partitions_mutex); | ||
| 574 | list_for_each_entry(p, &mtd_partitions, list) | ||
| 575 | if (p->master == master) { | ||
| 576 | if ((start >= p->offset) && | ||
| 577 | (start < (p->offset + p->mtd.size))) | ||
| 578 | goto err_inv; | ||
| 579 | |||
| 580 | if ((end >= p->offset) && | ||
| 581 | (end < (p->offset + p->mtd.size))) | ||
| 582 | goto err_inv; | ||
| 583 | } | ||
| 584 | |||
| 585 | list_add(&new->list, &mtd_partitions); | ||
| 586 | mutex_unlock(&mtd_partitions_mutex); | ||
| 587 | |||
| 588 | add_mtd_device(&new->mtd); | ||
| 589 | |||
| 590 | return ret; | ||
| 591 | err_inv: | ||
| 592 | mutex_unlock(&mtd_partitions_mutex); | ||
| 593 | free_partition(new); | ||
| 594 | return -EINVAL; | ||
| 595 | } | ||
| 596 | EXPORT_SYMBOL_GPL(mtd_add_partition); | ||
| 597 | |||
| 598 | int mtd_del_partition(struct mtd_info *master, int partno) | ||
| 599 | { | ||
| 600 | struct mtd_part *slave, *next; | ||
| 601 | int ret = -EINVAL; | ||
| 602 | |||
| 603 | mutex_lock(&mtd_partitions_mutex); | ||
| 604 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) | ||
| 605 | if ((slave->master == master) && | ||
| 606 | (slave->mtd.index == partno)) { | ||
| 607 | ret = del_mtd_device(&slave->mtd); | ||
| 608 | if (ret < 0) | ||
| 609 | break; | ||
| 610 | |||
| 611 | list_del(&slave->list); | ||
| 612 | free_partition(slave); | ||
| 613 | break; | ||
| 614 | } | ||
| 615 | mutex_unlock(&mtd_partitions_mutex); | ||
| 616 | |||
| 617 | return ret; | ||
| 618 | } | ||
| 619 | EXPORT_SYMBOL_GPL(mtd_del_partition); | ||
| 620 | |||
| 527 | /* | 621 | /* |
| 528 | * This function, given a master MTD object and a partition table, creates | 622 | * This function, given a master MTD object and a partition table, creates |
| 529 | * and registers slave MTD objects which are bound to the master according to | 623 | * and registers slave MTD objects which are bound to the master according to |
| @@ -544,9 +638,16 @@ int add_mtd_partitions(struct mtd_info *master, | |||
| 544 | printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); | 638 | printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); |
| 545 | 639 | ||
| 546 | for (i = 0; i < nbparts; i++) { | 640 | for (i = 0; i < nbparts; i++) { |
| 547 | slave = add_one_partition(master, parts + i, i, cur_offset); | 641 | slave = allocate_partition(master, parts + i, i, cur_offset); |
| 548 | if (!slave) | 642 | if (IS_ERR(slave)) |
| 549 | return -ENOMEM; | 643 | return PTR_ERR(slave); |
| 644 | |||
| 645 | mutex_lock(&mtd_partitions_mutex); | ||
| 646 | list_add(&slave->list, &mtd_partitions); | ||
| 647 | mutex_unlock(&mtd_partitions_mutex); | ||
| 648 | |||
| 649 | add_mtd_device(&slave->mtd); | ||
| 650 | |||
| 550 | cur_offset = slave->offset + slave->mtd.size; | 651 | cur_offset = slave->offset + slave->mtd.size; |
| 551 | } | 652 | } |
| 552 | 653 | ||
| @@ -618,3 +719,20 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, | |||
| 618 | return ret; | 719 | return ret; |
| 619 | } | 720 | } |
| 620 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); | 721 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); |
| 722 | |||
| 723 | int mtd_is_master(struct mtd_info *mtd) | ||
| 724 | { | ||
| 725 | struct mtd_part *part; | ||
| 726 | int nopart = 0; | ||
| 727 | |||
| 728 | mutex_lock(&mtd_partitions_mutex); | ||
| 729 | list_for_each_entry(part, &mtd_partitions, list) | ||
| 730 | if (&part->mtd == mtd) { | ||
| 731 | nopart = 1; | ||
| 732 | break; | ||
| 733 | } | ||
| 734 | mutex_unlock(&mtd_partitions_mutex); | ||
| 735 | |||
| 736 | return nopart; | ||
| 737 | } | ||
| 738 | EXPORT_SYMBOL_GPL(mtd_is_master); | ||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8b4b67c8a391..8229802b4346 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
| @@ -400,13 +400,6 @@ config MTD_NAND_PXA3xx | |||
| 400 | This enables the driver for the NAND flash device found on | 400 | This enables the driver for the NAND flash device found on |
| 401 | PXA3xx processors | 401 | PXA3xx processors |
| 402 | 402 | ||
| 403 | config MTD_NAND_PXA3xx_BUILTIN | ||
| 404 | bool "Use builtin definitions for some NAND chips (deprecated)" | ||
| 405 | depends on MTD_NAND_PXA3xx | ||
| 406 | help | ||
| 407 | This enables builtin definitions for some NAND chips. This | ||
| 408 | is deprecated in favor of platform specific data. | ||
| 409 | |||
| 410 | config MTD_NAND_CM_X270 | 403 | config MTD_NAND_CM_X270 |
| 411 | tristate "Support for NAND Flash on CM-X270 modules" | 404 | tristate "Support for NAND Flash on CM-X270 modules" |
| 412 | depends on MACH_ARMCORE | 405 | depends on MACH_ARMCORE |
| @@ -458,6 +451,7 @@ config MTD_NAND_ORION | |||
| 458 | config MTD_NAND_FSL_ELBC | 451 | config MTD_NAND_FSL_ELBC |
| 459 | tristate "NAND support for Freescale eLBC controllers" | 452 | tristate "NAND support for Freescale eLBC controllers" |
| 460 | depends on PPC_OF | 453 | depends on PPC_OF |
| 454 | select FSL_LBC | ||
| 461 | help | 455 | help |
| 462 | Various Freescale chips, including the 8313, include a NAND Flash | 456 | Various Freescale chips, including the 8313, include a NAND Flash |
| 463 | Controller Module with built-in hardware ECC capabilities. | 457 | Controller Module with built-in hardware ECC capabilities. |
| @@ -531,4 +525,11 @@ config MTD_NAND_JZ4740 | |||
| 531 | help | 525 | help |
| 532 | Enables support for NAND Flash on JZ4740 SoC based boards. | 526 | Enables support for NAND Flash on JZ4740 SoC based boards. |
| 533 | 527 | ||
| 528 | config MTD_NAND_FSMC | ||
| 529 | tristate "Support for NAND on ST Micros FSMC" | ||
| 530 | depends on PLAT_SPEAR || PLAT_NOMADIK || MACH_U300 | ||
| 531 | help | ||
| 532 | Enables support for NAND Flash chips on the ST Microelectronics | ||
| 533 | Flexible Static Memory Controller (FSMC) | ||
| 534 | |||
| 534 | endif # MTD_NAND | 535 | endif # MTD_NAND |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index ac83dcdac5d6..8ad6faec72cb 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
| @@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o | |||
| 19 | obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o | 19 | obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o |
| 20 | obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o | 20 | obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o |
| 21 | obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o | 21 | obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o |
| 22 | obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o | ||
| 22 | obj-$(CONFIG_MTD_NAND_H1900) += h1910.o | 23 | obj-$(CONFIG_MTD_NAND_H1900) += h1910.o |
| 23 | obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o | 24 | obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o |
| 24 | obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o | 25 | obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o |
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 6fbeefa3a766..79947bea4d57 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
| @@ -110,15 +110,6 @@ static const unsigned short bfin_nfc_pin_req[] = | |||
| 110 | 0}; | 110 | 0}; |
| 111 | 111 | ||
| 112 | #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC | 112 | #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC |
| 113 | static uint8_t bbt_pattern[] = { 0xff }; | ||
| 114 | |||
| 115 | static struct nand_bbt_descr bootrom_bbt = { | ||
| 116 | .options = 0, | ||
| 117 | .offs = 63, | ||
| 118 | .len = 1, | ||
| 119 | .pattern = bbt_pattern, | ||
| 120 | }; | ||
| 121 | |||
| 122 | static struct nand_ecclayout bootrom_ecclayout = { | 113 | static struct nand_ecclayout bootrom_ecclayout = { |
| 123 | .eccbytes = 24, | 114 | .eccbytes = 24, |
| 124 | .eccpos = { | 115 | .eccpos = { |
| @@ -809,7 +800,6 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) | |||
| 809 | /* setup hardware ECC data struct */ | 800 | /* setup hardware ECC data struct */ |
| 810 | if (hardware_ecc) { | 801 | if (hardware_ecc) { |
| 811 | #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC | 802 | #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC |
| 812 | chip->badblock_pattern = &bootrom_bbt; | ||
| 813 | chip->ecc.layout = &bootrom_ecclayout; | 803 | chip->ecc.layout = &bootrom_ecclayout; |
| 814 | #endif | 804 | #endif |
| 815 | chip->read_buf = bf5xx_nand_dma_read_buf; | 805 | chip->read_buf = bf5xx_nand_dma_read_buf; |
| @@ -830,6 +820,10 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) | |||
| 830 | goto out_err_nand_scan; | 820 | goto out_err_nand_scan; |
| 831 | } | 821 | } |
| 832 | 822 | ||
| 823 | #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC | ||
| 824 | chip->badblockpos = 63; | ||
| 825 | #endif | ||
| 826 | |||
| 833 | /* add NAND partition */ | 827 | /* add NAND partition */ |
| 834 | bf5xx_nand_add_partition(info); | 828 | bf5xx_nand_add_partition(info); |
| 835 | 829 | ||
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 8beb0d0233b5..a90fde3ede28 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c | |||
| @@ -316,7 +316,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd, | |||
| 316 | u32 syndrome[4]; | 316 | u32 syndrome[4]; |
| 317 | u32 ecc_state; | 317 | u32 ecc_state; |
| 318 | unsigned num_errors, corrected; | 318 | unsigned num_errors, corrected; |
| 319 | unsigned long timeo = jiffies + msecs_to_jiffies(100); | 319 | unsigned long timeo; |
| 320 | 320 | ||
| 321 | /* All bytes 0xff? It's an erased page; ignore its ECC. */ | 321 | /* All bytes 0xff? It's an erased page; ignore its ECC. */ |
| 322 | for (i = 0; i < 10; i++) { | 322 | for (i = 0; i < 10; i++) { |
| @@ -372,9 +372,11 @@ compare: | |||
| 372 | * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately | 372 | * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately |
| 373 | * begin trying to poll for the state, you may fall right out of your | 373 | * begin trying to poll for the state, you may fall right out of your |
| 374 | * loop without any of the correction calculations having taken place. | 374 | * loop without any of the correction calculations having taken place. |
| 375 | * The recommendation from the hardware team is to wait till ECC_STATE | 375 | * The recommendation from the hardware team is to initially delay as |
| 376 | * reads less than 4, which means ECC HW has entered correction state. | 376 | * long as ECC_STATE reads less than 4. After that, ECC HW has entered |
| 377 | * correction state. | ||
| 377 | */ | 378 | */ |
| 379 | timeo = jiffies + usecs_to_jiffies(100); | ||
| 378 | do { | 380 | do { |
| 379 | ecc_state = (davinci_nand_readl(info, | 381 | ecc_state = (davinci_nand_readl(info, |
| 380 | NANDFSR_OFFSET) >> 8) & 0x0f; | 382 | NANDFSR_OFFSET) >> 8) & 0x0f; |
| @@ -733,6 +735,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) | |||
| 733 | * breaks userspace ioctl interface with mtd-utils. Once we | 735 | * breaks userspace ioctl interface with mtd-utils. Once we |
| 734 | * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used | 736 | * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used |
| 735 | * for the 4KiB page chips. | 737 | * for the 4KiB page chips. |
| 738 | * | ||
| 739 | * TODO: Note that nand_ecclayout has now been expanded and can | ||
| 740 | * hold plenty of OOB entries. | ||
| 736 | */ | 741 | */ |
| 737 | dev_warn(&pdev->dev, "no 4-bit ECC support yet " | 742 | dev_warn(&pdev->dev, "no 4-bit ECC support yet " |
| 738 | "for 4KiB-page NAND\n"); | 743 | "for 4KiB-page NAND\n"); |
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 532fe07cf886..8c8d3c86c0e8 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c | |||
| @@ -1292,6 +1292,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, | |||
| 1292 | read_status(denali); | 1292 | read_status(denali); |
| 1293 | break; | 1293 | break; |
| 1294 | case NAND_CMD_READID: | 1294 | case NAND_CMD_READID: |
| 1295 | case NAND_CMD_PARAM: | ||
| 1295 | reset_buf(denali); | 1296 | reset_buf(denali); |
| 1296 | /*sometimes ManufactureId read from register is not right | 1297 | /*sometimes ManufactureId read from register is not right |
| 1297 | * e.g. some of Micron MT29F32G08QAA MLC NAND chips | 1298 | * e.g. some of Micron MT29F32G08QAA MLC NAND chips |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 80de0bff6c3a..c141b07b25d1 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
| @@ -1,9 +1,11 @@ | |||
| 1 | /* Freescale Enhanced Local Bus Controller NAND driver | 1 | /* Freescale Enhanced Local Bus Controller NAND driver |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2006-2007 Freescale Semiconductor | 3 | * Copyright © 2006-2007, 2010 Freescale Semiconductor |
| 4 | * | 4 | * |
| 5 | * Authors: Nick Spence <nick.spence@freescale.com>, | 5 | * Authors: Nick Spence <nick.spence@freescale.com>, |
| 6 | * Scott Wood <scottwood@freescale.com> | 6 | * Scott Wood <scottwood@freescale.com> |
| 7 | * Jack Lan <jack.lan@freescale.com> | ||
| 8 | * Roy Zang <tie-fei.zang@freescale.com> | ||
| 7 | * | 9 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
| @@ -27,6 +29,7 @@ | |||
| 27 | #include <linux/string.h> | 29 | #include <linux/string.h> |
| 28 | #include <linux/ioport.h> | 30 | #include <linux/ioport.h> |
| 29 | #include <linux/of_platform.h> | 31 | #include <linux/of_platform.h> |
| 32 | #include <linux/platform_device.h> | ||
| 30 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 31 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
| 32 | 35 | ||
| @@ -42,14 +45,12 @@ | |||
| 42 | #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ | 45 | #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ |
| 43 | #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */ | 46 | #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */ |
| 44 | 47 | ||
| 45 | struct fsl_elbc_ctrl; | ||
| 46 | |||
| 47 | /* mtd information per set */ | 48 | /* mtd information per set */ |
| 48 | 49 | ||
| 49 | struct fsl_elbc_mtd { | 50 | struct fsl_elbc_mtd { |
| 50 | struct mtd_info mtd; | 51 | struct mtd_info mtd; |
| 51 | struct nand_chip chip; | 52 | struct nand_chip chip; |
| 52 | struct fsl_elbc_ctrl *ctrl; | 53 | struct fsl_lbc_ctrl *ctrl; |
| 53 | 54 | ||
| 54 | struct device *dev; | 55 | struct device *dev; |
| 55 | int bank; /* Chip select bank number */ | 56 | int bank; /* Chip select bank number */ |
| @@ -58,18 +59,12 @@ struct fsl_elbc_mtd { | |||
| 58 | unsigned int fmr; /* FCM Flash Mode Register value */ | 59 | unsigned int fmr; /* FCM Flash Mode Register value */ |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 61 | /* overview of the fsl elbc controller */ | 62 | /* Freescale eLBC FCM controller infomation */ |
| 62 | 63 | ||
| 63 | struct fsl_elbc_ctrl { | 64 | struct fsl_elbc_fcm_ctrl { |
| 64 | struct nand_hw_control controller; | 65 | struct nand_hw_control controller; |
| 65 | struct fsl_elbc_mtd *chips[MAX_BANKS]; | 66 | struct fsl_elbc_mtd *chips[MAX_BANKS]; |
| 66 | 67 | ||
| 67 | /* device info */ | ||
| 68 | struct device *dev; | ||
| 69 | struct fsl_lbc_regs __iomem *regs; | ||
| 70 | int irq; | ||
| 71 | wait_queue_head_t irq_wait; | ||
| 72 | unsigned int irq_status; /* status read from LTESR by irq handler */ | ||
| 73 | u8 __iomem *addr; /* Address of assigned FCM buffer */ | 68 | u8 __iomem *addr; /* Address of assigned FCM buffer */ |
| 74 | unsigned int page; /* Last page written to / read from */ | 69 | unsigned int page; /* Last page written to / read from */ |
| 75 | unsigned int read_bytes; /* Number of bytes read during command */ | 70 | unsigned int read_bytes; /* Number of bytes read during command */ |
| @@ -79,6 +74,7 @@ struct fsl_elbc_ctrl { | |||
| 79 | unsigned int mdr; /* UPM/FCM Data Register value */ | 74 | unsigned int mdr; /* UPM/FCM Data Register value */ |
| 80 | unsigned int use_mdr; /* Non zero if the MDR is to be set */ | 75 | unsigned int use_mdr; /* Non zero if the MDR is to be set */ |
| 81 | unsigned int oob; /* Non zero if operating on OOB data */ | 76 | unsigned int oob; /* Non zero if operating on OOB data */ |
| 77 | unsigned int counter; /* counter for the initializations */ | ||
| 82 | char *oob_poi; /* Place to write ECC after read back */ | 78 | char *oob_poi; /* Place to write ECC after read back */ |
| 83 | }; | 79 | }; |
| 84 | 80 | ||
| @@ -164,11 +160,12 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) | |||
| 164 | { | 160 | { |
| 165 | struct nand_chip *chip = mtd->priv; | 161 | struct nand_chip *chip = mtd->priv; |
| 166 | struct fsl_elbc_mtd *priv = chip->priv; | 162 | struct fsl_elbc_mtd *priv = chip->priv; |
| 167 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 163 | struct fsl_lbc_ctrl *ctrl = priv->ctrl; |
| 168 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 164 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
| 165 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; | ||
| 169 | int buf_num; | 166 | int buf_num; |
| 170 | 167 | ||
| 171 | ctrl->page = page_addr; | 168 | elbc_fcm_ctrl->page = page_addr; |
| 172 | 169 | ||
| 173 | out_be32(&lbc->fbar, | 170 | out_be32(&lbc->fbar, |
| 174 | page_addr >> (chip->phys_erase_shift - chip->page_shift)); | 171 | page_addr >> (chip->phys_erase_shift - chip->page_shift)); |
| @@ -185,16 +182,18 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) | |||
| 185 | buf_num = page_addr & 7; | 182 | buf_num = page_addr & 7; |
| 186 | } | 183 | } |
| 187 | 184 | ||
| 188 | ctrl->addr = priv->vbase + buf_num * 1024; | 185 | elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024; |
| 189 | ctrl->index = column; | 186 | elbc_fcm_ctrl->index = column; |
| 190 | 187 | ||
| 191 | /* for OOB data point to the second half of the buffer */ | 188 | /* for OOB data point to the second half of the buffer */ |
| 192 | if (oob) | 189 | if (oob) |
| 193 | ctrl->index += priv->page_size ? 2048 : 512; | 190 | elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512; |
| 194 | 191 | ||
| 195 | dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " | 192 | dev_vdbg(priv->dev, "set_addr: bank=%d, " |
| 193 | "elbc_fcm_ctrl->addr=0x%p (0x%p), " | ||
| 196 | "index %x, pes %d ps %d\n", | 194 | "index %x, pes %d ps %d\n", |
| 197 | buf_num, ctrl->addr, priv->vbase, ctrl->index, | 195 | buf_num, elbc_fcm_ctrl->addr, priv->vbase, |
| 196 | elbc_fcm_ctrl->index, | ||
| 198 | chip->phys_erase_shift, chip->page_shift); | 197 | chip->phys_erase_shift, chip->page_shift); |
| 199 | } | 198 | } |
| 200 | 199 | ||
| @@ -205,18 +204,19 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) | |||
| 205 | { | 204 | { |
| 206 | struct nand_chip *chip = mtd->priv; | 205 | struct nand_chip *chip = mtd->priv; |
| 207 | struct fsl_elbc_mtd *priv = chip->priv; | 206 | struct fsl_elbc_mtd *priv = chip->priv; |
| 208 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 207 | struct fsl_lbc_ctrl *ctrl = priv->ctrl; |
| 208 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; | ||
| 209 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 209 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
| 210 | 210 | ||
| 211 | /* Setup the FMR[OP] to execute without write protection */ | 211 | /* Setup the FMR[OP] to execute without write protection */ |
| 212 | out_be32(&lbc->fmr, priv->fmr | 3); | 212 | out_be32(&lbc->fmr, priv->fmr | 3); |
| 213 | if (ctrl->use_mdr) | 213 | if (elbc_fcm_ctrl->use_mdr) |
| 214 | out_be32(&lbc->mdr, ctrl->mdr); | 214 | out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr); |
| 215 | 215 | ||
| 216 | dev_vdbg(ctrl->dev, | 216 | dev_vdbg(priv->dev, |
| 217 | "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", | 217 | "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", |
| 218 | in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); | 218 | in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); |
| 219 | dev_vdbg(ctrl->dev, | 219 | dev_vdbg(priv->dev, |
| 220 | "fsl_elbc_run_command: fbar=%08x fpar=%08x " | 220 | "fsl_elbc_run_command: fbar=%08x fpar=%08x " |
| 221 | "fbcr=%08x bank=%d\n", | 221 | "fbcr=%08x bank=%d\n", |
| 222 | in_be32(&lbc->fbar), in_be32(&lbc->fpar), | 222 | in_be32(&lbc->fbar), in_be32(&lbc->fpar), |
| @@ -229,19 +229,18 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) | |||
| 229 | /* wait for FCM complete flag or timeout */ | 229 | /* wait for FCM complete flag or timeout */ |
| 230 | wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, | 230 | wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, |
| 231 | FCM_TIMEOUT_MSECS * HZ/1000); | 231 | FCM_TIMEOUT_MSECS * HZ/1000); |
| 232 | ctrl->status = ctrl->irq_status; | 232 | elbc_fcm_ctrl->status = ctrl->irq_status; |
| 233 | |||
| 234 | /* store mdr value in case it was needed */ | 233 | /* store mdr value in case it was needed */ |
| 235 | if (ctrl->use_mdr) | 234 | if (elbc_fcm_ctrl->use_mdr) |
| 236 | ctrl->mdr = in_be32(&lbc->mdr); | 235 | elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr); |
| 237 | 236 | ||
| 238 | ctrl->use_mdr = 0; | 237 | elbc_fcm_ctrl->use_mdr = 0; |
| 239 | 238 | ||
| 240 | if (ctrl->status != LTESR_CC) { | 239 | if (elbc_fcm_ctrl->status != LTESR_CC) { |
| 241 | dev_info(ctrl->dev, | 240 | dev_info(priv->dev, |
| 242 | "command failed: fir %x fcr %x status %x mdr %x\n", | 241 | "command failed: fir %x fcr %x status %x mdr %x\n", |
| 243 | in_be32(&lbc->fir), in_be32(&lbc->fcr), | 242 | in_be32(&lbc->fir), in_be32(&lbc->fcr), |
| 244 | ctrl->status, ctrl->mdr); | 243 | elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr); |
| 245 | return -EIO; | 244 | return -EIO; |
| 246 | } | 245 | } |
| 247 | 246 | ||
| @@ -251,7 +250,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) | |||
| 251 | static void fsl_elbc_do_read(struct nand_chip *chip, int oob) | 250 | static void fsl_elbc_do_read(struct nand_chip *chip, int oob) |
| 252 | { | 251 | { |
| 253 | struct fsl_elbc_mtd *priv = chip->priv; | 252 | struct fsl_elbc_mtd *priv = chip->priv; |
| 254 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 253 | struct fsl_lbc_ctrl *ctrl = priv->ctrl; |
| 255 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 254 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
| 256 | 255 | ||
| 257 | if (priv->page_size) { | 256 | if (priv->page_size) { |
| @@ -284,15 +283,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 284 | { | 283 | { |
| 285 | struct nand_chip *chip = mtd->priv; | 284 | struct nand_chip *chip = mtd->priv; |
| 286 | struct fsl_elbc_mtd *priv = chip->priv; | 285 | struct fsl_elbc_mtd *priv = chip->priv; |
| 287 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 286 | struct fsl_lbc_ctrl *ctrl = priv->ctrl; |
| 287 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; | ||
| 288 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 288 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
| 289 | 289 | ||
| 290 | ctrl->use_mdr = 0; | 290 | elbc_fcm_ctrl->use_mdr = 0; |
| 291 | 291 | ||
| 292 | /* clear the read buffer */ | 292 | /* clear the read buffer */ |
| 293 | ctrl->read_bytes = 0; | 293 | elbc_fcm_ctrl->read_bytes = 0; |
| 294 | if (command != NAND_CMD_PAGEPROG) | 294 | if (command != NAND_CMD_PAGEPROG) |
| 295 | ctrl->index = 0; | 295 | elbc_fcm_ctrl->index = 0; |
| 296 | 296 | ||
| 297 | switch (command) { | 297 | switch (command) { |
| 298 | /* READ0 and READ1 read the entire buffer to use hardware ECC. */ | 298 | /* READ0 and READ1 read the entire buffer to use hardware ECC. */ |
| @@ -301,7 +301,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 301 | 301 | ||
| 302 | /* fall-through */ | 302 | /* fall-through */ |
| 303 | case NAND_CMD_READ0: | 303 | case NAND_CMD_READ0: |
| 304 | dev_dbg(ctrl->dev, | 304 | dev_dbg(priv->dev, |
| 305 | "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" | 305 | "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" |
| 306 | " 0x%x, column: 0x%x.\n", page_addr, column); | 306 | " 0x%x, column: 0x%x.\n", page_addr, column); |
| 307 | 307 | ||
| @@ -309,8 +309,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 309 | out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ | 309 | out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ |
| 310 | set_addr(mtd, 0, page_addr, 0); | 310 | set_addr(mtd, 0, page_addr, 0); |
| 311 | 311 | ||
| 312 | ctrl->read_bytes = mtd->writesize + mtd->oobsize; | 312 | elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize; |
| 313 | ctrl->index += column; | 313 | elbc_fcm_ctrl->index += column; |
| 314 | 314 | ||
| 315 | fsl_elbc_do_read(chip, 0); | 315 | fsl_elbc_do_read(chip, 0); |
| 316 | fsl_elbc_run_command(mtd); | 316 | fsl_elbc_run_command(mtd); |
| @@ -318,14 +318,14 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 318 | 318 | ||
| 319 | /* READOOB reads only the OOB because no ECC is performed. */ | 319 | /* READOOB reads only the OOB because no ECC is performed. */ |
| 320 | case NAND_CMD_READOOB: | 320 | case NAND_CMD_READOOB: |
| 321 | dev_vdbg(ctrl->dev, | 321 | dev_vdbg(priv->dev, |
| 322 | "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" | 322 | "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" |
| 323 | " 0x%x, column: 0x%x.\n", page_addr, column); | 323 | " 0x%x, column: 0x%x.\n", page_addr, column); |
| 324 | 324 | ||
| 325 | out_be32(&lbc->fbcr, mtd->oobsize - column); | 325 | out_be32(&lbc->fbcr, mtd->oobsize - column); |
| 326 | set_addr(mtd, column, page_addr, 1); | 326 | set_addr(mtd, column, page_addr, 1); |
| 327 | 327 | ||
| 328 | ctrl->read_bytes = mtd->writesize + mtd->oobsize; | 328 | elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize; |
| 329 | 329 | ||
| 330 | fsl_elbc_do_read(chip, 1); | 330 | fsl_elbc_do_read(chip, 1); |
| 331 | fsl_elbc_run_command(mtd); | 331 | fsl_elbc_run_command(mtd); |
| @@ -333,7 +333,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 333 | 333 | ||
| 334 | /* READID must read all 5 possible bytes while CEB is active */ | 334 | /* READID must read all 5 possible bytes while CEB is active */ |
| 335 | case NAND_CMD_READID: | 335 | case NAND_CMD_READID: |
| 336 | dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); | 336 | dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); |
| 337 | 337 | ||
| 338 | out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | | 338 | out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | |
| 339 | (FIR_OP_UA << FIR_OP1_SHIFT) | | 339 | (FIR_OP_UA << FIR_OP1_SHIFT) | |
| @@ -341,9 +341,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 341 | out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); | 341 | out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); |
| 342 | /* 5 bytes for manuf, device and exts */ | 342 | /* 5 bytes for manuf, device and exts */ |
| 343 | out_be32(&lbc->fbcr, 5); | 343 | out_be32(&lbc->fbcr, 5); |
| 344 | ctrl->read_bytes = 5; | 344 | elbc_fcm_ctrl->read_bytes = 5; |
| 345 | ctrl->use_mdr = 1; | 345 | elbc_fcm_ctrl->use_mdr = 1; |
| 346 | ctrl->mdr = 0; | 346 | elbc_fcm_ctrl->mdr = 0; |
| 347 | 347 | ||
| 348 | set_addr(mtd, 0, 0, 0); | 348 | set_addr(mtd, 0, 0, 0); |
| 349 | fsl_elbc_run_command(mtd); | 349 | fsl_elbc_run_command(mtd); |
| @@ -351,7 +351,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 351 | 351 | ||
| 352 | /* ERASE1 stores the block and page address */ | 352 | /* ERASE1 stores the block and page address */ |
| 353 | case NAND_CMD_ERASE1: | 353 | case NAND_CMD_ERASE1: |
| 354 | dev_vdbg(ctrl->dev, | 354 | dev_vdbg(priv->dev, |
| 355 | "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " | 355 | "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " |
| 356 | "page_addr: 0x%x.\n", page_addr); | 356 | "page_addr: 0x%x.\n", page_addr); |
| 357 | set_addr(mtd, 0, page_addr, 0); | 357 | set_addr(mtd, 0, page_addr, 0); |
| @@ -359,7 +359,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 359 | 359 | ||
| 360 | /* ERASE2 uses the block and page address from ERASE1 */ | 360 | /* ERASE2 uses the block and page address from ERASE1 */ |
| 361 | case NAND_CMD_ERASE2: | 361 | case NAND_CMD_ERASE2: |
| 362 | dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); | 362 | dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); |
| 363 | 363 | ||
| 364 | out_be32(&lbc->fir, | 364 | out_be32(&lbc->fir, |
| 365 | (FIR_OP_CM0 << FIR_OP0_SHIFT) | | 365 | (FIR_OP_CM0 << FIR_OP0_SHIFT) | |
| @@ -374,8 +374,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 374 | (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT)); | 374 | (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT)); |
| 375 | 375 | ||
| 376 | out_be32(&lbc->fbcr, 0); | 376 | out_be32(&lbc->fbcr, 0); |
| 377 | ctrl->read_bytes = 0; | 377 | elbc_fcm_ctrl->read_bytes = 0; |
| 378 | ctrl->use_mdr = 1; | 378 | elbc_fcm_ctrl->use_mdr = 1; |
| 379 | 379 | ||
| 380 | fsl_elbc_run_command(mtd); | 380 | fsl_elbc_run_command(mtd); |
| 381 | return; | 381 | return; |
| @@ -383,14 +383,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 383 | /* SEQIN sets up the addr buffer and all registers except the length */ | 383 | /* SEQIN sets up the addr buffer and all registers except the length */ |
| 384 | case NAND_CMD_SEQIN: { | 384 | case NAND_CMD_SEQIN: { |
| 385 | __be32 fcr; | 385 | __be32 fcr; |
| 386 | dev_vdbg(ctrl->dev, | 386 | dev_vdbg(priv->dev, |
| 387 | "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " | 387 | "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " |
| 388 | "page_addr: 0x%x, column: 0x%x.\n", | 388 | "page_addr: 0x%x, column: 0x%x.\n", |
| 389 | page_addr, column); | 389 | page_addr, column); |
| 390 | 390 | ||
| 391 | ctrl->column = column; | 391 | elbc_fcm_ctrl->use_mdr = 1; |
| 392 | ctrl->oob = 0; | ||
| 393 | ctrl->use_mdr = 1; | ||
| 394 | 392 | ||
| 395 | fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | | 393 | fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | |
| 396 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT) | | 394 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT) | |
| @@ -420,7 +418,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 420 | /* OOB area --> READOOB */ | 418 | /* OOB area --> READOOB */ |
| 421 | column -= mtd->writesize; | 419 | column -= mtd->writesize; |
| 422 | fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; | 420 | fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; |
| 423 | ctrl->oob = 1; | 421 | elbc_fcm_ctrl->oob = 1; |
| 424 | } else { | 422 | } else { |
| 425 | WARN_ON(column != 0); | 423 | WARN_ON(column != 0); |
| 426 | /* First 256 bytes --> READ0 */ | 424 | /* First 256 bytes --> READ0 */ |
| @@ -429,24 +427,24 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 429 | } | 427 | } |
| 430 | 428 | ||
| 431 | out_be32(&lbc->fcr, fcr); | 429 | out_be32(&lbc->fcr, fcr); |
| 432 | set_addr(mtd, column, page_addr, ctrl->oob); | 430 | set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob); |
| 433 | return; | 431 | return; |
| 434 | } | 432 | } |
| 435 | 433 | ||
| 436 | /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ | 434 | /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ |
| 437 | case NAND_CMD_PAGEPROG: { | 435 | case NAND_CMD_PAGEPROG: { |
| 438 | int full_page; | 436 | int full_page; |
| 439 | dev_vdbg(ctrl->dev, | 437 | dev_vdbg(priv->dev, |
| 440 | "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " | 438 | "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " |
| 441 | "writing %d bytes.\n", ctrl->index); | 439 | "writing %d bytes.\n", elbc_fcm_ctrl->index); |
| 442 | 440 | ||
| 443 | /* if the write did not start at 0 or is not a full page | 441 | /* if the write did not start at 0 or is not a full page |
| 444 | * then set the exact length, otherwise use a full page | 442 | * then set the exact length, otherwise use a full page |
| 445 | * write so the HW generates the ECC. | 443 | * write so the HW generates the ECC. |
| 446 | */ | 444 | */ |
| 447 | if (ctrl->oob || ctrl->column != 0 || | 445 | if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || |
| 448 | ctrl->index != mtd->writesize + mtd->oobsize) { | 446 | elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { |
| 449 | out_be32(&lbc->fbcr, ctrl->index); | 447 | out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); |
| 450 | full_page = 0; | 448 | full_page = 0; |
| 451 | } else { | 449 | } else { |
| 452 | out_be32(&lbc->fbcr, 0); | 450 | out_be32(&lbc->fbcr, 0); |
| @@ -458,21 +456,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 458 | /* Read back the page in order to fill in the ECC for the | 456 | /* Read back the page in order to fill in the ECC for the |
| 459 | * caller. Is this really needed? | 457 | * caller. Is this really needed? |
| 460 | */ | 458 | */ |
| 461 | if (full_page && ctrl->oob_poi) { | 459 | if (full_page && elbc_fcm_ctrl->oob_poi) { |
| 462 | out_be32(&lbc->fbcr, 3); | 460 | out_be32(&lbc->fbcr, 3); |
| 463 | set_addr(mtd, 6, page_addr, 1); | 461 | set_addr(mtd, 6, page_addr, 1); |
| 464 | 462 | ||
| 465 | ctrl->read_bytes = mtd->writesize + 9; | 463 | elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; |
| 466 | 464 | ||
| 467 | fsl_elbc_do_read(chip, 1); | 465 | fsl_elbc_do_read(chip, 1); |
| 468 | fsl_elbc_run_command(mtd); | 466 | fsl_elbc_run_command(mtd); |
| 469 | 467 | ||
| 470 | memcpy_fromio(ctrl->oob_poi + 6, | 468 | memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, |
| 471 | &ctrl->addr[ctrl->index], 3); | 469 | &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); |
| 472 | ctrl->index += 3; | 470 | elbc_fcm_ctrl->index += 3; |
| 473 | } | 471 | } |
| 474 | 472 | ||
| 475 | ctrl->oob_poi = NULL; | 473 | elbc_fcm_ctrl->oob_poi = NULL; |
| 476 | return; | 474 | return; |
| 477 | } | 475 | } |
| 478 | 476 | ||
| @@ -485,26 +483,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 485 | out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); | 483 | out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); |
| 486 | out_be32(&lbc->fbcr, 1); | 484 | out_be32(&lbc->fbcr, 1); |
| 487 | set_addr(mtd, 0, 0, 0); | 485 | set_addr(mtd, 0, 0, 0); |
| 488 | ctrl->read_bytes = 1; | 486 | elbc_fcm_ctrl->read_bytes = 1; |
| 489 | 487 | ||
| 490 | fsl_elbc_run_command(mtd); | 488 | fsl_elbc_run_command(mtd); |
| 491 | 489 | ||
| 492 | /* The chip always seems to report that it is | 490 | /* The chip always seems to report that it is |
| 493 | * write-protected, even when it is not. | 491 | * write-protected, even when it is not. |
| 494 | */ | 492 | */ |
| 495 | setbits8(ctrl->addr, NAND_STATUS_WP); | 493 | setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP); |
| 496 | return; | 494 | return; |
| 497 | 495 | ||
| 498 | /* RESET without waiting for the ready line */ | 496 | /* RESET without waiting for the ready line */ |
| 499 | case NAND_CMD_RESET: | 497 | case NAND_CMD_RESET: |
| 500 | dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); | 498 | dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); |
| 501 | out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); | 499 | out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); |
| 502 | out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); | 500 | out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); |
| 503 | fsl_elbc_run_command(mtd); | 501 | fsl_elbc_run_command(mtd); |
| 504 | return; | 502 | return; |
| 505 | 503 | ||
| 506 | default: | 504 | default: |
| 507 | dev_err(ctrl->dev, | 505 | dev_err(priv->dev, |
| 508 | "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", | 506 | "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", |
| 509 | command); | 507 | command); |
| 510 | } | 508 | } |
| @@ -524,24 +522,24 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |||
| 524 | { | 522 | { |
| 525 | struct nand_chip *chip = mtd->priv; | 523 | struct nand_chip *chip = mtd->priv; |
| 526 | struct fsl_elbc_mtd *priv = chip->priv; | 524 | struct fsl_elbc_mtd *priv = chip->priv; |
| 527 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 525 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; |
| 528 | unsigned int bufsize = mtd->writesize + mtd->oobsize; | 526 | unsigned int bufsize = mtd->writesize + mtd->oobsize; |
| 529 | 527 | ||
| 530 | if (len <= 0) { | 528 | if (len <= 0) { |
| 531 | dev_err(ctrl->dev, "write_buf of %d bytes", len); | 529 | dev_err(priv->dev, "write_buf of %d bytes", len); |
| 532 | ctrl->status = 0; | 530 | elbc_fcm_ctrl->status = 0; |
| 533 | return; | 531 | return; |
| 534 | } | 532 | } |
| 535 | 533 | ||
| 536 | if ((unsigned int)len > bufsize - ctrl->index) { | 534 | if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) { |
| 537 | dev_err(ctrl->dev, | 535 | dev_err(priv->dev, |
| 538 | "write_buf beyond end of buffer " | 536 | "write_buf beyond end of buffer " |
| 539 | "(%d requested, %u available)\n", | 537 | "(%d requested, %u available)\n", |
| 540 | len, bufsize - ctrl->index); | 538 | len, bufsize - elbc_fcm_ctrl->index); |
| 541 | len = bufsize - ctrl->index; | 539 | len = bufsize - elbc_fcm_ctrl->index; |
| 542 | } | 540 | } |
| 543 | 541 | ||
| 544 | memcpy_toio(&ctrl->addr[ctrl->index], buf, len); | 542 | memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len); |
| 545 | /* | 543 | /* |
| 546 | * This is workaround for the weird elbc hangs during nand write, | 544 | * This is workaround for the weird elbc hangs during nand write, |
| 547 | * Scott Wood says: "...perhaps difference in how long it takes a | 545 | * Scott Wood says: "...perhaps difference in how long it takes a |
| @@ -549,9 +547,9 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |||
| 549 | * is causing problems, and sync isn't helping for some reason." | 547 | * is causing problems, and sync isn't helping for some reason." |
| 550 | * Reading back the last byte helps though. | 548 | * Reading back the last byte helps though. |
| 551 | */ | 549 | */ |
| 552 | in_8(&ctrl->addr[ctrl->index] + len - 1); | 550 | in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1); |
| 553 | 551 | ||
| 554 | ctrl->index += len; | 552 | elbc_fcm_ctrl->index += len; |
| 555 | } | 553 | } |
| 556 | 554 | ||
| 557 | /* | 555 | /* |
| @@ -562,13 +560,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd) | |||
| 562 | { | 560 | { |
| 563 | struct nand_chip *chip = mtd->priv; | 561 | struct nand_chip *chip = mtd->priv; |
| 564 | struct fsl_elbc_mtd *priv = chip->priv; | 562 | struct fsl_elbc_mtd *priv = chip->priv; |
| 565 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 563 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; |
| 566 | 564 | ||
| 567 | /* If there are still bytes in the FCM, then use the next byte. */ | 565 | /* If there are still bytes in the FCM, then use the next byte. */ |
| 568 | if (ctrl->index < ctrl->read_bytes) | 566 | if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes) |
| 569 | return in_8(&ctrl->addr[ctrl->index++]); | 567 | return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]); |
| 570 | 568 | ||
| 571 | dev_err(ctrl->dev, "read_byte beyond end of buffer\n"); | 569 | dev_err(priv->dev, "read_byte beyond end of buffer\n"); |
| 572 | return ERR_BYTE; | 570 | return ERR_BYTE; |
| 573 | } | 571 | } |
| 574 | 572 | ||
| @@ -579,18 +577,19 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) | |||
| 579 | { | 577 | { |
| 580 | struct nand_chip *chip = mtd->priv; | 578 | struct nand_chip *chip = mtd->priv; |
| 581 | struct fsl_elbc_mtd *priv = chip->priv; | 579 | struct fsl_elbc_mtd *priv = chip->priv; |
| 582 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 580 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; |
| 583 | int avail; | 581 | int avail; |
| 584 | 582 | ||
| 585 | if (len < 0) | 583 | if (len < 0) |
| 586 | return; | 584 | return; |
| 587 | 585 | ||
| 588 | avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); | 586 | avail = min((unsigned int)len, |
| 589 | memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); | 587 | elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index); |
| 590 | ctrl->index += avail; | 588 | memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail); |
| 589 | elbc_fcm_ctrl->index += avail; | ||
| 591 | 590 | ||
| 592 | if (len > avail) | 591 | if (len > avail) |
| 593 | dev_err(ctrl->dev, | 592 | dev_err(priv->dev, |
| 594 | "read_buf beyond end of buffer " | 593 | "read_buf beyond end of buffer " |
| 595 | "(%d requested, %d available)\n", | 594 | "(%d requested, %d available)\n", |
| 596 | len, avail); | 595 | len, avail); |
| @@ -603,30 +602,32 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
| 603 | { | 602 | { |
| 604 | struct nand_chip *chip = mtd->priv; | 603 | struct nand_chip *chip = mtd->priv; |
| 605 | struct fsl_elbc_mtd *priv = chip->priv; | 604 | struct fsl_elbc_mtd *priv = chip->priv; |
| 606 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 605 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; |
| 607 | int i; | 606 | int i; |
| 608 | 607 | ||
| 609 | if (len < 0) { | 608 | if (len < 0) { |
| 610 | dev_err(ctrl->dev, "write_buf of %d bytes", len); | 609 | dev_err(priv->dev, "write_buf of %d bytes", len); |
| 611 | return -EINVAL; | 610 | return -EINVAL; |
| 612 | } | 611 | } |
| 613 | 612 | ||
| 614 | if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { | 613 | if ((unsigned int)len > |
| 615 | dev_err(ctrl->dev, | 614 | elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) { |
| 616 | "verify_buf beyond end of buffer " | 615 | dev_err(priv->dev, |
| 617 | "(%d requested, %u available)\n", | 616 | "verify_buf beyond end of buffer " |
| 618 | len, ctrl->read_bytes - ctrl->index); | 617 | "(%d requested, %u available)\n", |
| 618 | len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index); | ||
| 619 | 619 | ||
| 620 | ctrl->index = ctrl->read_bytes; | 620 | elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes; |
| 621 | return -EINVAL; | 621 | return -EINVAL; |
| 622 | } | 622 | } |
| 623 | 623 | ||
| 624 | for (i = 0; i < len; i++) | 624 | for (i = 0; i < len; i++) |
| 625 | if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) | 625 | if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i]) |
| 626 | != buf[i]) | ||
| 626 | break; | 627 | break; |
| 627 | 628 | ||
| 628 | ctrl->index += len; | 629 | elbc_fcm_ctrl->index += len; |
| 629 | return i == len && ctrl->status == LTESR_CC ? 0 : -EIO; | 630 | return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO; |
| 630 | } | 631 | } |
| 631 | 632 | ||
| 632 | /* This function is called after Program and Erase Operations to | 633 | /* This function is called after Program and Erase Operations to |
| @@ -635,22 +636,22 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
| 635 | static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) | 636 | static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) |
| 636 | { | 637 | { |
| 637 | struct fsl_elbc_mtd *priv = chip->priv; | 638 | struct fsl_elbc_mtd *priv = chip->priv; |
| 638 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 639 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; |
| 639 | 640 | ||
| 640 | if (ctrl->status != LTESR_CC) | 641 | if (elbc_fcm_ctrl->status != LTESR_CC) |
| 641 | return NAND_STATUS_FAIL; | 642 | return NAND_STATUS_FAIL; |
| 642 | 643 | ||
| 643 | /* The chip always seems to report that it is | 644 | /* The chip always seems to report that it is |
| 644 | * write-protected, even when it is not. | 645 | * write-protected, even when it is not. |
| 645 | */ | 646 | */ |
| 646 | return (ctrl->mdr & 0xff) | NAND_STATUS_WP; | 647 | return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP; |
| 647 | } | 648 | } |
| 648 | 649 | ||
| 649 | static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | 650 | static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) |
| 650 | { | 651 | { |
| 651 | struct nand_chip *chip = mtd->priv; | 652 | struct nand_chip *chip = mtd->priv; |
| 652 | struct fsl_elbc_mtd *priv = chip->priv; | 653 | struct fsl_elbc_mtd *priv = chip->priv; |
| 653 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 654 | struct fsl_lbc_ctrl *ctrl = priv->ctrl; |
| 654 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 655 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
| 655 | unsigned int al; | 656 | unsigned int al; |
| 656 | 657 | ||
| @@ -665,41 +666,41 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
| 665 | priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */ | 666 | priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */ |
| 666 | (al << FMR_AL_SHIFT); | 667 | (al << FMR_AL_SHIFT); |
| 667 | 668 | ||
| 668 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n", | 669 | dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n", |
| 669 | chip->numchips); | 670 | chip->numchips); |
| 670 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %lld\n", | 671 | dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n", |
| 671 | chip->chipsize); | 672 | chip->chipsize); |
| 672 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n", | 673 | dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", |
| 673 | chip->pagemask); | 674 | chip->pagemask); |
| 674 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n", | 675 | dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n", |
| 675 | chip->chip_delay); | 676 | chip->chip_delay); |
| 676 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n", | 677 | dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n", |
| 677 | chip->badblockpos); | 678 | chip->badblockpos); |
| 678 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n", | 679 | dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n", |
| 679 | chip->chip_shift); | 680 | chip->chip_shift); |
| 680 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n", | 681 | dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n", |
| 681 | chip->page_shift); | 682 | chip->page_shift); |
| 682 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", | 683 | dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", |
| 683 | chip->phys_erase_shift); | 684 | chip->phys_erase_shift); |
| 684 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n", | 685 | dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n", |
| 685 | chip->ecclayout); | 686 | chip->ecclayout); |
| 686 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", | 687 | dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", |
| 687 | chip->ecc.mode); | 688 | chip->ecc.mode); |
| 688 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", | 689 | dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", |
| 689 | chip->ecc.steps); | 690 | chip->ecc.steps); |
| 690 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", | 691 | dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", |
| 691 | chip->ecc.bytes); | 692 | chip->ecc.bytes); |
| 692 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n", | 693 | dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n", |
| 693 | chip->ecc.total); | 694 | chip->ecc.total); |
| 694 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n", | 695 | dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n", |
| 695 | chip->ecc.layout); | 696 | chip->ecc.layout); |
| 696 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); | 697 | dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); |
| 697 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); | 698 | dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size); |
| 698 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n", | 699 | dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n", |
| 699 | mtd->erasesize); | 700 | mtd->erasesize); |
| 700 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n", | 701 | dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n", |
| 701 | mtd->writesize); | 702 | mtd->writesize); |
| 702 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n", | 703 | dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n", |
| 703 | mtd->oobsize); | 704 | mtd->oobsize); |
| 704 | 705 | ||
| 705 | /* adjust Option Register and ECC to match Flash page size */ | 706 | /* adjust Option Register and ECC to match Flash page size */ |
| @@ -719,7 +720,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
| 719 | chip->badblock_pattern = &largepage_memorybased; | 720 | chip->badblock_pattern = &largepage_memorybased; |
| 720 | } | 721 | } |
| 721 | } else { | 722 | } else { |
| 722 | dev_err(ctrl->dev, | 723 | dev_err(priv->dev, |
| 723 | "fsl_elbc_init: page size %d is not supported\n", | 724 | "fsl_elbc_init: page size %d is not supported\n", |
| 724 | mtd->writesize); | 725 | mtd->writesize); |
| 725 | return -1; | 726 | return -1; |
| @@ -750,18 +751,19 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, | |||
| 750 | const uint8_t *buf) | 751 | const uint8_t *buf) |
| 751 | { | 752 | { |
| 752 | struct fsl_elbc_mtd *priv = chip->priv; | 753 | struct fsl_elbc_mtd *priv = chip->priv; |
| 753 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 754 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; |
| 754 | 755 | ||
| 755 | fsl_elbc_write_buf(mtd, buf, mtd->writesize); | 756 | fsl_elbc_write_buf(mtd, buf, mtd->writesize); |
| 756 | fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); | 757 | fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); |
| 757 | 758 | ||
| 758 | ctrl->oob_poi = chip->oob_poi; | 759 | elbc_fcm_ctrl->oob_poi = chip->oob_poi; |
| 759 | } | 760 | } |
| 760 | 761 | ||
| 761 | static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | 762 | static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) |
| 762 | { | 763 | { |
| 763 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 764 | struct fsl_lbc_ctrl *ctrl = priv->ctrl; |
| 764 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 765 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
| 766 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; | ||
| 765 | struct nand_chip *chip = &priv->chip; | 767 | struct nand_chip *chip = &priv->chip; |
| 766 | 768 | ||
| 767 | dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank); | 769 | dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank); |
| @@ -790,7 +792,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
| 790 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | | 792 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | |
| 791 | NAND_USE_FLASH_BBT; | 793 | NAND_USE_FLASH_BBT; |
| 792 | 794 | ||
| 793 | chip->controller = &ctrl->controller; | 795 | chip->controller = &elbc_fcm_ctrl->controller; |
| 794 | chip->priv = priv; | 796 | chip->priv = priv; |
| 795 | 797 | ||
| 796 | chip->ecc.read_page = fsl_elbc_read_page; | 798 | chip->ecc.read_page = fsl_elbc_read_page; |
| @@ -815,8 +817,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
| 815 | 817 | ||
| 816 | static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | 818 | static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) |
| 817 | { | 819 | { |
| 818 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 820 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; |
| 819 | |||
| 820 | nand_release(&priv->mtd); | 821 | nand_release(&priv->mtd); |
| 821 | 822 | ||
| 822 | kfree(priv->mtd.name); | 823 | kfree(priv->mtd.name); |
| @@ -824,18 +825,21 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | |||
| 824 | if (priv->vbase) | 825 | if (priv->vbase) |
| 825 | iounmap(priv->vbase); | 826 | iounmap(priv->vbase); |
| 826 | 827 | ||
| 827 | ctrl->chips[priv->bank] = NULL; | 828 | elbc_fcm_ctrl->chips[priv->bank] = NULL; |
| 828 | kfree(priv); | 829 | kfree(priv); |
| 829 | 830 | kfree(elbc_fcm_ctrl); | |
| 830 | return 0; | 831 | return 0; |
| 831 | } | 832 | } |
| 832 | 833 | ||
| 833 | static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | 834 | static DEFINE_MUTEX(fsl_elbc_nand_mutex); |
| 834 | struct device_node *node) | 835 | |
| 836 | static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) | ||
| 835 | { | 837 | { |
| 836 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 838 | struct fsl_lbc_regs __iomem *lbc; |
| 837 | struct fsl_elbc_mtd *priv; | 839 | struct fsl_elbc_mtd *priv; |
| 838 | struct resource res; | 840 | struct resource res; |
| 841 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; | ||
| 842 | |||
| 839 | #ifdef CONFIG_MTD_PARTITIONS | 843 | #ifdef CONFIG_MTD_PARTITIONS |
| 840 | static const char *part_probe_types[] | 844 | static const char *part_probe_types[] |
| 841 | = { "cmdlinepart", "RedBoot", NULL }; | 845 | = { "cmdlinepart", "RedBoot", NULL }; |
| @@ -843,11 +847,18 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | |||
| 843 | #endif | 847 | #endif |
| 844 | int ret; | 848 | int ret; |
| 845 | int bank; | 849 | int bank; |
| 850 | struct device *dev; | ||
| 851 | struct device_node *node = pdev->dev.of_node; | ||
| 852 | |||
| 853 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) | ||
| 854 | return -ENODEV; | ||
| 855 | lbc = fsl_lbc_ctrl_dev->regs; | ||
| 856 | dev = fsl_lbc_ctrl_dev->dev; | ||
| 846 | 857 | ||
| 847 | /* get, allocate and map the memory resource */ | 858 | /* get, allocate and map the memory resource */ |
| 848 | ret = of_address_to_resource(node, 0, &res); | 859 | ret = of_address_to_resource(node, 0, &res); |
| 849 | if (ret) { | 860 | if (ret) { |
| 850 | dev_err(ctrl->dev, "failed to get resource\n"); | 861 | dev_err(dev, "failed to get resource\n"); |
| 851 | return ret; | 862 | return ret; |
| 852 | } | 863 | } |
| 853 | 864 | ||
| @@ -857,11 +868,11 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | |||
| 857 | (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM && | 868 | (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM && |
| 858 | (in_be32(&lbc->bank[bank].br) & | 869 | (in_be32(&lbc->bank[bank].br) & |
| 859 | in_be32(&lbc->bank[bank].or) & BR_BA) | 870 | in_be32(&lbc->bank[bank].or) & BR_BA) |
| 860 | == res.start) | 871 | == fsl_lbc_addr(res.start)) |
| 861 | break; | 872 | break; |
| 862 | 873 | ||
| 863 | if (bank >= MAX_BANKS) { | 874 | if (bank >= MAX_BANKS) { |
| 864 | dev_err(ctrl->dev, "address did not match any chip selects\n"); | 875 | dev_err(dev, "address did not match any chip selects\n"); |
| 865 | return -ENODEV; | 876 | return -ENODEV; |
| 866 | } | 877 | } |
| 867 | 878 | ||
| @@ -869,14 +880,33 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | |||
| 869 | if (!priv) | 880 | if (!priv) |
| 870 | return -ENOMEM; | 881 | return -ENOMEM; |
| 871 | 882 | ||
| 872 | ctrl->chips[bank] = priv; | 883 | mutex_lock(&fsl_elbc_nand_mutex); |
| 884 | if (!fsl_lbc_ctrl_dev->nand) { | ||
| 885 | elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); | ||
| 886 | if (!elbc_fcm_ctrl) { | ||
| 887 | dev_err(dev, "failed to allocate memory\n"); | ||
| 888 | mutex_unlock(&fsl_elbc_nand_mutex); | ||
| 889 | ret = -ENOMEM; | ||
| 890 | goto err; | ||
| 891 | } | ||
| 892 | elbc_fcm_ctrl->counter++; | ||
| 893 | |||
| 894 | spin_lock_init(&elbc_fcm_ctrl->controller.lock); | ||
| 895 | init_waitqueue_head(&elbc_fcm_ctrl->controller.wq); | ||
| 896 | fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl; | ||
| 897 | } else { | ||
| 898 | elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; | ||
| 899 | } | ||
| 900 | mutex_unlock(&fsl_elbc_nand_mutex); | ||
| 901 | |||
| 902 | elbc_fcm_ctrl->chips[bank] = priv; | ||
| 873 | priv->bank = bank; | 903 | priv->bank = bank; |
| 874 | priv->ctrl = ctrl; | 904 | priv->ctrl = fsl_lbc_ctrl_dev; |
| 875 | priv->dev = ctrl->dev; | 905 | priv->dev = dev; |
| 876 | 906 | ||
| 877 | priv->vbase = ioremap(res.start, resource_size(&res)); | 907 | priv->vbase = ioremap(res.start, resource_size(&res)); |
| 878 | if (!priv->vbase) { | 908 | if (!priv->vbase) { |
| 879 | dev_err(ctrl->dev, "failed to map chip region\n"); | 909 | dev_err(dev, "failed to map chip region\n"); |
| 880 | ret = -ENOMEM; | 910 | ret = -ENOMEM; |
| 881 | goto err; | 911 | goto err; |
| 882 | } | 912 | } |
| @@ -933,171 +963,53 @@ err: | |||
| 933 | return ret; | 963 | return ret; |
| 934 | } | 964 | } |
| 935 | 965 | ||
| 936 | static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) | 966 | static int fsl_elbc_nand_remove(struct platform_device *pdev) |
| 937 | { | 967 | { |
| 938 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
| 939 | |||
| 940 | /* | ||
| 941 | * NAND transactions can tie up the bus for a long time, so set the | ||
| 942 | * bus timeout to max by clearing LBCR[BMT] (highest base counter | ||
| 943 | * value) and setting LBCR[BMTPS] to the highest prescaler value. | ||
| 944 | */ | ||
| 945 | clrsetbits_be32(&lbc->lbcr, LBCR_BMT, 15); | ||
| 946 | |||
| 947 | /* clear event registers */ | ||
| 948 | setbits32(&lbc->ltesr, LTESR_NAND_MASK); | ||
| 949 | out_be32(&lbc->lteatr, 0); | ||
| 950 | |||
| 951 | /* Enable interrupts for any detected events */ | ||
| 952 | out_be32(&lbc->lteir, LTESR_NAND_MASK); | ||
| 953 | |||
| 954 | ctrl->read_bytes = 0; | ||
| 955 | ctrl->index = 0; | ||
| 956 | ctrl->addr = NULL; | ||
| 957 | |||
| 958 | return 0; | ||
| 959 | } | ||
| 960 | |||
| 961 | static int fsl_elbc_ctrl_remove(struct platform_device *ofdev) | ||
| 962 | { | ||
| 963 | struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); | ||
| 964 | int i; | 968 | int i; |
| 965 | 969 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; | |
| 966 | for (i = 0; i < MAX_BANKS; i++) | 970 | for (i = 0; i < MAX_BANKS; i++) |
| 967 | if (ctrl->chips[i]) | 971 | if (elbc_fcm_ctrl->chips[i]) |
| 968 | fsl_elbc_chip_remove(ctrl->chips[i]); | 972 | fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]); |
| 969 | 973 | ||
| 970 | if (ctrl->irq) | 974 | mutex_lock(&fsl_elbc_nand_mutex); |
| 971 | free_irq(ctrl->irq, ctrl); | 975 | elbc_fcm_ctrl->counter--; |
| 972 | 976 | if (!elbc_fcm_ctrl->counter) { | |
| 973 | if (ctrl->regs) | 977 | fsl_lbc_ctrl_dev->nand = NULL; |
| 974 | iounmap(ctrl->regs); | 978 | kfree(elbc_fcm_ctrl); |
| 975 | |||
| 976 | dev_set_drvdata(&ofdev->dev, NULL); | ||
| 977 | kfree(ctrl); | ||
| 978 | return 0; | ||
| 979 | } | ||
| 980 | |||
| 981 | /* NOTE: This interrupt is also used to report other localbus events, | ||
| 982 | * such as transaction errors on other chipselects. If we want to | ||
| 983 | * capture those, we'll need to move the IRQ code into a shared | ||
| 984 | * LBC driver. | ||
| 985 | */ | ||
| 986 | |||
| 987 | static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data) | ||
| 988 | { | ||
| 989 | struct fsl_elbc_ctrl *ctrl = data; | ||
| 990 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
| 991 | __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK; | ||
| 992 | |||
| 993 | if (status) { | ||
| 994 | out_be32(&lbc->ltesr, status); | ||
| 995 | out_be32(&lbc->lteatr, 0); | ||
| 996 | |||
| 997 | ctrl->irq_status = status; | ||
| 998 | smp_wmb(); | ||
| 999 | wake_up(&ctrl->irq_wait); | ||
| 1000 | |||
| 1001 | return IRQ_HANDLED; | ||
| 1002 | } | 979 | } |
| 1003 | 980 | mutex_unlock(&fsl_elbc_nand_mutex); | |
| 1004 | return IRQ_NONE; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /* fsl_elbc_ctrl_probe | ||
| 1008 | * | ||
| 1009 | * called by device layer when it finds a device matching | ||
| 1010 | * one our driver can handled. This code allocates all of | ||
| 1011 | * the resources needed for the controller only. The | ||
| 1012 | * resources for the NAND banks themselves are allocated | ||
| 1013 | * in the chip probe function. | ||
| 1014 | */ | ||
| 1015 | |||
| 1016 | static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev, | ||
| 1017 | const struct of_device_id *match) | ||
| 1018 | { | ||
| 1019 | struct device_node *child; | ||
| 1020 | struct fsl_elbc_ctrl *ctrl; | ||
| 1021 | int ret; | ||
| 1022 | |||
| 1023 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | ||
| 1024 | if (!ctrl) | ||
| 1025 | return -ENOMEM; | ||
| 1026 | |||
| 1027 | dev_set_drvdata(&ofdev->dev, ctrl); | ||
| 1028 | |||
| 1029 | spin_lock_init(&ctrl->controller.lock); | ||
| 1030 | init_waitqueue_head(&ctrl->controller.wq); | ||
| 1031 | init_waitqueue_head(&ctrl->irq_wait); | ||
| 1032 | |||
| 1033 | ctrl->regs = of_iomap(ofdev->dev.of_node, 0); | ||
| 1034 | if (!ctrl->regs) { | ||
| 1035 | dev_err(&ofdev->dev, "failed to get memory region\n"); | ||
| 1036 | ret = -ENODEV; | ||
| 1037 | goto err; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); | ||
| 1041 | if (ctrl->irq == NO_IRQ) { | ||
| 1042 | dev_err(&ofdev->dev, "failed to get irq resource\n"); | ||
| 1043 | ret = -ENODEV; | ||
| 1044 | goto err; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | ctrl->dev = &ofdev->dev; | ||
| 1048 | |||
| 1049 | ret = fsl_elbc_ctrl_init(ctrl); | ||
| 1050 | if (ret < 0) | ||
| 1051 | goto err; | ||
| 1052 | |||
| 1053 | ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl); | ||
| 1054 | if (ret != 0) { | ||
| 1055 | dev_err(&ofdev->dev, "failed to install irq (%d)\n", | ||
| 1056 | ctrl->irq); | ||
| 1057 | ret = ctrl->irq; | ||
| 1058 | goto err; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | for_each_child_of_node(ofdev->dev.of_node, child) | ||
| 1062 | if (of_device_is_compatible(child, "fsl,elbc-fcm-nand")) | ||
| 1063 | fsl_elbc_chip_probe(ctrl, child); | ||
| 1064 | 981 | ||
| 1065 | return 0; | 982 | return 0; |
| 1066 | 983 | ||
| 1067 | err: | ||
| 1068 | fsl_elbc_ctrl_remove(ofdev); | ||
| 1069 | return ret; | ||
| 1070 | } | 984 | } |
| 1071 | 985 | ||
| 1072 | static const struct of_device_id fsl_elbc_match[] = { | 986 | static const struct of_device_id fsl_elbc_nand_match[] = { |
| 1073 | { | 987 | { .compatible = "fsl,elbc-fcm-nand", }, |
| 1074 | .compatible = "fsl,elbc", | ||
| 1075 | }, | ||
| 1076 | {} | 988 | {} |
| 1077 | }; | 989 | }; |
| 1078 | 990 | ||
| 1079 | static struct of_platform_driver fsl_elbc_ctrl_driver = { | 991 | static struct platform_driver fsl_elbc_nand_driver = { |
| 1080 | .driver = { | 992 | .driver = { |
| 1081 | .name = "fsl-elbc", | 993 | .name = "fsl,elbc-fcm-nand", |
| 1082 | .owner = THIS_MODULE, | 994 | .owner = THIS_MODULE, |
| 1083 | .of_match_table = fsl_elbc_match, | 995 | .of_match_table = fsl_elbc_nand_match, |
| 1084 | }, | 996 | }, |
| 1085 | .probe = fsl_elbc_ctrl_probe, | 997 | .probe = fsl_elbc_nand_probe, |
| 1086 | .remove = fsl_elbc_ctrl_remove, | 998 | .remove = fsl_elbc_nand_remove, |
| 1087 | }; | 999 | }; |
| 1088 | 1000 | ||
| 1089 | static int __init fsl_elbc_init(void) | 1001 | static int __init fsl_elbc_nand_init(void) |
| 1090 | { | 1002 | { |
| 1091 | return of_register_platform_driver(&fsl_elbc_ctrl_driver); | 1003 | return platform_driver_register(&fsl_elbc_nand_driver); |
| 1092 | } | 1004 | } |
| 1093 | 1005 | ||
| 1094 | static void __exit fsl_elbc_exit(void) | 1006 | static void __exit fsl_elbc_nand_exit(void) |
| 1095 | { | 1007 | { |
| 1096 | of_unregister_platform_driver(&fsl_elbc_ctrl_driver); | 1008 | platform_driver_unregister(&fsl_elbc_nand_driver); |
| 1097 | } | 1009 | } |
| 1098 | 1010 | ||
| 1099 | module_init(fsl_elbc_init); | 1011 | module_init(fsl_elbc_nand_init); |
| 1100 | module_exit(fsl_elbc_exit); | 1012 | module_exit(fsl_elbc_nand_exit); |
| 1101 | 1013 | ||
| 1102 | MODULE_LICENSE("GPL"); | 1014 | MODULE_LICENSE("GPL"); |
| 1103 | MODULE_AUTHOR("Freescale"); | 1015 | MODULE_AUTHOR("Freescale"); |
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 4eff8b25e5af..efdcca94ce55 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c | |||
| @@ -186,7 +186,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, | |||
| 186 | if (!flash_np) | 186 | if (!flash_np) |
| 187 | return -ENODEV; | 187 | return -ENODEV; |
| 188 | 188 | ||
| 189 | fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start, | 189 | fun->mtd.name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start, |
| 190 | flash_np->name); | 190 | flash_np->name); |
| 191 | if (!fun->mtd.name) { | 191 | if (!fun->mtd.name) { |
| 192 | ret = -ENOMEM; | 192 | ret = -ENOMEM; |
| @@ -222,7 +222,7 @@ static int __devinit fun_probe(struct platform_device *ofdev, | |||
| 222 | { | 222 | { |
| 223 | struct fsl_upm_nand *fun; | 223 | struct fsl_upm_nand *fun; |
| 224 | struct resource io_res; | 224 | struct resource io_res; |
| 225 | const uint32_t *prop; | 225 | const __be32 *prop; |
| 226 | int rnb_gpio; | 226 | int rnb_gpio; |
| 227 | int ret; | 227 | int ret; |
| 228 | int size; | 228 | int size; |
| @@ -270,7 +270,7 @@ static int __devinit fun_probe(struct platform_device *ofdev, | |||
| 270 | goto err1; | 270 | goto err1; |
| 271 | } | 271 | } |
| 272 | for (i = 0; i < fun->mchip_count; i++) | 272 | for (i = 0; i < fun->mchip_count; i++) |
| 273 | fun->mchip_offsets[i] = prop[i]; | 273 | fun->mchip_offsets[i] = be32_to_cpu(prop[i]); |
| 274 | } else { | 274 | } else { |
| 275 | fun->mchip_count = 1; | 275 | fun->mchip_count = 1; |
| 276 | } | 276 | } |
| @@ -295,13 +295,13 @@ static int __devinit fun_probe(struct platform_device *ofdev, | |||
| 295 | 295 | ||
| 296 | prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); | 296 | prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); |
| 297 | if (prop) | 297 | if (prop) |
| 298 | fun->chip_delay = *prop; | 298 | fun->chip_delay = be32_to_cpup(prop); |
| 299 | else | 299 | else |
| 300 | fun->chip_delay = 50; | 300 | fun->chip_delay = 50; |
| 301 | 301 | ||
| 302 | prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); | 302 | prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); |
| 303 | if (prop && size == sizeof(uint32_t)) | 303 | if (prop && size == sizeof(uint32_t)) |
| 304 | fun->wait_flags = *prop; | 304 | fun->wait_flags = be32_to_cpup(prop); |
| 305 | else | 305 | else |
| 306 | fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | | 306 | fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | |
| 307 | FSL_UPM_WAIT_WRITE_BYTE; | 307 | FSL_UPM_WAIT_WRITE_BYTE; |
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c new file mode 100644 index 000000000000..02edfba25b0c --- /dev/null +++ b/drivers/mtd/nand/fsmc_nand.c | |||
| @@ -0,0 +1,866 @@ | |||
| 1 | /* | ||
| 2 | * drivers/mtd/nand/fsmc_nand.c | ||
| 3 | * | ||
| 4 | * ST Microelectronics | ||
| 5 | * Flexible Static Memory Controller (FSMC) | ||
| 6 | * Driver for NAND portions | ||
| 7 | * | ||
| 8 | * Copyright © 2010 ST Microelectronics | ||
| 9 | * Vipin Kumar <vipin.kumar@st.com> | ||
| 10 | * Ashish Priyadarshi | ||
| 11 | * | ||
| 12 | * Based on drivers/mtd/nand/nomadik_nand.c | ||
| 13 | * | ||
| 14 | * This file is licensed under the terms of the GNU General Public | ||
| 15 | * License version 2. This program is licensed "as is" without any | ||
| 16 | * warranty of any kind, whether express or implied. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/clk.h> | ||
| 20 | #include <linux/err.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/resource.h> | ||
| 24 | #include <linux/sched.h> | ||
| 25 | #include <linux/types.h> | ||
| 26 | #include <linux/mtd/mtd.h> | ||
| 27 | #include <linux/mtd/nand.h> | ||
| 28 | #include <linux/mtd/nand_ecc.h> | ||
| 29 | #include <linux/platform_device.h> | ||
| 30 | #include <linux/mtd/partitions.h> | ||
| 31 | #include <linux/io.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/mtd/fsmc.h> | ||
| 34 | #include <mtd/mtd-abi.h> | ||
| 35 | |||
| 36 | static struct nand_ecclayout fsmc_ecc1_layout = { | ||
| 37 | .eccbytes = 24, | ||
| 38 | .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52, | ||
| 39 | 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116}, | ||
| 40 | .oobfree = { | ||
| 41 | {.offset = 8, .length = 8}, | ||
| 42 | {.offset = 24, .length = 8}, | ||
| 43 | {.offset = 40, .length = 8}, | ||
| 44 | {.offset = 56, .length = 8}, | ||
| 45 | {.offset = 72, .length = 8}, | ||
| 46 | {.offset = 88, .length = 8}, | ||
| 47 | {.offset = 104, .length = 8}, | ||
| 48 | {.offset = 120, .length = 8} | ||
| 49 | } | ||
| 50 | }; | ||
| 51 | |||
| 52 | static struct nand_ecclayout fsmc_ecc4_lp_layout = { | ||
| 53 | .eccbytes = 104, | ||
| 54 | .eccpos = { 2, 3, 4, 5, 6, 7, 8, | ||
| 55 | 9, 10, 11, 12, 13, 14, | ||
| 56 | 18, 19, 20, 21, 22, 23, 24, | ||
| 57 | 25, 26, 27, 28, 29, 30, | ||
| 58 | 34, 35, 36, 37, 38, 39, 40, | ||
| 59 | 41, 42, 43, 44, 45, 46, | ||
| 60 | 50, 51, 52, 53, 54, 55, 56, | ||
| 61 | 57, 58, 59, 60, 61, 62, | ||
| 62 | 66, 67, 68, 69, 70, 71, 72, | ||
| 63 | 73, 74, 75, 76, 77, 78, | ||
| 64 | 82, 83, 84, 85, 86, 87, 88, | ||
| 65 | 89, 90, 91, 92, 93, 94, | ||
| 66 | 98, 99, 100, 101, 102, 103, 104, | ||
| 67 | 105, 106, 107, 108, 109, 110, | ||
| 68 | 114, 115, 116, 117, 118, 119, 120, | ||
| 69 | 121, 122, 123, 124, 125, 126 | ||
| 70 | }, | ||
| 71 | .oobfree = { | ||
| 72 | {.offset = 15, .length = 3}, | ||
| 73 | {.offset = 31, .length = 3}, | ||
| 74 | {.offset = 47, .length = 3}, | ||
| 75 | {.offset = 63, .length = 3}, | ||
| 76 | {.offset = 79, .length = 3}, | ||
| 77 | {.offset = 95, .length = 3}, | ||
| 78 | {.offset = 111, .length = 3}, | ||
| 79 | {.offset = 127, .length = 1} | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * ECC placement definitions in oobfree type format. | ||
| 85 | * There are 13 bytes of ecc for every 512 byte block and it has to be read | ||
| 86 | * consecutively and immediately after the 512 byte data block for hardware to | ||
| 87 | * generate the error bit offsets in 512 byte data. | ||
| 88 | * Managing the ecc bytes in the following way makes it easier for software to | ||
| 89 | * read ecc bytes consecutive to data bytes. This way is similar to | ||
| 90 | * oobfree structure maintained already in generic nand driver | ||
| 91 | */ | ||
| 92 | static struct fsmc_eccplace fsmc_ecc4_lp_place = { | ||
| 93 | .eccplace = { | ||
| 94 | {.offset = 2, .length = 13}, | ||
| 95 | {.offset = 18, .length = 13}, | ||
| 96 | {.offset = 34, .length = 13}, | ||
| 97 | {.offset = 50, .length = 13}, | ||
| 98 | {.offset = 66, .length = 13}, | ||
| 99 | {.offset = 82, .length = 13}, | ||
| 100 | {.offset = 98, .length = 13}, | ||
| 101 | {.offset = 114, .length = 13} | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | |||
| 105 | static struct nand_ecclayout fsmc_ecc4_sp_layout = { | ||
| 106 | .eccbytes = 13, | ||
| 107 | .eccpos = { 0, 1, 2, 3, 6, 7, 8, | ||
| 108 | 9, 10, 11, 12, 13, 14 | ||
| 109 | }, | ||
| 110 | .oobfree = { | ||
| 111 | {.offset = 15, .length = 1}, | ||
| 112 | } | ||
| 113 | }; | ||
| 114 | |||
| 115 | static struct fsmc_eccplace fsmc_ecc4_sp_place = { | ||
| 116 | .eccplace = { | ||
| 117 | {.offset = 0, .length = 4}, | ||
| 118 | {.offset = 6, .length = 9} | ||
| 119 | } | ||
| 120 | }; | ||
| 121 | |||
| 122 | /* | ||
| 123 | * Default partition tables to be used if the partition information not | ||
| 124 | * provided through platform data | ||
| 125 | */ | ||
| 126 | #define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz} | ||
| 127 | |||
| 128 | /* | ||
| 129 | * Default partition layout for small page(= 512 bytes) devices | ||
| 130 | * Size for "Root file system" is updated in driver based on actual device size | ||
| 131 | */ | ||
| 132 | static struct mtd_partition partition_info_16KB_blk[] = { | ||
| 133 | PARTITION("X-loader", 0, 4 * 0x4000), | ||
| 134 | PARTITION("U-Boot", 0x10000, 20 * 0x4000), | ||
| 135 | PARTITION("Kernel", 0x60000, 256 * 0x4000), | ||
| 136 | PARTITION("Root File System", 0x460000, 0), | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Default partition layout for large page(> 512 bytes) devices | ||
| 141 | * Size for "Root file system" is updated in driver based on actual device size | ||
| 142 | */ | ||
| 143 | static struct mtd_partition partition_info_128KB_blk[] = { | ||
| 144 | PARTITION("X-loader", 0, 4 * 0x20000), | ||
| 145 | PARTITION("U-Boot", 0x80000, 12 * 0x20000), | ||
| 146 | PARTITION("Kernel", 0x200000, 48 * 0x20000), | ||
| 147 | PARTITION("Root File System", 0x800000, 0), | ||
| 148 | }; | ||
| 149 | |||
| 150 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
| 151 | const char *part_probes[] = { "cmdlinepart", NULL }; | ||
| 152 | #endif | ||
| 153 | |||
| 154 | /** | ||
| 155 | * struct fsmc_nand_data - atructure for FSMC NAND device state | ||
| 156 | * | ||
| 157 | * @mtd: MTD info for a NAND flash. | ||
| 158 | * @nand: Chip related info for a NAND flash. | ||
| 159 | * @partitions: Partition info for a NAND Flash. | ||
| 160 | * @nr_partitions: Total number of partition of a NAND flash. | ||
| 161 | * | ||
| 162 | * @ecc_place: ECC placing locations in oobfree type format. | ||
| 163 | * @bank: Bank number for probed device. | ||
| 164 | * @clk: Clock structure for FSMC. | ||
| 165 | * | ||
| 166 | * @data_va: NAND port for Data. | ||
| 167 | * @cmd_va: NAND port for Command. | ||
| 168 | * @addr_va: NAND port for Address. | ||
| 169 | * @regs_va: FSMC regs base address. | ||
| 170 | */ | ||
| 171 | struct fsmc_nand_data { | ||
| 172 | struct mtd_info mtd; | ||
| 173 | struct nand_chip nand; | ||
| 174 | struct mtd_partition *partitions; | ||
| 175 | unsigned int nr_partitions; | ||
| 176 | |||
| 177 | struct fsmc_eccplace *ecc_place; | ||
| 178 | unsigned int bank; | ||
| 179 | struct clk *clk; | ||
| 180 | |||
| 181 | struct resource *resregs; | ||
| 182 | struct resource *rescmd; | ||
| 183 | struct resource *resaddr; | ||
| 184 | struct resource *resdata; | ||
| 185 | |||
| 186 | void __iomem *data_va; | ||
| 187 | void __iomem *cmd_va; | ||
| 188 | void __iomem *addr_va; | ||
| 189 | void __iomem *regs_va; | ||
| 190 | |||
| 191 | void (*select_chip)(uint32_t bank, uint32_t busw); | ||
| 192 | }; | ||
| 193 | |||
| 194 | /* Assert CS signal based on chipnr */ | ||
| 195 | static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) | ||
| 196 | { | ||
| 197 | struct nand_chip *chip = mtd->priv; | ||
| 198 | struct fsmc_nand_data *host; | ||
| 199 | |||
| 200 | host = container_of(mtd, struct fsmc_nand_data, mtd); | ||
| 201 | |||
| 202 | switch (chipnr) { | ||
| 203 | case -1: | ||
| 204 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); | ||
| 205 | break; | ||
| 206 | case 0: | ||
| 207 | case 1: | ||
| 208 | case 2: | ||
| 209 | case 3: | ||
| 210 | if (host->select_chip) | ||
| 211 | host->select_chip(chipnr, | ||
| 212 | chip->options & NAND_BUSWIDTH_16); | ||
| 213 | break; | ||
| 214 | |||
| 215 | default: | ||
| 216 | BUG(); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | /* | ||
| 221 | * fsmc_cmd_ctrl - For facilitaing Hardware access | ||
| 222 | * This routine allows hardware specific access to control-lines(ALE,CLE) | ||
| 223 | */ | ||
| 224 | static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | ||
| 225 | { | ||
| 226 | struct nand_chip *this = mtd->priv; | ||
| 227 | struct fsmc_nand_data *host = container_of(mtd, | ||
| 228 | struct fsmc_nand_data, mtd); | ||
| 229 | struct fsmc_regs *regs = host->regs_va; | ||
| 230 | unsigned int bank = host->bank; | ||
| 231 | |||
| 232 | if (ctrl & NAND_CTRL_CHANGE) { | ||
| 233 | if (ctrl & NAND_CLE) { | ||
| 234 | this->IO_ADDR_R = (void __iomem *)host->cmd_va; | ||
| 235 | this->IO_ADDR_W = (void __iomem *)host->cmd_va; | ||
| 236 | } else if (ctrl & NAND_ALE) { | ||
| 237 | this->IO_ADDR_R = (void __iomem *)host->addr_va; | ||
| 238 | this->IO_ADDR_W = (void __iomem *)host->addr_va; | ||
| 239 | } else { | ||
| 240 | this->IO_ADDR_R = (void __iomem *)host->data_va; | ||
| 241 | this->IO_ADDR_W = (void __iomem *)host->data_va; | ||
| 242 | } | ||
| 243 | |||
| 244 | if (ctrl & NAND_NCE) { | ||
| 245 | writel(readl(®s->bank_regs[bank].pc) | FSMC_ENABLE, | ||
| 246 | ®s->bank_regs[bank].pc); | ||
| 247 | } else { | ||
| 248 | writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ENABLE, | ||
| 249 | ®s->bank_regs[bank].pc); | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | mb(); | ||
| 254 | |||
| 255 | if (cmd != NAND_CMD_NONE) | ||
| 256 | writeb(cmd, this->IO_ADDR_W); | ||
| 257 | } | ||
| 258 | |||
| 259 | /* | ||
| 260 | * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine | ||
| 261 | * | ||
| 262 | * This routine initializes timing parameters related to NAND memory access in | ||
| 263 | * FSMC registers | ||
| 264 | */ | ||
| 265 | static void __init fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, | ||
| 266 | uint32_t busw) | ||
| 267 | { | ||
| 268 | uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; | ||
| 269 | |||
| 270 | if (busw) | ||
| 271 | writel(value | FSMC_DEVWID_16, ®s->bank_regs[bank].pc); | ||
| 272 | else | ||
| 273 | writel(value | FSMC_DEVWID_8, ®s->bank_regs[bank].pc); | ||
| 274 | |||
| 275 | writel(readl(®s->bank_regs[bank].pc) | FSMC_TCLR_1 | FSMC_TAR_1, | ||
| 276 | ®s->bank_regs[bank].pc); | ||
| 277 | writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, | ||
| 278 | ®s->bank_regs[bank].comm); | ||
| 279 | writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, | ||
| 280 | ®s->bank_regs[bank].attrib); | ||
| 281 | } | ||
| 282 | |||
| 283 | /* | ||
| 284 | * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers | ||
| 285 | */ | ||
| 286 | static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) | ||
| 287 | { | ||
| 288 | struct fsmc_nand_data *host = container_of(mtd, | ||
| 289 | struct fsmc_nand_data, mtd); | ||
| 290 | struct fsmc_regs *regs = host->regs_va; | ||
| 291 | uint32_t bank = host->bank; | ||
| 292 | |||
| 293 | writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCPLEN_256, | ||
| 294 | ®s->bank_regs[bank].pc); | ||
| 295 | writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCEN, | ||
| 296 | ®s->bank_regs[bank].pc); | ||
| 297 | writel(readl(®s->bank_regs[bank].pc) | FSMC_ECCEN, | ||
| 298 | ®s->bank_regs[bank].pc); | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by | ||
| 303 | * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction upto | ||
| 304 | * max of 8-bits) | ||
| 305 | */ | ||
| 306 | static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, | ||
| 307 | uint8_t *ecc) | ||
| 308 | { | ||
| 309 | struct fsmc_nand_data *host = container_of(mtd, | ||
| 310 | struct fsmc_nand_data, mtd); | ||
| 311 | struct fsmc_regs *regs = host->regs_va; | ||
| 312 | uint32_t bank = host->bank; | ||
| 313 | uint32_t ecc_tmp; | ||
| 314 | unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; | ||
| 315 | |||
| 316 | do { | ||
| 317 | if (readl(®s->bank_regs[bank].sts) & FSMC_CODE_RDY) | ||
| 318 | break; | ||
| 319 | else | ||
| 320 | cond_resched(); | ||
| 321 | } while (!time_after_eq(jiffies, deadline)); | ||
| 322 | |||
| 323 | ecc_tmp = readl(®s->bank_regs[bank].ecc1); | ||
| 324 | ecc[0] = (uint8_t) (ecc_tmp >> 0); | ||
| 325 | ecc[1] = (uint8_t) (ecc_tmp >> 8); | ||
| 326 | ecc[2] = (uint8_t) (ecc_tmp >> 16); | ||
| 327 | ecc[3] = (uint8_t) (ecc_tmp >> 24); | ||
| 328 | |||
| 329 | ecc_tmp = readl(®s->bank_regs[bank].ecc2); | ||
| 330 | ecc[4] = (uint8_t) (ecc_tmp >> 0); | ||
| 331 | ecc[5] = (uint8_t) (ecc_tmp >> 8); | ||
| 332 | ecc[6] = (uint8_t) (ecc_tmp >> 16); | ||
| 333 | ecc[7] = (uint8_t) (ecc_tmp >> 24); | ||
| 334 | |||
| 335 | ecc_tmp = readl(®s->bank_regs[bank].ecc3); | ||
| 336 | ecc[8] = (uint8_t) (ecc_tmp >> 0); | ||
| 337 | ecc[9] = (uint8_t) (ecc_tmp >> 8); | ||
| 338 | ecc[10] = (uint8_t) (ecc_tmp >> 16); | ||
| 339 | ecc[11] = (uint8_t) (ecc_tmp >> 24); | ||
| 340 | |||
| 341 | ecc_tmp = readl(®s->bank_regs[bank].sts); | ||
| 342 | ecc[12] = (uint8_t) (ecc_tmp >> 16); | ||
| 343 | |||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | /* | ||
| 348 | * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by | ||
| 349 | * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction upto | ||
| 350 | * max of 1-bit) | ||
| 351 | */ | ||
| 352 | static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, | ||
| 353 | uint8_t *ecc) | ||
| 354 | { | ||
| 355 | struct fsmc_nand_data *host = container_of(mtd, | ||
| 356 | struct fsmc_nand_data, mtd); | ||
| 357 | struct fsmc_regs *regs = host->regs_va; | ||
| 358 | uint32_t bank = host->bank; | ||
| 359 | uint32_t ecc_tmp; | ||
| 360 | |||
| 361 | ecc_tmp = readl(®s->bank_regs[bank].ecc1); | ||
| 362 | ecc[0] = (uint8_t) (ecc_tmp >> 0); | ||
| 363 | ecc[1] = (uint8_t) (ecc_tmp >> 8); | ||
| 364 | ecc[2] = (uint8_t) (ecc_tmp >> 16); | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | /* | ||
| 370 | * fsmc_read_page_hwecc | ||
| 371 | * @mtd: mtd info structure | ||
| 372 | * @chip: nand chip info structure | ||
| 373 | * @buf: buffer to store read data | ||
| 374 | * @page: page number to read | ||
| 375 | * | ||
| 376 | * This routine is needed for fsmc verison 8 as reading from NAND chip has to be | ||
| 377 | * performed in a strict sequence as follows: | ||
| 378 | * data(512 byte) -> ecc(13 byte) | ||
| 379 | * After this read, fsmc hardware generates and reports error data bits(upto a | ||
| 380 | * max of 8 bits) | ||
| 381 | */ | ||
| 382 | static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | ||
| 383 | uint8_t *buf, int page) | ||
| 384 | { | ||
| 385 | struct fsmc_nand_data *host = container_of(mtd, | ||
| 386 | struct fsmc_nand_data, mtd); | ||
| 387 | struct fsmc_eccplace *ecc_place = host->ecc_place; | ||
| 388 | int i, j, s, stat, eccsize = chip->ecc.size; | ||
| 389 | int eccbytes = chip->ecc.bytes; | ||
| 390 | int eccsteps = chip->ecc.steps; | ||
| 391 | uint8_t *p = buf; | ||
| 392 | uint8_t *ecc_calc = chip->buffers->ecccalc; | ||
| 393 | uint8_t *ecc_code = chip->buffers->ecccode; | ||
| 394 | int off, len, group = 0; | ||
| 395 | /* | ||
| 396 | * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we | ||
| 397 | * end up reading 14 bytes (7 words) from oob. The local array is | ||
| 398 | * to maintain word alignment | ||
| 399 | */ | ||
| 400 | uint16_t ecc_oob[7]; | ||
| 401 | uint8_t *oob = (uint8_t *)&ecc_oob[0]; | ||
| 402 | |||
| 403 | for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { | ||
| 404 | |||
| 405 | chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); | ||
| 406 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | ||
| 407 | chip->read_buf(mtd, p, eccsize); | ||
| 408 | |||
| 409 | for (j = 0; j < eccbytes;) { | ||
| 410 | off = ecc_place->eccplace[group].offset; | ||
| 411 | len = ecc_place->eccplace[group].length; | ||
| 412 | group++; | ||
| 413 | |||
| 414 | /* | ||
| 415 | * length is intentionally kept a higher multiple of 2 | ||
| 416 | * to read at least 13 bytes even in case of 16 bit NAND | ||
| 417 | * devices | ||
| 418 | */ | ||
| 419 | len = roundup(len, 2); | ||
| 420 | chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); | ||
| 421 | chip->read_buf(mtd, oob + j, len); | ||
| 422 | j += len; | ||
| 423 | } | ||
| 424 | |||
| 425 | memcpy(&ecc_code[i], oob, 13); | ||
| 426 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | ||
| 427 | |||
| 428 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); | ||
| 429 | if (stat < 0) | ||
| 430 | mtd->ecc_stats.failed++; | ||
| 431 | else | ||
| 432 | mtd->ecc_stats.corrected += stat; | ||
| 433 | } | ||
| 434 | |||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* | ||
| 439 | * fsmc_correct_data | ||
| 440 | * @mtd: mtd info structure | ||
| 441 | * @dat: buffer of read data | ||
| 442 | * @read_ecc: ecc read from device spare area | ||
| 443 | * @calc_ecc: ecc calculated from read data | ||
| 444 | * | ||
| 445 | * calc_ecc is a 104 bit information containing maximum of 8 error | ||
| 446 | * offset informations of 13 bits each in 512 bytes of read data. | ||
| 447 | */ | ||
| 448 | static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, | ||
| 449 | uint8_t *read_ecc, uint8_t *calc_ecc) | ||
| 450 | { | ||
| 451 | struct fsmc_nand_data *host = container_of(mtd, | ||
| 452 | struct fsmc_nand_data, mtd); | ||
| 453 | struct fsmc_regs *regs = host->regs_va; | ||
| 454 | unsigned int bank = host->bank; | ||
| 455 | uint16_t err_idx[8]; | ||
| 456 | uint64_t ecc_data[2]; | ||
| 457 | uint32_t num_err, i; | ||
| 458 | |||
| 459 | /* The calculated ecc is actually the correction index in data */ | ||
| 460 | memcpy(ecc_data, calc_ecc, 13); | ||
| 461 | |||
| 462 | /* | ||
| 463 | * ------------------- calc_ecc[] bit wise -----------|--13 bits--| | ||
| 464 | * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--| | ||
| 465 | * | ||
| 466 | * calc_ecc is a 104 bit information containing maximum of 8 error | ||
| 467 | * offset informations of 13 bits each. calc_ecc is copied into a | ||
| 468 | * uint64_t array and error offset indexes are populated in err_idx | ||
| 469 | * array | ||
| 470 | */ | ||
| 471 | for (i = 0; i < 8; i++) { | ||
| 472 | if (i == 4) { | ||
| 473 | err_idx[4] = ((ecc_data[1] & 0x1) << 12) | ecc_data[0]; | ||
| 474 | ecc_data[1] >>= 1; | ||
| 475 | continue; | ||
| 476 | } | ||
| 477 | err_idx[i] = (ecc_data[i/4] & 0x1FFF); | ||
| 478 | ecc_data[i/4] >>= 13; | ||
| 479 | } | ||
| 480 | |||
| 481 | num_err = (readl(®s->bank_regs[bank].sts) >> 10) & 0xF; | ||
| 482 | |||
| 483 | if (num_err == 0xF) | ||
| 484 | return -EBADMSG; | ||
| 485 | |||
| 486 | i = 0; | ||
| 487 | while (num_err--) { | ||
| 488 | change_bit(0, (unsigned long *)&err_idx[i]); | ||
| 489 | change_bit(1, (unsigned long *)&err_idx[i]); | ||
| 490 | |||
| 491 | if (err_idx[i] <= 512 * 8) { | ||
| 492 | change_bit(err_idx[i], (unsigned long *)dat); | ||
| 493 | i++; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | return i; | ||
| 497 | } | ||
| 498 | |||
| 499 | /* | ||
| 500 | * fsmc_nand_probe - Probe function | ||
| 501 | * @pdev: platform device structure | ||
| 502 | */ | ||
| 503 | static int __init fsmc_nand_probe(struct platform_device *pdev) | ||
| 504 | { | ||
| 505 | struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
| 506 | struct fsmc_nand_data *host; | ||
| 507 | struct mtd_info *mtd; | ||
| 508 | struct nand_chip *nand; | ||
| 509 | struct fsmc_regs *regs; | ||
| 510 | struct resource *res; | ||
| 511 | int nr_parts, ret = 0; | ||
| 512 | |||
| 513 | if (!pdata) { | ||
| 514 | dev_err(&pdev->dev, "platform data is NULL\n"); | ||
| 515 | return -EINVAL; | ||
| 516 | } | ||
| 517 | |||
| 518 | /* Allocate memory for the device structure (and zero it) */ | ||
| 519 | host = kzalloc(sizeof(*host), GFP_KERNEL); | ||
| 520 | if (!host) { | ||
| 521 | dev_err(&pdev->dev, "failed to allocate device structure\n"); | ||
| 522 | return -ENOMEM; | ||
| 523 | } | ||
| 524 | |||
| 525 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); | ||
| 526 | if (!res) { | ||
| 527 | ret = -EIO; | ||
| 528 | goto err_probe1; | ||
| 529 | } | ||
| 530 | |||
| 531 | host->resdata = request_mem_region(res->start, resource_size(res), | ||
| 532 | pdev->name); | ||
| 533 | if (!host->resdata) { | ||
| 534 | ret = -EIO; | ||
| 535 | goto err_probe1; | ||
| 536 | } | ||
| 537 | |||
| 538 | host->data_va = ioremap(res->start, resource_size(res)); | ||
| 539 | if (!host->data_va) { | ||
| 540 | ret = -EIO; | ||
| 541 | goto err_probe1; | ||
| 542 | } | ||
| 543 | |||
| 544 | host->resaddr = request_mem_region(res->start + PLAT_NAND_ALE, | ||
| 545 | resource_size(res), pdev->name); | ||
| 546 | if (!host->resaddr) { | ||
| 547 | ret = -EIO; | ||
| 548 | goto err_probe1; | ||
| 549 | } | ||
| 550 | |||
| 551 | host->addr_va = ioremap(res->start + PLAT_NAND_ALE, resource_size(res)); | ||
| 552 | if (!host->addr_va) { | ||
| 553 | ret = -EIO; | ||
| 554 | goto err_probe1; | ||
| 555 | } | ||
| 556 | |||
| 557 | host->rescmd = request_mem_region(res->start + PLAT_NAND_CLE, | ||
| 558 | resource_size(res), pdev->name); | ||
| 559 | if (!host->rescmd) { | ||
| 560 | ret = -EIO; | ||
| 561 | goto err_probe1; | ||
| 562 | } | ||
| 563 | |||
| 564 | host->cmd_va = ioremap(res->start + PLAT_NAND_CLE, resource_size(res)); | ||
| 565 | if (!host->cmd_va) { | ||
| 566 | ret = -EIO; | ||
| 567 | goto err_probe1; | ||
| 568 | } | ||
| 569 | |||
| 570 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs"); | ||
| 571 | if (!res) { | ||
| 572 | ret = -EIO; | ||
| 573 | goto err_probe1; | ||
| 574 | } | ||
| 575 | |||
| 576 | host->resregs = request_mem_region(res->start, resource_size(res), | ||
| 577 | pdev->name); | ||
| 578 | if (!host->resregs) { | ||
| 579 | ret = -EIO; | ||
| 580 | goto err_probe1; | ||
| 581 | } | ||
| 582 | |||
| 583 | host->regs_va = ioremap(res->start, resource_size(res)); | ||
| 584 | if (!host->regs_va) { | ||
| 585 | ret = -EIO; | ||
| 586 | goto err_probe1; | ||
| 587 | } | ||
| 588 | |||
| 589 | host->clk = clk_get(&pdev->dev, NULL); | ||
| 590 | if (IS_ERR(host->clk)) { | ||
| 591 | dev_err(&pdev->dev, "failed to fetch block clock\n"); | ||
| 592 | ret = PTR_ERR(host->clk); | ||
| 593 | host->clk = NULL; | ||
| 594 | goto err_probe1; | ||
| 595 | } | ||
| 596 | |||
| 597 | ret = clk_enable(host->clk); | ||
| 598 | if (ret) | ||
| 599 | goto err_probe1; | ||
| 600 | |||
| 601 | host->bank = pdata->bank; | ||
| 602 | host->select_chip = pdata->select_bank; | ||
| 603 | regs = host->regs_va; | ||
| 604 | |||
| 605 | /* Link all private pointers */ | ||
| 606 | mtd = &host->mtd; | ||
| 607 | nand = &host->nand; | ||
| 608 | mtd->priv = nand; | ||
| 609 | nand->priv = host; | ||
| 610 | |||
| 611 | host->mtd.owner = THIS_MODULE; | ||
| 612 | nand->IO_ADDR_R = host->data_va; | ||
| 613 | nand->IO_ADDR_W = host->data_va; | ||
| 614 | nand->cmd_ctrl = fsmc_cmd_ctrl; | ||
| 615 | nand->chip_delay = 30; | ||
| 616 | |||
| 617 | nand->ecc.mode = NAND_ECC_HW; | ||
| 618 | nand->ecc.hwctl = fsmc_enable_hwecc; | ||
| 619 | nand->ecc.size = 512; | ||
| 620 | nand->options = pdata->options; | ||
| 621 | nand->select_chip = fsmc_select_chip; | ||
| 622 | |||
| 623 | if (pdata->width == FSMC_NAND_BW16) | ||
| 624 | nand->options |= NAND_BUSWIDTH_16; | ||
| 625 | |||
| 626 | fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); | ||
| 627 | |||
| 628 | if (get_fsmc_version(host->regs_va) == FSMC_VER8) { | ||
| 629 | nand->ecc.read_page = fsmc_read_page_hwecc; | ||
| 630 | nand->ecc.calculate = fsmc_read_hwecc_ecc4; | ||
| 631 | nand->ecc.correct = fsmc_correct_data; | ||
| 632 | nand->ecc.bytes = 13; | ||
| 633 | } else { | ||
| 634 | nand->ecc.calculate = fsmc_read_hwecc_ecc1; | ||
| 635 | nand->ecc.correct = nand_correct_data; | ||
| 636 | nand->ecc.bytes = 3; | ||
| 637 | } | ||
| 638 | |||
| 639 | /* | ||
| 640 | * Scan to find existance of the device | ||
| 641 | */ | ||
| 642 | if (nand_scan_ident(&host->mtd, 1, NULL)) { | ||
| 643 | ret = -ENXIO; | ||
| 644 | dev_err(&pdev->dev, "No NAND Device found!\n"); | ||
| 645 | goto err_probe; | ||
| 646 | } | ||
| 647 | |||
| 648 | if (get_fsmc_version(host->regs_va) == FSMC_VER8) { | ||
| 649 | if (host->mtd.writesize == 512) { | ||
| 650 | nand->ecc.layout = &fsmc_ecc4_sp_layout; | ||
| 651 | host->ecc_place = &fsmc_ecc4_sp_place; | ||
| 652 | } else { | ||
| 653 | nand->ecc.layout = &fsmc_ecc4_lp_layout; | ||
| 654 | host->ecc_place = &fsmc_ecc4_lp_place; | ||
| 655 | } | ||
| 656 | } else { | ||
| 657 | nand->ecc.layout = &fsmc_ecc1_layout; | ||
| 658 | } | ||
| 659 | |||
| 660 | /* Second stage of scan to fill MTD data-structures */ | ||
| 661 | if (nand_scan_tail(&host->mtd)) { | ||
| 662 | ret = -ENXIO; | ||
| 663 | goto err_probe; | ||
| 664 | } | ||
| 665 | |||
| 666 | /* | ||
| 667 | * The partition information can is accessed by (in the same precedence) | ||
| 668 | * | ||
| 669 | * command line through Bootloader, | ||
| 670 | * platform data, | ||
| 671 | * default partition information present in driver. | ||
| 672 | */ | ||
| 673 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 674 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
| 675 | /* | ||
| 676 | * Check if partition info passed via command line | ||
| 677 | */ | ||
| 678 | host->mtd.name = "nand"; | ||
| 679 | nr_parts = parse_mtd_partitions(&host->mtd, part_probes, | ||
| 680 | &host->partitions, 0); | ||
| 681 | if (nr_parts > 0) { | ||
| 682 | host->nr_partitions = nr_parts; | ||
| 683 | } else { | ||
| 684 | #endif | ||
| 685 | /* | ||
| 686 | * Check if partition info passed via command line | ||
| 687 | */ | ||
| 688 | if (pdata->partitions) { | ||
| 689 | host->partitions = pdata->partitions; | ||
| 690 | host->nr_partitions = pdata->nr_partitions; | ||
| 691 | } else { | ||
| 692 | struct mtd_partition *partition; | ||
| 693 | int i; | ||
| 694 | |||
| 695 | /* Select the default partitions info */ | ||
| 696 | switch (host->mtd.size) { | ||
| 697 | case 0x01000000: | ||
| 698 | case 0x02000000: | ||
| 699 | case 0x04000000: | ||
| 700 | host->partitions = partition_info_16KB_blk; | ||
| 701 | host->nr_partitions = | ||
| 702 | sizeof(partition_info_16KB_blk) / | ||
| 703 | sizeof(struct mtd_partition); | ||
| 704 | break; | ||
| 705 | case 0x08000000: | ||
| 706 | case 0x10000000: | ||
| 707 | case 0x20000000: | ||
| 708 | case 0x40000000: | ||
| 709 | host->partitions = partition_info_128KB_blk; | ||
| 710 | host->nr_partitions = | ||
| 711 | sizeof(partition_info_128KB_blk) / | ||
| 712 | sizeof(struct mtd_partition); | ||
| 713 | break; | ||
| 714 | default: | ||
| 715 | ret = -ENXIO; | ||
| 716 | pr_err("Unsupported NAND size\n"); | ||
| 717 | goto err_probe; | ||
| 718 | } | ||
| 719 | |||
| 720 | partition = host->partitions; | ||
| 721 | for (i = 0; i < host->nr_partitions; i++, partition++) { | ||
| 722 | if (partition->size == 0) { | ||
| 723 | partition->size = host->mtd.size - | ||
| 724 | partition->offset; | ||
| 725 | break; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | } | ||
| 729 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
| 730 | } | ||
| 731 | #endif | ||
| 732 | |||
| 733 | if (host->partitions) { | ||
| 734 | ret = add_mtd_partitions(&host->mtd, host->partitions, | ||
| 735 | host->nr_partitions); | ||
| 736 | if (ret) | ||
| 737 | goto err_probe; | ||
| 738 | } | ||
| 739 | #else | ||
| 740 | dev_info(&pdev->dev, "Registering %s as whole device\n", mtd->name); | ||
| 741 | if (!add_mtd_device(mtd)) { | ||
| 742 | ret = -ENXIO; | ||
| 743 | goto err_probe; | ||
| 744 | } | ||
| 745 | #endif | ||
| 746 | |||
| 747 | platform_set_drvdata(pdev, host); | ||
| 748 | dev_info(&pdev->dev, "FSMC NAND driver registration successful\n"); | ||
| 749 | return 0; | ||
| 750 | |||
| 751 | err_probe: | ||
| 752 | clk_disable(host->clk); | ||
| 753 | err_probe1: | ||
| 754 | if (host->clk) | ||
| 755 | clk_put(host->clk); | ||
| 756 | if (host->regs_va) | ||
| 757 | iounmap(host->regs_va); | ||
| 758 | if (host->resregs) | ||
| 759 | release_mem_region(host->resregs->start, | ||
| 760 | resource_size(host->resregs)); | ||
| 761 | if (host->cmd_va) | ||
| 762 | iounmap(host->cmd_va); | ||
| 763 | if (host->rescmd) | ||
| 764 | release_mem_region(host->rescmd->start, | ||
| 765 | resource_size(host->rescmd)); | ||
| 766 | if (host->addr_va) | ||
| 767 | iounmap(host->addr_va); | ||
| 768 | if (host->resaddr) | ||
| 769 | release_mem_region(host->resaddr->start, | ||
| 770 | resource_size(host->resaddr)); | ||
| 771 | if (host->data_va) | ||
| 772 | iounmap(host->data_va); | ||
| 773 | if (host->resdata) | ||
| 774 | release_mem_region(host->resdata->start, | ||
| 775 | resource_size(host->resdata)); | ||
| 776 | |||
| 777 | kfree(host); | ||
| 778 | return ret; | ||
| 779 | } | ||
| 780 | |||
| 781 | /* | ||
| 782 | * Clean up routine | ||
| 783 | */ | ||
| 784 | static int fsmc_nand_remove(struct platform_device *pdev) | ||
| 785 | { | ||
| 786 | struct fsmc_nand_data *host = platform_get_drvdata(pdev); | ||
| 787 | |||
| 788 | platform_set_drvdata(pdev, NULL); | ||
| 789 | |||
| 790 | if (host) { | ||
| 791 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 792 | del_mtd_partitions(&host->mtd); | ||
| 793 | #else | ||
| 794 | del_mtd_device(&host->mtd); | ||
| 795 | #endif | ||
| 796 | clk_disable(host->clk); | ||
| 797 | clk_put(host->clk); | ||
| 798 | |||
| 799 | iounmap(host->regs_va); | ||
| 800 | release_mem_region(host->resregs->start, | ||
| 801 | resource_size(host->resregs)); | ||
| 802 | iounmap(host->cmd_va); | ||
| 803 | release_mem_region(host->rescmd->start, | ||
| 804 | resource_size(host->rescmd)); | ||
| 805 | iounmap(host->addr_va); | ||
| 806 | release_mem_region(host->resaddr->start, | ||
| 807 | resource_size(host->resaddr)); | ||
| 808 | iounmap(host->data_va); | ||
| 809 | release_mem_region(host->resdata->start, | ||
| 810 | resource_size(host->resdata)); | ||
| 811 | |||
| 812 | kfree(host); | ||
| 813 | } | ||
| 814 | return 0; | ||
| 815 | } | ||
| 816 | |||
| 817 | #ifdef CONFIG_PM | ||
| 818 | static int fsmc_nand_suspend(struct device *dev) | ||
| 819 | { | ||
| 820 | struct fsmc_nand_data *host = dev_get_drvdata(dev); | ||
| 821 | if (host) | ||
| 822 | clk_disable(host->clk); | ||
| 823 | return 0; | ||
| 824 | } | ||
| 825 | |||
| 826 | static int fsmc_nand_resume(struct device *dev) | ||
| 827 | { | ||
| 828 | struct fsmc_nand_data *host = dev_get_drvdata(dev); | ||
| 829 | if (host) | ||
| 830 | clk_enable(host->clk); | ||
| 831 | return 0; | ||
| 832 | } | ||
| 833 | |||
| 834 | static const struct dev_pm_ops fsmc_nand_pm_ops = { | ||
| 835 | .suspend = fsmc_nand_suspend, | ||
| 836 | .resume = fsmc_nand_resume, | ||
| 837 | }; | ||
| 838 | #endif | ||
| 839 | |||
| 840 | static struct platform_driver fsmc_nand_driver = { | ||
| 841 | .remove = fsmc_nand_remove, | ||
| 842 | .driver = { | ||
| 843 | .owner = THIS_MODULE, | ||
| 844 | .name = "fsmc-nand", | ||
| 845 | #ifdef CONFIG_PM | ||
| 846 | .pm = &fsmc_nand_pm_ops, | ||
| 847 | #endif | ||
| 848 | }, | ||
| 849 | }; | ||
| 850 | |||
| 851 | static int __init fsmc_nand_init(void) | ||
| 852 | { | ||
| 853 | return platform_driver_probe(&fsmc_nand_driver, | ||
| 854 | fsmc_nand_probe); | ||
| 855 | } | ||
| 856 | module_init(fsmc_nand_init); | ||
| 857 | |||
| 858 | static void __exit fsmc_nand_exit(void) | ||
| 859 | { | ||
| 860 | platform_driver_unregister(&fsmc_nand_driver); | ||
| 861 | } | ||
| 862 | module_exit(fsmc_nand_exit); | ||
| 863 | |||
| 864 | MODULE_LICENSE("GPL"); | ||
| 865 | MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi"); | ||
| 866 | MODULE_DESCRIPTION("NAND driver for SPEAr Platforms"); | ||
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index df0c1da4ff49..469e649c911c 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c | |||
| @@ -568,6 +568,7 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) | |||
| 568 | uint rcw_width; | 568 | uint rcw_width; |
| 569 | uint rcwh; | 569 | uint rcwh; |
| 570 | uint romloc, ps; | 570 | uint romloc, ps; |
| 571 | int ret = 0; | ||
| 571 | 572 | ||
| 572 | rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); | 573 | rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); |
| 573 | if (!rmnode) { | 574 | if (!rmnode) { |
| @@ -579,7 +580,8 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) | |||
| 579 | rm = of_iomap(rmnode, 0); | 580 | rm = of_iomap(rmnode, 0); |
| 580 | if (!rm) { | 581 | if (!rm) { |
| 581 | dev_err(prv->dev, "Error mapping reset module node!\n"); | 582 | dev_err(prv->dev, "Error mapping reset module node!\n"); |
| 582 | return -EBUSY; | 583 | ret = -EBUSY; |
| 584 | goto out; | ||
| 583 | } | 585 | } |
| 584 | 586 | ||
| 585 | rcwh = in_be32(&rm->rcwhr); | 587 | rcwh = in_be32(&rm->rcwhr); |
| @@ -628,8 +630,9 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) | |||
| 628 | rcw_width * 8, rcw_pagesize, | 630 | rcw_width * 8, rcw_pagesize, |
| 629 | rcw_sparesize); | 631 | rcw_sparesize); |
| 630 | iounmap(rm); | 632 | iounmap(rm); |
| 633 | out: | ||
| 631 | of_node_put(rmnode); | 634 | of_node_put(rmnode); |
| 632 | return 0; | 635 | return ret; |
| 633 | } | 636 | } |
| 634 | 637 | ||
| 635 | /* Free driver resources */ | 638 | /* Free driver resources */ |
| @@ -660,7 +663,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op, | |||
| 660 | #endif | 663 | #endif |
| 661 | struct nand_chip *chip; | 664 | struct nand_chip *chip; |
| 662 | unsigned long regs_paddr, regs_size; | 665 | unsigned long regs_paddr, regs_size; |
| 663 | const uint *chips_no; | 666 | const __be32 *chips_no; |
| 664 | int resettime = 0; | 667 | int resettime = 0; |
| 665 | int retval = 0; | 668 | int retval = 0; |
| 666 | int rev, len; | 669 | int rev, len; |
| @@ -803,7 +806,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op, | |||
| 803 | } | 806 | } |
| 804 | 807 | ||
| 805 | /* Detect NAND chips */ | 808 | /* Detect NAND chips */ |
| 806 | if (nand_scan(mtd, *chips_no)) { | 809 | if (nand_scan(mtd, be32_to_cpup(chips_no))) { |
| 807 | dev_err(dev, "NAND Flash not found !\n"); | 810 | dev_err(dev, "NAND Flash not found !\n"); |
| 808 | devm_free_irq(dev, prv->irq, mtd); | 811 | devm_free_irq(dev, prv->irq, mtd); |
| 809 | retval = -ENXIO; | 812 | retval = -ENXIO; |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d551ddd9537a..1f75a1b1f7c3 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -45,7 +45,7 @@ | |||
| 45 | #include <linux/interrupt.h> | 45 | #include <linux/interrupt.h> |
| 46 | #include <linux/bitops.h> | 46 | #include <linux/bitops.h> |
| 47 | #include <linux/leds.h> | 47 | #include <linux/leds.h> |
| 48 | #include <asm/io.h> | 48 | #include <linux/io.h> |
| 49 | 49 | ||
| 50 | #ifdef CONFIG_MTD_PARTITIONS | 50 | #ifdef CONFIG_MTD_PARTITIONS |
| 51 | #include <linux/mtd/partitions.h> | 51 | #include <linux/mtd/partitions.h> |
| @@ -59,7 +59,7 @@ static struct nand_ecclayout nand_oob_8 = { | |||
| 59 | {.offset = 3, | 59 | {.offset = 3, |
| 60 | .length = 2}, | 60 | .length = 2}, |
| 61 | {.offset = 6, | 61 | {.offset = 6, |
| 62 | .length = 2}} | 62 | .length = 2} } |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | static struct nand_ecclayout nand_oob_16 = { | 65 | static struct nand_ecclayout nand_oob_16 = { |
| @@ -67,7 +67,7 @@ static struct nand_ecclayout nand_oob_16 = { | |||
| 67 | .eccpos = {0, 1, 2, 3, 6, 7}, | 67 | .eccpos = {0, 1, 2, 3, 6, 7}, |
| 68 | .oobfree = { | 68 | .oobfree = { |
| 69 | {.offset = 8, | 69 | {.offset = 8, |
| 70 | . length = 8}} | 70 | . length = 8} } |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | static struct nand_ecclayout nand_oob_64 = { | 73 | static struct nand_ecclayout nand_oob_64 = { |
| @@ -78,7 +78,7 @@ static struct nand_ecclayout nand_oob_64 = { | |||
| 78 | 56, 57, 58, 59, 60, 61, 62, 63}, | 78 | 56, 57, 58, 59, 60, 61, 62, 63}, |
| 79 | .oobfree = { | 79 | .oobfree = { |
| 80 | {.offset = 2, | 80 | {.offset = 2, |
| 81 | .length = 38}} | 81 | .length = 38} } |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | static struct nand_ecclayout nand_oob_128 = { | 84 | static struct nand_ecclayout nand_oob_128 = { |
| @@ -92,7 +92,7 @@ static struct nand_ecclayout nand_oob_128 = { | |||
| 92 | 120, 121, 122, 123, 124, 125, 126, 127}, | 92 | 120, 121, 122, 123, 124, 125, 126, 127}, |
| 93 | .oobfree = { | 93 | .oobfree = { |
| 94 | {.offset = 2, | 94 | {.offset = 2, |
| 95 | .length = 78}} | 95 | .length = 78} } |
| 96 | }; | 96 | }; |
| 97 | 97 | ||
| 98 | static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, | 98 | static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, |
| @@ -612,7 +612,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, | |||
| 612 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); | 612 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
| 613 | chip->cmd_ctrl(mtd, | 613 | chip->cmd_ctrl(mtd, |
| 614 | NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); | 614 | NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
| 615 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; | 615 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) |
| 616 | ; | ||
| 616 | return; | 617 | return; |
| 617 | 618 | ||
| 618 | /* This applies to read commands */ | 619 | /* This applies to read commands */ |
| @@ -718,7 +719,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, | |||
| 718 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); | 719 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); |
| 719 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, | 720 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, |
| 720 | NAND_NCE | NAND_CTRL_CHANGE); | 721 | NAND_NCE | NAND_CTRL_CHANGE); |
| 721 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; | 722 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) |
| 723 | ; | ||
| 722 | return; | 724 | return; |
| 723 | 725 | ||
| 724 | case NAND_CMD_RNDOUT: | 726 | case NAND_CMD_RNDOUT: |
| @@ -784,7 +786,7 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | |||
| 784 | spinlock_t *lock = &chip->controller->lock; | 786 | spinlock_t *lock = &chip->controller->lock; |
| 785 | wait_queue_head_t *wq = &chip->controller->wq; | 787 | wait_queue_head_t *wq = &chip->controller->wq; |
| 786 | DECLARE_WAITQUEUE(wait, current); | 788 | DECLARE_WAITQUEUE(wait, current); |
| 787 | retry: | 789 | retry: |
| 788 | spin_lock(lock); | 790 | spin_lock(lock); |
| 789 | 791 | ||
| 790 | /* Hardware controller shared among independent devices */ | 792 | /* Hardware controller shared among independent devices */ |
| @@ -834,7 +836,7 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 834 | break; | 836 | break; |
| 835 | } | 837 | } |
| 836 | mdelay(1); | 838 | mdelay(1); |
| 837 | } | 839 | } |
| 838 | } | 840 | } |
| 839 | 841 | ||
| 840 | /** | 842 | /** |
| @@ -980,6 +982,7 @@ out: | |||
| 980 | 982 | ||
| 981 | return ret; | 983 | return ret; |
| 982 | } | 984 | } |
| 985 | EXPORT_SYMBOL(nand_unlock); | ||
| 983 | 986 | ||
| 984 | /** | 987 | /** |
| 985 | * nand_lock - [REPLACEABLE] locks all blocks present in the device | 988 | * nand_lock - [REPLACEABLE] locks all blocks present in the device |
| @@ -1049,6 +1052,7 @@ out: | |||
| 1049 | 1052 | ||
| 1050 | return ret; | 1053 | return ret; |
| 1051 | } | 1054 | } |
| 1055 | EXPORT_SYMBOL(nand_lock); | ||
| 1052 | 1056 | ||
| 1053 | /** | 1057 | /** |
| 1054 | * nand_read_page_raw - [Intern] read raw page data without ecc | 1058 | * nand_read_page_raw - [Intern] read raw page data without ecc |
| @@ -1076,8 +1080,9 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1076 | * | 1080 | * |
| 1077 | * We need a special oob layout and handling even when OOB isn't used. | 1081 | * We need a special oob layout and handling even when OOB isn't used. |
| 1078 | */ | 1082 | */ |
| 1079 | static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | 1083 | static int nand_read_page_raw_syndrome(struct mtd_info *mtd, |
| 1080 | uint8_t *buf, int page) | 1084 | struct nand_chip *chip, |
| 1085 | uint8_t *buf, int page) | ||
| 1081 | { | 1086 | { |
| 1082 | int eccsize = chip->ecc.size; | 1087 | int eccsize = chip->ecc.size; |
| 1083 | int eccbytes = chip->ecc.bytes; | 1088 | int eccbytes = chip->ecc.bytes; |
| @@ -1158,7 +1163,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1158 | * @readlen: data length | 1163 | * @readlen: data length |
| 1159 | * @bufpoi: buffer to store read data | 1164 | * @bufpoi: buffer to store read data |
| 1160 | */ | 1165 | */ |
| 1161 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) | 1166 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, |
| 1167 | uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) | ||
| 1162 | { | 1168 | { |
| 1163 | int start_step, end_step, num_steps; | 1169 | int start_step, end_step, num_steps; |
| 1164 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 1170 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
| @@ -1166,6 +1172,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 | |||
| 1166 | int data_col_addr, i, gaps = 0; | 1172 | int data_col_addr, i, gaps = 0; |
| 1167 | int datafrag_len, eccfrag_len, aligned_len, aligned_pos; | 1173 | int datafrag_len, eccfrag_len, aligned_len, aligned_pos; |
| 1168 | int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; | 1174 | int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; |
| 1175 | int index = 0; | ||
| 1169 | 1176 | ||
| 1170 | /* Column address wihin the page aligned to ECC size (256bytes). */ | 1177 | /* Column address wihin the page aligned to ECC size (256bytes). */ |
| 1171 | start_step = data_offs / chip->ecc.size; | 1178 | start_step = data_offs / chip->ecc.size; |
| @@ -1204,26 +1211,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 | |||
| 1204 | } else { | 1211 | } else { |
| 1205 | /* send the command to read the particular ecc bytes */ | 1212 | /* send the command to read the particular ecc bytes */ |
| 1206 | /* take care about buswidth alignment in read_buf */ | 1213 | /* take care about buswidth alignment in read_buf */ |
| 1207 | aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); | 1214 | index = start_step * chip->ecc.bytes; |
| 1215 | |||
| 1216 | aligned_pos = eccpos[index] & ~(busw - 1); | ||
| 1208 | aligned_len = eccfrag_len; | 1217 | aligned_len = eccfrag_len; |
| 1209 | if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) | 1218 | if (eccpos[index] & (busw - 1)) |
| 1210 | aligned_len++; | 1219 | aligned_len++; |
| 1211 | if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) | 1220 | if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) |
| 1212 | aligned_len++; | 1221 | aligned_len++; |
| 1213 | 1222 | ||
| 1214 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); | 1223 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, |
| 1224 | mtd->writesize + aligned_pos, -1); | ||
| 1215 | chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); | 1225 | chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); |
| 1216 | } | 1226 | } |
| 1217 | 1227 | ||
| 1218 | for (i = 0; i < eccfrag_len; i++) | 1228 | for (i = 0; i < eccfrag_len; i++) |
| 1219 | chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; | 1229 | chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; |
| 1220 | 1230 | ||
| 1221 | p = bufpoi + data_col_addr; | 1231 | p = bufpoi + data_col_addr; |
| 1222 | for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { | 1232 | for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { |
| 1223 | int stat; | 1233 | int stat; |
| 1224 | 1234 | ||
| 1225 | stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); | 1235 | stat = chip->ecc.correct(mtd, p, |
| 1226 | if (stat == -1) | 1236 | &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); |
| 1237 | if (stat < 0) | ||
| 1227 | mtd->ecc_stats.failed++; | 1238 | mtd->ecc_stats.failed++; |
| 1228 | else | 1239 | else |
| 1229 | mtd->ecc_stats.corrected += stat; | 1240 | mtd->ecc_stats.corrected += stat; |
| @@ -1390,7 +1401,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1390 | static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, | 1401 | static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, |
| 1391 | struct mtd_oob_ops *ops, size_t len) | 1402 | struct mtd_oob_ops *ops, size_t len) |
| 1392 | { | 1403 | { |
| 1393 | switch(ops->mode) { | 1404 | switch (ops->mode) { |
| 1394 | 1405 | ||
| 1395 | case MTD_OOB_PLACE: | 1406 | case MTD_OOB_PLACE: |
| 1396 | case MTD_OOB_RAW: | 1407 | case MTD_OOB_RAW: |
| @@ -1402,7 +1413,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, | |||
| 1402 | uint32_t boffs = 0, roffs = ops->ooboffs; | 1413 | uint32_t boffs = 0, roffs = ops->ooboffs; |
| 1403 | size_t bytes = 0; | 1414 | size_t bytes = 0; |
| 1404 | 1415 | ||
| 1405 | for(; free->length && len; free++, len -= bytes) { | 1416 | for (; free->length && len; free++, len -= bytes) { |
| 1406 | /* Read request not from offset 0 ? */ | 1417 | /* Read request not from offset 0 ? */ |
| 1407 | if (unlikely(roffs)) { | 1418 | if (unlikely(roffs)) { |
| 1408 | if (roffs >= free->length) { | 1419 | if (roffs >= free->length) { |
| @@ -1466,7 +1477,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1466 | buf = ops->datbuf; | 1477 | buf = ops->datbuf; |
| 1467 | oob = ops->oobbuf; | 1478 | oob = ops->oobbuf; |
| 1468 | 1479 | ||
| 1469 | while(1) { | 1480 | while (1) { |
| 1470 | bytes = min(mtd->writesize - col, readlen); | 1481 | bytes = min(mtd->writesize - col, readlen); |
| 1471 | aligned = (bytes == mtd->writesize); | 1482 | aligned = (bytes == mtd->writesize); |
| 1472 | 1483 | ||
| @@ -1484,7 +1495,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1484 | ret = chip->ecc.read_page_raw(mtd, chip, | 1495 | ret = chip->ecc.read_page_raw(mtd, chip, |
| 1485 | bufpoi, page); | 1496 | bufpoi, page); |
| 1486 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) | 1497 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) |
| 1487 | ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); | 1498 | ret = chip->ecc.read_subpage(mtd, chip, |
| 1499 | col, bytes, bufpoi); | ||
| 1488 | else | 1500 | else |
| 1489 | ret = chip->ecc.read_page(mtd, chip, bufpoi, | 1501 | ret = chip->ecc.read_page(mtd, chip, bufpoi, |
| 1490 | page); | 1502 | page); |
| @@ -1493,7 +1505,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1493 | 1505 | ||
| 1494 | /* Transfer not aligned data */ | 1506 | /* Transfer not aligned data */ |
| 1495 | if (!aligned) { | 1507 | if (!aligned) { |
| 1496 | if (!NAND_SUBPAGE_READ(chip) && !oob) | 1508 | if (!NAND_SUBPAGE_READ(chip) && !oob && |
| 1509 | !(mtd->ecc_stats.failed - stats.failed)) | ||
| 1497 | chip->pagebuf = realpage; | 1510 | chip->pagebuf = realpage; |
| 1498 | memcpy(buf, chip->buffers->databuf + col, bytes); | 1511 | memcpy(buf, chip->buffers->databuf + col, bytes); |
| 1499 | } | 1512 | } |
| @@ -1791,7 +1804,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 1791 | realpage = (int)(from >> chip->page_shift); | 1804 | realpage = (int)(from >> chip->page_shift); |
| 1792 | page = realpage & chip->pagemask; | 1805 | page = realpage & chip->pagemask; |
| 1793 | 1806 | ||
| 1794 | while(1) { | 1807 | while (1) { |
| 1795 | sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); | 1808 | sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); |
| 1796 | 1809 | ||
| 1797 | len = min(len, readlen); | 1810 | len = min(len, readlen); |
| @@ -1861,7 +1874,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 1861 | 1874 | ||
| 1862 | nand_get_device(chip, mtd, FL_READING); | 1875 | nand_get_device(chip, mtd, FL_READING); |
| 1863 | 1876 | ||
| 1864 | switch(ops->mode) { | 1877 | switch (ops->mode) { |
| 1865 | case MTD_OOB_PLACE: | 1878 | case MTD_OOB_PLACE: |
| 1866 | case MTD_OOB_AUTO: | 1879 | case MTD_OOB_AUTO: |
| 1867 | case MTD_OOB_RAW: | 1880 | case MTD_OOB_RAW: |
| @@ -1876,7 +1889,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 1876 | else | 1889 | else |
| 1877 | ret = nand_do_read_ops(mtd, from, ops); | 1890 | ret = nand_do_read_ops(mtd, from, ops); |
| 1878 | 1891 | ||
| 1879 | out: | 1892 | out: |
| 1880 | nand_release_device(mtd); | 1893 | nand_release_device(mtd); |
| 1881 | return ret; | 1894 | return ret; |
| 1882 | } | 1895 | } |
| @@ -1905,8 +1918,9 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1905 | * | 1918 | * |
| 1906 | * We need a special oob layout and handling even when ECC isn't checked. | 1919 | * We need a special oob layout and handling even when ECC isn't checked. |
| 1907 | */ | 1920 | */ |
| 1908 | static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | 1921 | static void nand_write_page_raw_syndrome(struct mtd_info *mtd, |
| 1909 | const uint8_t *buf) | 1922 | struct nand_chip *chip, |
| 1923 | const uint8_t *buf) | ||
| 1910 | { | 1924 | { |
| 1911 | int eccsize = chip->ecc.size; | 1925 | int eccsize = chip->ecc.size; |
| 1912 | int eccbytes = chip->ecc.bytes; | 1926 | int eccbytes = chip->ecc.bytes; |
| @@ -2099,7 +2113,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 2099 | static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, | 2113 | static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, |
| 2100 | struct mtd_oob_ops *ops) | 2114 | struct mtd_oob_ops *ops) |
| 2101 | { | 2115 | { |
| 2102 | switch(ops->mode) { | 2116 | switch (ops->mode) { |
| 2103 | 2117 | ||
| 2104 | case MTD_OOB_PLACE: | 2118 | case MTD_OOB_PLACE: |
| 2105 | case MTD_OOB_RAW: | 2119 | case MTD_OOB_RAW: |
| @@ -2111,7 +2125,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, | |||
| 2111 | uint32_t boffs = 0, woffs = ops->ooboffs; | 2125 | uint32_t boffs = 0, woffs = ops->ooboffs; |
| 2112 | size_t bytes = 0; | 2126 | size_t bytes = 0; |
| 2113 | 2127 | ||
| 2114 | for(; free->length && len; free++, len -= bytes) { | 2128 | for (; free->length && len; free++, len -= bytes) { |
| 2115 | /* Write request not from offset 0 ? */ | 2129 | /* Write request not from offset 0 ? */ |
| 2116 | if (unlikely(woffs)) { | 2130 | if (unlikely(woffs)) { |
| 2117 | if (woffs >= free->length) { | 2131 | if (woffs >= free->length) { |
| @@ -2137,7 +2151,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, | |||
| 2137 | return NULL; | 2151 | return NULL; |
| 2138 | } | 2152 | } |
| 2139 | 2153 | ||
| 2140 | #define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0 | 2154 | #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) |
| 2141 | 2155 | ||
| 2142 | /** | 2156 | /** |
| 2143 | * nand_do_write_ops - [Internal] NAND write with ECC | 2157 | * nand_do_write_ops - [Internal] NAND write with ECC |
| @@ -2200,10 +2214,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
| 2200 | memset(chip->oob_poi, 0xff, mtd->oobsize); | 2214 | memset(chip->oob_poi, 0xff, mtd->oobsize); |
| 2201 | 2215 | ||
| 2202 | /* Don't allow multipage oob writes with offset */ | 2216 | /* Don't allow multipage oob writes with offset */ |
| 2203 | if (ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) | 2217 | if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) |
| 2204 | return -EINVAL; | 2218 | return -EINVAL; |
| 2205 | 2219 | ||
| 2206 | while(1) { | 2220 | while (1) { |
| 2207 | int bytes = mtd->writesize; | 2221 | int bytes = mtd->writesize; |
| 2208 | int cached = writelen > bytes && page != blockmask; | 2222 | int cached = writelen > bytes && page != blockmask; |
| 2209 | uint8_t *wbuf = buf; | 2223 | uint8_t *wbuf = buf; |
| @@ -2431,7 +2445,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, | |||
| 2431 | 2445 | ||
| 2432 | nand_get_device(chip, mtd, FL_WRITING); | 2446 | nand_get_device(chip, mtd, FL_WRITING); |
| 2433 | 2447 | ||
| 2434 | switch(ops->mode) { | 2448 | switch (ops->mode) { |
| 2435 | case MTD_OOB_PLACE: | 2449 | case MTD_OOB_PLACE: |
| 2436 | case MTD_OOB_AUTO: | 2450 | case MTD_OOB_AUTO: |
| 2437 | case MTD_OOB_RAW: | 2451 | case MTD_OOB_RAW: |
| @@ -2446,7 +2460,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, | |||
| 2446 | else | 2460 | else |
| 2447 | ret = nand_do_write_ops(mtd, to, ops); | 2461 | ret = nand_do_write_ops(mtd, to, ops); |
| 2448 | 2462 | ||
| 2449 | out: | 2463 | out: |
| 2450 | nand_release_device(mtd); | 2464 | nand_release_device(mtd); |
| 2451 | return ret; | 2465 | return ret; |
| 2452 | } | 2466 | } |
| @@ -2511,7 +2525,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
| 2511 | { | 2525 | { |
| 2512 | int page, status, pages_per_block, ret, chipnr; | 2526 | int page, status, pages_per_block, ret, chipnr; |
| 2513 | struct nand_chip *chip = mtd->priv; | 2527 | struct nand_chip *chip = mtd->priv; |
| 2514 | loff_t rewrite_bbt[NAND_MAX_CHIPS]={0}; | 2528 | loff_t rewrite_bbt[NAND_MAX_CHIPS] = {0}; |
| 2515 | unsigned int bbt_masked_page = 0xffffffff; | 2529 | unsigned int bbt_masked_page = 0xffffffff; |
| 2516 | loff_t len; | 2530 | loff_t len; |
| 2517 | 2531 | ||
| @@ -2632,7 +2646,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
| 2632 | } | 2646 | } |
| 2633 | instr->state = MTD_ERASE_DONE; | 2647 | instr->state = MTD_ERASE_DONE; |
| 2634 | 2648 | ||
| 2635 | erase_exit: | 2649 | erase_exit: |
| 2636 | 2650 | ||
| 2637 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; | 2651 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; |
| 2638 | 2652 | ||
| @@ -2706,7 +2720,8 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
| 2706 | struct nand_chip *chip = mtd->priv; | 2720 | struct nand_chip *chip = mtd->priv; |
| 2707 | int ret; | 2721 | int ret; |
| 2708 | 2722 | ||
| 2709 | if ((ret = nand_block_isbad(mtd, ofs))) { | 2723 | ret = nand_block_isbad(mtd, ofs); |
| 2724 | if (ret) { | ||
| 2710 | /* If it was bad already, return success and do nothing. */ | 2725 | /* If it was bad already, return success and do nothing. */ |
| 2711 | if (ret > 0) | 2726 | if (ret > 0) |
| 2712 | return 0; | 2727 | return 0; |
| @@ -2787,15 +2802,115 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) | |||
| 2787 | } | 2802 | } |
| 2788 | 2803 | ||
| 2789 | /* | 2804 | /* |
| 2805 | * sanitize ONFI strings so we can safely print them | ||
| 2806 | */ | ||
| 2807 | static void sanitize_string(uint8_t *s, size_t len) | ||
| 2808 | { | ||
| 2809 | ssize_t i; | ||
| 2810 | |||
| 2811 | /* null terminate */ | ||
| 2812 | s[len - 1] = 0; | ||
| 2813 | |||
| 2814 | /* remove non printable chars */ | ||
| 2815 | for (i = 0; i < len - 1; i++) { | ||
| 2816 | if (s[i] < ' ' || s[i] > 127) | ||
| 2817 | s[i] = '?'; | ||
| 2818 | } | ||
| 2819 | |||
| 2820 | /* remove trailing spaces */ | ||
| 2821 | strim(s); | ||
| 2822 | } | ||
| 2823 | |||
| 2824 | static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) | ||
| 2825 | { | ||
| 2826 | int i; | ||
| 2827 | while (len--) { | ||
| 2828 | crc ^= *p++ << 8; | ||
| 2829 | for (i = 0; i < 8; i++) | ||
| 2830 | crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); | ||
| 2831 | } | ||
| 2832 | |||
| 2833 | return crc; | ||
| 2834 | } | ||
| 2835 | |||
| 2836 | /* | ||
| 2837 | * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise | ||
| 2838 | */ | ||
| 2839 | static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | ||
| 2840 | int busw) | ||
| 2841 | { | ||
| 2842 | struct nand_onfi_params *p = &chip->onfi_params; | ||
| 2843 | int i; | ||
| 2844 | int val; | ||
| 2845 | |||
| 2846 | /* try ONFI for unknow chip or LP */ | ||
| 2847 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); | ||
| 2848 | if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || | ||
| 2849 | chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') | ||
| 2850 | return 0; | ||
| 2851 | |||
| 2852 | printk(KERN_INFO "ONFI flash detected\n"); | ||
| 2853 | chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); | ||
| 2854 | for (i = 0; i < 3; i++) { | ||
| 2855 | chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); | ||
| 2856 | if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == | ||
| 2857 | le16_to_cpu(p->crc)) { | ||
| 2858 | printk(KERN_INFO "ONFI param page %d valid\n", i); | ||
| 2859 | break; | ||
| 2860 | } | ||
| 2861 | } | ||
| 2862 | |||
| 2863 | if (i == 3) | ||
| 2864 | return 0; | ||
| 2865 | |||
| 2866 | /* check version */ | ||
| 2867 | val = le16_to_cpu(p->revision); | ||
| 2868 | if (val == 1 || val > (1 << 4)) { | ||
| 2869 | printk(KERN_INFO "%s: unsupported ONFI version: %d\n", | ||
| 2870 | __func__, val); | ||
| 2871 | return 0; | ||
| 2872 | } | ||
| 2873 | |||
| 2874 | if (val & (1 << 4)) | ||
| 2875 | chip->onfi_version = 22; | ||
| 2876 | else if (val & (1 << 3)) | ||
| 2877 | chip->onfi_version = 21; | ||
| 2878 | else if (val & (1 << 2)) | ||
| 2879 | chip->onfi_version = 20; | ||
| 2880 | else | ||
| 2881 | chip->onfi_version = 10; | ||
| 2882 | |||
| 2883 | sanitize_string(p->manufacturer, sizeof(p->manufacturer)); | ||
| 2884 | sanitize_string(p->model, sizeof(p->model)); | ||
| 2885 | if (!mtd->name) | ||
| 2886 | mtd->name = p->model; | ||
| 2887 | mtd->writesize = le32_to_cpu(p->byte_per_page); | ||
| 2888 | mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; | ||
| 2889 | mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); | ||
| 2890 | chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; | ||
| 2891 | busw = 0; | ||
| 2892 | if (le16_to_cpu(p->features) & 1) | ||
| 2893 | busw = NAND_BUSWIDTH_16; | ||
| 2894 | |||
| 2895 | chip->options &= ~NAND_CHIPOPTIONS_MSK; | ||
| 2896 | chip->options |= (NAND_NO_READRDY | | ||
| 2897 | NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; | ||
| 2898 | |||
| 2899 | return 1; | ||
| 2900 | } | ||
| 2901 | |||
| 2902 | /* | ||
| 2790 | * Get the flash and manufacturer id and lookup if the type is supported | 2903 | * Get the flash and manufacturer id and lookup if the type is supported |
| 2791 | */ | 2904 | */ |
| 2792 | static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | 2905 | static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, |
| 2793 | struct nand_chip *chip, | 2906 | struct nand_chip *chip, |
| 2794 | int busw, int *maf_id, | 2907 | int busw, |
| 2908 | int *maf_id, int *dev_id, | ||
| 2795 | struct nand_flash_dev *type) | 2909 | struct nand_flash_dev *type) |
| 2796 | { | 2910 | { |
| 2797 | int i, dev_id, maf_idx; | 2911 | int i, maf_idx; |
| 2798 | u8 id_data[8]; | 2912 | u8 id_data[8]; |
| 2913 | int ret; | ||
| 2799 | 2914 | ||
| 2800 | /* Select the device */ | 2915 | /* Select the device */ |
| 2801 | chip->select_chip(mtd, 0); | 2916 | chip->select_chip(mtd, 0); |
| @@ -2811,7 +2926,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2811 | 2926 | ||
| 2812 | /* Read manufacturer and device IDs */ | 2927 | /* Read manufacturer and device IDs */ |
| 2813 | *maf_id = chip->read_byte(mtd); | 2928 | *maf_id = chip->read_byte(mtd); |
| 2814 | dev_id = chip->read_byte(mtd); | 2929 | *dev_id = chip->read_byte(mtd); |
| 2815 | 2930 | ||
| 2816 | /* Try again to make sure, as some systems the bus-hold or other | 2931 | /* Try again to make sure, as some systems the bus-hold or other |
| 2817 | * interface concerns can cause random data which looks like a | 2932 | * interface concerns can cause random data which looks like a |
| @@ -2821,15 +2936,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2821 | 2936 | ||
| 2822 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 2937 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
| 2823 | 2938 | ||
| 2824 | /* Read entire ID string */ | 2939 | for (i = 0; i < 2; i++) |
| 2825 | |||
| 2826 | for (i = 0; i < 8; i++) | ||
| 2827 | id_data[i] = chip->read_byte(mtd); | 2940 | id_data[i] = chip->read_byte(mtd); |
| 2828 | 2941 | ||
| 2829 | if (id_data[0] != *maf_id || id_data[1] != dev_id) { | 2942 | if (id_data[0] != *maf_id || id_data[1] != *dev_id) { |
| 2830 | printk(KERN_INFO "%s: second ID read did not match " | 2943 | printk(KERN_INFO "%s: second ID read did not match " |
| 2831 | "%02x,%02x against %02x,%02x\n", __func__, | 2944 | "%02x,%02x against %02x,%02x\n", __func__, |
| 2832 | *maf_id, dev_id, id_data[0], id_data[1]); | 2945 | *maf_id, *dev_id, id_data[0], id_data[1]); |
| 2833 | return ERR_PTR(-ENODEV); | 2946 | return ERR_PTR(-ENODEV); |
| 2834 | } | 2947 | } |
| 2835 | 2948 | ||
| @@ -2837,8 +2950,23 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2837 | type = nand_flash_ids; | 2950 | type = nand_flash_ids; |
| 2838 | 2951 | ||
| 2839 | for (; type->name != NULL; type++) | 2952 | for (; type->name != NULL; type++) |
| 2840 | if (dev_id == type->id) | 2953 | if (*dev_id == type->id) |
| 2841 | break; | 2954 | break; |
| 2955 | |||
| 2956 | chip->onfi_version = 0; | ||
| 2957 | if (!type->name || !type->pagesize) { | ||
| 2958 | /* Check is chip is ONFI compliant */ | ||
| 2959 | ret = nand_flash_detect_onfi(mtd, chip, busw); | ||
| 2960 | if (ret) | ||
| 2961 | goto ident_done; | ||
| 2962 | } | ||
| 2963 | |||
| 2964 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | ||
| 2965 | |||
| 2966 | /* Read entire ID string */ | ||
| 2967 | |||
| 2968 | for (i = 0; i < 8; i++) | ||
| 2969 | id_data[i] = chip->read_byte(mtd); | ||
| 2842 | 2970 | ||
| 2843 | if (!type->name) | 2971 | if (!type->name) |
| 2844 | return ERR_PTR(-ENODEV); | 2972 | return ERR_PTR(-ENODEV); |
| @@ -2848,8 +2976,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2848 | 2976 | ||
| 2849 | chip->chipsize = (uint64_t)type->chipsize << 20; | 2977 | chip->chipsize = (uint64_t)type->chipsize << 20; |
| 2850 | 2978 | ||
| 2851 | /* Newer devices have all the information in additional id bytes */ | 2979 | if (!type->pagesize && chip->init_size) { |
| 2852 | if (!type->pagesize) { | 2980 | /* set the pagesize, oobsize, erasesize by the driver*/ |
| 2981 | busw = chip->init_size(mtd, chip, id_data); | ||
| 2982 | } else if (!type->pagesize) { | ||
| 2853 | int extid; | 2983 | int extid; |
| 2854 | /* The 3rd id byte holds MLC / multichip data */ | 2984 | /* The 3rd id byte holds MLC / multichip data */ |
| 2855 | chip->cellinfo = id_data[2]; | 2985 | chip->cellinfo = id_data[2]; |
| @@ -2859,7 +2989,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2859 | /* | 2989 | /* |
| 2860 | * Field definitions are in the following datasheets: | 2990 | * Field definitions are in the following datasheets: |
| 2861 | * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) | 2991 | * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) |
| 2862 | * New style (6 byte ID): Samsung K9GAG08U0D (p.40) | 2992 | * New style (6 byte ID): Samsung K9GBG08U0M (p.40) |
| 2863 | * | 2993 | * |
| 2864 | * Check for wraparound + Samsung ID + nonzero 6th byte | 2994 | * Check for wraparound + Samsung ID + nonzero 6th byte |
| 2865 | * to decide what to do. | 2995 | * to decide what to do. |
| @@ -2872,7 +3002,20 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2872 | mtd->writesize = 2048 << (extid & 0x03); | 3002 | mtd->writesize = 2048 << (extid & 0x03); |
| 2873 | extid >>= 2; | 3003 | extid >>= 2; |
| 2874 | /* Calc oobsize */ | 3004 | /* Calc oobsize */ |
| 2875 | mtd->oobsize = (extid & 0x03) == 0x01 ? 128 : 218; | 3005 | switch (extid & 0x03) { |
| 3006 | case 1: | ||
| 3007 | mtd->oobsize = 128; | ||
| 3008 | break; | ||
| 3009 | case 2: | ||
| 3010 | mtd->oobsize = 218; | ||
| 3011 | break; | ||
| 3012 | case 3: | ||
| 3013 | mtd->oobsize = 400; | ||
| 3014 | break; | ||
| 3015 | default: | ||
| 3016 | mtd->oobsize = 436; | ||
| 3017 | break; | ||
| 3018 | } | ||
| 2876 | extid >>= 2; | 3019 | extid >>= 2; |
| 2877 | /* Calc blocksize */ | 3020 | /* Calc blocksize */ |
| 2878 | mtd->erasesize = (128 * 1024) << | 3021 | mtd->erasesize = (128 * 1024) << |
| @@ -2900,7 +3043,35 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2900 | mtd->writesize = type->pagesize; | 3043 | mtd->writesize = type->pagesize; |
| 2901 | mtd->oobsize = mtd->writesize / 32; | 3044 | mtd->oobsize = mtd->writesize / 32; |
| 2902 | busw = type->options & NAND_BUSWIDTH_16; | 3045 | busw = type->options & NAND_BUSWIDTH_16; |
| 3046 | |||
| 3047 | /* | ||
| 3048 | * Check for Spansion/AMD ID + repeating 5th, 6th byte since | ||
| 3049 | * some Spansion chips have erasesize that conflicts with size | ||
| 3050 | * listed in nand_ids table | ||
| 3051 | * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) | ||
| 3052 | */ | ||
| 3053 | if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && | ||
| 3054 | id_data[5] == 0x00 && id_data[6] == 0x00 && | ||
| 3055 | id_data[7] == 0x00 && mtd->writesize == 512) { | ||
| 3056 | mtd->erasesize = 128 * 1024; | ||
| 3057 | mtd->erasesize <<= ((id_data[3] & 0x03) << 1); | ||
| 3058 | } | ||
| 2903 | } | 3059 | } |
| 3060 | /* Get chip options, preserve non chip based options */ | ||
| 3061 | chip->options &= ~NAND_CHIPOPTIONS_MSK; | ||
| 3062 | chip->options |= type->options & NAND_CHIPOPTIONS_MSK; | ||
| 3063 | |||
| 3064 | /* Check if chip is a not a samsung device. Do not clear the | ||
| 3065 | * options for chips which are not having an extended id. | ||
| 3066 | */ | ||
| 3067 | if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) | ||
| 3068 | chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; | ||
| 3069 | ident_done: | ||
| 3070 | |||
| 3071 | /* | ||
| 3072 | * Set chip as a default. Board drivers can override it, if necessary | ||
| 3073 | */ | ||
| 3074 | chip->options |= NAND_NO_AUTOINCR; | ||
| 2904 | 3075 | ||
| 2905 | /* Try to identify manufacturer */ | 3076 | /* Try to identify manufacturer */ |
| 2906 | for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { | 3077 | for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { |
| @@ -2915,7 +3086,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2915 | if (busw != (chip->options & NAND_BUSWIDTH_16)) { | 3086 | if (busw != (chip->options & NAND_BUSWIDTH_16)) { |
| 2916 | printk(KERN_INFO "NAND device: Manufacturer ID:" | 3087 | printk(KERN_INFO "NAND device: Manufacturer ID:" |
| 2917 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, | 3088 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, |
| 2918 | dev_id, nand_manuf_ids[maf_idx].name, mtd->name); | 3089 | *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); |
| 2919 | printk(KERN_WARNING "NAND bus width %d instead %d bit\n", | 3090 | printk(KERN_WARNING "NAND bus width %d instead %d bit\n", |
| 2920 | (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, | 3091 | (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, |
| 2921 | busw ? 16 : 8); | 3092 | busw ? 16 : 8); |
| @@ -2931,8 +3102,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2931 | ffs(mtd->erasesize) - 1; | 3102 | ffs(mtd->erasesize) - 1; |
| 2932 | if (chip->chipsize & 0xffffffff) | 3103 | if (chip->chipsize & 0xffffffff) |
| 2933 | chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; | 3104 | chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; |
| 2934 | else | 3105 | else { |
| 2935 | chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; | 3106 | chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); |
| 3107 | chip->chip_shift += 32 - 1; | ||
| 3108 | } | ||
| 2936 | 3109 | ||
| 2937 | /* Set the bad block position */ | 3110 | /* Set the bad block position */ |
| 2938 | if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) | 3111 | if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) |
| @@ -2940,27 +3113,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2940 | else | 3113 | else |
| 2941 | chip->badblockpos = NAND_SMALL_BADBLOCK_POS; | 3114 | chip->badblockpos = NAND_SMALL_BADBLOCK_POS; |
| 2942 | 3115 | ||
| 2943 | /* Get chip options, preserve non chip based options */ | ||
| 2944 | chip->options &= ~NAND_CHIPOPTIONS_MSK; | ||
| 2945 | chip->options |= type->options & NAND_CHIPOPTIONS_MSK; | ||
| 2946 | |||
| 2947 | /* | ||
| 2948 | * Set chip as a default. Board drivers can override it, if necessary | ||
| 2949 | */ | ||
| 2950 | chip->options |= NAND_NO_AUTOINCR; | ||
| 2951 | |||
| 2952 | /* Check if chip is a not a samsung device. Do not clear the | ||
| 2953 | * options for chips which are not having an extended id. | ||
| 2954 | */ | ||
| 2955 | if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) | ||
| 2956 | chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; | ||
| 2957 | |||
| 2958 | /* | 3116 | /* |
| 2959 | * Bad block marker is stored in the last page of each block | 3117 | * Bad block marker is stored in the last page of each block |
| 2960 | * on Samsung and Hynix MLC devices; stored in first two pages | 3118 | * on Samsung and Hynix MLC devices; stored in first two pages |
| 2961 | * of each block on Micron devices with 2KiB pages and on | 3119 | * of each block on Micron devices with 2KiB pages and on |
| 2962 | * SLC Samsung, Hynix, and AMD/Spansion. All others scan only | 3120 | * SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan |
| 2963 | * the first page. | 3121 | * only the first page. |
| 2964 | */ | 3122 | */ |
| 2965 | if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && | 3123 | if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && |
| 2966 | (*maf_id == NAND_MFR_SAMSUNG || | 3124 | (*maf_id == NAND_MFR_SAMSUNG || |
| @@ -2969,6 +3127,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2969 | else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && | 3127 | else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && |
| 2970 | (*maf_id == NAND_MFR_SAMSUNG || | 3128 | (*maf_id == NAND_MFR_SAMSUNG || |
| 2971 | *maf_id == NAND_MFR_HYNIX || | 3129 | *maf_id == NAND_MFR_HYNIX || |
| 3130 | *maf_id == NAND_MFR_TOSHIBA || | ||
| 2972 | *maf_id == NAND_MFR_AMD)) || | 3131 | *maf_id == NAND_MFR_AMD)) || |
| 2973 | (mtd->writesize == 2048 && | 3132 | (mtd->writesize == 2048 && |
| 2974 | *maf_id == NAND_MFR_MICRON)) | 3133 | *maf_id == NAND_MFR_MICRON)) |
| @@ -2994,9 +3153,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 2994 | if (mtd->writesize > 512 && chip->cmdfunc == nand_command) | 3153 | if (mtd->writesize > 512 && chip->cmdfunc == nand_command) |
| 2995 | chip->cmdfunc = nand_command_lp; | 3154 | chip->cmdfunc = nand_command_lp; |
| 2996 | 3155 | ||
| 3156 | /* TODO onfi flash name */ | ||
| 2997 | printk(KERN_INFO "NAND device: Manufacturer ID:" | 3157 | printk(KERN_INFO "NAND device: Manufacturer ID:" |
| 2998 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, | 3158 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, |
| 2999 | nand_manuf_ids[maf_idx].name, type->name); | 3159 | nand_manuf_ids[maf_idx].name, |
| 3160 | chip->onfi_version ? type->name : chip->onfi_params.model); | ||
| 3000 | 3161 | ||
| 3001 | return type; | 3162 | return type; |
| 3002 | } | 3163 | } |
| @@ -3015,7 +3176,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 3015 | int nand_scan_ident(struct mtd_info *mtd, int maxchips, | 3176 | int nand_scan_ident(struct mtd_info *mtd, int maxchips, |
| 3016 | struct nand_flash_dev *table) | 3177 | struct nand_flash_dev *table) |
| 3017 | { | 3178 | { |
| 3018 | int i, busw, nand_maf_id; | 3179 | int i, busw, nand_maf_id, nand_dev_id; |
| 3019 | struct nand_chip *chip = mtd->priv; | 3180 | struct nand_chip *chip = mtd->priv; |
| 3020 | struct nand_flash_dev *type; | 3181 | struct nand_flash_dev *type; |
| 3021 | 3182 | ||
| @@ -3025,7 +3186,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
| 3025 | nand_set_defaults(chip, busw); | 3186 | nand_set_defaults(chip, busw); |
| 3026 | 3187 | ||
| 3027 | /* Read the flash type */ | 3188 | /* Read the flash type */ |
| 3028 | type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, table); | 3189 | type = nand_get_flash_type(mtd, chip, busw, |
| 3190 | &nand_maf_id, &nand_dev_id, table); | ||
| 3029 | 3191 | ||
| 3030 | if (IS_ERR(type)) { | 3192 | if (IS_ERR(type)) { |
| 3031 | if (!(chip->options & NAND_SCAN_SILENT_NODEV)) | 3193 | if (!(chip->options & NAND_SCAN_SILENT_NODEV)) |
| @@ -3043,7 +3205,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
| 3043 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 3205 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
| 3044 | /* Read manufacturer and device IDs */ | 3206 | /* Read manufacturer and device IDs */ |
| 3045 | if (nand_maf_id != chip->read_byte(mtd) || | 3207 | if (nand_maf_id != chip->read_byte(mtd) || |
| 3046 | type->id != chip->read_byte(mtd)) | 3208 | nand_dev_id != chip->read_byte(mtd)) |
| 3047 | break; | 3209 | break; |
| 3048 | } | 3210 | } |
| 3049 | if (i > 1) | 3211 | if (i > 1) |
| @@ -3055,6 +3217,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
| 3055 | 3217 | ||
| 3056 | return 0; | 3218 | return 0; |
| 3057 | } | 3219 | } |
| 3220 | EXPORT_SYMBOL(nand_scan_ident); | ||
| 3058 | 3221 | ||
| 3059 | 3222 | ||
| 3060 | /** | 3223 | /** |
| @@ -3219,7 +3382,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 3219 | * mode | 3382 | * mode |
| 3220 | */ | 3383 | */ |
| 3221 | chip->ecc.steps = mtd->writesize / chip->ecc.size; | 3384 | chip->ecc.steps = mtd->writesize / chip->ecc.size; |
| 3222 | if(chip->ecc.steps * chip->ecc.size != mtd->writesize) { | 3385 | if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { |
| 3223 | printk(KERN_WARNING "Invalid ecc parameters\n"); | 3386 | printk(KERN_WARNING "Invalid ecc parameters\n"); |
| 3224 | BUG(); | 3387 | BUG(); |
| 3225 | } | 3388 | } |
| @@ -3231,7 +3394,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 3231 | */ | 3394 | */ |
| 3232 | if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && | 3395 | if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && |
| 3233 | !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { | 3396 | !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { |
| 3234 | switch(chip->ecc.steps) { | 3397 | switch (chip->ecc.steps) { |
| 3235 | case 2: | 3398 | case 2: |
| 3236 | mtd->subpage_sft = 1; | 3399 | mtd->subpage_sft = 1; |
| 3237 | break; | 3400 | break; |
| @@ -3283,10 +3446,11 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 3283 | /* Build bad block table */ | 3446 | /* Build bad block table */ |
| 3284 | return chip->scan_bbt(mtd); | 3447 | return chip->scan_bbt(mtd); |
| 3285 | } | 3448 | } |
| 3449 | EXPORT_SYMBOL(nand_scan_tail); | ||
| 3286 | 3450 | ||
| 3287 | /* is_module_text_address() isn't exported, and it's mostly a pointless | 3451 | /* is_module_text_address() isn't exported, and it's mostly a pointless |
| 3288 | test if this is a module _anyway_ -- they'd have to try _really_ hard | 3452 | * test if this is a module _anyway_ -- they'd have to try _really_ hard |
| 3289 | to call us from in-kernel code if the core NAND support is modular. */ | 3453 | * to call us from in-kernel code if the core NAND support is modular. */ |
| 3290 | #ifdef MODULE | 3454 | #ifdef MODULE |
| 3291 | #define caller_is_module() (1) | 3455 | #define caller_is_module() (1) |
| 3292 | #else | 3456 | #else |
| @@ -3322,6 +3486,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
| 3322 | ret = nand_scan_tail(mtd); | 3486 | ret = nand_scan_tail(mtd); |
| 3323 | return ret; | 3487 | return ret; |
| 3324 | } | 3488 | } |
| 3489 | EXPORT_SYMBOL(nand_scan); | ||
| 3325 | 3490 | ||
| 3326 | /** | 3491 | /** |
| 3327 | * nand_release - [NAND Interface] Free resources held by the NAND device | 3492 | * nand_release - [NAND Interface] Free resources held by the NAND device |
| @@ -3348,12 +3513,6 @@ void nand_release(struct mtd_info *mtd) | |||
| 3348 | & NAND_BBT_DYNAMICSTRUCT) | 3513 | & NAND_BBT_DYNAMICSTRUCT) |
| 3349 | kfree(chip->badblock_pattern); | 3514 | kfree(chip->badblock_pattern); |
| 3350 | } | 3515 | } |
| 3351 | |||
| 3352 | EXPORT_SYMBOL_GPL(nand_lock); | ||
| 3353 | EXPORT_SYMBOL_GPL(nand_unlock); | ||
| 3354 | EXPORT_SYMBOL_GPL(nand_scan); | ||
| 3355 | EXPORT_SYMBOL_GPL(nand_scan_ident); | ||
| 3356 | EXPORT_SYMBOL_GPL(nand_scan_tail); | ||
| 3357 | EXPORT_SYMBOL_GPL(nand_release); | 3516 | EXPORT_SYMBOL_GPL(nand_release); |
| 3358 | 3517 | ||
| 3359 | static int __init nand_base_init(void) | 3518 | static int __init nand_base_init(void) |
| @@ -3371,5 +3530,6 @@ module_init(nand_base_init); | |||
| 3371 | module_exit(nand_base_exit); | 3530 | module_exit(nand_base_exit); |
| 3372 | 3531 | ||
| 3373 | MODULE_LICENSE("GPL"); | 3532 | MODULE_LICENSE("GPL"); |
| 3374 | MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); | 3533 | MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); |
| 3534 | MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); | ||
| 3375 | MODULE_DESCRIPTION("Generic NAND flash driver code"); | 3535 | MODULE_DESCRIPTION("Generic NAND flash driver code"); |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5fedf4a74f16..586b981f0e61 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
| @@ -13,28 +13,37 @@ | |||
| 13 | * Description: | 13 | * Description: |
| 14 | * | 14 | * |
| 15 | * When nand_scan_bbt is called, then it tries to find the bad block table | 15 | * When nand_scan_bbt is called, then it tries to find the bad block table |
| 16 | * depending on the options in the bbt descriptor(s). If a bbt is found | 16 | * depending on the options in the BBT descriptor(s). If no flash based BBT |
| 17 | * then the contents are read and the memory based bbt is created. If a | 17 | * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory |
| 18 | * mirrored bbt is selected then the mirror is searched too and the | 18 | * marked good / bad blocks. This information is used to create a memory BBT. |
| 19 | * versions are compared. If the mirror has a greater version number | 19 | * Once a new bad block is discovered then the "factory" information is updated |
| 20 | * than the mirror bbt is used to build the memory based bbt. | 20 | * on the device. |
| 21 | * If a flash based BBT is specified then the function first tries to find the | ||
| 22 | * BBT on flash. If a BBT is found then the contents are read and the memory | ||
| 23 | * based BBT is created. If a mirrored BBT is selected then the mirror is | ||
| 24 | * searched too and the versions are compared. If the mirror has a greater | ||
| 25 | * version number than the mirror BBT is used to build the memory based BBT. | ||
| 21 | * If the tables are not versioned, then we "or" the bad block information. | 26 | * If the tables are not versioned, then we "or" the bad block information. |
| 22 | * If one of the bbt's is out of date or does not exist it is (re)created. | 27 | * If one of the BBTs is out of date or does not exist it is (re)created. |
| 23 | * If no bbt exists at all then the device is scanned for factory marked | 28 | * If no BBT exists at all then the device is scanned for factory marked |
| 24 | * good / bad blocks and the bad block tables are created. | 29 | * good / bad blocks and the bad block tables are created. |
| 25 | * | 30 | * |
| 26 | * For manufacturer created bbts like the one found on M-SYS DOC devices | 31 | * For manufacturer created BBTs like the one found on M-SYS DOC devices |
| 27 | * the bbt is searched and read but never created | 32 | * the BBT is searched and read but never created |
| 28 | * | 33 | * |
| 29 | * The autogenerated bad block table is located in the last good blocks | 34 | * The auto generated bad block table is located in the last good blocks |
| 30 | * of the device. The table is mirrored, so it can be updated eventually. | 35 | * of the device. The table is mirrored, so it can be updated eventually. |
| 31 | * The table is marked in the oob area with an ident pattern and a version | 36 | * The table is marked in the OOB area with an ident pattern and a version |
| 32 | * number which indicates which of both tables is more up to date. | 37 | * number which indicates which of both tables is more up to date. If the NAND |
| 38 | * controller needs the complete OOB area for the ECC information then the | ||
| 39 | * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern | ||
| 40 | * and the version byte into the data area and the OOB area will remain | ||
| 41 | * untouched. | ||
| 33 | * | 42 | * |
| 34 | * The table uses 2 bits per block | 43 | * The table uses 2 bits per block |
| 35 | * 11b: block is good | 44 | * 11b: block is good |
| 36 | * 00b: block is factory marked bad | 45 | * 00b: block is factory marked bad |
| 37 | * 01b, 10b: block is marked bad due to wear | 46 | * 01b, 10b: block is marked bad due to wear |
| 38 | * | 47 | * |
| 39 | * The memory bad block table uses the following scheme: | 48 | * The memory bad block table uses the following scheme: |
| 40 | * 00b: block is good | 49 | * 00b: block is good |
| @@ -59,6 +68,16 @@ | |||
| 59 | #include <linux/delay.h> | 68 | #include <linux/delay.h> |
| 60 | #include <linux/vmalloc.h> | 69 | #include <linux/vmalloc.h> |
| 61 | 70 | ||
| 71 | static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) | ||
| 72 | { | ||
| 73 | int ret; | ||
| 74 | |||
| 75 | ret = memcmp(buf, td->pattern, td->len); | ||
| 76 | if (!ret) | ||
| 77 | return ret; | ||
| 78 | return -1; | ||
| 79 | } | ||
| 80 | |||
| 62 | /** | 81 | /** |
| 63 | * check_pattern - [GENERIC] check if a pattern is in the buffer | 82 | * check_pattern - [GENERIC] check if a pattern is in the buffer |
| 64 | * @buf: the buffer to search | 83 | * @buf: the buffer to search |
| @@ -77,6 +96,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc | |||
| 77 | int i, end = 0; | 96 | int i, end = 0; |
| 78 | uint8_t *p = buf; | 97 | uint8_t *p = buf; |
| 79 | 98 | ||
| 99 | if (td->options & NAND_BBT_NO_OOB) | ||
| 100 | return check_pattern_no_oob(buf, td); | ||
| 101 | |||
| 80 | end = paglen + td->offs; | 102 | end = paglen + td->offs; |
| 81 | if (td->options & NAND_BBT_SCANEMPTY) { | 103 | if (td->options & NAND_BBT_SCANEMPTY) { |
| 82 | for (i = 0; i < end; i++) { | 104 | for (i = 0; i < end; i++) { |
| @@ -156,32 +178,63 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) | |||
| 156 | } | 178 | } |
| 157 | 179 | ||
| 158 | /** | 180 | /** |
| 181 | * add_marker_len - compute the length of the marker in data area | ||
| 182 | * @td: BBT descriptor used for computation | ||
| 183 | * | ||
| 184 | * The length will be 0 if the markeris located in OOB area. | ||
| 185 | */ | ||
| 186 | static u32 add_marker_len(struct nand_bbt_descr *td) | ||
| 187 | { | ||
| 188 | u32 len; | ||
| 189 | |||
| 190 | if (!(td->options & NAND_BBT_NO_OOB)) | ||
| 191 | return 0; | ||
| 192 | |||
| 193 | len = td->len; | ||
| 194 | if (td->options & NAND_BBT_VERSION) | ||
| 195 | len++; | ||
| 196 | return len; | ||
| 197 | } | ||
| 198 | |||
| 199 | /** | ||
| 159 | * read_bbt - [GENERIC] Read the bad block table starting from page | 200 | * read_bbt - [GENERIC] Read the bad block table starting from page |
| 160 | * @mtd: MTD device structure | 201 | * @mtd: MTD device structure |
| 161 | * @buf: temporary buffer | 202 | * @buf: temporary buffer |
| 162 | * @page: the starting page | 203 | * @page: the starting page |
| 163 | * @num: the number of bbt descriptors to read | 204 | * @num: the number of bbt descriptors to read |
| 164 | * @bits: number of bits per block | 205 | * @td: the bbt describtion table |
| 165 | * @offs: offset in the memory table | 206 | * @offs: offset in the memory table |
| 166 | * @reserved_block_code: Pattern to identify reserved blocks | ||
| 167 | * | 207 | * |
| 168 | * Read the bad block table starting from page. | 208 | * Read the bad block table starting from page. |
| 169 | * | 209 | * |
| 170 | */ | 210 | */ |
| 171 | static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, | 211 | static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, |
| 172 | int bits, int offs, int reserved_block_code) | 212 | struct nand_bbt_descr *td, int offs) |
| 173 | { | 213 | { |
| 174 | int res, i, j, act = 0; | 214 | int res, i, j, act = 0; |
| 175 | struct nand_chip *this = mtd->priv; | 215 | struct nand_chip *this = mtd->priv; |
| 176 | size_t retlen, len, totlen; | 216 | size_t retlen, len, totlen; |
| 177 | loff_t from; | 217 | loff_t from; |
| 218 | int bits = td->options & NAND_BBT_NRBITS_MSK; | ||
| 178 | uint8_t msk = (uint8_t) ((1 << bits) - 1); | 219 | uint8_t msk = (uint8_t) ((1 << bits) - 1); |
| 220 | u32 marker_len; | ||
| 221 | int reserved_block_code = td->reserved_block_code; | ||
| 179 | 222 | ||
| 180 | totlen = (num * bits) >> 3; | 223 | totlen = (num * bits) >> 3; |
| 224 | marker_len = add_marker_len(td); | ||
| 181 | from = ((loff_t) page) << this->page_shift; | 225 | from = ((loff_t) page) << this->page_shift; |
| 182 | 226 | ||
| 183 | while (totlen) { | 227 | while (totlen) { |
| 184 | len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); | 228 | len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); |
| 229 | if (marker_len) { | ||
| 230 | /* | ||
| 231 | * In case the BBT marker is not in the OOB area it | ||
| 232 | * will be just in the first page. | ||
| 233 | */ | ||
| 234 | len -= marker_len; | ||
| 235 | from += marker_len; | ||
| 236 | marker_len = 0; | ||
| 237 | } | ||
| 185 | res = mtd->read(mtd, from, len, &retlen, buf); | 238 | res = mtd->read(mtd, from, len, &retlen, buf); |
| 186 | if (res < 0) { | 239 | if (res < 0) { |
| 187 | if (retlen != len) { | 240 | if (retlen != len) { |
| @@ -238,20 +291,21 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
| 238 | { | 291 | { |
| 239 | struct nand_chip *this = mtd->priv; | 292 | struct nand_chip *this = mtd->priv; |
| 240 | int res = 0, i; | 293 | int res = 0, i; |
| 241 | int bits; | ||
| 242 | 294 | ||
| 243 | bits = td->options & NAND_BBT_NRBITS_MSK; | ||
| 244 | if (td->options & NAND_BBT_PERCHIP) { | 295 | if (td->options & NAND_BBT_PERCHIP) { |
| 245 | int offs = 0; | 296 | int offs = 0; |
| 246 | for (i = 0; i < this->numchips; i++) { | 297 | for (i = 0; i < this->numchips; i++) { |
| 247 | if (chip == -1 || chip == i) | 298 | if (chip == -1 || chip == i) |
| 248 | res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); | 299 | res = read_bbt(mtd, buf, td->pages[i], |
| 300 | this->chipsize >> this->bbt_erase_shift, | ||
| 301 | td, offs); | ||
| 249 | if (res) | 302 | if (res) |
| 250 | return res; | 303 | return res; |
| 251 | offs += this->chipsize >> (this->bbt_erase_shift + 2); | 304 | offs += this->chipsize >> (this->bbt_erase_shift + 2); |
| 252 | } | 305 | } |
| 253 | } else { | 306 | } else { |
| 254 | res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); | 307 | res = read_bbt(mtd, buf, td->pages[0], |
| 308 | mtd->size >> this->bbt_erase_shift, td, 0); | ||
| 255 | if (res) | 309 | if (res) |
| 256 | return res; | 310 | return res; |
| 257 | } | 311 | } |
| @@ -259,9 +313,25 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
| 259 | } | 313 | } |
| 260 | 314 | ||
| 261 | /* | 315 | /* |
| 316 | * BBT marker is in the first page, no OOB. | ||
| 317 | */ | ||
| 318 | static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, | ||
| 319 | struct nand_bbt_descr *td) | ||
| 320 | { | ||
| 321 | size_t retlen; | ||
| 322 | size_t len; | ||
| 323 | |||
| 324 | len = td->len; | ||
| 325 | if (td->options & NAND_BBT_VERSION) | ||
| 326 | len++; | ||
| 327 | |||
| 328 | return mtd->read(mtd, offs, len, &retlen, buf); | ||
| 329 | } | ||
| 330 | |||
| 331 | /* | ||
| 262 | * Scan read raw data from flash | 332 | * Scan read raw data from flash |
| 263 | */ | 333 | */ |
| 264 | static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, | 334 | static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, |
| 265 | size_t len) | 335 | size_t len) |
| 266 | { | 336 | { |
| 267 | struct mtd_oob_ops ops; | 337 | struct mtd_oob_ops ops; |
| @@ -294,6 +364,15 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, | |||
| 294 | return 0; | 364 | return 0; |
| 295 | } | 365 | } |
| 296 | 366 | ||
| 367 | static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, | ||
| 368 | size_t len, struct nand_bbt_descr *td) | ||
| 369 | { | ||
| 370 | if (td->options & NAND_BBT_NO_OOB) | ||
| 371 | return scan_read_raw_data(mtd, buf, offs, td); | ||
| 372 | else | ||
| 373 | return scan_read_raw_oob(mtd, buf, offs, len); | ||
| 374 | } | ||
| 375 | |||
| 297 | /* | 376 | /* |
| 298 | * Scan write data with oob to flash | 377 | * Scan write data with oob to flash |
| 299 | */ | 378 | */ |
| @@ -312,6 +391,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, | |||
| 312 | return mtd->write_oob(mtd, offs, &ops); | 391 | return mtd->write_oob(mtd, offs, &ops); |
| 313 | } | 392 | } |
| 314 | 393 | ||
| 394 | static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) | ||
| 395 | { | ||
| 396 | u32 ver_offs = td->veroffs; | ||
| 397 | |||
| 398 | if (!(td->options & NAND_BBT_NO_OOB)) | ||
| 399 | ver_offs += mtd->writesize; | ||
| 400 | return ver_offs; | ||
| 401 | } | ||
| 402 | |||
| 315 | /** | 403 | /** |
| 316 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page | 404 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page |
| 317 | * @mtd: MTD device structure | 405 | * @mtd: MTD device structure |
| @@ -331,8 +419,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, | |||
| 331 | /* Read the primary version, if available */ | 419 | /* Read the primary version, if available */ |
| 332 | if (td->options & NAND_BBT_VERSION) { | 420 | if (td->options & NAND_BBT_VERSION) { |
| 333 | scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, | 421 | scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, |
| 334 | mtd->writesize); | 422 | mtd->writesize, td); |
| 335 | td->version[0] = buf[mtd->writesize + td->veroffs]; | 423 | td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; |
| 336 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", | 424 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", |
| 337 | td->pages[0], td->version[0]); | 425 | td->pages[0], td->version[0]); |
| 338 | } | 426 | } |
| @@ -340,8 +428,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, | |||
| 340 | /* Read the mirror version, if available */ | 428 | /* Read the mirror version, if available */ |
| 341 | if (md && (md->options & NAND_BBT_VERSION)) { | 429 | if (md && (md->options & NAND_BBT_VERSION)) { |
| 342 | scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, | 430 | scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, |
| 343 | mtd->writesize); | 431 | mtd->writesize, td); |
| 344 | md->version[0] = buf[mtd->writesize + md->veroffs]; | 432 | md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; |
| 345 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", | 433 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", |
| 346 | md->pages[0], md->version[0]); | 434 | md->pages[0], md->version[0]); |
| 347 | } | 435 | } |
| @@ -357,7 +445,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, | |||
| 357 | { | 445 | { |
| 358 | int ret, j; | 446 | int ret, j; |
| 359 | 447 | ||
| 360 | ret = scan_read_raw(mtd, buf, offs, readlen); | 448 | ret = scan_read_raw_oob(mtd, buf, offs, readlen); |
| 361 | if (ret) | 449 | if (ret) |
| 362 | return ret; | 450 | return ret; |
| 363 | 451 | ||
| @@ -464,6 +552,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
| 464 | for (i = startblock; i < numblocks;) { | 552 | for (i = startblock; i < numblocks;) { |
| 465 | int ret; | 553 | int ret; |
| 466 | 554 | ||
| 555 | BUG_ON(bd->options & NAND_BBT_NO_OOB); | ||
| 556 | |||
| 467 | if (bd->options & NAND_BBT_SCANALLPAGES) | 557 | if (bd->options & NAND_BBT_SCANALLPAGES) |
| 468 | ret = scan_block_full(mtd, bd, from, buf, readlen, | 558 | ret = scan_block_full(mtd, bd, from, buf, readlen, |
| 469 | scanlen, len); | 559 | scanlen, len); |
| @@ -545,11 +635,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
| 545 | loff_t offs = (loff_t)actblock << this->bbt_erase_shift; | 635 | loff_t offs = (loff_t)actblock << this->bbt_erase_shift; |
| 546 | 636 | ||
| 547 | /* Read first page */ | 637 | /* Read first page */ |
| 548 | scan_read_raw(mtd, buf, offs, mtd->writesize); | 638 | scan_read_raw(mtd, buf, offs, mtd->writesize, td); |
| 549 | if (!check_pattern(buf, scanlen, mtd->writesize, td)) { | 639 | if (!check_pattern(buf, scanlen, mtd->writesize, td)) { |
| 550 | td->pages[i] = actblock << blocktopage; | 640 | td->pages[i] = actblock << blocktopage; |
| 551 | if (td->options & NAND_BBT_VERSION) { | 641 | if (td->options & NAND_BBT_VERSION) { |
| 552 | td->version[i] = buf[mtd->writesize + td->veroffs]; | 642 | offs = bbt_get_ver_offs(mtd, td); |
| 643 | td->version[i] = buf[offs]; | ||
| 553 | } | 644 | } |
| 554 | break; | 645 | break; |
| 555 | } | 646 | } |
| @@ -733,12 +824,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
| 733 | memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); | 824 | memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); |
| 734 | ooboffs = len + (pageoffs * mtd->oobsize); | 825 | ooboffs = len + (pageoffs * mtd->oobsize); |
| 735 | 826 | ||
| 827 | } else if (td->options & NAND_BBT_NO_OOB) { | ||
| 828 | ooboffs = 0; | ||
| 829 | offs = td->len; | ||
| 830 | /* the version byte */ | ||
| 831 | if (td->options & NAND_BBT_VERSION) | ||
| 832 | offs++; | ||
| 833 | /* Calc length */ | ||
| 834 | len = (size_t) (numblocks >> sft); | ||
| 835 | len += offs; | ||
| 836 | /* Make it page aligned ! */ | ||
| 837 | len = ALIGN(len, mtd->writesize); | ||
| 838 | /* Preset the buffer with 0xff */ | ||
| 839 | memset(buf, 0xff, len); | ||
| 840 | /* Pattern is located at the begin of first page */ | ||
| 841 | memcpy(buf, td->pattern, td->len); | ||
| 736 | } else { | 842 | } else { |
| 737 | /* Calc length */ | 843 | /* Calc length */ |
| 738 | len = (size_t) (numblocks >> sft); | 844 | len = (size_t) (numblocks >> sft); |
| 739 | /* Make it page aligned ! */ | 845 | /* Make it page aligned ! */ |
| 740 | len = (len + (mtd->writesize - 1)) & | 846 | len = ALIGN(len, mtd->writesize); |
| 741 | ~(mtd->writesize - 1); | ||
| 742 | /* Preset the buffer with 0xff */ | 847 | /* Preset the buffer with 0xff */ |
| 743 | memset(buf, 0xff, len + | 848 | memset(buf, 0xff, len + |
| 744 | (len >> this->page_shift)* mtd->oobsize); | 849 | (len >> this->page_shift)* mtd->oobsize); |
| @@ -772,7 +877,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
| 772 | if (res < 0) | 877 | if (res < 0) |
| 773 | goto outerr; | 878 | goto outerr; |
| 774 | 879 | ||
| 775 | res = scan_write_bbt(mtd, to, len, buf, &buf[len]); | 880 | res = scan_write_bbt(mtd, to, len, buf, |
| 881 | td->options & NAND_BBT_NO_OOB ? NULL : | ||
| 882 | &buf[len]); | ||
| 776 | if (res < 0) | 883 | if (res < 0) |
| 777 | goto outerr; | 884 | goto outerr; |
| 778 | 885 | ||
| @@ -892,7 +999,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
| 892 | continue; | 999 | continue; |
| 893 | 1000 | ||
| 894 | /* Create the table in memory by scanning the chip(s) */ | 1001 | /* Create the table in memory by scanning the chip(s) */ |
| 895 | create_bbt(mtd, buf, bd, chipsel); | 1002 | if (!(this->options & NAND_CREATE_EMPTY_BBT)) |
| 1003 | create_bbt(mtd, buf, bd, chipsel); | ||
| 896 | 1004 | ||
| 897 | td->version[i] = 1; | 1005 | td->version[i] = 1; |
| 898 | if (md) | 1006 | if (md) |
| @@ -983,6 +1091,49 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
| 983 | } | 1091 | } |
| 984 | 1092 | ||
| 985 | /** | 1093 | /** |
| 1094 | * verify_bbt_descr - verify the bad block description | ||
| 1095 | * @bd: the table to verify | ||
| 1096 | * | ||
| 1097 | * This functions performs a few sanity checks on the bad block description | ||
| 1098 | * table. | ||
| 1099 | */ | ||
| 1100 | static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) | ||
| 1101 | { | ||
| 1102 | struct nand_chip *this = mtd->priv; | ||
| 1103 | u32 pattern_len = bd->len; | ||
| 1104 | u32 bits = bd->options & NAND_BBT_NRBITS_MSK; | ||
| 1105 | u32 table_size; | ||
| 1106 | |||
| 1107 | if (!bd) | ||
| 1108 | return; | ||
| 1109 | BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && | ||
| 1110 | !(this->options & NAND_USE_FLASH_BBT)); | ||
| 1111 | BUG_ON(!bits); | ||
| 1112 | |||
| 1113 | if (bd->options & NAND_BBT_VERSION) | ||
| 1114 | pattern_len++; | ||
| 1115 | |||
| 1116 | if (bd->options & NAND_BBT_NO_OOB) { | ||
| 1117 | BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); | ||
| 1118 | BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); | ||
| 1119 | BUG_ON(bd->offs); | ||
| 1120 | if (bd->options & NAND_BBT_VERSION) | ||
| 1121 | BUG_ON(bd->veroffs != bd->len); | ||
| 1122 | BUG_ON(bd->options & NAND_BBT_SAVECONTENT); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | if (bd->options & NAND_BBT_PERCHIP) | ||
| 1126 | table_size = this->chipsize >> this->bbt_erase_shift; | ||
| 1127 | else | ||
| 1128 | table_size = mtd->size >> this->bbt_erase_shift; | ||
| 1129 | table_size >>= 3; | ||
| 1130 | table_size *= bits; | ||
| 1131 | if (bd->options & NAND_BBT_NO_OOB) | ||
| 1132 | table_size += pattern_len; | ||
| 1133 | BUG_ON(table_size > (1 << this->bbt_erase_shift)); | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | /** | ||
| 986 | * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) | 1137 | * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) |
| 987 | * @mtd: MTD device structure | 1138 | * @mtd: MTD device structure |
| 988 | * @bd: descriptor for the good/bad block search pattern | 1139 | * @bd: descriptor for the good/bad block search pattern |
| @@ -1023,6 +1174,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
| 1023 | } | 1174 | } |
| 1024 | return res; | 1175 | return res; |
| 1025 | } | 1176 | } |
| 1177 | verify_bbt_descr(mtd, td); | ||
| 1178 | verify_bbt_descr(mtd, md); | ||
| 1026 | 1179 | ||
| 1027 | /* Allocate a temporary buffer for one eraseblock incl. oob */ | 1180 | /* Allocate a temporary buffer for one eraseblock incl. oob */ |
| 1028 | len = (1 << this->bbt_erase_shift); | 1181 | len = (1 << this->bbt_erase_shift); |
| @@ -1166,6 +1319,26 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
| 1166 | .pattern = mirror_pattern | 1319 | .pattern = mirror_pattern |
| 1167 | }; | 1320 | }; |
| 1168 | 1321 | ||
| 1322 | static struct nand_bbt_descr bbt_main_no_bbt_descr = { | ||
| 1323 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | ||
| 1324 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | ||
| 1325 | | NAND_BBT_NO_OOB, | ||
| 1326 | .len = 4, | ||
| 1327 | .veroffs = 4, | ||
| 1328 | .maxblocks = 4, | ||
| 1329 | .pattern = bbt_pattern | ||
| 1330 | }; | ||
| 1331 | |||
| 1332 | static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { | ||
| 1333 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | ||
| 1334 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | ||
| 1335 | | NAND_BBT_NO_OOB, | ||
| 1336 | .len = 4, | ||
| 1337 | .veroffs = 4, | ||
| 1338 | .maxblocks = 4, | ||
| 1339 | .pattern = mirror_pattern | ||
| 1340 | }; | ||
| 1341 | |||
| 1169 | #define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ | 1342 | #define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ |
| 1170 | NAND_BBT_SCANBYTE1AND6) | 1343 | NAND_BBT_SCANBYTE1AND6) |
| 1171 | /** | 1344 | /** |
| @@ -1236,8 +1409,13 @@ int nand_default_bbt(struct mtd_info *mtd) | |||
| 1236 | if (this->options & NAND_USE_FLASH_BBT) { | 1409 | if (this->options & NAND_USE_FLASH_BBT) { |
| 1237 | /* Use the default pattern descriptors */ | 1410 | /* Use the default pattern descriptors */ |
| 1238 | if (!this->bbt_td) { | 1411 | if (!this->bbt_td) { |
| 1239 | this->bbt_td = &bbt_main_descr; | 1412 | if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { |
| 1240 | this->bbt_md = &bbt_mirror_descr; | 1413 | this->bbt_td = &bbt_main_no_bbt_descr; |
| 1414 | this->bbt_md = &bbt_mirror_no_bbt_descr; | ||
| 1415 | } else { | ||
| 1416 | this->bbt_td = &bbt_main_descr; | ||
| 1417 | this->bbt_md = &bbt_mirror_descr; | ||
| 1418 | } | ||
| 1241 | } | 1419 | } |
| 1242 | if (!this->badblock_pattern) { | 1420 | if (!this->badblock_pattern) { |
| 1243 | this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; | 1421 | this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index c65f19074bc8..00cf1b0d6053 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
| @@ -75,9 +75,13 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
| 75 | 75 | ||
| 76 | /*512 Megabit */ | 76 | /*512 Megabit */ |
| 77 | {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, | 77 | {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, |
| 78 | {"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS}, | ||
| 78 | {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, | 79 | {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, |
| 80 | {"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS}, | ||
| 79 | {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, | 81 | {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, |
| 82 | {"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16}, | ||
| 80 | {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, | 83 | {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, |
| 84 | {"NAND 64MiB 3,3V 16-bit", 0xC0, 0, 64, 0, LP_OPTIONS16}, | ||
| 81 | 85 | ||
| 82 | /* 1 Gigabit */ | 86 | /* 1 Gigabit */ |
| 83 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS}, | 87 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS}, |
| @@ -112,7 +116,34 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
| 112 | {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, | 116 | {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, |
| 113 | 117 | ||
| 114 | /* 32 Gigabit */ | 118 | /* 32 Gigabit */ |
| 119 | {"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS}, | ||
| 115 | {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, | 120 | {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, |
| 121 | {"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16}, | ||
| 122 | {"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16}, | ||
| 123 | |||
| 124 | /* 64 Gigabit */ | ||
| 125 | {"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS}, | ||
| 126 | {"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS}, | ||
| 127 | {"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16}, | ||
| 128 | {"NAND 8GiB 3,3V 16-bit", 0xCE, 0, 8192, 0, LP_OPTIONS16}, | ||
| 129 | |||
| 130 | /* 128 Gigabit */ | ||
| 131 | {"NAND 16GiB 1,8V 8-bit", 0x1A, 0, 16384, 0, LP_OPTIONS}, | ||
| 132 | {"NAND 16GiB 3,3V 8-bit", 0x3A, 0, 16384, 0, LP_OPTIONS}, | ||
| 133 | {"NAND 16GiB 1,8V 16-bit", 0x2A, 0, 16384, 0, LP_OPTIONS16}, | ||
| 134 | {"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16}, | ||
| 135 | |||
| 136 | /* 256 Gigabit */ | ||
| 137 | {"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS}, | ||
| 138 | {"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS}, | ||
| 139 | {"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16}, | ||
| 140 | {"NAND 32GiB 3,3V 16-bit", 0x4C, 0, 32768, 0, LP_OPTIONS16}, | ||
| 141 | |||
| 142 | /* 512 Gigabit */ | ||
| 143 | {"NAND 64GiB 1,8V 8-bit", 0x1E, 0, 65536, 0, LP_OPTIONS}, | ||
| 144 | {"NAND 64GiB 3,3V 8-bit", 0x3E, 0, 65536, 0, LP_OPTIONS}, | ||
| 145 | {"NAND 64GiB 1,8V 16-bit", 0x2E, 0, 65536, 0, LP_OPTIONS16}, | ||
| 146 | {"NAND 64GiB 3,3V 16-bit", 0x4E, 0, 65536, 0, LP_OPTIONS16}, | ||
| 116 | 147 | ||
| 117 | /* | 148 | /* |
| 118 | * Renesas AND 1 Gigabit. Those chips do not support extended id and | 149 | * Renesas AND 1 Gigabit. Those chips do not support extended id and |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c25648bb5793..a6a73aab1253 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
| @@ -107,6 +107,7 @@ static char *gravepages = NULL; | |||
| 107 | static unsigned int rptwear = 0; | 107 | static unsigned int rptwear = 0; |
| 108 | static unsigned int overridesize = 0; | 108 | static unsigned int overridesize = 0; |
| 109 | static char *cache_file = NULL; | 109 | static char *cache_file = NULL; |
| 110 | static unsigned int bbt; | ||
| 110 | 111 | ||
| 111 | module_param(first_id_byte, uint, 0400); | 112 | module_param(first_id_byte, uint, 0400); |
| 112 | module_param(second_id_byte, uint, 0400); | 113 | module_param(second_id_byte, uint, 0400); |
| @@ -130,6 +131,7 @@ module_param(gravepages, charp, 0400); | |||
| 130 | module_param(rptwear, uint, 0400); | 131 | module_param(rptwear, uint, 0400); |
| 131 | module_param(overridesize, uint, 0400); | 132 | module_param(overridesize, uint, 0400); |
| 132 | module_param(cache_file, charp, 0400); | 133 | module_param(cache_file, charp, 0400); |
| 134 | module_param(bbt, uint, 0400); | ||
| 133 | 135 | ||
| 134 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); | 136 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); |
| 135 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); | 137 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); |
| @@ -162,6 +164,7 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I | |||
| 162 | "The size is specified in erase blocks and as the exponent of a power of two" | 164 | "The size is specified in erase blocks and as the exponent of a power of two" |
| 163 | " e.g. 5 means a size of 32 erase blocks"); | 165 | " e.g. 5 means a size of 32 erase blocks"); |
| 164 | MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); | 166 | MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); |
| 167 | MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area"); | ||
| 165 | 168 | ||
| 166 | /* The largest possible page size */ | 169 | /* The largest possible page size */ |
| 167 | #define NS_LARGEST_PAGE_SIZE 4096 | 170 | #define NS_LARGEST_PAGE_SIZE 4096 |
| @@ -2264,6 +2267,18 @@ static int __init ns_init_module(void) | |||
| 2264 | /* and 'badblocks' parameters to work */ | 2267 | /* and 'badblocks' parameters to work */ |
| 2265 | chip->options |= NAND_SKIP_BBTSCAN; | 2268 | chip->options |= NAND_SKIP_BBTSCAN; |
| 2266 | 2269 | ||
| 2270 | switch (bbt) { | ||
| 2271 | case 2: | ||
| 2272 | chip->options |= NAND_USE_FLASH_BBT_NO_OOB; | ||
| 2273 | case 1: | ||
| 2274 | chip->options |= NAND_USE_FLASH_BBT; | ||
| 2275 | case 0: | ||
| 2276 | break; | ||
| 2277 | default: | ||
| 2278 | NS_ERR("bbt has to be 0..2\n"); | ||
| 2279 | retval = -EINVAL; | ||
| 2280 | goto error; | ||
| 2281 | } | ||
| 2267 | /* | 2282 | /* |
| 2268 | * Perform minimum nandsim structure initialization to handle | 2283 | * Perform minimum nandsim structure initialization to handle |
| 2269 | * the initial ID read command correctly | 2284 | * the initial ID read command correctly |
| @@ -2321,10 +2336,10 @@ static int __init ns_init_module(void) | |||
| 2321 | if ((retval = init_nandsim(nsmtd)) != 0) | 2336 | if ((retval = init_nandsim(nsmtd)) != 0) |
| 2322 | goto err_exit; | 2337 | goto err_exit; |
| 2323 | 2338 | ||
| 2324 | if ((retval = parse_badblocks(nand, nsmtd)) != 0) | 2339 | if ((retval = nand_default_bbt(nsmtd)) != 0) |
| 2325 | goto err_exit; | 2340 | goto err_exit; |
| 2326 | 2341 | ||
| 2327 | if ((retval = nand_default_bbt(nsmtd)) != 0) | 2342 | if ((retval = parse_badblocks(nand, nsmtd)) != 0) |
| 2328 | goto err_exit; | 2343 | goto err_exit; |
| 2329 | 2344 | ||
| 2330 | /* Register NAND partitions */ | 2345 | /* Register NAND partitions */ |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 510554e6c115..c9ae0a5023b6 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
| @@ -229,7 +229,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, | |||
| 229 | const struct of_device_id *match) | 229 | const struct of_device_id *match) |
| 230 | { | 230 | { |
| 231 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 231 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
| 232 | const u32 *reg; | 232 | const __be32 *reg; |
| 233 | u32 ccr; | 233 | u32 ccr; |
| 234 | int err, len; | 234 | int err, len; |
| 235 | 235 | ||
| @@ -244,7 +244,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, | |||
| 244 | dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); | 244 | dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); |
| 245 | return -ENOENT; | 245 | return -ENOENT; |
| 246 | } | 246 | } |
| 247 | ndfc->chip_select = reg[0]; | 247 | ndfc->chip_select = be32_to_cpu(reg[0]); |
| 248 | 248 | ||
| 249 | ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); | 249 | ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); |
| 250 | if (!ndfc->ndfcbase) { | 250 | if (!ndfc->ndfcbase) { |
| @@ -257,7 +257,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, | |||
| 257 | /* It is ok if ccr does not exist - just default to 0 */ | 257 | /* It is ok if ccr does not exist - just default to 0 */ |
| 258 | reg = of_get_property(ofdev->dev.of_node, "ccr", NULL); | 258 | reg = of_get_property(ofdev->dev.of_node, "ccr", NULL); |
| 259 | if (reg) | 259 | if (reg) |
| 260 | ccr |= *reg; | 260 | ccr |= be32_to_cpup(reg); |
| 261 | 261 | ||
| 262 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); | 262 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); |
| 263 | 263 | ||
| @@ -265,7 +265,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev, | |||
| 265 | reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); | 265 | reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); |
| 266 | if (reg) { | 266 | if (reg) { |
| 267 | int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); | 267 | int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); |
| 268 | out_be32(ndfc->ndfcbase + offset, *reg); | 268 | out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg)); |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | err = ndfc_chip_init(ndfc, ofdev->dev.of_node); | 271 | err = ndfc_chip_init(ndfc, ofdev->dev.of_node); |
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 513e0a76a4a7..cd41c58b5bbd 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
| @@ -111,11 +111,11 @@ static int use_dma = 1; | |||
| 111 | module_param(use_dma, bool, 0); | 111 | module_param(use_dma, bool, 0); |
| 112 | MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); | 112 | MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); |
| 113 | #else | 113 | #else |
| 114 | const int use_dma; | 114 | static const int use_dma; |
| 115 | #endif | 115 | #endif |
| 116 | #else | 116 | #else |
| 117 | const int use_prefetch; | 117 | const int use_prefetch; |
| 118 | const int use_dma; | 118 | static const int use_dma; |
| 119 | #endif | 119 | #endif |
| 120 | 120 | ||
| 121 | struct omap_nand_info { | 121 | struct omap_nand_info { |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4d01cda68844..17f8518cc5eb 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
| @@ -117,7 +117,7 @@ struct pxa3xx_nand_info { | |||
| 117 | struct nand_chip nand_chip; | 117 | struct nand_chip nand_chip; |
| 118 | 118 | ||
| 119 | struct platform_device *pdev; | 119 | struct platform_device *pdev; |
| 120 | const struct pxa3xx_nand_flash *flash_info; | 120 | struct pxa3xx_nand_cmdset *cmdset; |
| 121 | 121 | ||
| 122 | struct clk *clk; | 122 | struct clk *clk; |
| 123 | void __iomem *mmio_base; | 123 | void __iomem *mmio_base; |
| @@ -131,6 +131,7 @@ struct pxa3xx_nand_info { | |||
| 131 | int drcmr_cmd; | 131 | int drcmr_cmd; |
| 132 | 132 | ||
| 133 | unsigned char *data_buff; | 133 | unsigned char *data_buff; |
| 134 | unsigned char *oob_buff; | ||
| 134 | dma_addr_t data_buff_phys; | 135 | dma_addr_t data_buff_phys; |
| 135 | size_t data_buff_size; | 136 | size_t data_buff_size; |
| 136 | int data_dma_ch; | 137 | int data_dma_ch; |
| @@ -149,7 +150,8 @@ struct pxa3xx_nand_info { | |||
| 149 | int use_ecc; /* use HW ECC ? */ | 150 | int use_ecc; /* use HW ECC ? */ |
| 150 | int use_dma; /* use DMA ? */ | 151 | int use_dma; /* use DMA ? */ |
| 151 | 152 | ||
| 152 | size_t data_size; /* data size in FIFO */ | 153 | unsigned int page_size; /* page size of attached chip */ |
| 154 | unsigned int data_size; /* data size in FIFO */ | ||
| 153 | int retcode; | 155 | int retcode; |
| 154 | struct completion cmd_complete; | 156 | struct completion cmd_complete; |
| 155 | 157 | ||
| @@ -158,6 +160,10 @@ struct pxa3xx_nand_info { | |||
| 158 | uint32_t ndcb1; | 160 | uint32_t ndcb1; |
| 159 | uint32_t ndcb2; | 161 | uint32_t ndcb2; |
| 160 | 162 | ||
| 163 | /* timing calcuted from setting */ | ||
| 164 | uint32_t ndtr0cs0; | ||
| 165 | uint32_t ndtr1cs0; | ||
| 166 | |||
| 161 | /* calculated from pxa3xx_nand_flash data */ | 167 | /* calculated from pxa3xx_nand_flash data */ |
| 162 | size_t oob_size; | 168 | size_t oob_size; |
| 163 | size_t read_id_bytes; | 169 | size_t read_id_bytes; |
| @@ -174,23 +180,7 @@ MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); | |||
| 174 | * Default NAND flash controller configuration setup by the | 180 | * Default NAND flash controller configuration setup by the |
| 175 | * bootloader. This configuration is used only when pdata->keep_config is set | 181 | * bootloader. This configuration is used only when pdata->keep_config is set |
| 176 | */ | 182 | */ |
| 177 | static struct pxa3xx_nand_timing default_timing; | 183 | static struct pxa3xx_nand_cmdset default_cmdset = { |
| 178 | static struct pxa3xx_nand_flash default_flash; | ||
| 179 | |||
| 180 | static struct pxa3xx_nand_cmdset smallpage_cmdset = { | ||
| 181 | .read1 = 0x0000, | ||
| 182 | .read2 = 0x0050, | ||
| 183 | .program = 0x1080, | ||
| 184 | .read_status = 0x0070, | ||
| 185 | .read_id = 0x0090, | ||
| 186 | .erase = 0xD060, | ||
| 187 | .reset = 0x00FF, | ||
| 188 | .lock = 0x002A, | ||
| 189 | .unlock = 0x2423, | ||
| 190 | .lock_status = 0x007A, | ||
| 191 | }; | ||
| 192 | |||
| 193 | static struct pxa3xx_nand_cmdset largepage_cmdset = { | ||
| 194 | .read1 = 0x3000, | 184 | .read1 = 0x3000, |
| 195 | .read2 = 0x0050, | 185 | .read2 = 0x0050, |
| 196 | .program = 0x1080, | 186 | .program = 0x1080, |
| @@ -203,142 +193,27 @@ static struct pxa3xx_nand_cmdset largepage_cmdset = { | |||
| 203 | .lock_status = 0x007A, | 193 | .lock_status = 0x007A, |
| 204 | }; | 194 | }; |
| 205 | 195 | ||
| 206 | #ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN | 196 | static struct pxa3xx_nand_timing timing[] = { |
| 207 | static struct pxa3xx_nand_timing samsung512MbX16_timing = { | 197 | { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, |
| 208 | .tCH = 10, | 198 | { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, |
| 209 | .tCS = 0, | 199 | { 10, 25, 15, 25, 15, 30, 25000, 60, 10, }, |
| 210 | .tWH = 20, | 200 | { 10, 35, 15, 25, 15, 25, 25000, 60, 10, }, |
| 211 | .tWP = 40, | ||
| 212 | .tRH = 30, | ||
| 213 | .tRP = 40, | ||
| 214 | .tR = 11123, | ||
| 215 | .tWHR = 110, | ||
| 216 | .tAR = 10, | ||
| 217 | }; | ||
| 218 | |||
| 219 | static struct pxa3xx_nand_flash samsung512MbX16 = { | ||
| 220 | .timing = &samsung512MbX16_timing, | ||
| 221 | .cmdset = &smallpage_cmdset, | ||
| 222 | .page_per_block = 32, | ||
| 223 | .page_size = 512, | ||
| 224 | .flash_width = 16, | ||
| 225 | .dfc_width = 16, | ||
| 226 | .num_blocks = 4096, | ||
| 227 | .chip_id = 0x46ec, | ||
| 228 | }; | ||
| 229 | |||
| 230 | static struct pxa3xx_nand_flash samsung2GbX8 = { | ||
| 231 | .timing = &samsung512MbX16_timing, | ||
| 232 | .cmdset = &smallpage_cmdset, | ||
| 233 | .page_per_block = 64, | ||
| 234 | .page_size = 2048, | ||
| 235 | .flash_width = 8, | ||
| 236 | .dfc_width = 8, | ||
| 237 | .num_blocks = 2048, | ||
| 238 | .chip_id = 0xdaec, | ||
| 239 | }; | 201 | }; |
| 240 | 202 | ||
| 241 | static struct pxa3xx_nand_flash samsung32GbX8 = { | 203 | static struct pxa3xx_nand_flash builtin_flash_types[] = { |
| 242 | .timing = &samsung512MbX16_timing, | 204 | { 0, 0, 2048, 8, 8, 0, &default_cmdset, &timing[0] }, |
| 243 | .cmdset = &smallpage_cmdset, | 205 | { 0x46ec, 32, 512, 16, 16, 4096, &default_cmdset, &timing[1] }, |
| 244 | .page_per_block = 128, | 206 | { 0xdaec, 64, 2048, 8, 8, 2048, &default_cmdset, &timing[1] }, |
| 245 | .page_size = 4096, | 207 | { 0xd7ec, 128, 4096, 8, 8, 8192, &default_cmdset, &timing[1] }, |
| 246 | .flash_width = 8, | 208 | { 0xa12c, 64, 2048, 8, 8, 1024, &default_cmdset, &timing[2] }, |
| 247 | .dfc_width = 8, | 209 | { 0xb12c, 64, 2048, 16, 16, 1024, &default_cmdset, &timing[2] }, |
| 248 | .num_blocks = 8192, | 210 | { 0xdc2c, 64, 2048, 8, 8, 4096, &default_cmdset, &timing[2] }, |
| 249 | .chip_id = 0xd7ec, | 211 | { 0xcc2c, 64, 2048, 16, 16, 4096, &default_cmdset, &timing[2] }, |
| 212 | { 0xba20, 64, 2048, 16, 16, 2048, &default_cmdset, &timing[3] }, | ||
| 250 | }; | 213 | }; |
| 251 | 214 | ||
| 252 | static struct pxa3xx_nand_timing micron_timing = { | 215 | /* Define a default flash type setting serve as flash detecting only */ |
| 253 | .tCH = 10, | 216 | #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) |
| 254 | .tCS = 25, | ||
| 255 | .tWH = 15, | ||
| 256 | .tWP = 25, | ||
| 257 | .tRH = 15, | ||
| 258 | .tRP = 30, | ||
| 259 | .tR = 25000, | ||
| 260 | .tWHR = 60, | ||
| 261 | .tAR = 10, | ||
| 262 | }; | ||
| 263 | |||
| 264 | static struct pxa3xx_nand_flash micron1GbX8 = { | ||
| 265 | .timing = µn_timing, | ||
| 266 | .cmdset = &largepage_cmdset, | ||
| 267 | .page_per_block = 64, | ||
| 268 | .page_size = 2048, | ||
| 269 | .flash_width = 8, | ||
| 270 | .dfc_width = 8, | ||
| 271 | .num_blocks = 1024, | ||
| 272 | .chip_id = 0xa12c, | ||
| 273 | }; | ||
| 274 | |||
| 275 | static struct pxa3xx_nand_flash micron1GbX16 = { | ||
| 276 | .timing = µn_timing, | ||
| 277 | .cmdset = &largepage_cmdset, | ||
| 278 | .page_per_block = 64, | ||
| 279 | .page_size = 2048, | ||
| 280 | .flash_width = 16, | ||
| 281 | .dfc_width = 16, | ||
| 282 | .num_blocks = 1024, | ||
| 283 | .chip_id = 0xb12c, | ||
| 284 | }; | ||
| 285 | |||
| 286 | static struct pxa3xx_nand_flash micron4GbX8 = { | ||
| 287 | .timing = µn_timing, | ||
| 288 | .cmdset = &largepage_cmdset, | ||
| 289 | .page_per_block = 64, | ||
| 290 | .page_size = 2048, | ||
| 291 | .flash_width = 8, | ||
| 292 | .dfc_width = 8, | ||
| 293 | .num_blocks = 4096, | ||
| 294 | .chip_id = 0xdc2c, | ||
| 295 | }; | ||
| 296 | |||
| 297 | static struct pxa3xx_nand_flash micron4GbX16 = { | ||
| 298 | .timing = µn_timing, | ||
| 299 | .cmdset = &largepage_cmdset, | ||
| 300 | .page_per_block = 64, | ||
| 301 | .page_size = 2048, | ||
| 302 | .flash_width = 16, | ||
| 303 | .dfc_width = 16, | ||
| 304 | .num_blocks = 4096, | ||
| 305 | .chip_id = 0xcc2c, | ||
| 306 | }; | ||
| 307 | |||
| 308 | static struct pxa3xx_nand_timing stm2GbX16_timing = { | ||
| 309 | .tCH = 10, | ||
| 310 | .tCS = 35, | ||
| 311 | .tWH = 15, | ||
| 312 | .tWP = 25, | ||
| 313 | .tRH = 15, | ||
| 314 | .tRP = 25, | ||
| 315 | .tR = 25000, | ||
| 316 | .tWHR = 60, | ||
| 317 | .tAR = 10, | ||
| 318 | }; | ||
| 319 | |||
| 320 | static struct pxa3xx_nand_flash stm2GbX16 = { | ||
| 321 | .timing = &stm2GbX16_timing, | ||
| 322 | .cmdset = &largepage_cmdset, | ||
| 323 | .page_per_block = 64, | ||
| 324 | .page_size = 2048, | ||
| 325 | .flash_width = 16, | ||
| 326 | .dfc_width = 16, | ||
| 327 | .num_blocks = 2048, | ||
| 328 | .chip_id = 0xba20, | ||
| 329 | }; | ||
| 330 | |||
| 331 | static struct pxa3xx_nand_flash *builtin_flash_types[] = { | ||
| 332 | &samsung512MbX16, | ||
| 333 | &samsung2GbX8, | ||
| 334 | &samsung32GbX8, | ||
| 335 | µn1GbX8, | ||
| 336 | µn1GbX16, | ||
| 337 | µn4GbX8, | ||
| 338 | µn4GbX16, | ||
| 339 | &stm2GbX16, | ||
| 340 | }; | ||
| 341 | #endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */ | ||
| 342 | 217 | ||
| 343 | #define NDTR0_tCH(c) (min((c), 7) << 19) | 218 | #define NDTR0_tCH(c) (min((c), 7) << 19) |
| 344 | #define NDTR0_tCS(c) (min((c), 7) << 16) | 219 | #define NDTR0_tCS(c) (min((c), 7) << 16) |
| @@ -351,23 +226,9 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { | |||
| 351 | #define NDTR1_tWHR(c) (min((c), 15) << 4) | 226 | #define NDTR1_tWHR(c) (min((c), 15) << 4) |
| 352 | #define NDTR1_tAR(c) (min((c), 15) << 0) | 227 | #define NDTR1_tAR(c) (min((c), 15) << 0) |
| 353 | 228 | ||
| 354 | #define tCH_NDTR0(r) (((r) >> 19) & 0x7) | ||
| 355 | #define tCS_NDTR0(r) (((r) >> 16) & 0x7) | ||
| 356 | #define tWH_NDTR0(r) (((r) >> 11) & 0x7) | ||
| 357 | #define tWP_NDTR0(r) (((r) >> 8) & 0x7) | ||
| 358 | #define tRH_NDTR0(r) (((r) >> 3) & 0x7) | ||
| 359 | #define tRP_NDTR0(r) (((r) >> 0) & 0x7) | ||
| 360 | |||
| 361 | #define tR_NDTR1(r) (((r) >> 16) & 0xffff) | ||
| 362 | #define tWHR_NDTR1(r) (((r) >> 4) & 0xf) | ||
| 363 | #define tAR_NDTR1(r) (((r) >> 0) & 0xf) | ||
| 364 | |||
| 365 | /* convert nano-seconds to nand flash controller clock cycles */ | 229 | /* convert nano-seconds to nand flash controller clock cycles */ |
| 366 | #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) | 230 | #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) |
| 367 | 231 | ||
| 368 | /* convert nand flash controller clock cycles to nano-seconds */ | ||
| 369 | #define cycle2ns(c, clk) ((((c) + 1) * 1000000 + clk / 500) / (clk / 1000)) | ||
| 370 | |||
| 371 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, | 232 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, |
| 372 | const struct pxa3xx_nand_timing *t) | 233 | const struct pxa3xx_nand_timing *t) |
| 373 | { | 234 | { |
| @@ -385,6 +246,8 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, | |||
| 385 | NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | | 246 | NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | |
| 386 | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); | 247 | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); |
| 387 | 248 | ||
| 249 | info->ndtr0cs0 = ndtr0; | ||
| 250 | info->ndtr1cs0 = ndtr1; | ||
| 388 | nand_writel(info, NDTR0CS0, ndtr0); | 251 | nand_writel(info, NDTR0CS0, ndtr0); |
| 389 | nand_writel(info, NDTR1CS0, ndtr1); | 252 | nand_writel(info, NDTR1CS0, ndtr1); |
| 390 | } | 253 | } |
| @@ -408,23 +271,31 @@ static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) | |||
| 408 | return -ETIMEDOUT; | 271 | return -ETIMEDOUT; |
| 409 | } | 272 | } |
| 410 | 273 | ||
| 411 | static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, | 274 | static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) |
| 412 | uint16_t cmd, int column, int page_addr) | ||
| 413 | { | 275 | { |
| 414 | const struct pxa3xx_nand_flash *f = info->flash_info; | 276 | int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; |
| 415 | const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; | ||
| 416 | 277 | ||
| 417 | /* calculate data size */ | 278 | info->data_size = info->page_size; |
| 418 | switch (f->page_size) { | 279 | if (!oob_enable) { |
| 280 | info->oob_size = 0; | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | |||
| 284 | switch (info->page_size) { | ||
| 419 | case 2048: | 285 | case 2048: |
| 420 | info->data_size = (info->use_ecc) ? 2088 : 2112; | 286 | info->oob_size = (info->use_ecc) ? 40 : 64; |
| 421 | break; | 287 | break; |
| 422 | case 512: | 288 | case 512: |
| 423 | info->data_size = (info->use_ecc) ? 520 : 528; | 289 | info->oob_size = (info->use_ecc) ? 8 : 16; |
| 424 | break; | 290 | break; |
| 425 | default: | ||
| 426 | return -EINVAL; | ||
| 427 | } | 291 | } |
| 292 | } | ||
| 293 | |||
| 294 | static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, | ||
| 295 | uint16_t cmd, int column, int page_addr) | ||
| 296 | { | ||
| 297 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; | ||
| 298 | pxa3xx_set_datasize(info); | ||
| 428 | 299 | ||
| 429 | /* generate values for NDCBx registers */ | 300 | /* generate values for NDCBx registers */ |
| 430 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | 301 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); |
| @@ -463,12 +334,13 @@ static int prepare_erase_cmd(struct pxa3xx_nand_info *info, | |||
| 463 | 334 | ||
| 464 | static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) | 335 | static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) |
| 465 | { | 336 | { |
| 466 | const struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; | 337 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; |
| 467 | 338 | ||
| 468 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | 339 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); |
| 469 | info->ndcb1 = 0; | 340 | info->ndcb1 = 0; |
| 470 | info->ndcb2 = 0; | 341 | info->ndcb2 = 0; |
| 471 | 342 | ||
| 343 | info->oob_size = 0; | ||
| 472 | if (cmd == cmdset->read_id) { | 344 | if (cmd == cmdset->read_id) { |
| 473 | info->ndcb0 |= NDCB0_CMD_TYPE(3); | 345 | info->ndcb0 |= NDCB0_CMD_TYPE(3); |
| 474 | info->data_size = 8; | 346 | info->data_size = 8; |
| @@ -537,6 +409,9 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) | |||
| 537 | case STATE_PIO_WRITING: | 409 | case STATE_PIO_WRITING: |
| 538 | __raw_writesl(info->mmio_base + NDDB, info->data_buff, | 410 | __raw_writesl(info->mmio_base + NDDB, info->data_buff, |
| 539 | DIV_ROUND_UP(info->data_size, 4)); | 411 | DIV_ROUND_UP(info->data_size, 4)); |
| 412 | if (info->oob_size > 0) | ||
| 413 | __raw_writesl(info->mmio_base + NDDB, info->oob_buff, | ||
| 414 | DIV_ROUND_UP(info->oob_size, 4)); | ||
| 540 | 415 | ||
| 541 | enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | 416 | enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); |
| 542 | 417 | ||
| @@ -549,6 +424,9 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) | |||
| 549 | case STATE_PIO_READING: | 424 | case STATE_PIO_READING: |
| 550 | __raw_readsl(info->mmio_base + NDDB, info->data_buff, | 425 | __raw_readsl(info->mmio_base + NDDB, info->data_buff, |
| 551 | DIV_ROUND_UP(info->data_size, 4)); | 426 | DIV_ROUND_UP(info->data_size, 4)); |
| 427 | if (info->oob_size > 0) | ||
| 428 | __raw_readsl(info->mmio_base + NDDB, info->oob_buff, | ||
| 429 | DIV_ROUND_UP(info->oob_size, 4)); | ||
| 552 | break; | 430 | break; |
| 553 | default: | 431 | default: |
| 554 | printk(KERN_ERR "%s: invalid state %d\n", __func__, | 432 | printk(KERN_ERR "%s: invalid state %d\n", __func__, |
| @@ -563,7 +441,7 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) | |||
| 563 | static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) | 441 | static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) |
| 564 | { | 442 | { |
| 565 | struct pxa_dma_desc *desc = info->data_desc; | 443 | struct pxa_dma_desc *desc = info->data_desc; |
| 566 | int dma_len = ALIGN(info->data_size, 32); | 444 | int dma_len = ALIGN(info->data_size + info->oob_size, 32); |
| 567 | 445 | ||
| 568 | desc->ddadr = DDADR_STOP; | 446 | desc->ddadr = DDADR_STOP; |
| 569 | desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; | 447 | desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; |
| @@ -700,8 +578,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
| 700 | int column, int page_addr) | 578 | int column, int page_addr) |
| 701 | { | 579 | { |
| 702 | struct pxa3xx_nand_info *info = mtd->priv; | 580 | struct pxa3xx_nand_info *info = mtd->priv; |
| 703 | const struct pxa3xx_nand_flash *flash_info = info->flash_info; | 581 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; |
| 704 | const struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; | ||
| 705 | int ret; | 582 | int ret; |
| 706 | 583 | ||
| 707 | info->use_dma = (use_dma) ? 1 : 0; | 584 | info->use_dma = (use_dma) ? 1 : 0; |
| @@ -925,8 +802,7 @@ static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, | |||
| 925 | 802 | ||
| 926 | static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) | 803 | static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) |
| 927 | { | 804 | { |
| 928 | const struct pxa3xx_nand_flash *f = info->flash_info; | 805 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; |
| 929 | const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; | ||
| 930 | uint32_t ndcr; | 806 | uint32_t ndcr; |
| 931 | uint8_t id_buff[8]; | 807 | uint8_t id_buff[8]; |
| 932 | 808 | ||
| @@ -968,7 +844,9 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
| 968 | return -EINVAL; | 844 | return -EINVAL; |
| 969 | 845 | ||
| 970 | /* calculate flash information */ | 846 | /* calculate flash information */ |
| 971 | info->oob_size = (f->page_size == 2048) ? 64 : 16; | 847 | info->cmdset = f->cmdset; |
| 848 | info->page_size = f->page_size; | ||
| 849 | info->oob_buff = info->data_buff + f->page_size; | ||
| 972 | info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; | 850 | info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; |
| 973 | 851 | ||
| 974 | /* calculate addressing information */ | 852 | /* calculate addressing information */ |
| @@ -992,49 +870,20 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
| 992 | info->reg_ndcr = ndcr; | 870 | info->reg_ndcr = ndcr; |
| 993 | 871 | ||
| 994 | pxa3xx_nand_set_timing(info, f->timing); | 872 | pxa3xx_nand_set_timing(info, f->timing); |
| 995 | info->flash_info = f; | ||
| 996 | return 0; | 873 | return 0; |
| 997 | } | 874 | } |
| 998 | 875 | ||
| 999 | static void pxa3xx_nand_detect_timing(struct pxa3xx_nand_info *info, | ||
| 1000 | struct pxa3xx_nand_timing *t) | ||
| 1001 | { | ||
| 1002 | unsigned long nand_clk = clk_get_rate(info->clk); | ||
| 1003 | uint32_t ndtr0 = nand_readl(info, NDTR0CS0); | ||
| 1004 | uint32_t ndtr1 = nand_readl(info, NDTR1CS0); | ||
| 1005 | |||
| 1006 | t->tCH = cycle2ns(tCH_NDTR0(ndtr0), nand_clk); | ||
| 1007 | t->tCS = cycle2ns(tCS_NDTR0(ndtr0), nand_clk); | ||
| 1008 | t->tWH = cycle2ns(tWH_NDTR0(ndtr0), nand_clk); | ||
| 1009 | t->tWP = cycle2ns(tWP_NDTR0(ndtr0), nand_clk); | ||
| 1010 | t->tRH = cycle2ns(tRH_NDTR0(ndtr0), nand_clk); | ||
| 1011 | t->tRP = cycle2ns(tRP_NDTR0(ndtr0), nand_clk); | ||
| 1012 | |||
| 1013 | t->tR = cycle2ns(tR_NDTR1(ndtr1), nand_clk); | ||
| 1014 | t->tWHR = cycle2ns(tWHR_NDTR1(ndtr1), nand_clk); | ||
| 1015 | t->tAR = cycle2ns(tAR_NDTR1(ndtr1), nand_clk); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | 876 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) |
| 1019 | { | 877 | { |
| 1020 | uint32_t ndcr = nand_readl(info, NDCR); | 878 | uint32_t ndcr = nand_readl(info, NDCR); |
| 1021 | struct nand_flash_dev *type = NULL; | 879 | struct nand_flash_dev *type = NULL; |
| 1022 | uint32_t id = -1; | 880 | uint32_t id = -1, page_per_block, num_blocks; |
| 1023 | int i; | 881 | int i; |
| 1024 | 882 | ||
| 1025 | default_flash.page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; | 883 | page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; |
| 1026 | default_flash.page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; | 884 | info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; |
| 1027 | default_flash.flash_width = ndcr & NDCR_DWIDTH_M ? 16 : 8; | ||
| 1028 | default_flash.dfc_width = ndcr & NDCR_DWIDTH_C ? 16 : 8; | ||
| 1029 | |||
| 1030 | if (default_flash.page_size == 2048) | ||
| 1031 | default_flash.cmdset = &largepage_cmdset; | ||
| 1032 | else | ||
| 1033 | default_flash.cmdset = &smallpage_cmdset; | ||
| 1034 | |||
| 1035 | /* set info fields needed to __readid */ | 885 | /* set info fields needed to __readid */ |
| 1036 | info->flash_info = &default_flash; | 886 | info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; |
| 1037 | info->read_id_bytes = (default_flash.page_size == 2048) ? 4 : 2; | ||
| 1038 | info->reg_ndcr = ndcr; | 887 | info->reg_ndcr = ndcr; |
| 1039 | 888 | ||
| 1040 | if (__readid(info, &id)) | 889 | if (__readid(info, &id)) |
| @@ -1053,21 +902,20 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | |||
| 1053 | return -ENODEV; | 902 | return -ENODEV; |
| 1054 | 903 | ||
| 1055 | /* fill the missing flash information */ | 904 | /* fill the missing flash information */ |
| 1056 | i = __ffs(default_flash.page_per_block * default_flash.page_size); | 905 | i = __ffs(page_per_block * info->page_size); |
| 1057 | default_flash.num_blocks = type->chipsize << (20 - i); | 906 | num_blocks = type->chipsize << (20 - i); |
| 1058 | |||
| 1059 | info->oob_size = (default_flash.page_size == 2048) ? 64 : 16; | ||
| 1060 | 907 | ||
| 1061 | /* calculate addressing information */ | 908 | /* calculate addressing information */ |
| 1062 | info->col_addr_cycles = (default_flash.page_size == 2048) ? 2 : 1; | 909 | info->col_addr_cycles = (info->page_size == 2048) ? 2 : 1; |
| 1063 | 910 | ||
| 1064 | if (default_flash.num_blocks * default_flash.page_per_block > 65536) | 911 | if (num_blocks * page_per_block > 65536) |
| 1065 | info->row_addr_cycles = 3; | 912 | info->row_addr_cycles = 3; |
| 1066 | else | 913 | else |
| 1067 | info->row_addr_cycles = 2; | 914 | info->row_addr_cycles = 2; |
| 1068 | 915 | ||
| 1069 | pxa3xx_nand_detect_timing(info, &default_timing); | 916 | info->ndtr0cs0 = nand_readl(info, NDTR0CS0); |
| 1070 | default_flash.timing = &default_timing; | 917 | info->ndtr1cs0 = nand_readl(info, NDTR1CS0); |
| 918 | info->cmdset = &default_cmdset; | ||
| 1071 | 919 | ||
| 1072 | return 0; | 920 | return 0; |
| 1073 | } | 921 | } |
| @@ -1083,38 +931,29 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, | |||
| 1083 | if (pxa3xx_nand_detect_config(info) == 0) | 931 | if (pxa3xx_nand_detect_config(info) == 0) |
| 1084 | return 0; | 932 | return 0; |
| 1085 | 933 | ||
| 1086 | for (i = 0; i<pdata->num_flash; ++i) { | 934 | /* we use default timing to detect id */ |
| 1087 | f = pdata->flash + i; | 935 | f = DEFAULT_FLASH_TYPE; |
| 1088 | 936 | pxa3xx_nand_config_flash(info, f); | |
| 1089 | if (pxa3xx_nand_config_flash(info, f)) | 937 | if (__readid(info, &id)) |
| 1090 | continue; | 938 | goto fail_detect; |
| 1091 | 939 | ||
| 1092 | if (__readid(info, &id)) | 940 | for (i=0; i<ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; i++) { |
| 1093 | continue; | 941 | /* we first choose the flash definition from platfrom */ |
| 1094 | 942 | if (i < pdata->num_flash) | |
| 1095 | if (id == f->chip_id) | 943 | f = pdata->flash + i; |
| 1096 | return 0; | 944 | else |
| 1097 | } | 945 | f = &builtin_flash_types[i - pdata->num_flash + 1]; |
| 1098 | 946 | if (f->chip_id == id) { | |
| 1099 | #ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN | 947 | dev_info(&info->pdev->dev, "detect chip id: 0x%x\n", id); |
| 1100 | for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) { | 948 | pxa3xx_nand_config_flash(info, f); |
| 1101 | |||
| 1102 | f = builtin_flash_types[i]; | ||
| 1103 | |||
| 1104 | if (pxa3xx_nand_config_flash(info, f)) | ||
| 1105 | continue; | ||
| 1106 | |||
| 1107 | if (__readid(info, &id)) | ||
| 1108 | continue; | ||
| 1109 | |||
| 1110 | if (id == f->chip_id) | ||
| 1111 | return 0; | 949 | return 0; |
| 950 | } | ||
| 1112 | } | 951 | } |
| 1113 | #endif | ||
| 1114 | 952 | ||
| 1115 | dev_warn(&info->pdev->dev, | 953 | dev_warn(&info->pdev->dev, |
| 1116 | "failed to detect configured nand flash; found %04x instead of\n", | 954 | "failed to detect configured nand flash; found %04x instead of\n", |
| 1117 | id); | 955 | id); |
| 956 | fail_detect: | ||
| 1118 | return -ENODEV; | 957 | return -ENODEV; |
| 1119 | } | 958 | } |
| 1120 | 959 | ||
| @@ -1177,10 +1016,9 @@ static struct nand_ecclayout hw_largepage_ecclayout = { | |||
| 1177 | static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, | 1016 | static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, |
| 1178 | struct pxa3xx_nand_info *info) | 1017 | struct pxa3xx_nand_info *info) |
| 1179 | { | 1018 | { |
| 1180 | const struct pxa3xx_nand_flash *f = info->flash_info; | ||
| 1181 | struct nand_chip *this = &info->nand_chip; | 1019 | struct nand_chip *this = &info->nand_chip; |
| 1182 | 1020 | ||
| 1183 | this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0; | 1021 | this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0; |
| 1184 | 1022 | ||
| 1185 | this->waitfunc = pxa3xx_nand_waitfunc; | 1023 | this->waitfunc = pxa3xx_nand_waitfunc; |
| 1186 | this->select_chip = pxa3xx_nand_select_chip; | 1024 | this->select_chip = pxa3xx_nand_select_chip; |
| @@ -1196,9 +1034,9 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, | |||
| 1196 | this->ecc.hwctl = pxa3xx_nand_ecc_hwctl; | 1034 | this->ecc.hwctl = pxa3xx_nand_ecc_hwctl; |
| 1197 | this->ecc.calculate = pxa3xx_nand_ecc_calculate; | 1035 | this->ecc.calculate = pxa3xx_nand_ecc_calculate; |
| 1198 | this->ecc.correct = pxa3xx_nand_ecc_correct; | 1036 | this->ecc.correct = pxa3xx_nand_ecc_correct; |
| 1199 | this->ecc.size = f->page_size; | 1037 | this->ecc.size = info->page_size; |
| 1200 | 1038 | ||
| 1201 | if (f->page_size == 2048) | 1039 | if (info->page_size == 2048) |
| 1202 | this->ecc.layout = &hw_largepage_ecclayout; | 1040 | this->ecc.layout = &hw_largepage_ecclayout; |
| 1203 | else | 1041 | else |
| 1204 | this->ecc.layout = &hw_smallpage_ecclayout; | 1042 | this->ecc.layout = &hw_smallpage_ecclayout; |
| @@ -1411,9 +1249,11 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) | |||
| 1411 | struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); | 1249 | struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); |
| 1412 | struct pxa3xx_nand_info *info = mtd->priv; | 1250 | struct pxa3xx_nand_info *info = mtd->priv; |
| 1413 | 1251 | ||
| 1252 | nand_writel(info, NDTR0CS0, info->ndtr0cs0); | ||
| 1253 | nand_writel(info, NDTR1CS0, info->ndtr1cs0); | ||
| 1414 | clk_enable(info->clk); | 1254 | clk_enable(info->clk); |
| 1415 | 1255 | ||
| 1416 | return pxa3xx_nand_config_flash(info, info->flash_info); | 1256 | return 0; |
| 1417 | } | 1257 | } |
| 1418 | #else | 1258 | #else |
| 1419 | #define pxa3xx_nand_suspend NULL | 1259 | #define pxa3xx_nand_suspend NULL |
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 5169ca6a66bc..d9d7efbc77cc 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c | |||
| @@ -757,11 +757,6 @@ static irqreturn_t r852_irq(int irq, void *data) | |||
| 757 | 757 | ||
| 758 | spin_lock_irqsave(&dev->irqlock, flags); | 758 | spin_lock_irqsave(&dev->irqlock, flags); |
| 759 | 759 | ||
| 760 | /* We can recieve shared interrupt while pci is suspended | ||
| 761 | in that case reads will return 0xFFFFFFFF.... */ | ||
| 762 | if (dev->insuspend) | ||
| 763 | goto out; | ||
| 764 | |||
| 765 | /* handle card detection interrupts first */ | 760 | /* handle card detection interrupts first */ |
| 766 | card_status = r852_read_reg(dev, R852_CARD_IRQ_STA); | 761 | card_status = r852_read_reg(dev, R852_CARD_IRQ_STA); |
| 767 | r852_write_reg(dev, R852_CARD_IRQ_STA, card_status); | 762 | r852_write_reg(dev, R852_CARD_IRQ_STA, card_status); |
| @@ -1035,7 +1030,6 @@ void r852_shutdown(struct pci_dev *pci_dev) | |||
| 1035 | int r852_suspend(struct device *device) | 1030 | int r852_suspend(struct device *device) |
| 1036 | { | 1031 | { |
| 1037 | struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); | 1032 | struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); |
| 1038 | unsigned long flags; | ||
| 1039 | 1033 | ||
| 1040 | if (dev->ctlreg & R852_CTL_CARDENABLE) | 1034 | if (dev->ctlreg & R852_CTL_CARDENABLE) |
| 1041 | return -EBUSY; | 1035 | return -EBUSY; |
| @@ -1047,43 +1041,22 @@ int r852_suspend(struct device *device) | |||
| 1047 | r852_disable_irqs(dev); | 1041 | r852_disable_irqs(dev); |
| 1048 | r852_engine_disable(dev); | 1042 | r852_engine_disable(dev); |
| 1049 | 1043 | ||
| 1050 | spin_lock_irqsave(&dev->irqlock, flags); | ||
| 1051 | dev->insuspend = 1; | ||
| 1052 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
| 1053 | |||
| 1054 | /* At that point, even if interrupt handler is running, it will quit */ | ||
| 1055 | /* So wait for this to happen explictly */ | ||
| 1056 | synchronize_irq(dev->irq); | ||
| 1057 | |||
| 1058 | /* If card was pulled off just during the suspend, which is very | 1044 | /* If card was pulled off just during the suspend, which is very |
| 1059 | unlikely, we will remove it on resume, it too late now | 1045 | unlikely, we will remove it on resume, it too late now |
| 1060 | anyway... */ | 1046 | anyway... */ |
| 1061 | dev->card_unstable = 0; | 1047 | dev->card_unstable = 0; |
| 1062 | 1048 | return 0; | |
| 1063 | pci_save_state(to_pci_dev(device)); | ||
| 1064 | return pci_prepare_to_sleep(to_pci_dev(device)); | ||
| 1065 | } | 1049 | } |
| 1066 | 1050 | ||
| 1067 | int r852_resume(struct device *device) | 1051 | int r852_resume(struct device *device) |
| 1068 | { | 1052 | { |
| 1069 | struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); | 1053 | struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); |
| 1070 | unsigned long flags; | ||
| 1071 | |||
| 1072 | /* Turn on the hardware */ | ||
| 1073 | pci_back_from_sleep(to_pci_dev(device)); | ||
| 1074 | pci_restore_state(to_pci_dev(device)); | ||
| 1075 | 1054 | ||
| 1076 | r852_disable_irqs(dev); | 1055 | r852_disable_irqs(dev); |
| 1077 | r852_card_update_present(dev); | 1056 | r852_card_update_present(dev); |
| 1078 | r852_engine_disable(dev); | 1057 | r852_engine_disable(dev); |
| 1079 | 1058 | ||
| 1080 | 1059 | ||
| 1081 | /* Now its safe for IRQ to run */ | ||
| 1082 | spin_lock_irqsave(&dev->irqlock, flags); | ||
| 1083 | dev->insuspend = 0; | ||
| 1084 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
| 1085 | |||
| 1086 | |||
| 1087 | /* If card status changed, just do the work */ | 1060 | /* If card status changed, just do the work */ |
| 1088 | if (dev->card_detected != dev->card_registred) { | 1061 | if (dev->card_detected != dev->card_registred) { |
| 1089 | dbg("card was %s during low power state", | 1062 | dbg("card was %s during low power state", |
| @@ -1121,7 +1094,6 @@ MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); | |||
| 1121 | 1094 | ||
| 1122 | SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); | 1095 | SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); |
| 1123 | 1096 | ||
| 1124 | |||
| 1125 | static struct pci_driver r852_pci_driver = { | 1097 | static struct pci_driver r852_pci_driver = { |
| 1126 | .name = DRV_NAME, | 1098 | .name = DRV_NAME, |
| 1127 | .id_table = r852_pci_id_tbl, | 1099 | .id_table = r852_pci_id_tbl, |
diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h index 8096cc280c73..e6a21d9d22c6 100644 --- a/drivers/mtd/nand/r852.h +++ b/drivers/mtd/nand/r852.h | |||
| @@ -140,8 +140,6 @@ struct r852_device { | |||
| 140 | /* interrupt handling */ | 140 | /* interrupt handling */ |
| 141 | spinlock_t irqlock; /* IRQ protecting lock */ | 141 | spinlock_t irqlock; /* IRQ protecting lock */ |
| 142 | int irq; /* irq num */ | 142 | int irq; /* irq num */ |
| 143 | int insuspend; /* device is suspended */ | ||
| 144 | |||
| 145 | /* misc */ | 143 | /* misc */ |
| 146 | void *tmp_buffer; /* temporary buffer */ | 144 | void *tmp_buffer; /* temporary buffer */ |
| 147 | uint8_t ctlreg; /* cached contents of control reg */ | 145 | uint8_t ctlreg; /* cached contents of control reg */ |
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 7bd171eefd21..a996718fa6b0 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c | |||
| @@ -44,7 +44,7 @@ int __devinit of_mtd_parse_partitions(struct device *dev, | |||
| 44 | pp = NULL; | 44 | pp = NULL; |
| 45 | i = 0; | 45 | i = 0; |
| 46 | while ((pp = of_get_next_child(node, pp))) { | 46 | while ((pp = of_get_next_child(node, pp))) { |
| 47 | const u32 *reg; | 47 | const __be32 *reg; |
| 48 | int len; | 48 | int len; |
| 49 | 49 | ||
| 50 | reg = of_get_property(pp, "reg", &len); | 50 | reg = of_get_property(pp, "reg", &len); |
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index 3f32289fdbb5..4dbd0f58eebf 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig | |||
| @@ -32,10 +32,11 @@ config MTD_ONENAND_OMAP2 | |||
| 32 | 32 | ||
| 33 | config MTD_ONENAND_SAMSUNG | 33 | config MTD_ONENAND_SAMSUNG |
| 34 | tristate "OneNAND on Samsung SOC controller support" | 34 | tristate "OneNAND on Samsung SOC controller support" |
| 35 | depends on ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 | 35 | depends on ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310 |
| 36 | help | 36 | help |
| 37 | Support for a OneNAND flash device connected to an Samsung SOC | 37 | Support for a OneNAND flash device connected to an Samsung SOC. |
| 38 | S3C64XX/S5PC1XX controller. | 38 | S3C64XX/S5PC100 use command mapping method. |
| 39 | S5PC110/S5PC210 use generic OneNAND method. | ||
| 39 | 40 | ||
| 40 | config MTD_ONENAND_OTP | 41 | config MTD_ONENAND_OTP |
| 41 | bool "OneNAND OTP Support" | 42 | bool "OneNAND OTP Support" |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a2bb520286f8..6b3a875647c9 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
| @@ -3365,18 +3365,19 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, | |||
| 3365 | static void onenand_check_features(struct mtd_info *mtd) | 3365 | static void onenand_check_features(struct mtd_info *mtd) |
| 3366 | { | 3366 | { |
| 3367 | struct onenand_chip *this = mtd->priv; | 3367 | struct onenand_chip *this = mtd->priv; |
| 3368 | unsigned int density, process; | 3368 | unsigned int density, process, numbufs; |
| 3369 | 3369 | ||
| 3370 | /* Lock scheme depends on density and process */ | 3370 | /* Lock scheme depends on density and process */ |
| 3371 | density = onenand_get_density(this->device_id); | 3371 | density = onenand_get_density(this->device_id); |
| 3372 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; | 3372 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; |
| 3373 | numbufs = this->read_word(this->base + ONENAND_REG_NUM_BUFFERS) >> 8; | ||
| 3373 | 3374 | ||
| 3374 | /* Lock scheme */ | 3375 | /* Lock scheme */ |
| 3375 | switch (density) { | 3376 | switch (density) { |
| 3376 | case ONENAND_DEVICE_DENSITY_4Gb: | 3377 | case ONENAND_DEVICE_DENSITY_4Gb: |
| 3377 | if (ONENAND_IS_DDP(this)) | 3378 | if (ONENAND_IS_DDP(this)) |
| 3378 | this->options |= ONENAND_HAS_2PLANE; | 3379 | this->options |= ONENAND_HAS_2PLANE; |
| 3379 | else | 3380 | else if (numbufs == 1) |
| 3380 | this->options |= ONENAND_HAS_4KB_PAGE; | 3381 | this->options |= ONENAND_HAS_4KB_PAGE; |
| 3381 | 3382 | ||
| 3382 | case ONENAND_DEVICE_DENSITY_2Gb: | 3383 | case ONENAND_DEVICE_DENSITY_2Gb: |
| @@ -4027,7 +4028,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
| 4027 | mtd->ecclayout = this->ecclayout; | 4028 | mtd->ecclayout = this->ecclayout; |
| 4028 | 4029 | ||
| 4029 | /* Fill in remaining MTD driver data */ | 4030 | /* Fill in remaining MTD driver data */ |
| 4030 | mtd->type = MTD_NANDFLASH; | 4031 | mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH; |
| 4031 | mtd->flags = MTD_CAP_NANDFLASH; | 4032 | mtd->flags = MTD_CAP_NANDFLASH; |
| 4032 | mtd->erase = onenand_erase; | 4033 | mtd->erase = onenand_erase; |
| 4033 | mtd->point = NULL; | 4034 | mtd->point = NULL; |
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index a460f1b748c2..0de7a05e6de0 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/mtd/onenand.h> | 22 | #include <linux/mtd/onenand.h> |
| 23 | #include <linux/mtd/partitions.h> | 23 | #include <linux/mtd/partitions.h> |
| 24 | #include <linux/dma-mapping.h> | 24 | #include <linux/dma-mapping.h> |
| 25 | #include <linux/interrupt.h> | ||
| 25 | 26 | ||
| 26 | #include <asm/mach/flash.h> | 27 | #include <asm/mach/flash.h> |
| 27 | #include <plat/regs-onenand.h> | 28 | #include <plat/regs-onenand.h> |
| @@ -58,7 +59,7 @@ enum soc_type { | |||
| 58 | #define MAP_11 (0x3) | 59 | #define MAP_11 (0x3) |
| 59 | 60 | ||
| 60 | #define S3C64XX_CMD_MAP_SHIFT 24 | 61 | #define S3C64XX_CMD_MAP_SHIFT 24 |
| 61 | #define S5PC1XX_CMD_MAP_SHIFT 26 | 62 | #define S5PC100_CMD_MAP_SHIFT 26 |
| 62 | 63 | ||
| 63 | #define S3C6400_FBA_SHIFT 10 | 64 | #define S3C6400_FBA_SHIFT 10 |
| 64 | #define S3C6400_FPA_SHIFT 4 | 65 | #define S3C6400_FPA_SHIFT 4 |
| @@ -81,6 +82,17 @@ enum soc_type { | |||
| 81 | #define S5PC110_DMA_TRANS_CMD 0x418 | 82 | #define S5PC110_DMA_TRANS_CMD 0x418 |
| 82 | #define S5PC110_DMA_TRANS_STATUS 0x41C | 83 | #define S5PC110_DMA_TRANS_STATUS 0x41C |
| 83 | #define S5PC110_DMA_TRANS_DIR 0x420 | 84 | #define S5PC110_DMA_TRANS_DIR 0x420 |
| 85 | #define S5PC110_INTC_DMA_CLR 0x1004 | ||
| 86 | #define S5PC110_INTC_ONENAND_CLR 0x1008 | ||
| 87 | #define S5PC110_INTC_DMA_MASK 0x1024 | ||
| 88 | #define S5PC110_INTC_ONENAND_MASK 0x1028 | ||
| 89 | #define S5PC110_INTC_DMA_PEND 0x1044 | ||
| 90 | #define S5PC110_INTC_ONENAND_PEND 0x1048 | ||
| 91 | #define S5PC110_INTC_DMA_STATUS 0x1064 | ||
| 92 | #define S5PC110_INTC_ONENAND_STATUS 0x1068 | ||
| 93 | |||
| 94 | #define S5PC110_INTC_DMA_TD (1 << 24) | ||
| 95 | #define S5PC110_INTC_DMA_TE (1 << 16) | ||
| 84 | 96 | ||
| 85 | #define S5PC110_DMA_CFG_SINGLE (0x0 << 16) | 97 | #define S5PC110_DMA_CFG_SINGLE (0x0 << 16) |
| 86 | #define S5PC110_DMA_CFG_4BURST (0x2 << 16) | 98 | #define S5PC110_DMA_CFG_4BURST (0x2 << 16) |
| @@ -134,6 +146,7 @@ struct s3c_onenand { | |||
| 134 | void __iomem *dma_addr; | 146 | void __iomem *dma_addr; |
| 135 | struct resource *dma_res; | 147 | struct resource *dma_res; |
| 136 | unsigned long phys_base; | 148 | unsigned long phys_base; |
| 149 | struct completion complete; | ||
| 137 | #ifdef CONFIG_MTD_PARTITIONS | 150 | #ifdef CONFIG_MTD_PARTITIONS |
| 138 | struct mtd_partition *parts; | 151 | struct mtd_partition *parts; |
| 139 | #endif | 152 | #endif |
| @@ -191,7 +204,7 @@ static unsigned int s3c64xx_cmd_map(unsigned type, unsigned val) | |||
| 191 | 204 | ||
| 192 | static unsigned int s5pc1xx_cmd_map(unsigned type, unsigned val) | 205 | static unsigned int s5pc1xx_cmd_map(unsigned type, unsigned val) |
| 193 | { | 206 | { |
| 194 | return (type << S5PC1XX_CMD_MAP_SHIFT) | val; | 207 | return (type << S5PC100_CMD_MAP_SHIFT) | val; |
| 195 | } | 208 | } |
| 196 | 209 | ||
| 197 | static unsigned int s3c6400_mem_addr(int fba, int fpa, int fsa) | 210 | static unsigned int s3c6400_mem_addr(int fba, int fpa, int fsa) |
| @@ -531,10 +544,13 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, | |||
| 531 | return 0; | 544 | return 0; |
| 532 | } | 545 | } |
| 533 | 546 | ||
| 534 | static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) | 547 | static int (*s5pc110_dma_ops)(void *dst, void *src, size_t count, int direction); |
| 548 | |||
| 549 | static int s5pc110_dma_poll(void *dst, void *src, size_t count, int direction) | ||
| 535 | { | 550 | { |
| 536 | void __iomem *base = onenand->dma_addr; | 551 | void __iomem *base = onenand->dma_addr; |
| 537 | int status; | 552 | int status; |
| 553 | unsigned long timeout; | ||
| 538 | 554 | ||
| 539 | writel(src, base + S5PC110_DMA_SRC_ADDR); | 555 | writel(src, base + S5PC110_DMA_SRC_ADDR); |
| 540 | writel(dst, base + S5PC110_DMA_DST_ADDR); | 556 | writel(dst, base + S5PC110_DMA_DST_ADDR); |
| @@ -552,6 +568,13 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) | |||
| 552 | 568 | ||
| 553 | writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD); | 569 | writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD); |
| 554 | 570 | ||
| 571 | /* | ||
| 572 | * There's no exact timeout values at Spec. | ||
| 573 | * In real case it takes under 1 msec. | ||
| 574 | * So 20 msecs are enough. | ||
| 575 | */ | ||
| 576 | timeout = jiffies + msecs_to_jiffies(20); | ||
| 577 | |||
| 555 | do { | 578 | do { |
| 556 | status = readl(base + S5PC110_DMA_TRANS_STATUS); | 579 | status = readl(base + S5PC110_DMA_TRANS_STATUS); |
| 557 | if (status & S5PC110_DMA_TRANS_STATUS_TE) { | 580 | if (status & S5PC110_DMA_TRANS_STATUS_TE) { |
| @@ -559,13 +582,68 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) | |||
| 559 | base + S5PC110_DMA_TRANS_CMD); | 582 | base + S5PC110_DMA_TRANS_CMD); |
| 560 | return -EIO; | 583 | return -EIO; |
| 561 | } | 584 | } |
| 562 | } while (!(status & S5PC110_DMA_TRANS_STATUS_TD)); | 585 | } while (!(status & S5PC110_DMA_TRANS_STATUS_TD) && |
| 586 | time_before(jiffies, timeout)); | ||
| 563 | 587 | ||
| 564 | writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD); | 588 | writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD); |
| 565 | 589 | ||
| 566 | return 0; | 590 | return 0; |
| 567 | } | 591 | } |
| 568 | 592 | ||
| 593 | static irqreturn_t s5pc110_onenand_irq(int irq, void *data) | ||
| 594 | { | ||
| 595 | void __iomem *base = onenand->dma_addr; | ||
| 596 | int status, cmd = 0; | ||
| 597 | |||
| 598 | status = readl(base + S5PC110_INTC_DMA_STATUS); | ||
| 599 | |||
| 600 | if (likely(status & S5PC110_INTC_DMA_TD)) | ||
| 601 | cmd = S5PC110_DMA_TRANS_CMD_TDC; | ||
| 602 | |||
| 603 | if (unlikely(status & S5PC110_INTC_DMA_TE)) | ||
| 604 | cmd = S5PC110_DMA_TRANS_CMD_TEC; | ||
| 605 | |||
| 606 | writel(cmd, base + S5PC110_DMA_TRANS_CMD); | ||
| 607 | writel(status, base + S5PC110_INTC_DMA_CLR); | ||
| 608 | |||
| 609 | if (!onenand->complete.done) | ||
| 610 | complete(&onenand->complete); | ||
| 611 | |||
| 612 | return IRQ_HANDLED; | ||
| 613 | } | ||
| 614 | |||
| 615 | static int s5pc110_dma_irq(void *dst, void *src, size_t count, int direction) | ||
| 616 | { | ||
| 617 | void __iomem *base = onenand->dma_addr; | ||
| 618 | int status; | ||
| 619 | |||
| 620 | status = readl(base + S5PC110_INTC_DMA_MASK); | ||
| 621 | if (status) { | ||
| 622 | status &= ~(S5PC110_INTC_DMA_TD | S5PC110_INTC_DMA_TE); | ||
| 623 | writel(status, base + S5PC110_INTC_DMA_MASK); | ||
| 624 | } | ||
| 625 | |||
| 626 | writel(src, base + S5PC110_DMA_SRC_ADDR); | ||
| 627 | writel(dst, base + S5PC110_DMA_DST_ADDR); | ||
| 628 | |||
| 629 | if (direction == S5PC110_DMA_DIR_READ) { | ||
| 630 | writel(S5PC110_DMA_SRC_CFG_READ, base + S5PC110_DMA_SRC_CFG); | ||
| 631 | writel(S5PC110_DMA_DST_CFG_READ, base + S5PC110_DMA_DST_CFG); | ||
| 632 | } else { | ||
| 633 | writel(S5PC110_DMA_SRC_CFG_WRITE, base + S5PC110_DMA_SRC_CFG); | ||
| 634 | writel(S5PC110_DMA_DST_CFG_WRITE, base + S5PC110_DMA_DST_CFG); | ||
| 635 | } | ||
| 636 | |||
| 637 | writel(count, base + S5PC110_DMA_TRANS_SIZE); | ||
| 638 | writel(direction, base + S5PC110_DMA_TRANS_DIR); | ||
| 639 | |||
| 640 | writel(S5PC110_DMA_TRANS_CMD_TR, base + S5PC110_DMA_TRANS_CMD); | ||
| 641 | |||
| 642 | wait_for_completion_timeout(&onenand->complete, msecs_to_jiffies(20)); | ||
| 643 | |||
| 644 | return 0; | ||
| 645 | } | ||
| 646 | |||
| 569 | static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, | 647 | static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, |
| 570 | unsigned char *buffer, int offset, size_t count) | 648 | unsigned char *buffer, int offset, size_t count) |
| 571 | { | 649 | { |
| @@ -573,7 +651,8 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, | |||
| 573 | void __iomem *p; | 651 | void __iomem *p; |
| 574 | void *buf = (void *) buffer; | 652 | void *buf = (void *) buffer; |
| 575 | dma_addr_t dma_src, dma_dst; | 653 | dma_addr_t dma_src, dma_dst; |
| 576 | int err; | 654 | int err, page_dma = 0; |
| 655 | struct device *dev = &onenand->pdev->dev; | ||
| 577 | 656 | ||
| 578 | p = this->base + area; | 657 | p = this->base + area; |
| 579 | if (ONENAND_CURRENT_BUFFERRAM(this)) { | 658 | if (ONENAND_CURRENT_BUFFERRAM(this)) { |
| @@ -597,21 +676,27 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, | |||
| 597 | page = vmalloc_to_page(buf); | 676 | page = vmalloc_to_page(buf); |
| 598 | if (!page) | 677 | if (!page) |
| 599 | goto normal; | 678 | goto normal; |
| 600 | buf = page_address(page) + ((size_t) buf & ~PAGE_MASK); | ||
| 601 | } | ||
| 602 | 679 | ||
| 603 | /* DMA routine */ | 680 | page_dma = 1; |
| 604 | dma_src = onenand->phys_base + (p - this->base); | 681 | /* DMA routine */ |
| 605 | dma_dst = dma_map_single(&onenand->pdev->dev, | 682 | dma_src = onenand->phys_base + (p - this->base); |
| 606 | buf, count, DMA_FROM_DEVICE); | 683 | dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE); |
| 607 | if (dma_mapping_error(&onenand->pdev->dev, dma_dst)) { | 684 | } else { |
| 608 | dev_err(&onenand->pdev->dev, | 685 | /* DMA routine */ |
| 609 | "Couldn't map a %d byte buffer for DMA\n", count); | 686 | dma_src = onenand->phys_base + (p - this->base); |
| 687 | dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE); | ||
| 688 | } | ||
| 689 | if (dma_mapping_error(dev, dma_dst)) { | ||
| 690 | dev_err(dev, "Couldn't map a %d byte buffer for DMA\n", count); | ||
| 610 | goto normal; | 691 | goto normal; |
| 611 | } | 692 | } |
| 612 | err = s5pc110_dma_ops((void *) dma_dst, (void *) dma_src, | 693 | err = s5pc110_dma_ops((void *) dma_dst, (void *) dma_src, |
| 613 | count, S5PC110_DMA_DIR_READ); | 694 | count, S5PC110_DMA_DIR_READ); |
| 614 | dma_unmap_single(&onenand->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); | 695 | |
| 696 | if (page_dma) | ||
| 697 | dma_unmap_page(dev, dma_dst, count, DMA_FROM_DEVICE); | ||
| 698 | else | ||
| 699 | dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE); | ||
| 615 | 700 | ||
| 616 | if (!err) | 701 | if (!err) |
| 617 | return 0; | 702 | return 0; |
| @@ -759,7 +844,6 @@ static void s3c_onenand_setup(struct mtd_info *mtd) | |||
| 759 | onenand->cmd_map = s5pc1xx_cmd_map; | 844 | onenand->cmd_map = s5pc1xx_cmd_map; |
| 760 | } else if (onenand->type == TYPE_S5PC110) { | 845 | } else if (onenand->type == TYPE_S5PC110) { |
| 761 | /* Use generic onenand functions */ | 846 | /* Use generic onenand functions */ |
| 762 | onenand->cmd_map = s5pc1xx_cmd_map; | ||
| 763 | this->read_bufferram = s5pc110_read_bufferram; | 847 | this->read_bufferram = s5pc110_read_bufferram; |
| 764 | this->chip_probe = s5pc110_chip_probe; | 848 | this->chip_probe = s5pc110_chip_probe; |
| 765 | return; | 849 | return; |
| @@ -904,6 +988,20 @@ static int s3c_onenand_probe(struct platform_device *pdev) | |||
| 904 | } | 988 | } |
| 905 | 989 | ||
| 906 | onenand->phys_base = onenand->base_res->start; | 990 | onenand->phys_base = onenand->base_res->start; |
| 991 | |||
| 992 | s5pc110_dma_ops = s5pc110_dma_poll; | ||
| 993 | /* Interrupt support */ | ||
| 994 | r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
| 995 | if (r) { | ||
| 996 | init_completion(&onenand->complete); | ||
| 997 | s5pc110_dma_ops = s5pc110_dma_irq; | ||
| 998 | err = request_irq(r->start, s5pc110_onenand_irq, | ||
| 999 | IRQF_SHARED, "onenand", &onenand); | ||
| 1000 | if (err) { | ||
| 1001 | dev_err(&pdev->dev, "failed to get irq\n"); | ||
| 1002 | goto scan_failed; | ||
| 1003 | } | ||
| 1004 | } | ||
| 907 | } | 1005 | } |
| 908 | 1006 | ||
| 909 | if (onenand_scan(mtd, 1)) { | 1007 | if (onenand_scan(mtd, 1)) { |
| @@ -1000,7 +1098,7 @@ static int s3c_pm_ops_suspend(struct device *dev) | |||
| 1000 | struct onenand_chip *this = mtd->priv; | 1098 | struct onenand_chip *this = mtd->priv; |
| 1001 | 1099 | ||
| 1002 | this->wait(mtd, FL_PM_SUSPENDED); | 1100 | this->wait(mtd, FL_PM_SUSPENDED); |
| 1003 | return mtd->suspend(mtd); | 1101 | return 0; |
| 1004 | } | 1102 | } |
| 1005 | 1103 | ||
| 1006 | static int s3c_pm_ops_resume(struct device *dev) | 1104 | static int s3c_pm_ops_resume(struct device *dev) |
| @@ -1009,7 +1107,6 @@ static int s3c_pm_ops_resume(struct device *dev) | |||
| 1009 | struct mtd_info *mtd = platform_get_drvdata(pdev); | 1107 | struct mtd_info *mtd = platform_get_drvdata(pdev); |
| 1010 | struct onenand_chip *this = mtd->priv; | 1108 | struct onenand_chip *this = mtd->priv; |
| 1011 | 1109 | ||
| 1012 | mtd->resume(mtd); | ||
| 1013 | this->unlock_all(mtd); | 1110 | this->unlock_all(mtd); |
| 1014 | return 0; | 1111 | return 0; |
| 1015 | } | 1112 | } |
diff --git a/drivers/mtd/sm_ftl.h b/drivers/mtd/sm_ftl.h index e30e48e7f63d..43bb7300785b 100644 --- a/drivers/mtd/sm_ftl.h +++ b/drivers/mtd/sm_ftl.h | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | struct ftl_zone { | 22 | struct ftl_zone { |
| 23 | int initialized; | 23 | bool initialized; |
| 24 | int16_t *lba_to_phys_table; /* LBA to physical table */ | 24 | int16_t *lba_to_phys_table; /* LBA to physical table */ |
| 25 | struct kfifo free_sectors; /* queue of free sectors */ | 25 | struct kfifo free_sectors; /* queue of free sectors */ |
| 26 | }; | 26 | }; |
| @@ -37,8 +37,8 @@ struct sm_ftl { | |||
| 37 | int zone_count; /* number of zones */ | 37 | int zone_count; /* number of zones */ |
| 38 | int max_lba; /* maximum lba in a zone */ | 38 | int max_lba; /* maximum lba in a zone */ |
| 39 | int smallpagenand; /* 256 bytes/page nand */ | 39 | int smallpagenand; /* 256 bytes/page nand */ |
| 40 | int readonly; /* is FS readonly */ | 40 | bool readonly; /* is FS readonly */ |
| 41 | int unstable; | 41 | bool unstable; |
| 42 | int cis_block; /* CIS block location */ | 42 | int cis_block; /* CIS block location */ |
| 43 | int cis_boffset; /* CIS offset in the block */ | 43 | int cis_boffset; /* CIS offset in the block */ |
| 44 | int cis_page_offset; /* CIS offset in the page */ | 44 | int cis_page_offset; /* CIS offset in the page */ |
| @@ -49,7 +49,7 @@ struct sm_ftl { | |||
| 49 | int cache_zone; /* zone of cached block */ | 49 | int cache_zone; /* zone of cached block */ |
| 50 | unsigned char *cache_data; /* cached block data */ | 50 | unsigned char *cache_data; /* cached block data */ |
| 51 | long unsigned int cache_data_invalid_bitmap; | 51 | long unsigned int cache_data_invalid_bitmap; |
| 52 | int cache_clean; | 52 | bool cache_clean; |
| 53 | struct work_struct flush_work; | 53 | struct work_struct flush_work; |
| 54 | struct timer_list timer; | 54 | struct timer_list timer; |
| 55 | 55 | ||
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b7e755f4178a..a3984f4ef192 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c | |||
| @@ -190,7 +190,7 @@ void sync_stop(void) | |||
| 190 | profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); | 190 | profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); |
| 191 | task_handoff_unregister(&task_free_nb); | 191 | task_handoff_unregister(&task_free_nb); |
| 192 | mutex_unlock(&buffer_mutex); | 192 | mutex_unlock(&buffer_mutex); |
| 193 | flush_scheduled_work(); | 193 | flush_cpu_work(); |
| 194 | 194 | ||
| 195 | /* make sure we don't leak task structs */ | 195 | /* make sure we don't leak task structs */ |
| 196 | process_task_mortuary(); | 196 | process_task_mortuary(); |
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index f179ac2ea801..59f55441e075 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
| @@ -111,14 +111,18 @@ void start_cpu_work(void) | |||
| 111 | 111 | ||
| 112 | void end_cpu_work(void) | 112 | void end_cpu_work(void) |
| 113 | { | 113 | { |
| 114 | int i; | ||
| 115 | |||
| 116 | work_enabled = 0; | 114 | work_enabled = 0; |
| 115 | } | ||
| 116 | |||
| 117 | void flush_cpu_work(void) | ||
| 118 | { | ||
| 119 | int i; | ||
| 117 | 120 | ||
| 118 | for_each_online_cpu(i) { | 121 | for_each_online_cpu(i) { |
| 119 | struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); | 122 | struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); |
| 120 | 123 | ||
| 121 | cancel_delayed_work(&b->work); | 124 | /* these works are per-cpu, no need for flush_sync */ |
| 125 | flush_delayed_work(&b->work); | ||
| 122 | } | 126 | } |
| 123 | } | 127 | } |
| 124 | 128 | ||
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 68ea16ab645f..e1d097e250ae 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h | |||
| @@ -25,6 +25,7 @@ void free_cpu_buffers(void); | |||
| 25 | 25 | ||
| 26 | void start_cpu_work(void); | 26 | void start_cpu_work(void); |
| 27 | void end_cpu_work(void); | 27 | void end_cpu_work(void); |
| 28 | void flush_cpu_work(void); | ||
| 28 | 29 | ||
| 29 | /* CPU buffer is composed of such entries (which are | 30 | /* CPU buffer is composed of such entries (which are |
| 30 | * also used for context switch notes) | 31 | * also used for context switch notes) |
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index dc0ae4d14dff..010725117dbb 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "oprof.h" | 21 | #include "oprof.h" |
| 22 | 22 | ||
| 23 | static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer); | 23 | static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer); |
| 24 | static int ctr_running; | ||
| 24 | 25 | ||
| 25 | static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer) | 26 | static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer) |
| 26 | { | 27 | { |
| @@ -33,6 +34,9 @@ static void __oprofile_hrtimer_start(void *unused) | |||
| 33 | { | 34 | { |
| 34 | struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer); | 35 | struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer); |
| 35 | 36 | ||
| 37 | if (!ctr_running) | ||
| 38 | return; | ||
| 39 | |||
| 36 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 40 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 37 | hrtimer->function = oprofile_hrtimer_notify; | 41 | hrtimer->function = oprofile_hrtimer_notify; |
| 38 | 42 | ||
| @@ -42,7 +46,10 @@ static void __oprofile_hrtimer_start(void *unused) | |||
| 42 | 46 | ||
| 43 | static int oprofile_hrtimer_start(void) | 47 | static int oprofile_hrtimer_start(void) |
| 44 | { | 48 | { |
| 49 | get_online_cpus(); | ||
| 50 | ctr_running = 1; | ||
| 45 | on_each_cpu(__oprofile_hrtimer_start, NULL, 1); | 51 | on_each_cpu(__oprofile_hrtimer_start, NULL, 1); |
| 52 | put_online_cpus(); | ||
| 46 | return 0; | 53 | return 0; |
| 47 | } | 54 | } |
| 48 | 55 | ||
| @@ -50,6 +57,9 @@ static void __oprofile_hrtimer_stop(int cpu) | |||
| 50 | { | 57 | { |
| 51 | struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu); | 58 | struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu); |
| 52 | 59 | ||
| 60 | if (!ctr_running) | ||
| 61 | return; | ||
| 62 | |||
| 53 | hrtimer_cancel(hrtimer); | 63 | hrtimer_cancel(hrtimer); |
| 54 | } | 64 | } |
| 55 | 65 | ||
| @@ -57,8 +67,11 @@ static void oprofile_hrtimer_stop(void) | |||
| 57 | { | 67 | { |
| 58 | int cpu; | 68 | int cpu; |
| 59 | 69 | ||
| 70 | get_online_cpus(); | ||
| 60 | for_each_online_cpu(cpu) | 71 | for_each_online_cpu(cpu) |
| 61 | __oprofile_hrtimer_stop(cpu); | 72 | __oprofile_hrtimer_stop(cpu); |
| 73 | ctr_running = 0; | ||
| 74 | put_online_cpus(); | ||
| 62 | } | 75 | } |
| 63 | 76 | ||
| 64 | static int __cpuinit oprofile_cpu_notify(struct notifier_block *self, | 77 | static int __cpuinit oprofile_cpu_notify(struct notifier_block *self, |
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 5699ce0c1780..3f3d431033ca 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c | |||
| @@ -123,83 +123,87 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
| 123 | u32 linelength; | 123 | u32 linelength; |
| 124 | bool yuv; | 124 | bool yuv; |
| 125 | 125 | ||
| 126 | /* Select data format */ | 126 | /* |
| 127 | * Select data format. MIPI DSI is not hot-pluggable, so, we just use | ||
| 128 | * the default videomode. If this ever becomes a problem, We'll have to | ||
| 129 | * move this to mipi_display_on() above and use info->var.xres | ||
| 130 | */ | ||
| 127 | switch (pdata->data_format) { | 131 | switch (pdata->data_format) { |
| 128 | case MIPI_RGB888: | 132 | case MIPI_RGB888: |
| 129 | pctype = 0; | 133 | pctype = 0; |
| 130 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 134 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
| 131 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 135 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 132 | linelength = ch->lcd_cfg.xres * 3; | 136 | linelength = ch->lcd_cfg[0].xres * 3; |
| 133 | yuv = false; | 137 | yuv = false; |
| 134 | break; | 138 | break; |
| 135 | case MIPI_RGB565: | 139 | case MIPI_RGB565: |
| 136 | pctype = 1; | 140 | pctype = 1; |
| 137 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 141 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
| 138 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 142 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 139 | linelength = ch->lcd_cfg.xres * 2; | 143 | linelength = ch->lcd_cfg[0].xres * 2; |
| 140 | yuv = false; | 144 | yuv = false; |
| 141 | break; | 145 | break; |
| 142 | case MIPI_RGB666_LP: | 146 | case MIPI_RGB666_LP: |
| 143 | pctype = 2; | 147 | pctype = 2; |
| 144 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 148 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
| 145 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 149 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 146 | linelength = ch->lcd_cfg.xres * 3; | 150 | linelength = ch->lcd_cfg[0].xres * 3; |
| 147 | yuv = false; | 151 | yuv = false; |
| 148 | break; | 152 | break; |
| 149 | case MIPI_RGB666: | 153 | case MIPI_RGB666: |
| 150 | pctype = 3; | 154 | pctype = 3; |
| 151 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 155 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
| 152 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 156 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
| 153 | linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; | 157 | linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; |
| 154 | yuv = false; | 158 | yuv = false; |
| 155 | break; | 159 | break; |
| 156 | case MIPI_BGR888: | 160 | case MIPI_BGR888: |
| 157 | pctype = 8; | 161 | pctype = 8; |
| 158 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 162 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
| 159 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 163 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 160 | linelength = ch->lcd_cfg.xres * 3; | 164 | linelength = ch->lcd_cfg[0].xres * 3; |
| 161 | yuv = false; | 165 | yuv = false; |
| 162 | break; | 166 | break; |
| 163 | case MIPI_BGR565: | 167 | case MIPI_BGR565: |
| 164 | pctype = 9; | 168 | pctype = 9; |
| 165 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 169 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
| 166 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 170 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 167 | linelength = ch->lcd_cfg.xres * 2; | 171 | linelength = ch->lcd_cfg[0].xres * 2; |
| 168 | yuv = false; | 172 | yuv = false; |
| 169 | break; | 173 | break; |
| 170 | case MIPI_BGR666_LP: | 174 | case MIPI_BGR666_LP: |
| 171 | pctype = 0xa; | 175 | pctype = 0xa; |
| 172 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 176 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
| 173 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 177 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 174 | linelength = ch->lcd_cfg.xres * 3; | 178 | linelength = ch->lcd_cfg[0].xres * 3; |
| 175 | yuv = false; | 179 | yuv = false; |
| 176 | break; | 180 | break; |
| 177 | case MIPI_BGR666: | 181 | case MIPI_BGR666: |
| 178 | pctype = 0xb; | 182 | pctype = 0xb; |
| 179 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 183 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
| 180 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 184 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
| 181 | linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; | 185 | linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; |
| 182 | yuv = false; | 186 | yuv = false; |
| 183 | break; | 187 | break; |
| 184 | case MIPI_YUYV: | 188 | case MIPI_YUYV: |
| 185 | pctype = 4; | 189 | pctype = 4; |
| 186 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 190 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
| 187 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 191 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 188 | linelength = ch->lcd_cfg.xres * 2; | 192 | linelength = ch->lcd_cfg[0].xres * 2; |
| 189 | yuv = true; | 193 | yuv = true; |
| 190 | break; | 194 | break; |
| 191 | case MIPI_UYVY: | 195 | case MIPI_UYVY: |
| 192 | pctype = 5; | 196 | pctype = 5; |
| 193 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 197 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
| 194 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 198 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 195 | linelength = ch->lcd_cfg.xres * 2; | 199 | linelength = ch->lcd_cfg[0].xres * 2; |
| 196 | yuv = true; | 200 | yuv = true; |
| 197 | break; | 201 | break; |
| 198 | case MIPI_YUV420_L: | 202 | case MIPI_YUV420_L: |
| 199 | pctype = 6; | 203 | pctype = 6; |
| 200 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 204 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
| 201 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 205 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
| 202 | linelength = (ch->lcd_cfg.xres * 12 + 7) / 8; | 206 | linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8; |
| 203 | yuv = true; | 207 | yuv = true; |
| 204 | break; | 208 | break; |
| 205 | case MIPI_YUV420: | 209 | case MIPI_YUV420: |
| @@ -207,7 +211,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
| 207 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 211 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
| 208 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 212 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
| 209 | /* Length of U/V line */ | 213 | /* Length of U/V line */ |
| 210 | linelength = (ch->lcd_cfg.xres + 1) / 2; | 214 | linelength = (ch->lcd_cfg[0].xres + 1) / 2; |
| 211 | yuv = true; | 215 | yuv = true; |
| 212 | break; | 216 | break; |
| 213 | default: | 217 | default: |
| @@ -281,7 +285,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
| 281 | iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ | 285 | iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ |
| 282 | /* | 286 | /* |
| 283 | * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see | 287 | * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see |
| 284 | * sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default | 288 | * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default |
| 285 | * (unused, since VMCTR2[HSABM] = 0) | 289 | * (unused, since VMCTR2[HSABM] = 0) |
| 286 | */ | 290 | */ |
| 287 | iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ | 291 | iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ |
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index ef989d94511c..55b3077ff6ff 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | #include <video/sh_mobile_hdmi.h> | 28 | #include <video/sh_mobile_hdmi.h> |
| 29 | #include <video/sh_mobile_lcdc.h> | 29 | #include <video/sh_mobile_lcdc.h> |
| 30 | 30 | ||
| 31 | #include "sh_mobile_lcdcfb.h" | ||
| 32 | |||
| 31 | #define HDMI_SYSTEM_CTRL 0x00 /* System control */ | 33 | #define HDMI_SYSTEM_CTRL 0x00 /* System control */ |
| 32 | #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, | 34 | #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, |
| 33 | bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ | 35 | bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ |
| @@ -206,12 +208,15 @@ enum hotplug_state { | |||
| 206 | 208 | ||
| 207 | struct sh_hdmi { | 209 | struct sh_hdmi { |
| 208 | void __iomem *base; | 210 | void __iomem *base; |
| 209 | enum hotplug_state hp_state; | 211 | enum hotplug_state hp_state; /* hot-plug status */ |
| 212 | bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ | ||
| 210 | struct clk *hdmi_clk; | 213 | struct clk *hdmi_clk; |
| 211 | struct device *dev; | 214 | struct device *dev; |
| 212 | struct fb_info *info; | 215 | struct fb_info *info; |
| 216 | struct mutex mutex; /* Protect the info pointer */ | ||
| 213 | struct delayed_work edid_work; | 217 | struct delayed_work edid_work; |
| 214 | struct fb_var_screeninfo var; | 218 | struct fb_var_screeninfo var; |
| 219 | struct fb_monspecs monspec; | ||
| 215 | }; | 220 | }; |
| 216 | 221 | ||
| 217 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) | 222 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) |
| @@ -277,7 +282,7 @@ static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = { | |||
| 277 | */ | 282 | */ |
| 278 | 283 | ||
| 279 | /* External video parameter settings */ | 284 | /* External video parameter settings */ |
| 280 | static void hdmi_external_video_param(struct sh_hdmi *hdmi) | 285 | static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) |
| 281 | { | 286 | { |
| 282 | struct fb_var_screeninfo *var = &hdmi->var; | 287 | struct fb_var_screeninfo *var = &hdmi->var; |
| 283 | u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; | 288 | u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; |
| @@ -309,9 +314,9 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) | |||
| 309 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | 314 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) |
| 310 | sync |= 8; | 315 | sync |= 8; |
| 311 | 316 | ||
| 312 | pr_debug("H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", | 317 | dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", |
| 313 | htotal, hblank, hdelay, var->hsync_len, | 318 | htotal, hblank, hdelay, var->hsync_len, |
| 314 | vtotal, vblank, vdelay, var->vsync_len, sync); | 319 | vtotal, vblank, vdelay, var->vsync_len, sync); |
| 315 | 320 | ||
| 316 | hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); | 321 | hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); |
| 317 | 322 | ||
| @@ -336,7 +341,10 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) | |||
| 336 | 341 | ||
| 337 | hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); | 342 | hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); |
| 338 | 343 | ||
| 339 | /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for manual mode */ | 344 | /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ |
| 345 | if (!hdmi->preprogrammed_mode) | ||
| 346 | hdmi_write(hdmi, sync | 1 | (voffset << 4), | ||
| 347 | HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); | ||
| 340 | } | 348 | } |
| 341 | 349 | ||
| 342 | /** | 350 | /** |
| @@ -454,21 +462,61 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) | |||
| 454 | } | 462 | } |
| 455 | 463 | ||
| 456 | /** | 464 | /** |
| 457 | * sh_hdmi_phy_config() | 465 | * sh_hdmi_phy_config() - configure the HDMI PHY for the used video mode |
| 458 | */ | 466 | */ |
| 459 | static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) | 467 | static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) |
| 460 | { | 468 | { |
| 461 | /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ | 469 | if (hdmi->var.yres > 480) { |
| 462 | hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); | 470 | /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ |
| 463 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | 471 | /* |
| 464 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); | 472 | * [1:0] Speed_A |
| 465 | /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ | 473 | * [3:2] Speed_B |
| 466 | hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); | 474 | * [4] PLLA_Bypass |
| 467 | hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); | 475 | * [6] DRV_TEST_EN |
| 468 | hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); | 476 | * [7] DRV_TEST_IN |
| 469 | hdmi_write(hdmi, 0x0E, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | 477 | */ |
| 470 | hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | 478 | hdmi_write(hdmi, 0x0f, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); |
| 471 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | 479 | /* PLLB_CONFIG[17], PLLA_CONFIG[17] - not in PHY datasheet */ |
| 480 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | ||
| 481 | /* | ||
| 482 | * [2:0] BGR_I_OFFSET | ||
| 483 | * [6:4] BGR_V_OFFSET | ||
| 484 | */ | ||
| 485 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); | ||
| 486 | /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ | ||
| 487 | hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); | ||
| 488 | /* | ||
| 489 | * PLLA_CONFIG[15:8]: regulator voltage[0], CP current, | ||
| 490 | * LPF capacitance, LPF resistance[1] | ||
| 491 | */ | ||
| 492 | hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); | ||
| 493 | /* PLLB_CONFIG[7:0]: LPF resistance[0], VCO offset, VCO gain */ | ||
| 494 | hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); | ||
| 495 | /* | ||
| 496 | * PLLB_CONFIG[15:8]: regulator voltage[0], CP current, | ||
| 497 | * LPF capacitance, LPF resistance[1] | ||
| 498 | */ | ||
| 499 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | ||
| 500 | /* DRV_CONFIG, PE_CONFIG */ | ||
| 501 | hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | ||
| 502 | /* | ||
| 503 | * [2:0] AMON_SEL (4 == LPF voltage) | ||
| 504 | * [4] PLLA_CONFIG[16] | ||
| 505 | * [5] PLLB_CONFIG[16] | ||
| 506 | */ | ||
| 507 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | ||
| 508 | } else { | ||
| 509 | /* for 480p8bit 27MHz */ | ||
| 510 | hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); | ||
| 511 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | ||
| 512 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); | ||
| 513 | hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); | ||
| 514 | hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); | ||
| 515 | hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); | ||
| 516 | hdmi_write(hdmi, 0x0F, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | ||
| 517 | hdmi_write(hdmi, 0x20, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | ||
| 518 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | ||
| 519 | } | ||
| 472 | } | 520 | } |
| 473 | 521 | ||
| 474 | /** | 522 | /** |
| @@ -476,6 +524,8 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) | |||
| 476 | */ | 524 | */ |
| 477 | static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) | 525 | static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) |
| 478 | { | 526 | { |
| 527 | u8 vic; | ||
| 528 | |||
| 479 | /* AVI InfoFrame */ | 529 | /* AVI InfoFrame */ |
| 480 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); | 530 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); |
| 481 | 531 | ||
| @@ -500,9 +550,9 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) | |||
| 500 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); | 550 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); |
| 501 | 551 | ||
| 502 | /* | 552 | /* |
| 503 | * C = No Data | 553 | * [7:6] C = Colorimetry: no data |
| 504 | * M = 16:9 Picture Aspect Ratio | 554 | * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio |
| 505 | * R = Same as picture aspect ratio | 555 | * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio |
| 506 | */ | 556 | */ |
| 507 | hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); | 557 | hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); |
| 508 | 558 | ||
| @@ -516,9 +566,15 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) | |||
| 516 | 566 | ||
| 517 | /* | 567 | /* |
| 518 | * VIC = 1280 x 720p: ignored if external config is used | 568 | * VIC = 1280 x 720p: ignored if external config is used |
| 519 | * Send 2 for 720 x 480p, 16 for 1080p | 569 | * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode |
| 520 | */ | 570 | */ |
| 521 | hdmi_write(hdmi, 4, HDMI_CTRL_PKT_BUF_ACCESS_PB4); | 571 | if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) |
| 572 | vic = 16; | ||
| 573 | else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) | ||
| 574 | vic = 2; | ||
| 575 | else | ||
| 576 | vic = 4; | ||
| 577 | hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); | ||
| 522 | 578 | ||
| 523 | /* PR = No Repetition */ | 579 | /* PR = No Repetition */ |
| 524 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); | 580 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); |
| @@ -592,100 +648,6 @@ static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi) | |||
| 592 | } | 648 | } |
| 593 | 649 | ||
| 594 | /** | 650 | /** |
| 595 | * sh_hdmi_gamut_metadata_setup() - Gamut Metadata Packet of CONTROL PACKET | ||
| 596 | */ | ||
| 597 | static void sh_hdmi_gamut_metadata_setup(struct sh_hdmi *hdmi) | ||
| 598 | { | ||
| 599 | int i; | ||
| 600 | |||
| 601 | /* Gamut Metadata Packet */ | ||
| 602 | hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_INDEX); | ||
| 603 | |||
| 604 | /* Packet Type = 0x0A */ | ||
| 605 | hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
| 606 | /* Gamut Packet is not used, so default value */ | ||
| 607 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
| 608 | /* Gamut Packet is not used, so default value */ | ||
| 609 | hdmi_write(hdmi, 0x10, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
| 610 | |||
| 611 | /* GBD bytes 0 through 27 */ | ||
| 612 | for (i = 0; i <= 27; i++) | ||
| 613 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0_63H - PB27_7EH */ | ||
| 614 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
| 615 | } | ||
| 616 | |||
| 617 | /** | ||
| 618 | * sh_hdmi_acp_setup() - Audio Content Protection Packet (ACP) | ||
| 619 | */ | ||
| 620 | static void sh_hdmi_acp_setup(struct sh_hdmi *hdmi) | ||
| 621 | { | ||
| 622 | int i; | ||
| 623 | |||
| 624 | /* Audio Content Protection Packet (ACP) */ | ||
| 625 | hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_INDEX); | ||
| 626 | |||
| 627 | /* Packet Type = 0x04 */ | ||
| 628 | hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
| 629 | /* ACP_Type */ | ||
| 630 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
| 631 | /* Reserved (0) */ | ||
| 632 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
| 633 | |||
| 634 | /* GBD bytes 0 through 27 */ | ||
| 635 | for (i = 0; i <= 27; i++) | ||
| 636 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
| 637 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
| 638 | } | ||
| 639 | |||
| 640 | /** | ||
| 641 | * sh_hdmi_isrc1_setup() - ISRC1 Packet | ||
| 642 | */ | ||
| 643 | static void sh_hdmi_isrc1_setup(struct sh_hdmi *hdmi) | ||
| 644 | { | ||
| 645 | int i; | ||
| 646 | |||
| 647 | /* ISRC1 Packet */ | ||
| 648 | hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_INDEX); | ||
| 649 | |||
| 650 | /* Packet Type = 0x05 */ | ||
| 651 | hdmi_write(hdmi, 0x05, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
| 652 | /* ISRC_Cont, ISRC_Valid, Reserved (0), ISRC_Status */ | ||
| 653 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
| 654 | /* Reserved (0) */ | ||
| 655 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
| 656 | |||
| 657 | /* PB0 UPC_EAN_ISRC_0-15 */ | ||
| 658 | /* Bytes PB16-PB27 shall be set to a value of 0. */ | ||
| 659 | for (i = 0; i <= 27; i++) | ||
| 660 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
| 661 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
| 662 | } | ||
| 663 | |||
| 664 | /** | ||
| 665 | * sh_hdmi_isrc2_setup() - ISRC2 Packet | ||
| 666 | */ | ||
| 667 | static void sh_hdmi_isrc2_setup(struct sh_hdmi *hdmi) | ||
| 668 | { | ||
| 669 | int i; | ||
| 670 | |||
| 671 | /* ISRC2 Packet */ | ||
| 672 | hdmi_write(hdmi, 0x03, HDMI_CTRL_PKT_BUF_INDEX); | ||
| 673 | |||
| 674 | /* HB0 Packet Type = 0x06 */ | ||
| 675 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
| 676 | /* Reserved (0) */ | ||
| 677 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
| 678 | /* Reserved (0) */ | ||
| 679 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
| 680 | |||
| 681 | /* PB0 UPC_EAN_ISRC_16-31 */ | ||
| 682 | /* Bytes PB16-PB27 shall be set to a value of 0. */ | ||
| 683 | for (i = 0; i <= 27; i++) | ||
| 684 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
| 685 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
| 686 | } | ||
| 687 | |||
| 688 | /** | ||
| 689 | * sh_hdmi_configure() - Initialise HDMI for output | 651 | * sh_hdmi_configure() - Initialise HDMI for output |
| 690 | */ | 652 | */ |
| 691 | static void sh_hdmi_configure(struct sh_hdmi *hdmi) | 653 | static void sh_hdmi_configure(struct sh_hdmi *hdmi) |
| @@ -705,18 +667,6 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) | |||
| 705 | /* Audio InfoFrame */ | 667 | /* Audio InfoFrame */ |
| 706 | sh_hdmi_audio_infoframe_setup(hdmi); | 668 | sh_hdmi_audio_infoframe_setup(hdmi); |
| 707 | 669 | ||
| 708 | /* Gamut Metadata packet */ | ||
| 709 | sh_hdmi_gamut_metadata_setup(hdmi); | ||
| 710 | |||
| 711 | /* Audio Content Protection (ACP) Packet */ | ||
| 712 | sh_hdmi_acp_setup(hdmi); | ||
| 713 | |||
| 714 | /* ISRC1 Packet */ | ||
| 715 | sh_hdmi_isrc1_setup(hdmi); | ||
| 716 | |||
| 717 | /* ISRC2 Packet */ | ||
| 718 | sh_hdmi_isrc2_setup(hdmi); | ||
| 719 | |||
| 720 | /* | 670 | /* |
| 721 | * Control packet auto send with VSYNC control: auto send | 671 | * Control packet auto send with VSYNC control: auto send |
| 722 | * General control, Gamut metadata, ISRC, and ACP packets | 672 | * General control, Gamut metadata, ISRC, and ACP packets |
| @@ -734,17 +684,42 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) | |||
| 734 | hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); | 684 | hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); |
| 735 | } | 685 | } |
| 736 | 686 | ||
| 737 | static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) | 687 | static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, |
| 688 | const struct fb_videomode *mode) | ||
| 738 | { | 689 | { |
| 739 | struct fb_var_screeninfo *var = &hdmi->var; | 690 | long target = PICOS2KHZ(mode->pixclock) * 1000, |
| 740 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 691 | rate = clk_round_rate(hdmi->hdmi_clk, target); |
| 741 | struct fb_videomode *lcd_cfg = &pdata->lcd_chan->lcd_cfg; | 692 | unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; |
| 742 | unsigned long height = var->height, width = var->width; | 693 | |
| 743 | int i; | 694 | dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", |
| 695 | mode->left_margin, mode->xres, | ||
| 696 | mode->right_margin, mode->hsync_len, | ||
| 697 | mode->upper_margin, mode->yres, | ||
| 698 | mode->lower_margin, mode->vsync_len); | ||
| 699 | |||
| 700 | dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, | ||
| 701 | rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, | ||
| 702 | mode->refresh); | ||
| 703 | |||
| 704 | return rate_error; | ||
| 705 | } | ||
| 706 | |||
| 707 | static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) | ||
| 708 | { | ||
| 709 | struct fb_var_screeninfo tmpvar; | ||
| 710 | struct fb_var_screeninfo *var = &tmpvar; | ||
| 711 | const struct fb_videomode *mode, *found = NULL; | ||
| 712 | struct fb_info *info = hdmi->info; | ||
| 713 | struct fb_modelist *modelist = NULL; | ||
| 714 | unsigned int f_width = 0, f_height = 0, f_refresh = 0; | ||
| 715 | unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ | ||
| 716 | bool exact_match = false; | ||
| 744 | u8 edid[128]; | 717 | u8 edid[128]; |
| 718 | char *forced; | ||
| 719 | int i; | ||
| 745 | 720 | ||
| 746 | /* Read EDID */ | 721 | /* Read EDID */ |
| 747 | pr_debug("Read back EDID code:"); | 722 | dev_dbg(hdmi->dev, "Read back EDID code:"); |
| 748 | for (i = 0; i < 128; i++) { | 723 | for (i = 0; i < 128; i++) { |
| 749 | edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); | 724 | edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); |
| 750 | #ifdef DEBUG | 725 | #ifdef DEBUG |
| @@ -759,29 +734,97 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) | |||
| 759 | #ifdef DEBUG | 734 | #ifdef DEBUG |
| 760 | printk(KERN_CONT "\n"); | 735 | printk(KERN_CONT "\n"); |
| 761 | #endif | 736 | #endif |
| 762 | fb_parse_edid(edid, var); | 737 | |
| 763 | pr_debug("%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", | 738 | fb_edid_to_monspecs(edid, &hdmi->monspec); |
| 764 | var->left_margin, var->xres, var->right_margin, var->hsync_len, | 739 | |
| 765 | var->upper_margin, var->yres, var->lower_margin, var->vsync_len, | 740 | fb_get_options("sh_mobile_lcdc", &forced); |
| 766 | PICOS2KHZ(var->pixclock)); | 741 | if (forced && *forced) { |
| 767 | 742 | /* Only primitive parsing so far */ | |
| 768 | /* FIXME: Use user-provided configuration instead of EDID */ | 743 | i = sscanf(forced, "%ux%u@%u", |
| 769 | var->width = width; | 744 | &f_width, &f_height, &f_refresh); |
| 770 | var->xres = lcd_cfg->xres; | 745 | if (i < 2) { |
| 771 | var->xres_virtual = lcd_cfg->xres; | 746 | f_width = 0; |
| 772 | var->left_margin = lcd_cfg->left_margin; | 747 | f_height = 0; |
| 773 | var->right_margin = lcd_cfg->right_margin; | 748 | } |
| 774 | var->hsync_len = lcd_cfg->hsync_len; | 749 | dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", |
| 775 | var->height = height; | 750 | f_width, f_height, f_refresh); |
| 776 | var->yres = lcd_cfg->yres; | 751 | } |
| 777 | var->yres_virtual = lcd_cfg->yres * 2; | 752 | |
| 778 | var->upper_margin = lcd_cfg->upper_margin; | 753 | /* Walk monitor modes to find the best or the exact match */ |
| 779 | var->lower_margin = lcd_cfg->lower_margin; | 754 | for (i = 0, mode = hdmi->monspec.modedb; |
| 780 | var->vsync_len = lcd_cfg->vsync_len; | 755 | f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; |
| 781 | var->sync = lcd_cfg->sync; | 756 | i++, mode++) { |
| 782 | var->pixclock = lcd_cfg->pixclock; | 757 | unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); |
| 783 | 758 | ||
| 784 | hdmi_external_video_param(hdmi); | 759 | /* No interest in unmatching modes */ |
| 760 | if (f_width != mode->xres || f_height != mode->yres) | ||
| 761 | continue; | ||
| 762 | if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) | ||
| 763 | /* | ||
| 764 | * Exact match if either the refresh rate matches or it | ||
| 765 | * hasn't been specified and we've found a mode, for | ||
| 766 | * which we can configure the clock precisely | ||
| 767 | */ | ||
| 768 | exact_match = true; | ||
| 769 | else if (found && found_rate_error <= rate_error) | ||
| 770 | /* | ||
| 771 | * We otherwise search for the closest matching clock | ||
| 772 | * rate - either if no refresh rate has been specified | ||
| 773 | * or we cannot find an exactly matching one | ||
| 774 | */ | ||
| 775 | continue; | ||
| 776 | |||
| 777 | /* Check if supported: sufficient fb memory, supported clock-rate */ | ||
| 778 | fb_videomode_to_var(var, mode); | ||
| 779 | |||
| 780 | if (info && info->fbops->fb_check_var && | ||
| 781 | info->fbops->fb_check_var(var, info)) { | ||
| 782 | exact_match = false; | ||
| 783 | continue; | ||
| 784 | } | ||
| 785 | |||
| 786 | found = mode; | ||
| 787 | found_rate_error = rate_error; | ||
| 788 | } | ||
| 789 | |||
| 790 | /* | ||
| 791 | * TODO 1: if no ->info is present, postpone running the config until | ||
| 792 | * after ->info first gets registered. | ||
| 793 | * TODO 2: consider registering the HDMI platform device from the LCDC | ||
| 794 | * driver, and passing ->info with HDMI platform data. | ||
| 795 | */ | ||
| 796 | if (info && !found) { | ||
| 797 | modelist = hdmi->info->modelist.next && | ||
| 798 | !list_empty(&hdmi->info->modelist) ? | ||
| 799 | list_entry(hdmi->info->modelist.next, | ||
| 800 | struct fb_modelist, list) : | ||
| 801 | NULL; | ||
| 802 | |||
| 803 | if (modelist) { | ||
| 804 | found = &modelist->mode; | ||
| 805 | found_rate_error = sh_hdmi_rate_error(hdmi, found); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 809 | /* No cookie today */ | ||
| 810 | if (!found) | ||
| 811 | return -ENXIO; | ||
| 812 | |||
| 813 | dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", | ||
| 814 | modelist ? "default" : "EDID", found->xres, found->yres, | ||
| 815 | found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); | ||
| 816 | |||
| 817 | if ((found->xres == 720 && found->yres == 480) || | ||
| 818 | (found->xres == 1280 && found->yres == 720) || | ||
| 819 | (found->xres == 1920 && found->yres == 1080)) | ||
| 820 | hdmi->preprogrammed_mode = true; | ||
| 821 | else | ||
| 822 | hdmi->preprogrammed_mode = false; | ||
| 823 | |||
| 824 | fb_videomode_to_var(&hdmi->var, found); | ||
| 825 | sh_hdmi_external_video_param(hdmi); | ||
| 826 | |||
| 827 | return 0; | ||
| 785 | } | 828 | } |
| 786 | 829 | ||
| 787 | static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | 830 | static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) |
| @@ -809,8 +852,8 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
| 809 | hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); | 852 | hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); |
| 810 | 853 | ||
| 811 | if (printk_ratelimit()) | 854 | if (printk_ratelimit()) |
| 812 | pr_debug("IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", | 855 | dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", |
| 813 | irq, status1, mask1, status2, mask2); | 856 | irq, status1, mask1, status2, mask2); |
| 814 | 857 | ||
| 815 | if (!((status1 & mask1) | (status2 & mask2))) { | 858 | if (!((status1 & mask1) | (status2 & mask2))) { |
| 816 | return IRQ_NONE; | 859 | return IRQ_NONE; |
| @@ -821,7 +864,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
| 821 | udelay(500); | 864 | udelay(500); |
| 822 | 865 | ||
| 823 | msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); | 866 | msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); |
| 824 | pr_debug("MSENS 0x%x\n", msens); | 867 | dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens); |
| 825 | /* Check, if hot plug & MSENS pin status are both high */ | 868 | /* Check, if hot plug & MSENS pin status are both high */ |
| 826 | if ((msens & 0xC0) == 0xC0) { | 869 | if ((msens & 0xC0) == 0xC0) { |
| 827 | /* Display plug in */ | 870 | /* Display plug in */ |
| @@ -857,83 +900,176 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
| 857 | return IRQ_HANDLED; | 900 | return IRQ_HANDLED; |
| 858 | } | 901 | } |
| 859 | 902 | ||
| 860 | static void hdmi_display_on(void *arg, struct fb_info *info) | 903 | /* locking: called with info->lock held, or before register_framebuffer() */ |
| 904 | static void sh_hdmi_display_on(void *arg, struct fb_info *info) | ||
| 861 | { | 905 | { |
| 906 | /* | ||
| 907 | * info is guaranteed to be valid, when we are called, because our | ||
| 908 | * FB_EVENT_FB_UNBIND notify is also called with info->lock held | ||
| 909 | */ | ||
| 862 | struct sh_hdmi *hdmi = arg; | 910 | struct sh_hdmi *hdmi = arg; |
| 863 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 911 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; |
| 912 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 864 | 913 | ||
| 865 | if (info->var.xres != 1280 || info->var.yres != 720) { | 914 | dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, |
| 866 | dev_warn(info->device, "Unsupported framebuffer geometry %ux%u\n", | 915 | pdata->lcd_dev, info->state); |
| 867 | info->var.xres, info->var.yres); | 916 | |
| 868 | return; | 917 | /* No need to lock */ |
| 869 | } | 918 | hdmi->info = info; |
| 870 | 919 | ||
| 871 | pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); | ||
| 872 | /* | 920 | /* |
| 873 | * FIXME: not a good place to store fb_info. And we cannot nullify it | 921 | * hp_state can be set to |
| 874 | * even on monitor disconnect. What should the lifecycle be? | 922 | * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug |
| 923 | * HDMI_HOTPLUG_CONNECTED: on monitor plug-in | ||
| 924 | * HDMI_HOTPLUG_EDID_DONE: on EDID read completion | ||
| 875 | */ | 925 | */ |
| 876 | hdmi->info = info; | ||
| 877 | switch (hdmi->hp_state) { | 926 | switch (hdmi->hp_state) { |
| 878 | case HDMI_HOTPLUG_EDID_DONE: | 927 | case HDMI_HOTPLUG_EDID_DONE: |
| 879 | /* PS mode d->e. All functions are active */ | 928 | /* PS mode d->e. All functions are active */ |
| 880 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); | 929 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); |
| 881 | pr_debug("HDMI running\n"); | 930 | dev_dbg(hdmi->dev, "HDMI running\n"); |
| 882 | break; | 931 | break; |
| 883 | case HDMI_HOTPLUG_DISCONNECTED: | 932 | case HDMI_HOTPLUG_DISCONNECTED: |
| 884 | info->state = FBINFO_STATE_SUSPENDED; | 933 | info->state = FBINFO_STATE_SUSPENDED; |
| 885 | default: | 934 | default: |
| 886 | hdmi->var = info->var; | 935 | hdmi->var = ch->display_var; |
| 887 | } | 936 | } |
| 888 | } | 937 | } |
| 889 | 938 | ||
| 890 | static void hdmi_display_off(void *arg) | 939 | /* locking: called with info->lock held */ |
| 940 | static void sh_hdmi_display_off(void *arg) | ||
| 891 | { | 941 | { |
| 892 | struct sh_hdmi *hdmi = arg; | 942 | struct sh_hdmi *hdmi = arg; |
| 893 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 943 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; |
| 894 | 944 | ||
| 895 | pr_debug("%s(%p)\n", __func__, pdata->lcd_dev); | 945 | dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); |
| 896 | /* PS mode e->a */ | 946 | /* PS mode e->a */ |
| 897 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); | 947 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); |
| 898 | } | 948 | } |
| 899 | 949 | ||
| 950 | static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) | ||
| 951 | { | ||
| 952 | struct fb_info *info = hdmi->info; | ||
| 953 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 954 | struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; | ||
| 955 | struct fb_videomode mode1, mode2; | ||
| 956 | |||
| 957 | fb_var_to_videomode(&mode1, old_var); | ||
| 958 | fb_var_to_videomode(&mode2, new_var); | ||
| 959 | |||
| 960 | dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", | ||
| 961 | mode1.xres, mode1.yres, mode2.xres, mode2.yres); | ||
| 962 | |||
| 963 | if (fb_mode_is_equal(&mode1, &mode2)) | ||
| 964 | return false; | ||
| 965 | |||
| 966 | dev_dbg(info->dev, "Switching %u -> %u lines\n", | ||
| 967 | mode1.yres, mode2.yres); | ||
| 968 | *old_var = *new_var; | ||
| 969 | |||
| 970 | return true; | ||
| 971 | } | ||
| 972 | |||
| 973 | /** | ||
| 974 | * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock | ||
| 975 | * @hdmi: driver context | ||
| 976 | * @pixclock: pixel clock period in picoseconds | ||
| 977 | * return: configured positive rate if successful | ||
| 978 | * 0 if couldn't set the rate, but managed to enable the clock | ||
| 979 | * negative error, if couldn't enable the clock | ||
| 980 | */ | ||
| 981 | static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) | ||
| 982 | { | ||
| 983 | long rate; | ||
| 984 | int ret; | ||
| 985 | |||
| 986 | rate = PICOS2KHZ(pixclock) * 1000; | ||
| 987 | rate = clk_round_rate(hdmi->hdmi_clk, rate); | ||
| 988 | if (rate > 0) { | ||
| 989 | ret = clk_set_rate(hdmi->hdmi_clk, rate); | ||
| 990 | if (ret < 0) { | ||
| 991 | dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); | ||
| 992 | rate = 0; | ||
| 993 | } else { | ||
| 994 | dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); | ||
| 995 | } | ||
| 996 | } else { | ||
| 997 | rate = 0; | ||
| 998 | dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | ret = clk_enable(hdmi->hdmi_clk); | ||
| 1002 | if (ret < 0) { | ||
| 1003 | dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); | ||
| 1004 | return ret; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | return rate; | ||
| 1008 | } | ||
| 1009 | |||
| 900 | /* Hotplug interrupt occurred, read EDID */ | 1010 | /* Hotplug interrupt occurred, read EDID */ |
| 901 | static void edid_work_fn(struct work_struct *work) | 1011 | static void sh_hdmi_edid_work_fn(struct work_struct *work) |
| 902 | { | 1012 | { |
| 903 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); | 1013 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); |
| 904 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 1014 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; |
| 1015 | struct sh_mobile_lcdc_chan *ch; | ||
| 1016 | int ret; | ||
| 905 | 1017 | ||
| 906 | pr_debug("%s(%p): begin, hotplug status %d\n", __func__, | 1018 | dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, |
| 907 | pdata->lcd_dev, hdmi->hp_state); | 1019 | pdata->lcd_dev, hdmi->hp_state); |
| 908 | 1020 | ||
| 909 | if (!pdata->lcd_dev) | 1021 | if (!pdata->lcd_dev) |
| 910 | return; | 1022 | return; |
| 911 | 1023 | ||
| 1024 | mutex_lock(&hdmi->mutex); | ||
| 1025 | |||
| 912 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { | 1026 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { |
| 913 | pm_runtime_get_sync(hdmi->dev); | ||
| 914 | /* A device has been plugged in */ | 1027 | /* A device has been plugged in */ |
| 915 | sh_hdmi_read_edid(hdmi); | 1028 | pm_runtime_get_sync(hdmi->dev); |
| 1029 | |||
| 1030 | ret = sh_hdmi_read_edid(hdmi); | ||
| 1031 | if (ret < 0) | ||
| 1032 | goto out; | ||
| 1033 | |||
| 1034 | /* Reconfigure the clock */ | ||
| 1035 | clk_disable(hdmi->hdmi_clk); | ||
| 1036 | ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); | ||
| 1037 | if (ret < 0) | ||
| 1038 | goto out; | ||
| 1039 | |||
| 916 | msleep(10); | 1040 | msleep(10); |
| 917 | sh_hdmi_configure(hdmi); | 1041 | sh_hdmi_configure(hdmi); |
| 918 | /* Switched to another (d) power-save mode */ | 1042 | /* Switched to another (d) power-save mode */ |
| 919 | msleep(10); | 1043 | msleep(10); |
| 920 | 1044 | ||
| 921 | if (!hdmi->info) | 1045 | if (!hdmi->info) |
| 922 | return; | 1046 | goto out; |
| 1047 | |||
| 1048 | ch = hdmi->info->par; | ||
| 923 | 1049 | ||
| 924 | acquire_console_sem(); | 1050 | acquire_console_sem(); |
| 925 | 1051 | ||
| 926 | /* HDMI plug in */ | 1052 | /* HDMI plug in */ |
| 927 | hdmi->info->var = hdmi->var; | 1053 | if (!sh_hdmi_must_reconfigure(hdmi) && |
| 928 | if (hdmi->info->state != FBINFO_STATE_RUNNING) | 1054 | hdmi->info->state == FBINFO_STATE_RUNNING) { |
| 1055 | /* | ||
| 1056 | * First activation with the default monitor - just turn | ||
| 1057 | * on, if we run a resume here, the logo disappears | ||
| 1058 | */ | ||
| 1059 | if (lock_fb_info(hdmi->info)) { | ||
| 1060 | sh_hdmi_display_on(hdmi, hdmi->info); | ||
| 1061 | unlock_fb_info(hdmi->info); | ||
| 1062 | } | ||
| 1063 | } else { | ||
| 1064 | /* New monitor or have to wake up */ | ||
| 929 | fb_set_suspend(hdmi->info, 0); | 1065 | fb_set_suspend(hdmi->info, 0); |
| 930 | else | 1066 | } |
| 931 | hdmi_display_on(hdmi, hdmi->info); | ||
| 932 | 1067 | ||
| 933 | release_console_sem(); | 1068 | release_console_sem(); |
| 934 | } else { | 1069 | } else { |
| 1070 | ret = 0; | ||
| 935 | if (!hdmi->info) | 1071 | if (!hdmi->info) |
| 936 | return; | 1072 | goto out; |
| 937 | 1073 | ||
| 938 | acquire_console_sem(); | 1074 | acquire_console_sem(); |
| 939 | 1075 | ||
| @@ -942,15 +1078,67 @@ static void edid_work_fn(struct work_struct *work) | |||
| 942 | 1078 | ||
| 943 | release_console_sem(); | 1079 | release_console_sem(); |
| 944 | pm_runtime_put(hdmi->dev); | 1080 | pm_runtime_put(hdmi->dev); |
| 1081 | fb_destroy_modedb(hdmi->monspec.modedb); | ||
| 945 | } | 1082 | } |
| 946 | 1083 | ||
| 947 | pr_debug("%s(%p): end\n", __func__, pdata->lcd_dev); | 1084 | out: |
| 1085 | if (ret < 0) | ||
| 1086 | hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; | ||
| 1087 | mutex_unlock(&hdmi->mutex); | ||
| 1088 | |||
| 1089 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | static int sh_hdmi_notify(struct notifier_block *nb, | ||
| 1093 | unsigned long action, void *data); | ||
| 1094 | |||
| 1095 | static struct notifier_block sh_hdmi_notifier = { | ||
| 1096 | .notifier_call = sh_hdmi_notify, | ||
| 1097 | }; | ||
| 1098 | |||
| 1099 | static int sh_hdmi_notify(struct notifier_block *nb, | ||
| 1100 | unsigned long action, void *data) | ||
| 1101 | { | ||
| 1102 | struct fb_event *event = data; | ||
| 1103 | struct fb_info *info = event->info; | ||
| 1104 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 1105 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | ||
| 1106 | struct sh_hdmi *hdmi = board_cfg->board_data; | ||
| 1107 | |||
| 1108 | if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) | ||
| 1109 | return NOTIFY_DONE; | ||
| 1110 | |||
| 1111 | switch(action) { | ||
| 1112 | case FB_EVENT_FB_REGISTERED: | ||
| 1113 | /* Unneeded, activation taken care by sh_hdmi_display_on() */ | ||
| 1114 | break; | ||
| 1115 | case FB_EVENT_FB_UNREGISTERED: | ||
| 1116 | /* | ||
| 1117 | * We are called from unregister_framebuffer() with the | ||
| 1118 | * info->lock held. This is bad for us, because we can race with | ||
| 1119 | * the scheduled work, which has to call fb_set_suspend(), which | ||
| 1120 | * takes info->lock internally, so, sh_hdmi_edid_work_fn() | ||
| 1121 | * cannot take and hold info->lock for the whole function | ||
| 1122 | * duration. Using an additional lock creates a classical AB-BA | ||
| 1123 | * lock up. Therefore, we have to release the info->lock | ||
| 1124 | * temporarily, synchronise with the work queue and re-acquire | ||
| 1125 | * the info->lock. | ||
| 1126 | */ | ||
| 1127 | unlock_fb_info(hdmi->info); | ||
| 1128 | mutex_lock(&hdmi->mutex); | ||
| 1129 | hdmi->info = NULL; | ||
| 1130 | mutex_unlock(&hdmi->mutex); | ||
| 1131 | lock_fb_info(hdmi->info); | ||
| 1132 | return NOTIFY_OK; | ||
| 1133 | } | ||
| 1134 | return NOTIFY_DONE; | ||
| 948 | } | 1135 | } |
| 949 | 1136 | ||
| 950 | static int __init sh_hdmi_probe(struct platform_device *pdev) | 1137 | static int __init sh_hdmi_probe(struct platform_device *pdev) |
| 951 | { | 1138 | { |
| 952 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1139 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; |
| 953 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1140 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1141 | struct sh_mobile_lcdc_board_cfg *board_cfg; | ||
| 954 | int irq = platform_get_irq(pdev, 0), ret; | 1142 | int irq = platform_get_irq(pdev, 0), ret; |
| 955 | struct sh_hdmi *hdmi; | 1143 | struct sh_hdmi *hdmi; |
| 956 | long rate; | 1144 | long rate; |
| @@ -964,10 +1152,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 964 | return -ENOMEM; | 1152 | return -ENOMEM; |
| 965 | } | 1153 | } |
| 966 | 1154 | ||
| 967 | ret = snd_soc_register_codec(&pdev->dev, | 1155 | mutex_init(&hdmi->mutex); |
| 968 | &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); | ||
| 969 | if (ret < 0) | ||
| 970 | goto esndreg; | ||
| 971 | 1156 | ||
| 972 | hdmi->dev = &pdev->dev; | 1157 | hdmi->dev = &pdev->dev; |
| 973 | 1158 | ||
| @@ -978,30 +1163,14 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 978 | goto egetclk; | 1163 | goto egetclk; |
| 979 | } | 1164 | } |
| 980 | 1165 | ||
| 981 | rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg.pixclock) * 1000; | 1166 | /* Some arbitrary relaxed pixclock just to get things started */ |
| 982 | 1167 | rate = sh_hdmi_clk_configure(hdmi, 37037); | |
| 983 | rate = clk_round_rate(hdmi->hdmi_clk, rate); | ||
| 984 | if (rate < 0) { | 1168 | if (rate < 0) { |
| 985 | ret = rate; | 1169 | ret = rate; |
| 986 | dev_err(&pdev->dev, "Cannot get suitable rate: %ld\n", rate); | ||
| 987 | goto erate; | 1170 | goto erate; |
| 988 | } | 1171 | } |
| 989 | 1172 | ||
| 990 | ret = clk_set_rate(hdmi->hdmi_clk, rate); | 1173 | dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); |
| 991 | if (ret < 0) { | ||
| 992 | dev_err(&pdev->dev, "Cannot set rate %ld: %d\n", rate, ret); | ||
| 993 | goto erate; | ||
| 994 | } | ||
| 995 | |||
| 996 | pr_debug("HDMI set frequency %lu\n", rate); | ||
| 997 | |||
| 998 | ret = clk_enable(hdmi->hdmi_clk); | ||
| 999 | if (ret < 0) { | ||
| 1000 | dev_err(&pdev->dev, "Cannot enable clock: %d\n", ret); | ||
| 1001 | goto eclkenable; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | dev_info(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); | ||
| 1005 | 1174 | ||
| 1006 | if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { | 1175 | if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { |
| 1007 | dev_err(&pdev->dev, "HDMI register region already claimed\n"); | 1176 | dev_err(&pdev->dev, "HDMI register region already claimed\n"); |
| @@ -1018,18 +1187,18 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 1018 | 1187 | ||
| 1019 | platform_set_drvdata(pdev, hdmi); | 1188 | platform_set_drvdata(pdev, hdmi); |
| 1020 | 1189 | ||
| 1021 | #if 1 | ||
| 1022 | /* Product and revision IDs are 0 in sh-mobile version */ | 1190 | /* Product and revision IDs are 0 in sh-mobile version */ |
| 1023 | dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", | 1191 | dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", |
| 1024 | hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); | 1192 | hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); |
| 1025 | #endif | ||
| 1026 | 1193 | ||
| 1027 | /* Set up LCDC callbacks */ | 1194 | /* Set up LCDC callbacks */ |
| 1028 | pdata->lcd_chan->board_cfg.board_data = hdmi; | 1195 | board_cfg = &pdata->lcd_chan->board_cfg; |
| 1029 | pdata->lcd_chan->board_cfg.display_on = hdmi_display_on; | 1196 | board_cfg->owner = THIS_MODULE; |
| 1030 | pdata->lcd_chan->board_cfg.display_off = hdmi_display_off; | 1197 | board_cfg->board_data = hdmi; |
| 1198 | board_cfg->display_on = sh_hdmi_display_on; | ||
| 1199 | board_cfg->display_off = sh_hdmi_display_off; | ||
| 1031 | 1200 | ||
| 1032 | INIT_DELAYED_WORK(&hdmi->edid_work, edid_work_fn); | 1201 | INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); |
| 1033 | 1202 | ||
| 1034 | pm_runtime_enable(&pdev->dev); | 1203 | pm_runtime_enable(&pdev->dev); |
| 1035 | pm_runtime_resume(&pdev->dev); | 1204 | pm_runtime_resume(&pdev->dev); |
| @@ -1041,8 +1210,17 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 1041 | goto ereqirq; | 1210 | goto ereqirq; |
| 1042 | } | 1211 | } |
| 1043 | 1212 | ||
| 1213 | ret = snd_soc_register_codec(&pdev->dev, | ||
| 1214 | &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); | ||
| 1215 | if (ret < 0) { | ||
| 1216 | dev_err(&pdev->dev, "codec registration failed\n"); | ||
| 1217 | goto ecodec; | ||
| 1218 | } | ||
| 1219 | |||
| 1044 | return 0; | 1220 | return 0; |
| 1045 | 1221 | ||
| 1222 | ecodec: | ||
| 1223 | free_irq(irq, hdmi); | ||
| 1046 | ereqirq: | 1224 | ereqirq: |
| 1047 | pm_runtime_disable(&pdev->dev); | 1225 | pm_runtime_disable(&pdev->dev); |
| 1048 | iounmap(hdmi->base); | 1226 | iounmap(hdmi->base); |
| @@ -1050,12 +1228,10 @@ emap: | |||
| 1050 | release_mem_region(res->start, resource_size(res)); | 1228 | release_mem_region(res->start, resource_size(res)); |
| 1051 | ereqreg: | 1229 | ereqreg: |
| 1052 | clk_disable(hdmi->hdmi_clk); | 1230 | clk_disable(hdmi->hdmi_clk); |
| 1053 | eclkenable: | ||
| 1054 | erate: | 1231 | erate: |
| 1055 | clk_put(hdmi->hdmi_clk); | 1232 | clk_put(hdmi->hdmi_clk); |
| 1056 | egetclk: | 1233 | egetclk: |
| 1057 | snd_soc_unregister_codec(&pdev->dev); | 1234 | mutex_destroy(&hdmi->mutex); |
| 1058 | esndreg: | ||
| 1059 | kfree(hdmi); | 1235 | kfree(hdmi); |
| 1060 | 1236 | ||
| 1061 | return ret; | 1237 | return ret; |
| @@ -1066,21 +1242,26 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) | |||
| 1066 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1242 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; |
| 1067 | struct sh_hdmi *hdmi = platform_get_drvdata(pdev); | 1243 | struct sh_hdmi *hdmi = platform_get_drvdata(pdev); |
| 1068 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1244 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1245 | struct sh_mobile_lcdc_board_cfg *board_cfg = &pdata->lcd_chan->board_cfg; | ||
| 1069 | int irq = platform_get_irq(pdev, 0); | 1246 | int irq = platform_get_irq(pdev, 0); |
| 1070 | 1247 | ||
| 1071 | snd_soc_unregister_codec(&pdev->dev); | 1248 | snd_soc_unregister_codec(&pdev->dev); |
| 1072 | 1249 | ||
| 1073 | pdata->lcd_chan->board_cfg.display_on = NULL; | 1250 | board_cfg->display_on = NULL; |
| 1074 | pdata->lcd_chan->board_cfg.display_off = NULL; | 1251 | board_cfg->display_off = NULL; |
| 1075 | pdata->lcd_chan->board_cfg.board_data = NULL; | 1252 | board_cfg->board_data = NULL; |
| 1253 | board_cfg->owner = NULL; | ||
| 1076 | 1254 | ||
| 1255 | /* No new work will be scheduled, wait for running ISR */ | ||
| 1077 | free_irq(irq, hdmi); | 1256 | free_irq(irq, hdmi); |
| 1078 | pm_runtime_disable(&pdev->dev); | 1257 | /* Wait for already scheduled work */ |
| 1079 | cancel_delayed_work_sync(&hdmi->edid_work); | 1258 | cancel_delayed_work_sync(&hdmi->edid_work); |
| 1259 | pm_runtime_disable(&pdev->dev); | ||
| 1080 | clk_disable(hdmi->hdmi_clk); | 1260 | clk_disable(hdmi->hdmi_clk); |
| 1081 | clk_put(hdmi->hdmi_clk); | 1261 | clk_put(hdmi->hdmi_clk); |
| 1082 | iounmap(hdmi->base); | 1262 | iounmap(hdmi->base); |
| 1083 | release_mem_region(res->start, resource_size(res)); | 1263 | release_mem_region(res->start, resource_size(res)); |
| 1264 | mutex_destroy(&hdmi->mutex); | ||
| 1084 | kfree(hdmi); | 1265 | kfree(hdmi); |
| 1085 | 1266 | ||
| 1086 | return 0; | 1267 | return 0; |
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 7a1419279c8f..50963739a409 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
| 14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
| 15 | #include <linux/fb.h> | ||
| 16 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
| 17 | #include <linux/pm_runtime.h> | 16 | #include <linux/pm_runtime.h> |
| 18 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| @@ -21,10 +20,12 @@ | |||
| 21 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
| 22 | #include <linux/ioctl.h> | 21 | #include <linux/ioctl.h> |
| 23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | #include <linux/console.h> | ||
| 24 | #include <video/sh_mobile_lcdc.h> | 24 | #include <video/sh_mobile_lcdc.h> |
| 25 | #include <asm/atomic.h> | 25 | #include <asm/atomic.h> |
| 26 | 26 | ||
| 27 | #define PALETTE_NR 16 | 27 | #include "sh_mobile_lcdcfb.h" |
| 28 | |||
| 28 | #define SIDE_B_OFFSET 0x1000 | 29 | #define SIDE_B_OFFSET 0x1000 |
| 29 | #define MIRROR_OFFSET 0x2000 | 30 | #define MIRROR_OFFSET 0x2000 |
| 30 | 31 | ||
| @@ -53,11 +54,8 @@ static int lcdc_shared_regs[] = { | |||
| 53 | }; | 54 | }; |
| 54 | #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) | 55 | #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) |
| 55 | 56 | ||
| 56 | /* per-channel registers */ | 57 | #define DEFAULT_XRES 1280 |
| 57 | enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, | 58 | #define DEFAULT_YRES 1024 |
| 58 | LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, | ||
| 59 | LDHAJR, | ||
| 60 | NR_CH_REGS }; | ||
| 61 | 59 | ||
| 62 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { | 60 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { |
| 63 | [LDDCKPAT1R] = 0x400, | 61 | [LDDCKPAT1R] = 0x400, |
| @@ -112,23 +110,21 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { | |||
| 112 | #define LDRCNTR_MRC 0x00000001 | 110 | #define LDRCNTR_MRC 0x00000001 |
| 113 | #define LDSR_MRS 0x00000100 | 111 | #define LDSR_MRS 0x00000100 |
| 114 | 112 | ||
| 115 | struct sh_mobile_lcdc_priv; | 113 | static const struct fb_videomode default_720p = { |
| 116 | struct sh_mobile_lcdc_chan { | 114 | .name = "HDMI 720p", |
| 117 | struct sh_mobile_lcdc_priv *lcdc; | 115 | .xres = 1280, |
| 118 | unsigned long *reg_offs; | 116 | .yres = 720, |
| 119 | unsigned long ldmt1r_value; | 117 | |
| 120 | unsigned long enabled; /* ME and SE in LDCNT2R */ | 118 | .left_margin = 200, |
| 121 | struct sh_mobile_lcdc_chan_cfg cfg; | 119 | .right_margin = 88, |
| 122 | u32 pseudo_palette[PALETTE_NR]; | 120 | .hsync_len = 48, |
| 123 | unsigned long saved_ch_regs[NR_CH_REGS]; | 121 | |
| 124 | struct fb_info *info; | 122 | .upper_margin = 20, |
| 125 | dma_addr_t dma_handle; | 123 | .lower_margin = 5, |
| 126 | struct fb_deferred_io defio; | 124 | .vsync_len = 5, |
| 127 | struct scatterlist *sglist; | 125 | |
| 128 | unsigned long frame_end; | 126 | .pixclock = 13468, |
| 129 | unsigned long pan_offset; | 127 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, |
| 130 | wait_queue_head_t frame_end_wait; | ||
| 131 | struct completion vsync_completion; | ||
| 132 | }; | 128 | }; |
| 133 | 129 | ||
| 134 | struct sh_mobile_lcdc_priv { | 130 | struct sh_mobile_lcdc_priv { |
| @@ -409,8 +405,8 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, | |||
| 409 | 405 | ||
| 410 | static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | 406 | static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) |
| 411 | { | 407 | { |
| 412 | struct fb_var_screeninfo *var = &ch->info->var; | 408 | struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var; |
| 413 | unsigned long h_total, hsync_pos; | 409 | unsigned long h_total, hsync_pos, display_h_total; |
| 414 | u32 tmp; | 410 | u32 tmp; |
| 415 | 411 | ||
| 416 | tmp = ch->ldmt1r_value; | 412 | tmp = ch->ldmt1r_value; |
| @@ -428,31 +424,33 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
| 428 | lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); | 424 | lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); |
| 429 | 425 | ||
| 430 | /* horizontal configuration */ | 426 | /* horizontal configuration */ |
| 431 | h_total = var->xres + var->hsync_len + | 427 | h_total = display_var->xres + display_var->hsync_len + |
| 432 | var->left_margin + var->right_margin; | 428 | display_var->left_margin + display_var->right_margin; |
| 433 | tmp = h_total / 8; /* HTCN */ | 429 | tmp = h_total / 8; /* HTCN */ |
| 434 | tmp |= (var->xres / 8) << 16; /* HDCN */ | 430 | tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */ |
| 435 | lcdc_write_chan(ch, LDHCNR, tmp); | 431 | lcdc_write_chan(ch, LDHCNR, tmp); |
| 436 | 432 | ||
| 437 | hsync_pos = var->xres + var->right_margin; | 433 | hsync_pos = display_var->xres + display_var->right_margin; |
| 438 | tmp = hsync_pos / 8; /* HSYNP */ | 434 | tmp = hsync_pos / 8; /* HSYNP */ |
| 439 | tmp |= (var->hsync_len / 8) << 16; /* HSYNW */ | 435 | tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */ |
| 440 | lcdc_write_chan(ch, LDHSYNR, tmp); | 436 | lcdc_write_chan(ch, LDHSYNR, tmp); |
| 441 | 437 | ||
| 442 | /* vertical configuration */ | 438 | /* vertical configuration */ |
| 443 | tmp = var->yres + var->vsync_len + | 439 | tmp = display_var->yres + display_var->vsync_len + |
| 444 | var->upper_margin + var->lower_margin; /* VTLN */ | 440 | display_var->upper_margin + display_var->lower_margin; /* VTLN */ |
| 445 | tmp |= var->yres << 16; /* VDLN */ | 441 | tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */ |
| 446 | lcdc_write_chan(ch, LDVLNR, tmp); | 442 | lcdc_write_chan(ch, LDVLNR, tmp); |
| 447 | 443 | ||
| 448 | tmp = var->yres + var->lower_margin; /* VSYNP */ | 444 | tmp = display_var->yres + display_var->lower_margin; /* VSYNP */ |
| 449 | tmp |= var->vsync_len << 16; /* VSYNW */ | 445 | tmp |= display_var->vsync_len << 16; /* VSYNW */ |
| 450 | lcdc_write_chan(ch, LDVSYNR, tmp); | 446 | lcdc_write_chan(ch, LDVSYNR, tmp); |
| 451 | 447 | ||
| 452 | /* Adjust horizontal synchronisation for HDMI */ | 448 | /* Adjust horizontal synchronisation for HDMI */ |
| 453 | tmp = ((var->xres & 7) << 24) | | 449 | display_h_total = display_var->xres + display_var->hsync_len + |
| 454 | ((h_total & 7) << 16) | | 450 | display_var->left_margin + display_var->right_margin; |
| 455 | ((var->hsync_len & 7) << 8) | | 451 | tmp = ((display_var->xres & 7) << 24) | |
| 452 | ((display_h_total & 7) << 16) | | ||
| 453 | ((display_var->hsync_len & 7) << 8) | | ||
| 456 | hsync_pos; | 454 | hsync_pos; |
| 457 | lcdc_write_chan(ch, LDHAJR, tmp); | 455 | lcdc_write_chan(ch, LDHAJR, tmp); |
| 458 | } | 456 | } |
| @@ -460,7 +458,6 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
| 460 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | 458 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) |
| 461 | { | 459 | { |
| 462 | struct sh_mobile_lcdc_chan *ch; | 460 | struct sh_mobile_lcdc_chan *ch; |
| 463 | struct fb_videomode *lcd_cfg; | ||
| 464 | struct sh_mobile_lcdc_board_cfg *board_cfg; | 461 | struct sh_mobile_lcdc_board_cfg *board_cfg; |
| 465 | unsigned long tmp; | 462 | unsigned long tmp; |
| 466 | int k, m; | 463 | int k, m; |
| @@ -503,7 +500,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 503 | m = 1 << 6; | 500 | m = 1 << 6; |
| 504 | tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); | 501 | tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); |
| 505 | 502 | ||
| 506 | lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); | 503 | /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ |
| 504 | lcdc_write_chan(ch, LDDCKPAT1R, 0); | ||
| 507 | lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); | 505 | lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); |
| 508 | } | 506 | } |
| 509 | 507 | ||
| @@ -518,7 +516,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 518 | 516 | ||
| 519 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 517 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
| 520 | ch = &priv->ch[k]; | 518 | ch = &priv->ch[k]; |
| 521 | lcd_cfg = &ch->cfg.lcd_cfg; | ||
| 522 | 519 | ||
| 523 | if (!ch->enabled) | 520 | if (!ch->enabled) |
| 524 | continue; | 521 | continue; |
| @@ -547,7 +544,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 547 | 544 | ||
| 548 | /* set bpp format in PKF[4:0] */ | 545 | /* set bpp format in PKF[4:0] */ |
| 549 | tmp = lcdc_read_chan(ch, LDDFR); | 546 | tmp = lcdc_read_chan(ch, LDDFR); |
| 550 | tmp &= ~(0x0001001f); | 547 | tmp &= ~0x0001001f; |
| 551 | tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; | 548 | tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; |
| 552 | lcdc_write_chan(ch, LDDFR, tmp); | 549 | lcdc_write_chan(ch, LDDFR, tmp); |
| 553 | 550 | ||
| @@ -591,8 +588,10 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 591 | continue; | 588 | continue; |
| 592 | 589 | ||
| 593 | board_cfg = &ch->cfg.board_cfg; | 590 | board_cfg = &ch->cfg.board_cfg; |
| 594 | if (board_cfg->display_on) | 591 | if (try_module_get(board_cfg->owner) && board_cfg->display_on) { |
| 595 | board_cfg->display_on(board_cfg->board_data, ch->info); | 592 | board_cfg->display_on(board_cfg->board_data, ch->info); |
| 593 | module_put(board_cfg->owner); | ||
| 594 | } | ||
| 596 | } | 595 | } |
| 597 | 596 | ||
| 598 | return 0; | 597 | return 0; |
| @@ -614,7 +613,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
| 614 | * flush frame, and wait for frame end interrupt | 613 | * flush frame, and wait for frame end interrupt |
| 615 | * clean up deferred io and enable clock | 614 | * clean up deferred io and enable clock |
| 616 | */ | 615 | */ |
| 617 | if (ch->info->fbdefio) { | 616 | if (ch->info && ch->info->fbdefio) { |
| 618 | ch->frame_end = 0; | 617 | ch->frame_end = 0; |
| 619 | schedule_delayed_work(&ch->info->deferred_work, 0); | 618 | schedule_delayed_work(&ch->info->deferred_work, 0); |
| 620 | wait_event(ch->frame_end_wait, ch->frame_end); | 619 | wait_event(ch->frame_end_wait, ch->frame_end); |
| @@ -624,8 +623,10 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
| 624 | } | 623 | } |
| 625 | 624 | ||
| 626 | board_cfg = &ch->cfg.board_cfg; | 625 | board_cfg = &ch->cfg.board_cfg; |
| 627 | if (board_cfg->display_off) | 626 | if (try_module_get(board_cfg->owner) && board_cfg->display_off) { |
| 628 | board_cfg->display_off(board_cfg->board_data); | 627 | board_cfg->display_off(board_cfg->board_data); |
| 628 | module_put(board_cfg->owner); | ||
| 629 | } | ||
| 629 | } | 630 | } |
| 630 | 631 | ||
| 631 | /* stop the lcdc */ | 632 | /* stop the lcdc */ |
| @@ -704,7 +705,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, | |||
| 704 | return PTR_ERR(priv->dot_clk); | 705 | return PTR_ERR(priv->dot_clk); |
| 705 | } | 706 | } |
| 706 | } | 707 | } |
| 707 | atomic_set(&priv->hw_usecnt, -1); | ||
| 708 | 708 | ||
| 709 | /* Runtime PM support involves two step for this driver: | 709 | /* Runtime PM support involves two step for this driver: |
| 710 | * 1) Enable Runtime PM | 710 | * 1) Enable Runtime PM |
| @@ -837,6 +837,102 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, | |||
| 837 | return retval; | 837 | return retval; |
| 838 | } | 838 | } |
| 839 | 839 | ||
| 840 | static void sh_mobile_fb_reconfig(struct fb_info *info) | ||
| 841 | { | ||
| 842 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 843 | struct fb_videomode mode1, mode2; | ||
| 844 | struct fb_event event; | ||
| 845 | int evnt = FB_EVENT_MODE_CHANGE_ALL; | ||
| 846 | |||
| 847 | if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) | ||
| 848 | /* More framebuffer users are active */ | ||
| 849 | return; | ||
| 850 | |||
| 851 | fb_var_to_videomode(&mode1, &ch->display_var); | ||
| 852 | fb_var_to_videomode(&mode2, &info->var); | ||
| 853 | |||
| 854 | if (fb_mode_is_equal(&mode1, &mode2)) | ||
| 855 | return; | ||
| 856 | |||
| 857 | /* Display has been re-plugged, framebuffer is free now, reconfigure */ | ||
| 858 | if (fb_set_var(info, &ch->display_var) < 0) | ||
| 859 | /* Couldn't reconfigure, hopefully, can continue as before */ | ||
| 860 | return; | ||
| 861 | |||
| 862 | info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8); | ||
| 863 | |||
| 864 | /* | ||
| 865 | * fb_set_var() calls the notifier change internally, only if | ||
| 866 | * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a | ||
| 867 | * user event, we have to call the chain ourselves. | ||
| 868 | */ | ||
| 869 | event.info = info; | ||
| 870 | event.data = &mode2; | ||
| 871 | fb_notifier_call_chain(evnt, &event); | ||
| 872 | } | ||
| 873 | |||
| 874 | /* | ||
| 875 | * Locking: both .fb_release() and .fb_open() are called with info->lock held if | ||
| 876 | * user == 1, or with console sem held, if user == 0. | ||
| 877 | */ | ||
| 878 | static int sh_mobile_release(struct fb_info *info, int user) | ||
| 879 | { | ||
| 880 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 881 | |||
| 882 | mutex_lock(&ch->open_lock); | ||
| 883 | dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); | ||
| 884 | |||
| 885 | ch->use_count--; | ||
| 886 | |||
| 887 | /* Nothing to reconfigure, when called from fbcon */ | ||
| 888 | if (user) { | ||
| 889 | acquire_console_sem(); | ||
| 890 | sh_mobile_fb_reconfig(info); | ||
| 891 | release_console_sem(); | ||
| 892 | } | ||
| 893 | |||
| 894 | mutex_unlock(&ch->open_lock); | ||
| 895 | |||
| 896 | return 0; | ||
| 897 | } | ||
| 898 | |||
| 899 | static int sh_mobile_open(struct fb_info *info, int user) | ||
| 900 | { | ||
| 901 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 902 | |||
| 903 | mutex_lock(&ch->open_lock); | ||
| 904 | ch->use_count++; | ||
| 905 | |||
| 906 | dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); | ||
| 907 | mutex_unlock(&ch->open_lock); | ||
| 908 | |||
| 909 | return 0; | ||
| 910 | } | ||
| 911 | |||
| 912 | static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
| 913 | { | ||
| 914 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 915 | |||
| 916 | if (var->xres < 160 || var->xres > 1920 || | ||
| 917 | var->yres < 120 || var->yres > 1080 || | ||
| 918 | var->left_margin < 32 || var->left_margin > 320 || | ||
| 919 | var->right_margin < 12 || var->right_margin > 240 || | ||
| 920 | var->upper_margin < 12 || var->upper_margin > 120 || | ||
| 921 | var->lower_margin < 1 || var->lower_margin > 64 || | ||
| 922 | var->hsync_len < 32 || var->hsync_len > 240 || | ||
| 923 | var->vsync_len < 2 || var->vsync_len > 64 || | ||
| 924 | var->pixclock < 6000 || var->pixclock > 40000 || | ||
| 925 | var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { | ||
| 926 | dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", | ||
| 927 | var->xres, var->yres, | ||
| 928 | var->left_margin, var->right_margin, | ||
| 929 | var->upper_margin, var->lower_margin, | ||
| 930 | var->hsync_len, var->vsync_len, | ||
| 931 | var->pixclock); | ||
| 932 | return -EINVAL; | ||
| 933 | } | ||
| 934 | return 0; | ||
| 935 | } | ||
| 840 | 936 | ||
| 841 | static struct fb_ops sh_mobile_lcdc_ops = { | 937 | static struct fb_ops sh_mobile_lcdc_ops = { |
| 842 | .owner = THIS_MODULE, | 938 | .owner = THIS_MODULE, |
| @@ -848,6 +944,9 @@ static struct fb_ops sh_mobile_lcdc_ops = { | |||
| 848 | .fb_imageblit = sh_mobile_lcdc_imageblit, | 944 | .fb_imageblit = sh_mobile_lcdc_imageblit, |
| 849 | .fb_pan_display = sh_mobile_fb_pan_display, | 945 | .fb_pan_display = sh_mobile_fb_pan_display, |
| 850 | .fb_ioctl = sh_mobile_ioctl, | 946 | .fb_ioctl = sh_mobile_ioctl, |
| 947 | .fb_open = sh_mobile_open, | ||
| 948 | .fb_release = sh_mobile_release, | ||
| 949 | .fb_check_var = sh_mobile_check_var, | ||
| 851 | }; | 950 | }; |
| 852 | 951 | ||
| 853 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) | 952 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) |
| @@ -958,6 +1057,7 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { | |||
| 958 | .runtime_resume = sh_mobile_lcdc_runtime_resume, | 1057 | .runtime_resume = sh_mobile_lcdc_runtime_resume, |
| 959 | }; | 1058 | }; |
| 960 | 1059 | ||
| 1060 | /* locking: called with info->lock held */ | ||
| 961 | static int sh_mobile_lcdc_notify(struct notifier_block *nb, | 1061 | static int sh_mobile_lcdc_notify(struct notifier_block *nb, |
| 962 | unsigned long action, void *data) | 1062 | unsigned long action, void *data) |
| 963 | { | 1063 | { |
| @@ -965,53 +1065,40 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
| 965 | struct fb_info *info = event->info; | 1065 | struct fb_info *info = event->info; |
| 966 | struct sh_mobile_lcdc_chan *ch = info->par; | 1066 | struct sh_mobile_lcdc_chan *ch = info->par; |
| 967 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | 1067 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; |
| 968 | struct fb_var_screeninfo *var; | 1068 | int ret; |
| 969 | 1069 | ||
| 970 | if (&ch->lcdc->notifier != nb) | 1070 | if (&ch->lcdc->notifier != nb) |
| 971 | return 0; | 1071 | return NOTIFY_DONE; |
| 972 | 1072 | ||
| 973 | dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", | 1073 | dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", |
| 974 | __func__, action, event->data); | 1074 | __func__, action, event->data); |
| 975 | 1075 | ||
| 976 | switch(action) { | 1076 | switch(action) { |
| 977 | case FB_EVENT_SUSPEND: | 1077 | case FB_EVENT_SUSPEND: |
| 978 | if (board_cfg->display_off) | 1078 | if (try_module_get(board_cfg->owner) && board_cfg->display_off) { |
| 979 | board_cfg->display_off(board_cfg->board_data); | 1079 | board_cfg->display_off(board_cfg->board_data); |
| 1080 | module_put(board_cfg->owner); | ||
| 1081 | } | ||
| 980 | pm_runtime_put(info->device); | 1082 | pm_runtime_put(info->device); |
| 1083 | sh_mobile_lcdc_stop(ch->lcdc); | ||
| 981 | break; | 1084 | break; |
| 982 | case FB_EVENT_RESUME: | 1085 | case FB_EVENT_RESUME: |
| 983 | var = &info->var; | 1086 | mutex_lock(&ch->open_lock); |
| 1087 | sh_mobile_fb_reconfig(info); | ||
| 1088 | mutex_unlock(&ch->open_lock); | ||
| 984 | 1089 | ||
| 985 | /* HDMI must be enabled before LCDC configuration */ | 1090 | /* HDMI must be enabled before LCDC configuration */ |
| 986 | if (board_cfg->display_on) | 1091 | if (try_module_get(board_cfg->owner) && board_cfg->display_on) { |
| 987 | board_cfg->display_on(board_cfg->board_data, ch->info); | 1092 | board_cfg->display_on(board_cfg->board_data, info); |
| 988 | 1093 | module_put(board_cfg->owner); | |
| 989 | /* Check if the new display is not in our modelist */ | ||
| 990 | if (ch->info->modelist.next && | ||
| 991 | !fb_match_mode(var, &ch->info->modelist)) { | ||
| 992 | struct fb_videomode mode; | ||
| 993 | int ret; | ||
| 994 | |||
| 995 | /* Can we handle this display? */ | ||
| 996 | if (var->xres > ch->cfg.lcd_cfg.xres || | ||
| 997 | var->yres > ch->cfg.lcd_cfg.yres) | ||
| 998 | return -ENOMEM; | ||
| 999 | |||
| 1000 | /* Add to the modelist */ | ||
| 1001 | fb_var_to_videomode(&mode, var); | ||
| 1002 | ret = fb_add_videomode(&mode, &ch->info->modelist); | ||
| 1003 | if (ret < 0) | ||
| 1004 | return ret; | ||
| 1005 | } | 1094 | } |
| 1006 | 1095 | ||
| 1007 | pm_runtime_get_sync(info->device); | 1096 | ret = sh_mobile_lcdc_start(ch->lcdc); |
| 1008 | 1097 | if (!ret) | |
| 1009 | sh_mobile_lcdc_geometry(ch); | 1098 | pm_runtime_get_sync(info->device); |
| 1010 | |||
| 1011 | break; | ||
| 1012 | } | 1099 | } |
| 1013 | 1100 | ||
| 1014 | return 0; | 1101 | return NOTIFY_OK; |
| 1015 | } | 1102 | } |
| 1016 | 1103 | ||
| 1017 | static int sh_mobile_lcdc_remove(struct platform_device *pdev); | 1104 | static int sh_mobile_lcdc_remove(struct platform_device *pdev); |
| @@ -1020,14 +1107,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 1020 | { | 1107 | { |
| 1021 | struct fb_info *info; | 1108 | struct fb_info *info; |
| 1022 | struct sh_mobile_lcdc_priv *priv; | 1109 | struct sh_mobile_lcdc_priv *priv; |
| 1023 | struct sh_mobile_lcdc_info *pdata; | 1110 | struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; |
| 1024 | struct sh_mobile_lcdc_chan_cfg *cfg; | ||
| 1025 | struct resource *res; | 1111 | struct resource *res; |
| 1026 | int error; | 1112 | int error; |
| 1027 | void *buf; | 1113 | void *buf; |
| 1028 | int i, j; | 1114 | int i, j; |
| 1029 | 1115 | ||
| 1030 | if (!pdev->dev.platform_data) { | 1116 | if (!pdata) { |
| 1031 | dev_err(&pdev->dev, "no platform data defined\n"); | 1117 | dev_err(&pdev->dev, "no platform data defined\n"); |
| 1032 | return -EINVAL; | 1118 | return -EINVAL; |
| 1033 | } | 1119 | } |
| @@ -1055,31 +1141,33 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 1055 | } | 1141 | } |
| 1056 | 1142 | ||
| 1057 | priv->irq = i; | 1143 | priv->irq = i; |
| 1058 | pdata = pdev->dev.platform_data; | 1144 | atomic_set(&priv->hw_usecnt, -1); |
| 1059 | 1145 | ||
| 1060 | j = 0; | 1146 | j = 0; |
| 1061 | for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { | 1147 | for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { |
| 1062 | priv->ch[j].lcdc = priv; | 1148 | struct sh_mobile_lcdc_chan *ch = priv->ch + j; |
| 1063 | memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); | 1149 | |
| 1150 | ch->lcdc = priv; | ||
| 1151 | memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); | ||
| 1064 | 1152 | ||
| 1065 | error = sh_mobile_lcdc_check_interface(&priv->ch[j]); | 1153 | error = sh_mobile_lcdc_check_interface(ch); |
| 1066 | if (error) { | 1154 | if (error) { |
| 1067 | dev_err(&pdev->dev, "unsupported interface type\n"); | 1155 | dev_err(&pdev->dev, "unsupported interface type\n"); |
| 1068 | goto err1; | 1156 | goto err1; |
| 1069 | } | 1157 | } |
| 1070 | init_waitqueue_head(&priv->ch[j].frame_end_wait); | 1158 | init_waitqueue_head(&ch->frame_end_wait); |
| 1071 | init_completion(&priv->ch[j].vsync_completion); | 1159 | init_completion(&ch->vsync_completion); |
| 1072 | priv->ch[j].pan_offset = 0; | 1160 | ch->pan_offset = 0; |
| 1073 | 1161 | ||
| 1074 | switch (pdata->ch[i].chan) { | 1162 | switch (pdata->ch[i].chan) { |
| 1075 | case LCDC_CHAN_MAINLCD: | 1163 | case LCDC_CHAN_MAINLCD: |
| 1076 | priv->ch[j].enabled = 1 << 1; | 1164 | ch->enabled = 1 << 1; |
| 1077 | priv->ch[j].reg_offs = lcdc_offs_mainlcd; | 1165 | ch->reg_offs = lcdc_offs_mainlcd; |
| 1078 | j++; | 1166 | j++; |
| 1079 | break; | 1167 | break; |
| 1080 | case LCDC_CHAN_SUBLCD: | 1168 | case LCDC_CHAN_SUBLCD: |
| 1081 | priv->ch[j].enabled = 1 << 2; | 1169 | ch->enabled = 1 << 2; |
| 1082 | priv->ch[j].reg_offs = lcdc_offs_sublcd; | 1170 | ch->reg_offs = lcdc_offs_sublcd; |
| 1083 | j++; | 1171 | j++; |
| 1084 | break; | 1172 | break; |
| 1085 | } | 1173 | } |
| @@ -1103,69 +1191,83 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 1103 | 1191 | ||
| 1104 | for (i = 0; i < j; i++) { | 1192 | for (i = 0; i < j; i++) { |
| 1105 | struct fb_var_screeninfo *var; | 1193 | struct fb_var_screeninfo *var; |
| 1106 | struct fb_videomode *lcd_cfg; | 1194 | const struct fb_videomode *lcd_cfg, *max_cfg = NULL; |
| 1107 | cfg = &priv->ch[i].cfg; | 1195 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; |
| 1196 | struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; | ||
| 1197 | const struct fb_videomode *mode = cfg->lcd_cfg; | ||
| 1198 | unsigned long max_size = 0; | ||
| 1199 | int k; | ||
| 1108 | 1200 | ||
| 1109 | priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); | 1201 | ch->info = framebuffer_alloc(0, &pdev->dev); |
| 1110 | if (!priv->ch[i].info) { | 1202 | if (!ch->info) { |
| 1111 | dev_err(&pdev->dev, "unable to allocate fb_info\n"); | 1203 | dev_err(&pdev->dev, "unable to allocate fb_info\n"); |
| 1112 | error = -ENOMEM; | 1204 | error = -ENOMEM; |
| 1113 | break; | 1205 | break; |
| 1114 | } | 1206 | } |
| 1115 | 1207 | ||
| 1116 | info = priv->ch[i].info; | 1208 | info = ch->info; |
| 1117 | var = &info->var; | 1209 | var = &info->var; |
| 1118 | lcd_cfg = &cfg->lcd_cfg; | ||
| 1119 | info->fbops = &sh_mobile_lcdc_ops; | 1210 | info->fbops = &sh_mobile_lcdc_ops; |
| 1120 | var->xres = var->xres_virtual = lcd_cfg->xres; | 1211 | info->par = ch; |
| 1121 | var->yres = lcd_cfg->yres; | 1212 | |
| 1213 | mutex_init(&ch->open_lock); | ||
| 1214 | |||
| 1215 | for (k = 0, lcd_cfg = mode; | ||
| 1216 | k < cfg->num_cfg && lcd_cfg; | ||
| 1217 | k++, lcd_cfg++) { | ||
| 1218 | unsigned long size = lcd_cfg->yres * lcd_cfg->xres; | ||
| 1219 | |||
| 1220 | if (size > max_size) { | ||
| 1221 | max_cfg = lcd_cfg; | ||
| 1222 | max_size = size; | ||
| 1223 | } | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | if (!mode) | ||
| 1227 | max_size = DEFAULT_XRES * DEFAULT_YRES; | ||
| 1228 | else if (max_cfg) | ||
| 1229 | dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", | ||
| 1230 | max_cfg->xres, max_cfg->yres); | ||
| 1231 | |||
| 1232 | info->fix = sh_mobile_lcdc_fix; | ||
| 1233 | info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; | ||
| 1234 | |||
| 1235 | if (!mode) | ||
| 1236 | mode = &default_720p; | ||
| 1237 | |||
| 1238 | fb_videomode_to_var(var, mode); | ||
| 1122 | /* Default Y virtual resolution is 2x panel size */ | 1239 | /* Default Y virtual resolution is 2x panel size */ |
| 1123 | var->yres_virtual = var->yres * 2; | 1240 | var->yres_virtual = var->yres * 2; |
| 1124 | var->width = cfg->lcd_size_cfg.width; | ||
| 1125 | var->height = cfg->lcd_size_cfg.height; | ||
| 1126 | var->activate = FB_ACTIVATE_NOW; | 1241 | var->activate = FB_ACTIVATE_NOW; |
| 1127 | var->left_margin = lcd_cfg->left_margin; | ||
| 1128 | var->right_margin = lcd_cfg->right_margin; | ||
| 1129 | var->upper_margin = lcd_cfg->upper_margin; | ||
| 1130 | var->lower_margin = lcd_cfg->lower_margin; | ||
| 1131 | var->hsync_len = lcd_cfg->hsync_len; | ||
| 1132 | var->vsync_len = lcd_cfg->vsync_len; | ||
| 1133 | var->sync = lcd_cfg->sync; | ||
| 1134 | var->pixclock = lcd_cfg->pixclock; | ||
| 1135 | 1242 | ||
| 1136 | error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); | 1243 | error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); |
| 1137 | if (error) | 1244 | if (error) |
| 1138 | break; | 1245 | break; |
| 1139 | 1246 | ||
| 1140 | info->fix = sh_mobile_lcdc_fix; | ||
| 1141 | info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8); | ||
| 1142 | info->fix.smem_len = info->fix.line_length * | ||
| 1143 | var->yres_virtual; | ||
| 1144 | |||
| 1145 | buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, | 1247 | buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, |
| 1146 | &priv->ch[i].dma_handle, GFP_KERNEL); | 1248 | &ch->dma_handle, GFP_KERNEL); |
| 1147 | if (!buf) { | 1249 | if (!buf) { |
| 1148 | dev_err(&pdev->dev, "unable to allocate buffer\n"); | 1250 | dev_err(&pdev->dev, "unable to allocate buffer\n"); |
| 1149 | error = -ENOMEM; | 1251 | error = -ENOMEM; |
| 1150 | break; | 1252 | break; |
| 1151 | } | 1253 | } |
| 1152 | 1254 | ||
| 1153 | info->pseudo_palette = &priv->ch[i].pseudo_palette; | 1255 | info->pseudo_palette = &ch->pseudo_palette; |
| 1154 | info->flags = FBINFO_FLAG_DEFAULT; | 1256 | info->flags = FBINFO_FLAG_DEFAULT; |
| 1155 | 1257 | ||
| 1156 | error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); | 1258 | error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); |
| 1157 | if (error < 0) { | 1259 | if (error < 0) { |
| 1158 | dev_err(&pdev->dev, "unable to allocate cmap\n"); | 1260 | dev_err(&pdev->dev, "unable to allocate cmap\n"); |
| 1159 | dma_free_coherent(&pdev->dev, info->fix.smem_len, | 1261 | dma_free_coherent(&pdev->dev, info->fix.smem_len, |
| 1160 | buf, priv->ch[i].dma_handle); | 1262 | buf, ch->dma_handle); |
| 1161 | break; | 1263 | break; |
| 1162 | } | 1264 | } |
| 1163 | 1265 | ||
| 1164 | memset(buf, 0, info->fix.smem_len); | 1266 | info->fix.smem_start = ch->dma_handle; |
| 1165 | info->fix.smem_start = priv->ch[i].dma_handle; | 1267 | info->fix.line_length = var->xres * (cfg->bpp / 8); |
| 1166 | info->screen_base = buf; | 1268 | info->screen_base = buf; |
| 1167 | info->device = &pdev->dev; | 1269 | info->device = &pdev->dev; |
| 1168 | info->par = &priv->ch[i]; | 1270 | ch->display_var = *var; |
| 1169 | } | 1271 | } |
| 1170 | 1272 | ||
| 1171 | if (error) | 1273 | if (error) |
| @@ -1179,6 +1281,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 1179 | 1281 | ||
| 1180 | for (i = 0; i < j; i++) { | 1282 | for (i = 0; i < j; i++) { |
| 1181 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; | 1283 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; |
| 1284 | const struct fb_videomode *mode = ch->cfg.lcd_cfg; | ||
| 1285 | |||
| 1286 | if (!mode) | ||
| 1287 | mode = &default_720p; | ||
| 1182 | 1288 | ||
| 1183 | info = ch->info; | 1289 | info = ch->info; |
| 1184 | 1290 | ||
| @@ -1191,6 +1297,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 1191 | } | 1297 | } |
| 1192 | } | 1298 | } |
| 1193 | 1299 | ||
| 1300 | fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist); | ||
| 1194 | error = register_framebuffer(info); | 1301 | error = register_framebuffer(info); |
| 1195 | if (error < 0) | 1302 | if (error < 0) |
| 1196 | goto err1; | 1303 | goto err1; |
| @@ -1200,8 +1307,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 1200 | pdev->name, | 1307 | pdev->name, |
| 1201 | (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? | 1308 | (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? |
| 1202 | "mainlcd" : "sublcd", | 1309 | "mainlcd" : "sublcd", |
| 1203 | (int) ch->cfg.lcd_cfg.xres, | 1310 | info->var.xres, info->var.yres, |
| 1204 | (int) ch->cfg.lcd_cfg.yres, | ||
| 1205 | ch->cfg.bpp); | 1311 | ch->cfg.bpp); |
| 1206 | 1312 | ||
| 1207 | /* deferred io mode: disable clock to save power */ | 1313 | /* deferred io mode: disable clock to save power */ |
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h new file mode 100644 index 000000000000..9ecee2fba1d7 --- /dev/null +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #ifndef SH_MOBILE_LCDCFB_H | ||
| 2 | #define SH_MOBILE_LCDCFB_H | ||
| 3 | |||
| 4 | #include <linux/completion.h> | ||
| 5 | #include <linux/fb.h> | ||
| 6 | #include <linux/mutex.h> | ||
| 7 | #include <linux/wait.h> | ||
| 8 | |||
| 9 | /* per-channel registers */ | ||
| 10 | enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, | ||
| 11 | LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, | ||
| 12 | LDHAJR, | ||
| 13 | NR_CH_REGS }; | ||
| 14 | |||
| 15 | #define PALETTE_NR 16 | ||
| 16 | |||
| 17 | struct sh_mobile_lcdc_priv; | ||
| 18 | struct fb_info; | ||
| 19 | |||
| 20 | struct sh_mobile_lcdc_chan { | ||
| 21 | struct sh_mobile_lcdc_priv *lcdc; | ||
| 22 | unsigned long *reg_offs; | ||
| 23 | unsigned long ldmt1r_value; | ||
| 24 | unsigned long enabled; /* ME and SE in LDCNT2R */ | ||
| 25 | struct sh_mobile_lcdc_chan_cfg cfg; | ||
| 26 | u32 pseudo_palette[PALETTE_NR]; | ||
| 27 | unsigned long saved_ch_regs[NR_CH_REGS]; | ||
| 28 | struct fb_info *info; | ||
| 29 | dma_addr_t dma_handle; | ||
| 30 | struct fb_deferred_io defio; | ||
| 31 | struct scatterlist *sglist; | ||
| 32 | unsigned long frame_end; | ||
| 33 | unsigned long pan_offset; | ||
| 34 | wait_queue_head_t frame_end_wait; | ||
| 35 | struct completion vsync_completion; | ||
| 36 | struct fb_var_screeninfo display_var; | ||
| 37 | int use_count; | ||
| 38 | struct mutex open_lock; /* protects the use counter */ | ||
| 39 | }; | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 396039b3a8a2..7845d1f7d1d9 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
| @@ -163,7 +163,6 @@ fail: | |||
| 163 | */ | 163 | */ |
| 164 | static void end_compressed_bio_read(struct bio *bio, int err) | 164 | static void end_compressed_bio_read(struct bio *bio, int err) |
| 165 | { | 165 | { |
| 166 | struct extent_io_tree *tree; | ||
| 167 | struct compressed_bio *cb = bio->bi_private; | 166 | struct compressed_bio *cb = bio->bi_private; |
| 168 | struct inode *inode; | 167 | struct inode *inode; |
| 169 | struct page *page; | 168 | struct page *page; |
| @@ -187,7 +186,6 @@ static void end_compressed_bio_read(struct bio *bio, int err) | |||
| 187 | /* ok, we're the last bio for this extent, lets start | 186 | /* ok, we're the last bio for this extent, lets start |
| 188 | * the decompression. | 187 | * the decompression. |
| 189 | */ | 188 | */ |
| 190 | tree = &BTRFS_I(inode)->io_tree; | ||
| 191 | ret = btrfs_zlib_decompress_biovec(cb->compressed_pages, | 189 | ret = btrfs_zlib_decompress_biovec(cb->compressed_pages, |
| 192 | cb->start, | 190 | cb->start, |
| 193 | cb->orig_bio->bi_io_vec, | 191 | cb->orig_bio->bi_io_vec, |
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index c3df14ce2cc2..9ac171599258 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -200,7 +200,6 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, | |||
| 200 | struct extent_buffer **cow_ret, u64 new_root_objectid) | 200 | struct extent_buffer **cow_ret, u64 new_root_objectid) |
| 201 | { | 201 | { |
| 202 | struct extent_buffer *cow; | 202 | struct extent_buffer *cow; |
| 203 | u32 nritems; | ||
| 204 | int ret = 0; | 203 | int ret = 0; |
| 205 | int level; | 204 | int level; |
| 206 | struct btrfs_disk_key disk_key; | 205 | struct btrfs_disk_key disk_key; |
| @@ -210,7 +209,6 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, | |||
| 210 | WARN_ON(root->ref_cows && trans->transid != root->last_trans); | 209 | WARN_ON(root->ref_cows && trans->transid != root->last_trans); |
| 211 | 210 | ||
| 212 | level = btrfs_header_level(buf); | 211 | level = btrfs_header_level(buf); |
| 213 | nritems = btrfs_header_nritems(buf); | ||
| 214 | if (level == 0) | 212 | if (level == 0) |
| 215 | btrfs_item_key(buf, &disk_key, 0); | 213 | btrfs_item_key(buf, &disk_key, 0); |
| 216 | else | 214 | else |
| @@ -1008,7 +1006,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
| 1008 | int wret; | 1006 | int wret; |
| 1009 | int pslot; | 1007 | int pslot; |
| 1010 | int orig_slot = path->slots[level]; | 1008 | int orig_slot = path->slots[level]; |
| 1011 | int err_on_enospc = 0; | ||
| 1012 | u64 orig_ptr; | 1009 | u64 orig_ptr; |
| 1013 | 1010 | ||
| 1014 | if (level == 0) | 1011 | if (level == 0) |
| @@ -1071,8 +1068,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
| 1071 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) | 1068 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) |
| 1072 | return 0; | 1069 | return 0; |
| 1073 | 1070 | ||
| 1074 | if (btrfs_header_nritems(mid) < 2) | 1071 | btrfs_header_nritems(mid); |
| 1075 | err_on_enospc = 1; | ||
| 1076 | 1072 | ||
| 1077 | left = read_node_slot(root, parent, pslot - 1); | 1073 | left = read_node_slot(root, parent, pslot - 1); |
| 1078 | if (left) { | 1074 | if (left) { |
| @@ -1103,8 +1099,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
| 1103 | wret = push_node_left(trans, root, left, mid, 1); | 1099 | wret = push_node_left(trans, root, left, mid, 1); |
| 1104 | if (wret < 0) | 1100 | if (wret < 0) |
| 1105 | ret = wret; | 1101 | ret = wret; |
| 1106 | if (btrfs_header_nritems(mid) < 2) | 1102 | btrfs_header_nritems(mid); |
| 1107 | err_on_enospc = 1; | ||
| 1108 | } | 1103 | } |
| 1109 | 1104 | ||
| 1110 | /* | 1105 | /* |
| @@ -1224,14 +1219,12 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
| 1224 | int wret; | 1219 | int wret; |
| 1225 | int pslot; | 1220 | int pslot; |
| 1226 | int orig_slot = path->slots[level]; | 1221 | int orig_slot = path->slots[level]; |
| 1227 | u64 orig_ptr; | ||
| 1228 | 1222 | ||
| 1229 | if (level == 0) | 1223 | if (level == 0) |
| 1230 | return 1; | 1224 | return 1; |
| 1231 | 1225 | ||
| 1232 | mid = path->nodes[level]; | 1226 | mid = path->nodes[level]; |
| 1233 | WARN_ON(btrfs_header_generation(mid) != trans->transid); | 1227 | WARN_ON(btrfs_header_generation(mid) != trans->transid); |
| 1234 | orig_ptr = btrfs_node_blockptr(mid, orig_slot); | ||
| 1235 | 1228 | ||
| 1236 | if (level < BTRFS_MAX_LEVEL - 1) | 1229 | if (level < BTRFS_MAX_LEVEL - 1) |
| 1237 | parent = path->nodes[level + 1]; | 1230 | parent = path->nodes[level + 1]; |
| @@ -1577,13 +1570,33 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
| 1577 | blocksize = btrfs_level_size(root, level - 1); | 1570 | blocksize = btrfs_level_size(root, level - 1); |
| 1578 | 1571 | ||
| 1579 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); | 1572 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
| 1580 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | 1573 | if (tmp) { |
| 1581 | /* | 1574 | if (btrfs_buffer_uptodate(tmp, 0)) { |
| 1582 | * we found an up to date block without sleeping, return | 1575 | if (btrfs_buffer_uptodate(tmp, gen)) { |
| 1583 | * right away | 1576 | /* |
| 1584 | */ | 1577 | * we found an up to date block without |
| 1585 | *eb_ret = tmp; | 1578 | * sleeping, return |
| 1586 | return 0; | 1579 | * right away |
| 1580 | */ | ||
| 1581 | *eb_ret = tmp; | ||
| 1582 | return 0; | ||
| 1583 | } | ||
| 1584 | /* the pages were up to date, but we failed | ||
| 1585 | * the generation number check. Do a full | ||
| 1586 | * read for the generation number that is correct. | ||
| 1587 | * We must do this without dropping locks so | ||
| 1588 | * we can trust our generation number | ||
| 1589 | */ | ||
| 1590 | free_extent_buffer(tmp); | ||
| 1591 | tmp = read_tree_block(root, blocknr, blocksize, gen); | ||
| 1592 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | ||
| 1593 | *eb_ret = tmp; | ||
| 1594 | return 0; | ||
| 1595 | } | ||
| 1596 | free_extent_buffer(tmp); | ||
| 1597 | btrfs_release_path(NULL, p); | ||
| 1598 | return -EIO; | ||
| 1599 | } | ||
| 1587 | } | 1600 | } |
| 1588 | 1601 | ||
| 1589 | /* | 1602 | /* |
| @@ -1596,8 +1609,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
| 1596 | btrfs_unlock_up_safe(p, level + 1); | 1609 | btrfs_unlock_up_safe(p, level + 1); |
| 1597 | btrfs_set_path_blocking(p); | 1610 | btrfs_set_path_blocking(p); |
| 1598 | 1611 | ||
| 1599 | if (tmp) | 1612 | free_extent_buffer(tmp); |
| 1600 | free_extent_buffer(tmp); | ||
| 1601 | if (p->reada) | 1613 | if (p->reada) |
| 1602 | reada_for_search(root, p, level, slot, key->objectid); | 1614 | reada_for_search(root, p, level, slot, key->objectid); |
| 1603 | 1615 | ||
| @@ -2548,7 +2560,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, | |||
| 2548 | { | 2560 | { |
| 2549 | struct btrfs_disk_key disk_key; | 2561 | struct btrfs_disk_key disk_key; |
| 2550 | struct extent_buffer *right = path->nodes[0]; | 2562 | struct extent_buffer *right = path->nodes[0]; |
| 2551 | int slot; | ||
| 2552 | int i; | 2563 | int i; |
| 2553 | int push_space = 0; | 2564 | int push_space = 0; |
| 2554 | int push_items = 0; | 2565 | int push_items = 0; |
| @@ -2560,8 +2571,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, | |||
| 2560 | u32 this_item_size; | 2571 | u32 this_item_size; |
| 2561 | u32 old_left_item_size; | 2572 | u32 old_left_item_size; |
| 2562 | 2573 | ||
| 2563 | slot = path->slots[1]; | ||
| 2564 | |||
| 2565 | if (empty) | 2574 | if (empty) |
| 2566 | nr = min(right_nritems, max_slot); | 2575 | nr = min(right_nritems, max_slot); |
| 2567 | else | 2576 | else |
| @@ -3330,7 +3339,6 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, | |||
| 3330 | { | 3339 | { |
| 3331 | int ret = 0; | 3340 | int ret = 0; |
| 3332 | int slot; | 3341 | int slot; |
| 3333 | int slot_orig; | ||
| 3334 | struct extent_buffer *leaf; | 3342 | struct extent_buffer *leaf; |
| 3335 | struct btrfs_item *item; | 3343 | struct btrfs_item *item; |
| 3336 | u32 nritems; | 3344 | u32 nritems; |
| @@ -3340,7 +3348,6 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, | |||
| 3340 | unsigned int size_diff; | 3348 | unsigned int size_diff; |
| 3341 | int i; | 3349 | int i; |
| 3342 | 3350 | ||
| 3343 | slot_orig = path->slots[0]; | ||
| 3344 | leaf = path->nodes[0]; | 3351 | leaf = path->nodes[0]; |
| 3345 | slot = path->slots[0]; | 3352 | slot = path->slots[0]; |
| 3346 | 3353 | ||
| @@ -3445,7 +3452,6 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans, | |||
| 3445 | { | 3452 | { |
| 3446 | int ret = 0; | 3453 | int ret = 0; |
| 3447 | int slot; | 3454 | int slot; |
| 3448 | int slot_orig; | ||
| 3449 | struct extent_buffer *leaf; | 3455 | struct extent_buffer *leaf; |
| 3450 | struct btrfs_item *item; | 3456 | struct btrfs_item *item; |
| 3451 | u32 nritems; | 3457 | u32 nritems; |
| @@ -3454,7 +3460,6 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans, | |||
| 3454 | unsigned int old_size; | 3460 | unsigned int old_size; |
| 3455 | int i; | 3461 | int i; |
| 3456 | 3462 | ||
| 3457 | slot_orig = path->slots[0]; | ||
| 3458 | leaf = path->nodes[0]; | 3463 | leaf = path->nodes[0]; |
| 3459 | 3464 | ||
| 3460 | nritems = btrfs_header_nritems(leaf); | 3465 | nritems = btrfs_header_nritems(leaf); |
| @@ -3787,7 +3792,6 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | |||
| 3787 | struct btrfs_key *cpu_key, u32 *data_size, | 3792 | struct btrfs_key *cpu_key, u32 *data_size, |
| 3788 | int nr) | 3793 | int nr) |
| 3789 | { | 3794 | { |
| 3790 | struct extent_buffer *leaf; | ||
| 3791 | int ret = 0; | 3795 | int ret = 0; |
| 3792 | int slot; | 3796 | int slot; |
| 3793 | int i; | 3797 | int i; |
| @@ -3804,7 +3808,6 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | |||
| 3804 | if (ret < 0) | 3808 | if (ret < 0) |
| 3805 | goto out; | 3809 | goto out; |
| 3806 | 3810 | ||
| 3807 | leaf = path->nodes[0]; | ||
| 3808 | slot = path->slots[0]; | 3811 | slot = path->slots[0]; |
| 3809 | BUG_ON(slot < 0); | 3812 | BUG_ON(slot < 0); |
| 3810 | 3813 | ||
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index eaf286abad17..8db9234f6b41 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -99,6 +99,9 @@ struct btrfs_ordered_sum; | |||
| 99 | */ | 99 | */ |
| 100 | #define BTRFS_EXTENT_CSUM_OBJECTID -10ULL | 100 | #define BTRFS_EXTENT_CSUM_OBJECTID -10ULL |
| 101 | 101 | ||
| 102 | /* For storing free space cache */ | ||
| 103 | #define BTRFS_FREE_SPACE_OBJECTID -11ULL | ||
| 104 | |||
| 102 | /* dummy objectid represents multiple objectids */ | 105 | /* dummy objectid represents multiple objectids */ |
| 103 | #define BTRFS_MULTIPLE_OBJECTIDS -255ULL | 106 | #define BTRFS_MULTIPLE_OBJECTIDS -255ULL |
| 104 | 107 | ||
| @@ -265,6 +268,22 @@ struct btrfs_chunk { | |||
| 265 | /* additional stripes go here */ | 268 | /* additional stripes go here */ |
| 266 | } __attribute__ ((__packed__)); | 269 | } __attribute__ ((__packed__)); |
| 267 | 270 | ||
| 271 | #define BTRFS_FREE_SPACE_EXTENT 1 | ||
| 272 | #define BTRFS_FREE_SPACE_BITMAP 2 | ||
| 273 | |||
| 274 | struct btrfs_free_space_entry { | ||
| 275 | __le64 offset; | ||
| 276 | __le64 bytes; | ||
| 277 | u8 type; | ||
| 278 | } __attribute__ ((__packed__)); | ||
| 279 | |||
| 280 | struct btrfs_free_space_header { | ||
| 281 | struct btrfs_disk_key location; | ||
| 282 | __le64 generation; | ||
| 283 | __le64 num_entries; | ||
| 284 | __le64 num_bitmaps; | ||
| 285 | } __attribute__ ((__packed__)); | ||
| 286 | |||
| 268 | static inline unsigned long btrfs_chunk_item_size(int num_stripes) | 287 | static inline unsigned long btrfs_chunk_item_size(int num_stripes) |
| 269 | { | 288 | { |
| 270 | BUG_ON(num_stripes == 0); | 289 | BUG_ON(num_stripes == 0); |
| @@ -365,8 +384,10 @@ struct btrfs_super_block { | |||
| 365 | 384 | ||
| 366 | char label[BTRFS_LABEL_SIZE]; | 385 | char label[BTRFS_LABEL_SIZE]; |
| 367 | 386 | ||
| 387 | __le64 cache_generation; | ||
| 388 | |||
| 368 | /* future expansion */ | 389 | /* future expansion */ |
| 369 | __le64 reserved[32]; | 390 | __le64 reserved[31]; |
| 370 | u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; | 391 | u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; |
| 371 | } __attribute__ ((__packed__)); | 392 | } __attribute__ ((__packed__)); |
| 372 | 393 | ||
| @@ -375,13 +396,15 @@ struct btrfs_super_block { | |||
| 375 | * ones specified below then we will fail to mount | 396 | * ones specified below then we will fail to mount |
| 376 | */ | 397 | */ |
| 377 | #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) | 398 | #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) |
| 378 | #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (2ULL << 0) | 399 | #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) |
| 400 | #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) | ||
| 379 | 401 | ||
| 380 | #define BTRFS_FEATURE_COMPAT_SUPP 0ULL | 402 | #define BTRFS_FEATURE_COMPAT_SUPP 0ULL |
| 381 | #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL | 403 | #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL |
| 382 | #define BTRFS_FEATURE_INCOMPAT_SUPP \ | 404 | #define BTRFS_FEATURE_INCOMPAT_SUPP \ |
| 383 | (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ | 405 | (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ |
| 384 | BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL) | 406 | BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ |
| 407 | BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) | ||
| 385 | 408 | ||
| 386 | /* | 409 | /* |
| 387 | * A leaf is full of items. offset and size tell us where to find | 410 | * A leaf is full of items. offset and size tell us where to find |
| @@ -675,7 +698,8 @@ struct btrfs_block_group_item { | |||
| 675 | struct btrfs_space_info { | 698 | struct btrfs_space_info { |
| 676 | u64 flags; | 699 | u64 flags; |
| 677 | 700 | ||
| 678 | u64 total_bytes; /* total bytes in the space */ | 701 | u64 total_bytes; /* total bytes in the space, |
| 702 | this doesn't take mirrors into account */ | ||
| 679 | u64 bytes_used; /* total bytes used, | 703 | u64 bytes_used; /* total bytes used, |
| 680 | this does't take mirrors into account */ | 704 | this does't take mirrors into account */ |
| 681 | u64 bytes_pinned; /* total bytes pinned, will be freed when the | 705 | u64 bytes_pinned; /* total bytes pinned, will be freed when the |
| @@ -687,6 +711,8 @@ struct btrfs_space_info { | |||
| 687 | u64 bytes_may_use; /* number of bytes that may be used for | 711 | u64 bytes_may_use; /* number of bytes that may be used for |
| 688 | delalloc/allocations */ | 712 | delalloc/allocations */ |
| 689 | u64 disk_used; /* total bytes used on disk */ | 713 | u64 disk_used; /* total bytes used on disk */ |
| 714 | u64 disk_total; /* total bytes on disk, takes mirrors into | ||
| 715 | account */ | ||
| 690 | 716 | ||
| 691 | int full; /* indicates that we cannot allocate any more | 717 | int full; /* indicates that we cannot allocate any more |
| 692 | chunks for this space */ | 718 | chunks for this space */ |
| @@ -750,6 +776,14 @@ enum btrfs_caching_type { | |||
| 750 | BTRFS_CACHE_FINISHED = 2, | 776 | BTRFS_CACHE_FINISHED = 2, |
| 751 | }; | 777 | }; |
| 752 | 778 | ||
| 779 | enum btrfs_disk_cache_state { | ||
| 780 | BTRFS_DC_WRITTEN = 0, | ||
| 781 | BTRFS_DC_ERROR = 1, | ||
| 782 | BTRFS_DC_CLEAR = 2, | ||
| 783 | BTRFS_DC_SETUP = 3, | ||
| 784 | BTRFS_DC_NEED_WRITE = 4, | ||
| 785 | }; | ||
| 786 | |||
| 753 | struct btrfs_caching_control { | 787 | struct btrfs_caching_control { |
| 754 | struct list_head list; | 788 | struct list_head list; |
| 755 | struct mutex mutex; | 789 | struct mutex mutex; |
| @@ -763,6 +797,7 @@ struct btrfs_block_group_cache { | |||
| 763 | struct btrfs_key key; | 797 | struct btrfs_key key; |
| 764 | struct btrfs_block_group_item item; | 798 | struct btrfs_block_group_item item; |
| 765 | struct btrfs_fs_info *fs_info; | 799 | struct btrfs_fs_info *fs_info; |
| 800 | struct inode *inode; | ||
| 766 | spinlock_t lock; | 801 | spinlock_t lock; |
| 767 | u64 pinned; | 802 | u64 pinned; |
| 768 | u64 reserved; | 803 | u64 reserved; |
| @@ -773,8 +808,11 @@ struct btrfs_block_group_cache { | |||
| 773 | int extents_thresh; | 808 | int extents_thresh; |
| 774 | int free_extents; | 809 | int free_extents; |
| 775 | int total_bitmaps; | 810 | int total_bitmaps; |
| 776 | int ro; | 811 | int ro:1; |
| 777 | int dirty; | 812 | int dirty:1; |
| 813 | int iref:1; | ||
| 814 | |||
| 815 | int disk_cache_state; | ||
| 778 | 816 | ||
| 779 | /* cache tracking stuff */ | 817 | /* cache tracking stuff */ |
| 780 | int cached; | 818 | int cached; |
| @@ -863,6 +901,7 @@ struct btrfs_fs_info { | |||
| 863 | struct btrfs_transaction *running_transaction; | 901 | struct btrfs_transaction *running_transaction; |
| 864 | wait_queue_head_t transaction_throttle; | 902 | wait_queue_head_t transaction_throttle; |
| 865 | wait_queue_head_t transaction_wait; | 903 | wait_queue_head_t transaction_wait; |
| 904 | wait_queue_head_t transaction_blocked_wait; | ||
| 866 | wait_queue_head_t async_submit_wait; | 905 | wait_queue_head_t async_submit_wait; |
| 867 | 906 | ||
| 868 | struct btrfs_super_block super_copy; | 907 | struct btrfs_super_block super_copy; |
| @@ -949,6 +988,7 @@ struct btrfs_fs_info { | |||
| 949 | struct btrfs_workers endio_meta_workers; | 988 | struct btrfs_workers endio_meta_workers; |
| 950 | struct btrfs_workers endio_meta_write_workers; | 989 | struct btrfs_workers endio_meta_write_workers; |
| 951 | struct btrfs_workers endio_write_workers; | 990 | struct btrfs_workers endio_write_workers; |
| 991 | struct btrfs_workers endio_freespace_worker; | ||
| 952 | struct btrfs_workers submit_workers; | 992 | struct btrfs_workers submit_workers; |
| 953 | /* | 993 | /* |
| 954 | * fixup workers take dirty pages that didn't properly go through | 994 | * fixup workers take dirty pages that didn't properly go through |
| @@ -1192,6 +1232,9 @@ struct btrfs_root { | |||
| 1192 | #define BTRFS_MOUNT_NOSSD (1 << 9) | 1232 | #define BTRFS_MOUNT_NOSSD (1 << 9) |
| 1193 | #define BTRFS_MOUNT_DISCARD (1 << 10) | 1233 | #define BTRFS_MOUNT_DISCARD (1 << 10) |
| 1194 | #define BTRFS_MOUNT_FORCE_COMPRESS (1 << 11) | 1234 | #define BTRFS_MOUNT_FORCE_COMPRESS (1 << 11) |
| 1235 | #define BTRFS_MOUNT_SPACE_CACHE (1 << 12) | ||
| 1236 | #define BTRFS_MOUNT_CLEAR_CACHE (1 << 13) | ||
| 1237 | #define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14) | ||
| 1195 | 1238 | ||
| 1196 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) | 1239 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) |
| 1197 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) | 1240 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) |
| @@ -1665,6 +1708,27 @@ static inline void btrfs_set_dir_item_key(struct extent_buffer *eb, | |||
| 1665 | write_eb_member(eb, item, struct btrfs_dir_item, location, key); | 1708 | write_eb_member(eb, item, struct btrfs_dir_item, location, key); |
| 1666 | } | 1709 | } |
| 1667 | 1710 | ||
| 1711 | BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header, | ||
| 1712 | num_entries, 64); | ||
| 1713 | BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header, | ||
| 1714 | num_bitmaps, 64); | ||
| 1715 | BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header, | ||
| 1716 | generation, 64); | ||
| 1717 | |||
| 1718 | static inline void btrfs_free_space_key(struct extent_buffer *eb, | ||
| 1719 | struct btrfs_free_space_header *h, | ||
| 1720 | struct btrfs_disk_key *key) | ||
| 1721 | { | ||
| 1722 | read_eb_member(eb, h, struct btrfs_free_space_header, location, key); | ||
| 1723 | } | ||
| 1724 | |||
| 1725 | static inline void btrfs_set_free_space_key(struct extent_buffer *eb, | ||
| 1726 | struct btrfs_free_space_header *h, | ||
| 1727 | struct btrfs_disk_key *key) | ||
| 1728 | { | ||
| 1729 | write_eb_member(eb, h, struct btrfs_free_space_header, location, key); | ||
| 1730 | } | ||
| 1731 | |||
| 1668 | /* struct btrfs_disk_key */ | 1732 | /* struct btrfs_disk_key */ |
| 1669 | BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key, | 1733 | BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key, |
| 1670 | objectid, 64); | 1734 | objectid, 64); |
| @@ -1876,6 +1940,8 @@ BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block, | |||
| 1876 | incompat_flags, 64); | 1940 | incompat_flags, 64); |
| 1877 | BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block, | 1941 | BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block, |
| 1878 | csum_type, 16); | 1942 | csum_type, 16); |
| 1943 | BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block, | ||
| 1944 | cache_generation, 64); | ||
| 1879 | 1945 | ||
| 1880 | static inline int btrfs_super_csum_size(struct btrfs_super_block *s) | 1946 | static inline int btrfs_super_csum_size(struct btrfs_super_block *s) |
| 1881 | { | 1947 | { |
| @@ -1988,6 +2054,12 @@ static inline struct dentry *fdentry(struct file *file) | |||
| 1988 | return file->f_path.dentry; | 2054 | return file->f_path.dentry; |
| 1989 | } | 2055 | } |
| 1990 | 2056 | ||
| 2057 | static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info) | ||
| 2058 | { | ||
| 2059 | return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) && | ||
| 2060 | (space_info->flags & BTRFS_BLOCK_GROUP_DATA)); | ||
| 2061 | } | ||
| 2062 | |||
| 1991 | /* extent-tree.c */ | 2063 | /* extent-tree.c */ |
| 1992 | void btrfs_put_block_group(struct btrfs_block_group_cache *cache); | 2064 | void btrfs_put_block_group(struct btrfs_block_group_cache *cache); |
| 1993 | int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, | 2065 | int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, |
| @@ -2079,7 +2151,7 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes); | |||
| 2079 | void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes); | 2151 | void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes); |
| 2080 | int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, | 2152 | int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, |
| 2081 | struct btrfs_root *root, | 2153 | struct btrfs_root *root, |
| 2082 | int num_items, int *retries); | 2154 | int num_items); |
| 2083 | void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, | 2155 | void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, |
| 2084 | struct btrfs_root *root); | 2156 | struct btrfs_root *root); |
| 2085 | int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, | 2157 | int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, |
| @@ -2100,7 +2172,7 @@ void btrfs_add_durable_block_rsv(struct btrfs_fs_info *fs_info, | |||
| 2100 | int btrfs_block_rsv_add(struct btrfs_trans_handle *trans, | 2172 | int btrfs_block_rsv_add(struct btrfs_trans_handle *trans, |
| 2101 | struct btrfs_root *root, | 2173 | struct btrfs_root *root, |
| 2102 | struct btrfs_block_rsv *block_rsv, | 2174 | struct btrfs_block_rsv *block_rsv, |
| 2103 | u64 num_bytes, int *retries); | 2175 | u64 num_bytes); |
| 2104 | int btrfs_block_rsv_check(struct btrfs_trans_handle *trans, | 2176 | int btrfs_block_rsv_check(struct btrfs_trans_handle *trans, |
| 2105 | struct btrfs_root *root, | 2177 | struct btrfs_root *root, |
| 2106 | struct btrfs_block_rsv *block_rsv, | 2178 | struct btrfs_block_rsv *block_rsv, |
| @@ -2115,6 +2187,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root, | |||
| 2115 | struct btrfs_block_group_cache *cache); | 2187 | struct btrfs_block_group_cache *cache); |
| 2116 | int btrfs_set_block_group_rw(struct btrfs_root *root, | 2188 | int btrfs_set_block_group_rw(struct btrfs_root *root, |
| 2117 | struct btrfs_block_group_cache *cache); | 2189 | struct btrfs_block_group_cache *cache); |
| 2190 | void btrfs_put_block_group_cache(struct btrfs_fs_info *info); | ||
| 2118 | /* ctree.c */ | 2191 | /* ctree.c */ |
| 2119 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, | 2192 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, |
| 2120 | int level, int *slot); | 2193 | int level, int *slot); |
| @@ -2373,7 +2446,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, | |||
| 2373 | u32 min_type); | 2446 | u32 min_type); |
| 2374 | 2447 | ||
| 2375 | int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput); | 2448 | int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput); |
| 2376 | int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput); | 2449 | int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput, |
| 2450 | int sync); | ||
| 2377 | int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, | 2451 | int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, |
| 2378 | struct extent_state **cached_state); | 2452 | struct extent_state **cached_state); |
| 2379 | int btrfs_writepages(struct address_space *mapping, | 2453 | int btrfs_writepages(struct address_space *mapping, |
| @@ -2426,6 +2500,10 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root); | |||
| 2426 | int btrfs_prealloc_file_range(struct inode *inode, int mode, | 2500 | int btrfs_prealloc_file_range(struct inode *inode, int mode, |
| 2427 | u64 start, u64 num_bytes, u64 min_size, | 2501 | u64 start, u64 num_bytes, u64 min_size, |
| 2428 | loff_t actual_len, u64 *alloc_hint); | 2502 | loff_t actual_len, u64 *alloc_hint); |
| 2503 | int btrfs_prealloc_file_range_trans(struct inode *inode, | ||
| 2504 | struct btrfs_trans_handle *trans, int mode, | ||
| 2505 | u64 start, u64 num_bytes, u64 min_size, | ||
| 2506 | loff_t actual_len, u64 *alloc_hint); | ||
| 2429 | extern const struct dentry_operations btrfs_dentry_operations; | 2507 | extern const struct dentry_operations btrfs_dentry_operations; |
| 2430 | 2508 | ||
| 2431 | /* ioctl.c */ | 2509 | /* ioctl.c */ |
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index e9103b3baa49..f0cad5ae5be7 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
| @@ -427,5 +427,5 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, | |||
| 427 | ret = btrfs_truncate_item(trans, root, path, | 427 | ret = btrfs_truncate_item(trans, root, path, |
| 428 | item_len - sub_item_len, 1); | 428 | item_len - sub_item_len, 1); |
| 429 | } | 429 | } |
| 430 | return 0; | 430 | return ret; |
| 431 | } | 431 | } |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 5e789f4a3ed0..fb827d0d7181 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -338,7 +338,6 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
| 338 | struct extent_io_tree *tree; | 338 | struct extent_io_tree *tree; |
| 339 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; | 339 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; |
| 340 | u64 found_start; | 340 | u64 found_start; |
| 341 | int found_level; | ||
| 342 | unsigned long len; | 341 | unsigned long len; |
| 343 | struct extent_buffer *eb; | 342 | struct extent_buffer *eb; |
| 344 | int ret; | 343 | int ret; |
| @@ -369,8 +368,6 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
| 369 | WARN_ON(1); | 368 | WARN_ON(1); |
| 370 | goto err; | 369 | goto err; |
| 371 | } | 370 | } |
| 372 | found_level = btrfs_header_level(eb); | ||
| 373 | |||
| 374 | csum_tree_block(root, eb, 0); | 371 | csum_tree_block(root, eb, 0); |
| 375 | err: | 372 | err: |
| 376 | free_extent_buffer(eb); | 373 | free_extent_buffer(eb); |
| @@ -481,9 +478,12 @@ static void end_workqueue_bio(struct bio *bio, int err) | |||
| 481 | end_io_wq->work.flags = 0; | 478 | end_io_wq->work.flags = 0; |
| 482 | 479 | ||
| 483 | if (bio->bi_rw & REQ_WRITE) { | 480 | if (bio->bi_rw & REQ_WRITE) { |
| 484 | if (end_io_wq->metadata) | 481 | if (end_io_wq->metadata == 1) |
| 485 | btrfs_queue_worker(&fs_info->endio_meta_write_workers, | 482 | btrfs_queue_worker(&fs_info->endio_meta_write_workers, |
| 486 | &end_io_wq->work); | 483 | &end_io_wq->work); |
| 484 | else if (end_io_wq->metadata == 2) | ||
| 485 | btrfs_queue_worker(&fs_info->endio_freespace_worker, | ||
| 486 | &end_io_wq->work); | ||
| 487 | else | 487 | else |
| 488 | btrfs_queue_worker(&fs_info->endio_write_workers, | 488 | btrfs_queue_worker(&fs_info->endio_write_workers, |
| 489 | &end_io_wq->work); | 489 | &end_io_wq->work); |
| @@ -497,6 +497,13 @@ static void end_workqueue_bio(struct bio *bio, int err) | |||
| 497 | } | 497 | } |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | /* | ||
| 501 | * For the metadata arg you want | ||
| 502 | * | ||
| 503 | * 0 - if data | ||
| 504 | * 1 - if normal metadta | ||
| 505 | * 2 - if writing to the free space cache area | ||
| 506 | */ | ||
| 500 | int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, | 507 | int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, |
| 501 | int metadata) | 508 | int metadata) |
| 502 | { | 509 | { |
| @@ -533,11 +540,9 @@ int btrfs_congested_async(struct btrfs_fs_info *info, int iodone) | |||
| 533 | 540 | ||
| 534 | static void run_one_async_start(struct btrfs_work *work) | 541 | static void run_one_async_start(struct btrfs_work *work) |
| 535 | { | 542 | { |
| 536 | struct btrfs_fs_info *fs_info; | ||
| 537 | struct async_submit_bio *async; | 543 | struct async_submit_bio *async; |
| 538 | 544 | ||
| 539 | async = container_of(work, struct async_submit_bio, work); | 545 | async = container_of(work, struct async_submit_bio, work); |
| 540 | fs_info = BTRFS_I(async->inode)->root->fs_info; | ||
| 541 | async->submit_bio_start(async->inode, async->rw, async->bio, | 546 | async->submit_bio_start(async->inode, async->rw, async->bio, |
| 542 | async->mirror_num, async->bio_flags, | 547 | async->mirror_num, async->bio_flags, |
| 543 | async->bio_offset); | 548 | async->bio_offset); |
| @@ -850,12 +855,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | |||
| 850 | u32 blocksize, u64 parent_transid) | 855 | u32 blocksize, u64 parent_transid) |
| 851 | { | 856 | { |
| 852 | struct extent_buffer *buf = NULL; | 857 | struct extent_buffer *buf = NULL; |
| 853 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
| 854 | struct extent_io_tree *io_tree; | ||
| 855 | int ret; | 858 | int ret; |
| 856 | 859 | ||
| 857 | io_tree = &BTRFS_I(btree_inode)->io_tree; | ||
| 858 | |||
| 859 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); | 860 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); |
| 860 | if (!buf) | 861 | if (!buf) |
| 861 | return NULL; | 862 | return NULL; |
| @@ -1377,7 +1378,6 @@ static int bio_ready_for_csum(struct bio *bio) | |||
| 1377 | u64 start = 0; | 1378 | u64 start = 0; |
| 1378 | struct page *page; | 1379 | struct page *page; |
| 1379 | struct extent_io_tree *io_tree = NULL; | 1380 | struct extent_io_tree *io_tree = NULL; |
| 1380 | struct btrfs_fs_info *info = NULL; | ||
| 1381 | struct bio_vec *bvec; | 1381 | struct bio_vec *bvec; |
| 1382 | int i; | 1382 | int i; |
| 1383 | int ret; | 1383 | int ret; |
| @@ -1396,7 +1396,6 @@ static int bio_ready_for_csum(struct bio *bio) | |||
| 1396 | buf_len = page->private >> 2; | 1396 | buf_len = page->private >> 2; |
| 1397 | start = page_offset(page) + bvec->bv_offset; | 1397 | start = page_offset(page) + bvec->bv_offset; |
| 1398 | io_tree = &BTRFS_I(page->mapping->host)->io_tree; | 1398 | io_tree = &BTRFS_I(page->mapping->host)->io_tree; |
| 1399 | info = BTRFS_I(page->mapping->host)->root->fs_info; | ||
| 1400 | } | 1399 | } |
| 1401 | /* are we fully contained in this bio? */ | 1400 | /* are we fully contained in this bio? */ |
| 1402 | if (buf_len <= length) | 1401 | if (buf_len <= length) |
| @@ -1680,12 +1679,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1680 | 1679 | ||
| 1681 | init_waitqueue_head(&fs_info->transaction_throttle); | 1680 | init_waitqueue_head(&fs_info->transaction_throttle); |
| 1682 | init_waitqueue_head(&fs_info->transaction_wait); | 1681 | init_waitqueue_head(&fs_info->transaction_wait); |
| 1682 | init_waitqueue_head(&fs_info->transaction_blocked_wait); | ||
| 1683 | init_waitqueue_head(&fs_info->async_submit_wait); | 1683 | init_waitqueue_head(&fs_info->async_submit_wait); |
| 1684 | 1684 | ||
| 1685 | __setup_root(4096, 4096, 4096, 4096, tree_root, | 1685 | __setup_root(4096, 4096, 4096, 4096, tree_root, |
| 1686 | fs_info, BTRFS_ROOT_TREE_OBJECTID); | 1686 | fs_info, BTRFS_ROOT_TREE_OBJECTID); |
| 1687 | 1687 | ||
| 1688 | |||
| 1689 | bh = btrfs_read_dev_super(fs_devices->latest_bdev); | 1688 | bh = btrfs_read_dev_super(fs_devices->latest_bdev); |
| 1690 | if (!bh) | 1689 | if (!bh) |
| 1691 | goto fail_iput; | 1690 | goto fail_iput; |
| @@ -1775,6 +1774,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1775 | btrfs_init_workers(&fs_info->endio_write_workers, "endio-write", | 1774 | btrfs_init_workers(&fs_info->endio_write_workers, "endio-write", |
| 1776 | fs_info->thread_pool_size, | 1775 | fs_info->thread_pool_size, |
| 1777 | &fs_info->generic_worker); | 1776 | &fs_info->generic_worker); |
| 1777 | btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write", | ||
| 1778 | 1, &fs_info->generic_worker); | ||
| 1778 | 1779 | ||
| 1779 | /* | 1780 | /* |
| 1780 | * endios are largely parallel and should have a very | 1781 | * endios are largely parallel and should have a very |
| @@ -1795,6 +1796,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1795 | btrfs_start_workers(&fs_info->endio_meta_workers, 1); | 1796 | btrfs_start_workers(&fs_info->endio_meta_workers, 1); |
| 1796 | btrfs_start_workers(&fs_info->endio_meta_write_workers, 1); | 1797 | btrfs_start_workers(&fs_info->endio_meta_write_workers, 1); |
| 1797 | btrfs_start_workers(&fs_info->endio_write_workers, 1); | 1798 | btrfs_start_workers(&fs_info->endio_write_workers, 1); |
| 1799 | btrfs_start_workers(&fs_info->endio_freespace_worker, 1); | ||
| 1798 | 1800 | ||
| 1799 | fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); | 1801 | fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); |
| 1800 | fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, | 1802 | fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, |
| @@ -1993,6 +1995,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1993 | if (!(sb->s_flags & MS_RDONLY)) { | 1995 | if (!(sb->s_flags & MS_RDONLY)) { |
| 1994 | down_read(&fs_info->cleanup_work_sem); | 1996 | down_read(&fs_info->cleanup_work_sem); |
| 1995 | btrfs_orphan_cleanup(fs_info->fs_root); | 1997 | btrfs_orphan_cleanup(fs_info->fs_root); |
| 1998 | btrfs_orphan_cleanup(fs_info->tree_root); | ||
| 1996 | up_read(&fs_info->cleanup_work_sem); | 1999 | up_read(&fs_info->cleanup_work_sem); |
| 1997 | } | 2000 | } |
| 1998 | 2001 | ||
| @@ -2035,6 +2038,7 @@ fail_sb_buffer: | |||
| 2035 | btrfs_stop_workers(&fs_info->endio_meta_workers); | 2038 | btrfs_stop_workers(&fs_info->endio_meta_workers); |
| 2036 | btrfs_stop_workers(&fs_info->endio_meta_write_workers); | 2039 | btrfs_stop_workers(&fs_info->endio_meta_write_workers); |
| 2037 | btrfs_stop_workers(&fs_info->endio_write_workers); | 2040 | btrfs_stop_workers(&fs_info->endio_write_workers); |
| 2041 | btrfs_stop_workers(&fs_info->endio_freespace_worker); | ||
| 2038 | btrfs_stop_workers(&fs_info->submit_workers); | 2042 | btrfs_stop_workers(&fs_info->submit_workers); |
| 2039 | fail_iput: | 2043 | fail_iput: |
| 2040 | invalidate_inode_pages2(fs_info->btree_inode->i_mapping); | 2044 | invalidate_inode_pages2(fs_info->btree_inode->i_mapping); |
| @@ -2410,6 +2414,7 @@ int close_ctree(struct btrfs_root *root) | |||
| 2410 | fs_info->closing = 1; | 2414 | fs_info->closing = 1; |
| 2411 | smp_mb(); | 2415 | smp_mb(); |
| 2412 | 2416 | ||
| 2417 | btrfs_put_block_group_cache(fs_info); | ||
| 2413 | if (!(fs_info->sb->s_flags & MS_RDONLY)) { | 2418 | if (!(fs_info->sb->s_flags & MS_RDONLY)) { |
| 2414 | ret = btrfs_commit_super(root); | 2419 | ret = btrfs_commit_super(root); |
| 2415 | if (ret) | 2420 | if (ret) |
| @@ -2456,6 +2461,7 @@ int close_ctree(struct btrfs_root *root) | |||
| 2456 | btrfs_stop_workers(&fs_info->endio_meta_workers); | 2461 | btrfs_stop_workers(&fs_info->endio_meta_workers); |
| 2457 | btrfs_stop_workers(&fs_info->endio_meta_write_workers); | 2462 | btrfs_stop_workers(&fs_info->endio_meta_write_workers); |
| 2458 | btrfs_stop_workers(&fs_info->endio_write_workers); | 2463 | btrfs_stop_workers(&fs_info->endio_write_workers); |
| 2464 | btrfs_stop_workers(&fs_info->endio_freespace_worker); | ||
| 2459 | btrfs_stop_workers(&fs_info->submit_workers); | 2465 | btrfs_stop_workers(&fs_info->submit_workers); |
| 2460 | 2466 | ||
| 2461 | btrfs_close_devices(fs_info->fs_devices); | 2467 | btrfs_close_devices(fs_info->fs_devices); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0b81ecdb101c..0c097f3aec41 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -242,6 +242,12 @@ get_caching_control(struct btrfs_block_group_cache *cache) | |||
| 242 | return NULL; | 242 | return NULL; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | /* We're loading it the fast way, so we don't have a caching_ctl. */ | ||
| 246 | if (!cache->caching_ctl) { | ||
| 247 | spin_unlock(&cache->lock); | ||
| 248 | return NULL; | ||
| 249 | } | ||
| 250 | |||
| 245 | ctl = cache->caching_ctl; | 251 | ctl = cache->caching_ctl; |
| 246 | atomic_inc(&ctl->count); | 252 | atomic_inc(&ctl->count); |
| 247 | spin_unlock(&cache->lock); | 253 | spin_unlock(&cache->lock); |
| @@ -421,7 +427,9 @@ err: | |||
| 421 | return 0; | 427 | return 0; |
| 422 | } | 428 | } |
| 423 | 429 | ||
| 424 | static int cache_block_group(struct btrfs_block_group_cache *cache) | 430 | static int cache_block_group(struct btrfs_block_group_cache *cache, |
| 431 | struct btrfs_trans_handle *trans, | ||
| 432 | int load_cache_only) | ||
| 425 | { | 433 | { |
| 426 | struct btrfs_fs_info *fs_info = cache->fs_info; | 434 | struct btrfs_fs_info *fs_info = cache->fs_info; |
| 427 | struct btrfs_caching_control *caching_ctl; | 435 | struct btrfs_caching_control *caching_ctl; |
| @@ -432,6 +440,36 @@ static int cache_block_group(struct btrfs_block_group_cache *cache) | |||
| 432 | if (cache->cached != BTRFS_CACHE_NO) | 440 | if (cache->cached != BTRFS_CACHE_NO) |
| 433 | return 0; | 441 | return 0; |
| 434 | 442 | ||
| 443 | /* | ||
| 444 | * We can't do the read from on-disk cache during a commit since we need | ||
| 445 | * to have the normal tree locking. | ||
| 446 | */ | ||
| 447 | if (!trans->transaction->in_commit) { | ||
| 448 | spin_lock(&cache->lock); | ||
| 449 | if (cache->cached != BTRFS_CACHE_NO) { | ||
| 450 | spin_unlock(&cache->lock); | ||
| 451 | return 0; | ||
| 452 | } | ||
| 453 | cache->cached = BTRFS_CACHE_STARTED; | ||
| 454 | spin_unlock(&cache->lock); | ||
| 455 | |||
| 456 | ret = load_free_space_cache(fs_info, cache); | ||
| 457 | |||
| 458 | spin_lock(&cache->lock); | ||
| 459 | if (ret == 1) { | ||
| 460 | cache->cached = BTRFS_CACHE_FINISHED; | ||
| 461 | cache->last_byte_to_unpin = (u64)-1; | ||
| 462 | } else { | ||
| 463 | cache->cached = BTRFS_CACHE_NO; | ||
| 464 | } | ||
| 465 | spin_unlock(&cache->lock); | ||
| 466 | if (ret == 1) | ||
| 467 | return 0; | ||
| 468 | } | ||
| 469 | |||
| 470 | if (load_cache_only) | ||
| 471 | return 0; | ||
| 472 | |||
| 435 | caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_KERNEL); | 473 | caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_KERNEL); |
| 436 | BUG_ON(!caching_ctl); | 474 | BUG_ON(!caching_ctl); |
| 437 | 475 | ||
| @@ -509,7 +547,7 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, | |||
| 509 | 547 | ||
| 510 | rcu_read_lock(); | 548 | rcu_read_lock(); |
| 511 | list_for_each_entry_rcu(found, head, list) { | 549 | list_for_each_entry_rcu(found, head, list) { |
| 512 | if (found->flags == flags) { | 550 | if (found->flags & flags) { |
| 513 | rcu_read_unlock(); | 551 | rcu_read_unlock(); |
| 514 | return found; | 552 | return found; |
| 515 | } | 553 | } |
| @@ -542,6 +580,15 @@ static u64 div_factor(u64 num, int factor) | |||
| 542 | return num; | 580 | return num; |
| 543 | } | 581 | } |
| 544 | 582 | ||
| 583 | static u64 div_factor_fine(u64 num, int factor) | ||
| 584 | { | ||
| 585 | if (factor == 100) | ||
| 586 | return num; | ||
| 587 | num *= factor; | ||
| 588 | do_div(num, 100); | ||
| 589 | return num; | ||
| 590 | } | ||
| 591 | |||
| 545 | u64 btrfs_find_block_group(struct btrfs_root *root, | 592 | u64 btrfs_find_block_group(struct btrfs_root *root, |
| 546 | u64 search_start, u64 search_hint, int owner) | 593 | u64 search_start, u64 search_hint, int owner) |
| 547 | { | 594 | { |
| @@ -2687,6 +2734,109 @@ next_block_group(struct btrfs_root *root, | |||
| 2687 | return cache; | 2734 | return cache; |
| 2688 | } | 2735 | } |
| 2689 | 2736 | ||
| 2737 | static int cache_save_setup(struct btrfs_block_group_cache *block_group, | ||
| 2738 | struct btrfs_trans_handle *trans, | ||
| 2739 | struct btrfs_path *path) | ||
| 2740 | { | ||
| 2741 | struct btrfs_root *root = block_group->fs_info->tree_root; | ||
| 2742 | struct inode *inode = NULL; | ||
| 2743 | u64 alloc_hint = 0; | ||
| 2744 | int num_pages = 0; | ||
| 2745 | int retries = 0; | ||
| 2746 | int ret = 0; | ||
| 2747 | |||
| 2748 | /* | ||
| 2749 | * If this block group is smaller than 100 megs don't bother caching the | ||
| 2750 | * block group. | ||
| 2751 | */ | ||
| 2752 | if (block_group->key.offset < (100 * 1024 * 1024)) { | ||
| 2753 | spin_lock(&block_group->lock); | ||
| 2754 | block_group->disk_cache_state = BTRFS_DC_WRITTEN; | ||
| 2755 | spin_unlock(&block_group->lock); | ||
| 2756 | return 0; | ||
| 2757 | } | ||
| 2758 | |||
| 2759 | again: | ||
| 2760 | inode = lookup_free_space_inode(root, block_group, path); | ||
| 2761 | if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) { | ||
| 2762 | ret = PTR_ERR(inode); | ||
| 2763 | btrfs_release_path(root, path); | ||
| 2764 | goto out; | ||
| 2765 | } | ||
| 2766 | |||
| 2767 | if (IS_ERR(inode)) { | ||
| 2768 | BUG_ON(retries); | ||
| 2769 | retries++; | ||
| 2770 | |||
| 2771 | if (block_group->ro) | ||
| 2772 | goto out_free; | ||
| 2773 | |||
| 2774 | ret = create_free_space_inode(root, trans, block_group, path); | ||
| 2775 | if (ret) | ||
| 2776 | goto out_free; | ||
| 2777 | goto again; | ||
| 2778 | } | ||
| 2779 | |||
| 2780 | /* | ||
| 2781 | * We want to set the generation to 0, that way if anything goes wrong | ||
| 2782 | * from here on out we know not to trust this cache when we load up next | ||
| 2783 | * time. | ||
| 2784 | */ | ||
| 2785 | BTRFS_I(inode)->generation = 0; | ||
| 2786 | ret = btrfs_update_inode(trans, root, inode); | ||
| 2787 | WARN_ON(ret); | ||
| 2788 | |||
| 2789 | if (i_size_read(inode) > 0) { | ||
| 2790 | ret = btrfs_truncate_free_space_cache(root, trans, path, | ||
| 2791 | inode); | ||
| 2792 | if (ret) | ||
| 2793 | goto out_put; | ||
| 2794 | } | ||
| 2795 | |||
| 2796 | spin_lock(&block_group->lock); | ||
| 2797 | if (block_group->cached != BTRFS_CACHE_FINISHED) { | ||
| 2798 | spin_unlock(&block_group->lock); | ||
| 2799 | goto out_put; | ||
| 2800 | } | ||
| 2801 | spin_unlock(&block_group->lock); | ||
| 2802 | |||
| 2803 | num_pages = (int)div64_u64(block_group->key.offset, 1024 * 1024 * 1024); | ||
| 2804 | if (!num_pages) | ||
| 2805 | num_pages = 1; | ||
| 2806 | |||
| 2807 | /* | ||
| 2808 | * Just to make absolutely sure we have enough space, we're going to | ||
| 2809 | * preallocate 12 pages worth of space for each block group. In | ||
| 2810 | * practice we ought to use at most 8, but we need extra space so we can | ||
| 2811 | * add our header and have a terminator between the extents and the | ||
| 2812 | * bitmaps. | ||
| 2813 | */ | ||
| 2814 | num_pages *= 16; | ||
| 2815 | num_pages *= PAGE_CACHE_SIZE; | ||
| 2816 | |||
| 2817 | ret = btrfs_check_data_free_space(inode, num_pages); | ||
| 2818 | if (ret) | ||
| 2819 | goto out_put; | ||
| 2820 | |||
| 2821 | ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages, | ||
| 2822 | num_pages, num_pages, | ||
| 2823 | &alloc_hint); | ||
| 2824 | btrfs_free_reserved_data_space(inode, num_pages); | ||
| 2825 | out_put: | ||
| 2826 | iput(inode); | ||
| 2827 | out_free: | ||
| 2828 | btrfs_release_path(root, path); | ||
| 2829 | out: | ||
| 2830 | spin_lock(&block_group->lock); | ||
| 2831 | if (ret) | ||
| 2832 | block_group->disk_cache_state = BTRFS_DC_ERROR; | ||
| 2833 | else | ||
| 2834 | block_group->disk_cache_state = BTRFS_DC_SETUP; | ||
| 2835 | spin_unlock(&block_group->lock); | ||
| 2836 | |||
| 2837 | return ret; | ||
| 2838 | } | ||
| 2839 | |||
| 2690 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | 2840 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, |
| 2691 | struct btrfs_root *root) | 2841 | struct btrfs_root *root) |
| 2692 | { | 2842 | { |
| @@ -2699,6 +2849,25 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
| 2699 | if (!path) | 2849 | if (!path) |
| 2700 | return -ENOMEM; | 2850 | return -ENOMEM; |
| 2701 | 2851 | ||
| 2852 | again: | ||
| 2853 | while (1) { | ||
| 2854 | cache = btrfs_lookup_first_block_group(root->fs_info, last); | ||
| 2855 | while (cache) { | ||
| 2856 | if (cache->disk_cache_state == BTRFS_DC_CLEAR) | ||
| 2857 | break; | ||
| 2858 | cache = next_block_group(root, cache); | ||
| 2859 | } | ||
| 2860 | if (!cache) { | ||
| 2861 | if (last == 0) | ||
| 2862 | break; | ||
| 2863 | last = 0; | ||
| 2864 | continue; | ||
| 2865 | } | ||
| 2866 | err = cache_save_setup(cache, trans, path); | ||
| 2867 | last = cache->key.objectid + cache->key.offset; | ||
| 2868 | btrfs_put_block_group(cache); | ||
| 2869 | } | ||
| 2870 | |||
| 2702 | while (1) { | 2871 | while (1) { |
| 2703 | if (last == 0) { | 2872 | if (last == 0) { |
| 2704 | err = btrfs_run_delayed_refs(trans, root, | 2873 | err = btrfs_run_delayed_refs(trans, root, |
| @@ -2708,6 +2877,11 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
| 2708 | 2877 | ||
| 2709 | cache = btrfs_lookup_first_block_group(root->fs_info, last); | 2878 | cache = btrfs_lookup_first_block_group(root->fs_info, last); |
| 2710 | while (cache) { | 2879 | while (cache) { |
| 2880 | if (cache->disk_cache_state == BTRFS_DC_CLEAR) { | ||
| 2881 | btrfs_put_block_group(cache); | ||
| 2882 | goto again; | ||
| 2883 | } | ||
| 2884 | |||
| 2711 | if (cache->dirty) | 2885 | if (cache->dirty) |
| 2712 | break; | 2886 | break; |
| 2713 | cache = next_block_group(root, cache); | 2887 | cache = next_block_group(root, cache); |
| @@ -2719,6 +2893,8 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
| 2719 | continue; | 2893 | continue; |
| 2720 | } | 2894 | } |
| 2721 | 2895 | ||
| 2896 | if (cache->disk_cache_state == BTRFS_DC_SETUP) | ||
| 2897 | cache->disk_cache_state = BTRFS_DC_NEED_WRITE; | ||
| 2722 | cache->dirty = 0; | 2898 | cache->dirty = 0; |
| 2723 | last = cache->key.objectid + cache->key.offset; | 2899 | last = cache->key.objectid + cache->key.offset; |
| 2724 | 2900 | ||
| @@ -2727,6 +2903,52 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
| 2727 | btrfs_put_block_group(cache); | 2903 | btrfs_put_block_group(cache); |
| 2728 | } | 2904 | } |
| 2729 | 2905 | ||
| 2906 | while (1) { | ||
| 2907 | /* | ||
| 2908 | * I don't think this is needed since we're just marking our | ||
| 2909 | * preallocated extent as written, but just in case it can't | ||
| 2910 | * hurt. | ||
| 2911 | */ | ||
| 2912 | if (last == 0) { | ||
| 2913 | err = btrfs_run_delayed_refs(trans, root, | ||
| 2914 | (unsigned long)-1); | ||
| 2915 | BUG_ON(err); | ||
| 2916 | } | ||
| 2917 | |||
| 2918 | cache = btrfs_lookup_first_block_group(root->fs_info, last); | ||
| 2919 | while (cache) { | ||
| 2920 | /* | ||
| 2921 | * Really this shouldn't happen, but it could if we | ||
| 2922 | * couldn't write the entire preallocated extent and | ||
| 2923 | * splitting the extent resulted in a new block. | ||
| 2924 | */ | ||
| 2925 | if (cache->dirty) { | ||
| 2926 | btrfs_put_block_group(cache); | ||
| 2927 | goto again; | ||
| 2928 | } | ||
| 2929 | if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE) | ||
| 2930 | break; | ||
| 2931 | cache = next_block_group(root, cache); | ||
| 2932 | } | ||
| 2933 | if (!cache) { | ||
| 2934 | if (last == 0) | ||
| 2935 | break; | ||
| 2936 | last = 0; | ||
| 2937 | continue; | ||
| 2938 | } | ||
| 2939 | |||
| 2940 | btrfs_write_out_cache(root, trans, cache, path); | ||
| 2941 | |||
| 2942 | /* | ||
| 2943 | * If we didn't have an error then the cache state is still | ||
| 2944 | * NEED_WRITE, so we can set it to WRITTEN. | ||
| 2945 | */ | ||
| 2946 | if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE) | ||
| 2947 | cache->disk_cache_state = BTRFS_DC_WRITTEN; | ||
| 2948 | last = cache->key.objectid + cache->key.offset; | ||
| 2949 | btrfs_put_block_group(cache); | ||
| 2950 | } | ||
| 2951 | |||
| 2730 | btrfs_free_path(path); | 2952 | btrfs_free_path(path); |
| 2731 | return 0; | 2953 | return 0; |
| 2732 | } | 2954 | } |
| @@ -2762,6 +2984,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, | |||
| 2762 | if (found) { | 2984 | if (found) { |
| 2763 | spin_lock(&found->lock); | 2985 | spin_lock(&found->lock); |
| 2764 | found->total_bytes += total_bytes; | 2986 | found->total_bytes += total_bytes; |
| 2987 | found->disk_total += total_bytes * factor; | ||
| 2765 | found->bytes_used += bytes_used; | 2988 | found->bytes_used += bytes_used; |
| 2766 | found->disk_used += bytes_used * factor; | 2989 | found->disk_used += bytes_used * factor; |
| 2767 | found->full = 0; | 2990 | found->full = 0; |
| @@ -2781,6 +3004,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, | |||
| 2781 | BTRFS_BLOCK_GROUP_SYSTEM | | 3004 | BTRFS_BLOCK_GROUP_SYSTEM | |
| 2782 | BTRFS_BLOCK_GROUP_METADATA); | 3005 | BTRFS_BLOCK_GROUP_METADATA); |
| 2783 | found->total_bytes = total_bytes; | 3006 | found->total_bytes = total_bytes; |
| 3007 | found->disk_total = total_bytes * factor; | ||
| 2784 | found->bytes_used = bytes_used; | 3008 | found->bytes_used = bytes_used; |
| 2785 | found->disk_used = bytes_used * factor; | 3009 | found->disk_used = bytes_used * factor; |
| 2786 | found->bytes_pinned = 0; | 3010 | found->bytes_pinned = 0; |
| @@ -2882,11 +3106,16 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) | |||
| 2882 | struct btrfs_space_info *data_sinfo; | 3106 | struct btrfs_space_info *data_sinfo; |
| 2883 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3107 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 2884 | u64 used; | 3108 | u64 used; |
| 2885 | int ret = 0, committed = 0; | 3109 | int ret = 0, committed = 0, alloc_chunk = 1; |
| 2886 | 3110 | ||
| 2887 | /* make sure bytes are sectorsize aligned */ | 3111 | /* make sure bytes are sectorsize aligned */ |
| 2888 | bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); | 3112 | bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); |
| 2889 | 3113 | ||
| 3114 | if (root == root->fs_info->tree_root) { | ||
| 3115 | alloc_chunk = 0; | ||
| 3116 | committed = 1; | ||
| 3117 | } | ||
| 3118 | |||
| 2890 | data_sinfo = BTRFS_I(inode)->space_info; | 3119 | data_sinfo = BTRFS_I(inode)->space_info; |
| 2891 | if (!data_sinfo) | 3120 | if (!data_sinfo) |
| 2892 | goto alloc; | 3121 | goto alloc; |
| @@ -2905,7 +3134,7 @@ again: | |||
| 2905 | * if we don't have enough free bytes in this space then we need | 3134 | * if we don't have enough free bytes in this space then we need |
| 2906 | * to alloc a new chunk. | 3135 | * to alloc a new chunk. |
| 2907 | */ | 3136 | */ |
| 2908 | if (!data_sinfo->full) { | 3137 | if (!data_sinfo->full && alloc_chunk) { |
| 2909 | u64 alloc_target; | 3138 | u64 alloc_target; |
| 2910 | 3139 | ||
| 2911 | data_sinfo->force_alloc = 1; | 3140 | data_sinfo->force_alloc = 1; |
| @@ -2997,10 +3226,11 @@ static void force_metadata_allocation(struct btrfs_fs_info *info) | |||
| 2997 | rcu_read_unlock(); | 3226 | rcu_read_unlock(); |
| 2998 | } | 3227 | } |
| 2999 | 3228 | ||
| 3000 | static int should_alloc_chunk(struct btrfs_space_info *sinfo, | 3229 | static int should_alloc_chunk(struct btrfs_root *root, |
| 3001 | u64 alloc_bytes) | 3230 | struct btrfs_space_info *sinfo, u64 alloc_bytes) |
| 3002 | { | 3231 | { |
| 3003 | u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly; | 3232 | u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly; |
| 3233 | u64 thresh; | ||
| 3004 | 3234 | ||
| 3005 | if (sinfo->bytes_used + sinfo->bytes_reserved + | 3235 | if (sinfo->bytes_used + sinfo->bytes_reserved + |
| 3006 | alloc_bytes + 256 * 1024 * 1024 < num_bytes) | 3236 | alloc_bytes + 256 * 1024 * 1024 < num_bytes) |
| @@ -3010,6 +3240,12 @@ static int should_alloc_chunk(struct btrfs_space_info *sinfo, | |||
| 3010 | alloc_bytes < div_factor(num_bytes, 8)) | 3240 | alloc_bytes < div_factor(num_bytes, 8)) |
| 3011 | return 0; | 3241 | return 0; |
| 3012 | 3242 | ||
| 3243 | thresh = btrfs_super_total_bytes(&root->fs_info->super_copy); | ||
| 3244 | thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 5)); | ||
| 3245 | |||
| 3246 | if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 3)) | ||
| 3247 | return 0; | ||
| 3248 | |||
| 3013 | return 1; | 3249 | return 1; |
| 3014 | } | 3250 | } |
| 3015 | 3251 | ||
| @@ -3041,13 +3277,21 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, | |||
| 3041 | goto out; | 3277 | goto out; |
| 3042 | } | 3278 | } |
| 3043 | 3279 | ||
| 3044 | if (!force && !should_alloc_chunk(space_info, alloc_bytes)) { | 3280 | if (!force && !should_alloc_chunk(extent_root, space_info, |
| 3281 | alloc_bytes)) { | ||
| 3045 | spin_unlock(&space_info->lock); | 3282 | spin_unlock(&space_info->lock); |
| 3046 | goto out; | 3283 | goto out; |
| 3047 | } | 3284 | } |
| 3048 | spin_unlock(&space_info->lock); | 3285 | spin_unlock(&space_info->lock); |
| 3049 | 3286 | ||
| 3050 | /* | 3287 | /* |
| 3288 | * If we have mixed data/metadata chunks we want to make sure we keep | ||
| 3289 | * allocating mixed chunks instead of individual chunks. | ||
| 3290 | */ | ||
| 3291 | if (btrfs_mixed_space_info(space_info)) | ||
| 3292 | flags |= (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA); | ||
| 3293 | |||
| 3294 | /* | ||
| 3051 | * if we're doing a data chunk, go ahead and make sure that | 3295 | * if we're doing a data chunk, go ahead and make sure that |
| 3052 | * we keep a reasonable number of metadata chunks allocated in the | 3296 | * we keep a reasonable number of metadata chunks allocated in the |
| 3053 | * FS as well. | 3297 | * FS as well. |
| @@ -3072,55 +3316,25 @@ out: | |||
| 3072 | return ret; | 3316 | return ret; |
| 3073 | } | 3317 | } |
| 3074 | 3318 | ||
| 3075 | static int maybe_allocate_chunk(struct btrfs_trans_handle *trans, | ||
| 3076 | struct btrfs_root *root, | ||
| 3077 | struct btrfs_space_info *sinfo, u64 num_bytes) | ||
| 3078 | { | ||
| 3079 | int ret; | ||
| 3080 | int end_trans = 0; | ||
| 3081 | |||
| 3082 | if (sinfo->full) | ||
| 3083 | return 0; | ||
| 3084 | |||
| 3085 | spin_lock(&sinfo->lock); | ||
| 3086 | ret = should_alloc_chunk(sinfo, num_bytes + 2 * 1024 * 1024); | ||
| 3087 | spin_unlock(&sinfo->lock); | ||
| 3088 | if (!ret) | ||
| 3089 | return 0; | ||
| 3090 | |||
| 3091 | if (!trans) { | ||
| 3092 | trans = btrfs_join_transaction(root, 1); | ||
| 3093 | BUG_ON(IS_ERR(trans)); | ||
| 3094 | end_trans = 1; | ||
| 3095 | } | ||
| 3096 | |||
| 3097 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | ||
| 3098 | num_bytes + 2 * 1024 * 1024, | ||
| 3099 | get_alloc_profile(root, sinfo->flags), 0); | ||
| 3100 | |||
| 3101 | if (end_trans) | ||
| 3102 | btrfs_end_transaction(trans, root); | ||
| 3103 | |||
| 3104 | return ret == 1 ? 1 : 0; | ||
| 3105 | } | ||
| 3106 | |||
| 3107 | /* | 3319 | /* |
| 3108 | * shrink metadata reservation for delalloc | 3320 | * shrink metadata reservation for delalloc |
| 3109 | */ | 3321 | */ |
| 3110 | static int shrink_delalloc(struct btrfs_trans_handle *trans, | 3322 | static int shrink_delalloc(struct btrfs_trans_handle *trans, |
| 3111 | struct btrfs_root *root, u64 to_reclaim) | 3323 | struct btrfs_root *root, u64 to_reclaim, int sync) |
| 3112 | { | 3324 | { |
| 3113 | struct btrfs_block_rsv *block_rsv; | 3325 | struct btrfs_block_rsv *block_rsv; |
| 3326 | struct btrfs_space_info *space_info; | ||
| 3114 | u64 reserved; | 3327 | u64 reserved; |
| 3115 | u64 max_reclaim; | 3328 | u64 max_reclaim; |
| 3116 | u64 reclaimed = 0; | 3329 | u64 reclaimed = 0; |
| 3117 | int pause = 1; | 3330 | int pause = 1; |
| 3118 | int ret; | 3331 | int nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT; |
| 3119 | 3332 | ||
| 3120 | block_rsv = &root->fs_info->delalloc_block_rsv; | 3333 | block_rsv = &root->fs_info->delalloc_block_rsv; |
| 3121 | spin_lock(&block_rsv->lock); | 3334 | space_info = block_rsv->space_info; |
| 3122 | reserved = block_rsv->reserved; | 3335 | |
| 3123 | spin_unlock(&block_rsv->lock); | 3336 | smp_mb(); |
| 3337 | reserved = space_info->bytes_reserved; | ||
| 3124 | 3338 | ||
| 3125 | if (reserved == 0) | 3339 | if (reserved == 0) |
| 3126 | return 0; | 3340 | return 0; |
| @@ -3128,104 +3342,169 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, | |||
| 3128 | max_reclaim = min(reserved, to_reclaim); | 3342 | max_reclaim = min(reserved, to_reclaim); |
| 3129 | 3343 | ||
| 3130 | while (1) { | 3344 | while (1) { |
| 3131 | ret = btrfs_start_one_delalloc_inode(root, trans ? 1 : 0); | 3345 | /* have the flusher threads jump in and do some IO */ |
| 3132 | if (!ret) { | 3346 | smp_mb(); |
| 3133 | __set_current_state(TASK_INTERRUPTIBLE); | 3347 | nr_pages = min_t(unsigned long, nr_pages, |
| 3134 | schedule_timeout(pause); | 3348 | root->fs_info->delalloc_bytes >> PAGE_CACHE_SHIFT); |
| 3135 | pause <<= 1; | 3349 | writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages); |
| 3136 | if (pause > HZ / 10) | ||
| 3137 | pause = HZ / 10; | ||
| 3138 | } else { | ||
| 3139 | pause = 1; | ||
| 3140 | } | ||
| 3141 | 3350 | ||
| 3142 | spin_lock(&block_rsv->lock); | 3351 | spin_lock(&space_info->lock); |
| 3143 | if (reserved > block_rsv->reserved) | 3352 | if (reserved > space_info->bytes_reserved) |
| 3144 | reclaimed = reserved - block_rsv->reserved; | 3353 | reclaimed += reserved - space_info->bytes_reserved; |
| 3145 | reserved = block_rsv->reserved; | 3354 | reserved = space_info->bytes_reserved; |
| 3146 | spin_unlock(&block_rsv->lock); | 3355 | spin_unlock(&space_info->lock); |
| 3147 | 3356 | ||
| 3148 | if (reserved == 0 || reclaimed >= max_reclaim) | 3357 | if (reserved == 0 || reclaimed >= max_reclaim) |
| 3149 | break; | 3358 | break; |
| 3150 | 3359 | ||
| 3151 | if (trans && trans->transaction->blocked) | 3360 | if (trans && trans->transaction->blocked) |
| 3152 | return -EAGAIN; | 3361 | return -EAGAIN; |
| 3362 | |||
| 3363 | __set_current_state(TASK_INTERRUPTIBLE); | ||
| 3364 | schedule_timeout(pause); | ||
| 3365 | pause <<= 1; | ||
| 3366 | if (pause > HZ / 10) | ||
| 3367 | pause = HZ / 10; | ||
| 3368 | |||
| 3153 | } | 3369 | } |
| 3154 | return reclaimed >= to_reclaim; | 3370 | return reclaimed >= to_reclaim; |
| 3155 | } | 3371 | } |
| 3156 | 3372 | ||
| 3157 | static int should_retry_reserve(struct btrfs_trans_handle *trans, | 3373 | /* |
| 3158 | struct btrfs_root *root, | 3374 | * Retries tells us how many times we've called reserve_metadata_bytes. The |
| 3159 | struct btrfs_block_rsv *block_rsv, | 3375 | * idea is if this is the first call (retries == 0) then we will add to our |
| 3160 | u64 num_bytes, int *retries) | 3376 | * reserved count if we can't make the allocation in order to hold our place |
| 3377 | * while we go and try and free up space. That way for retries > 1 we don't try | ||
| 3378 | * and add space, we just check to see if the amount of unused space is >= the | ||
| 3379 | * total space, meaning that our reservation is valid. | ||
| 3380 | * | ||
| 3381 | * However if we don't intend to retry this reservation, pass -1 as retries so | ||
| 3382 | * that it short circuits this logic. | ||
| 3383 | */ | ||
| 3384 | static int reserve_metadata_bytes(struct btrfs_trans_handle *trans, | ||
| 3385 | struct btrfs_root *root, | ||
| 3386 | struct btrfs_block_rsv *block_rsv, | ||
| 3387 | u64 orig_bytes, int flush) | ||
| 3161 | { | 3388 | { |
| 3162 | struct btrfs_space_info *space_info = block_rsv->space_info; | 3389 | struct btrfs_space_info *space_info = block_rsv->space_info; |
| 3163 | int ret; | 3390 | u64 unused; |
| 3391 | u64 num_bytes = orig_bytes; | ||
| 3392 | int retries = 0; | ||
| 3393 | int ret = 0; | ||
| 3394 | bool reserved = false; | ||
| 3395 | bool committed = false; | ||
| 3164 | 3396 | ||
| 3165 | if ((*retries) > 2) | 3397 | again: |
| 3166 | return -ENOSPC; | 3398 | ret = -ENOSPC; |
| 3399 | if (reserved) | ||
| 3400 | num_bytes = 0; | ||
| 3167 | 3401 | ||
| 3168 | ret = maybe_allocate_chunk(trans, root, space_info, num_bytes); | 3402 | spin_lock(&space_info->lock); |
| 3169 | if (ret) | 3403 | unused = space_info->bytes_used + space_info->bytes_reserved + |
| 3170 | return 1; | 3404 | space_info->bytes_pinned + space_info->bytes_readonly + |
| 3405 | space_info->bytes_may_use; | ||
| 3171 | 3406 | ||
| 3172 | if (trans && trans->transaction->in_commit) | 3407 | /* |
| 3173 | return -ENOSPC; | 3408 | * The idea here is that we've not already over-reserved the block group |
| 3409 | * then we can go ahead and save our reservation first and then start | ||
| 3410 | * flushing if we need to. Otherwise if we've already overcommitted | ||
| 3411 | * lets start flushing stuff first and then come back and try to make | ||
| 3412 | * our reservation. | ||
| 3413 | */ | ||
| 3414 | if (unused <= space_info->total_bytes) { | ||
| 3415 | unused -= space_info->total_bytes; | ||
| 3416 | if (unused >= num_bytes) { | ||
| 3417 | if (!reserved) | ||
| 3418 | space_info->bytes_reserved += orig_bytes; | ||
| 3419 | ret = 0; | ||
| 3420 | } else { | ||
| 3421 | /* | ||
| 3422 | * Ok set num_bytes to orig_bytes since we aren't | ||
| 3423 | * overocmmitted, this way we only try and reclaim what | ||
| 3424 | * we need. | ||
| 3425 | */ | ||
| 3426 | num_bytes = orig_bytes; | ||
| 3427 | } | ||
| 3428 | } else { | ||
| 3429 | /* | ||
| 3430 | * Ok we're over committed, set num_bytes to the overcommitted | ||
| 3431 | * amount plus the amount of bytes that we need for this | ||
| 3432 | * reservation. | ||
| 3433 | */ | ||
| 3434 | num_bytes = unused - space_info->total_bytes + | ||
| 3435 | (orig_bytes * (retries + 1)); | ||
| 3436 | } | ||
| 3174 | 3437 | ||
| 3175 | ret = shrink_delalloc(trans, root, num_bytes); | 3438 | /* |
| 3176 | if (ret) | 3439 | * Couldn't make our reservation, save our place so while we're trying |
| 3177 | return ret; | 3440 | * to reclaim space we can actually use it instead of somebody else |
| 3441 | * stealing it from us. | ||
| 3442 | */ | ||
| 3443 | if (ret && !reserved) { | ||
| 3444 | space_info->bytes_reserved += orig_bytes; | ||
| 3445 | reserved = true; | ||
| 3446 | } | ||
| 3178 | 3447 | ||
| 3179 | spin_lock(&space_info->lock); | ||
| 3180 | if (space_info->bytes_pinned < num_bytes) | ||
| 3181 | ret = 1; | ||
| 3182 | spin_unlock(&space_info->lock); | 3448 | spin_unlock(&space_info->lock); |
| 3183 | if (ret) | ||
| 3184 | return -ENOSPC; | ||
| 3185 | |||
| 3186 | (*retries)++; | ||
| 3187 | 3449 | ||
| 3188 | if (trans) | 3450 | if (!ret) |
| 3189 | return -EAGAIN; | 3451 | return 0; |
| 3190 | 3452 | ||
| 3191 | trans = btrfs_join_transaction(root, 1); | 3453 | if (!flush) |
| 3192 | BUG_ON(IS_ERR(trans)); | 3454 | goto out; |
| 3193 | ret = btrfs_commit_transaction(trans, root); | ||
| 3194 | BUG_ON(ret); | ||
| 3195 | 3455 | ||
| 3196 | return 1; | 3456 | /* |
| 3197 | } | 3457 | * We do synchronous shrinking since we don't actually unreserve |
| 3458 | * metadata until after the IO is completed. | ||
| 3459 | */ | ||
| 3460 | ret = shrink_delalloc(trans, root, num_bytes, 1); | ||
| 3461 | if (ret > 0) | ||
| 3462 | return 0; | ||
| 3463 | else if (ret < 0) | ||
| 3464 | goto out; | ||
| 3198 | 3465 | ||
| 3199 | static int reserve_metadata_bytes(struct btrfs_block_rsv *block_rsv, | 3466 | /* |
| 3200 | u64 num_bytes) | 3467 | * So if we were overcommitted it's possible that somebody else flushed |
| 3201 | { | 3468 | * out enough space and we simply didn't have enough space to reclaim, |
| 3202 | struct btrfs_space_info *space_info = block_rsv->space_info; | 3469 | * so go back around and try again. |
| 3203 | u64 unused; | 3470 | */ |
| 3204 | int ret = -ENOSPC; | 3471 | if (retries < 2) { |
| 3472 | retries++; | ||
| 3473 | goto again; | ||
| 3474 | } | ||
| 3205 | 3475 | ||
| 3206 | spin_lock(&space_info->lock); | 3476 | spin_lock(&space_info->lock); |
| 3207 | unused = space_info->bytes_used + space_info->bytes_reserved + | 3477 | /* |
| 3208 | space_info->bytes_pinned + space_info->bytes_readonly; | 3478 | * Not enough space to be reclaimed, don't bother committing the |
| 3479 | * transaction. | ||
| 3480 | */ | ||
| 3481 | if (space_info->bytes_pinned < orig_bytes) | ||
| 3482 | ret = -ENOSPC; | ||
| 3483 | spin_unlock(&space_info->lock); | ||
| 3484 | if (ret) | ||
| 3485 | goto out; | ||
| 3209 | 3486 | ||
| 3210 | if (unused < space_info->total_bytes) | 3487 | ret = -EAGAIN; |
| 3211 | unused = space_info->total_bytes - unused; | 3488 | if (trans || committed) |
| 3212 | else | 3489 | goto out; |
| 3213 | unused = 0; | ||
| 3214 | 3490 | ||
| 3215 | if (unused >= num_bytes) { | 3491 | ret = -ENOSPC; |
| 3216 | if (block_rsv->priority >= 10) { | 3492 | trans = btrfs_join_transaction(root, 1); |
| 3217 | space_info->bytes_reserved += num_bytes; | 3493 | if (IS_ERR(trans)) |
| 3218 | ret = 0; | 3494 | goto out; |
| 3219 | } else { | 3495 | ret = btrfs_commit_transaction(trans, root); |
| 3220 | if ((unused + block_rsv->reserved) * | 3496 | if (!ret) { |
| 3221 | block_rsv->priority >= | 3497 | trans = NULL; |
| 3222 | (num_bytes + block_rsv->reserved) * 10) { | 3498 | committed = true; |
| 3223 | space_info->bytes_reserved += num_bytes; | 3499 | goto again; |
| 3224 | ret = 0; | 3500 | } |
| 3225 | } | 3501 | |
| 3226 | } | 3502 | out: |
| 3503 | if (reserved) { | ||
| 3504 | spin_lock(&space_info->lock); | ||
| 3505 | space_info->bytes_reserved -= orig_bytes; | ||
| 3506 | spin_unlock(&space_info->lock); | ||
| 3227 | } | 3507 | } |
| 3228 | spin_unlock(&space_info->lock); | ||
| 3229 | 3508 | ||
| 3230 | return ret; | 3509 | return ret; |
| 3231 | } | 3510 | } |
| @@ -3327,18 +3606,14 @@ struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root) | |||
| 3327 | { | 3606 | { |
| 3328 | struct btrfs_block_rsv *block_rsv; | 3607 | struct btrfs_block_rsv *block_rsv; |
| 3329 | struct btrfs_fs_info *fs_info = root->fs_info; | 3608 | struct btrfs_fs_info *fs_info = root->fs_info; |
| 3330 | u64 alloc_target; | ||
| 3331 | 3609 | ||
| 3332 | block_rsv = kmalloc(sizeof(*block_rsv), GFP_NOFS); | 3610 | block_rsv = kmalloc(sizeof(*block_rsv), GFP_NOFS); |
| 3333 | if (!block_rsv) | 3611 | if (!block_rsv) |
| 3334 | return NULL; | 3612 | return NULL; |
| 3335 | 3613 | ||
| 3336 | btrfs_init_block_rsv(block_rsv); | 3614 | btrfs_init_block_rsv(block_rsv); |
| 3337 | |||
| 3338 | alloc_target = btrfs_get_alloc_profile(root, 0); | ||
| 3339 | block_rsv->space_info = __find_space_info(fs_info, | 3615 | block_rsv->space_info = __find_space_info(fs_info, |
| 3340 | BTRFS_BLOCK_GROUP_METADATA); | 3616 | BTRFS_BLOCK_GROUP_METADATA); |
| 3341 | |||
| 3342 | return block_rsv; | 3617 | return block_rsv; |
| 3343 | } | 3618 | } |
| 3344 | 3619 | ||
| @@ -3369,23 +3644,19 @@ void btrfs_add_durable_block_rsv(struct btrfs_fs_info *fs_info, | |||
| 3369 | int btrfs_block_rsv_add(struct btrfs_trans_handle *trans, | 3644 | int btrfs_block_rsv_add(struct btrfs_trans_handle *trans, |
| 3370 | struct btrfs_root *root, | 3645 | struct btrfs_root *root, |
| 3371 | struct btrfs_block_rsv *block_rsv, | 3646 | struct btrfs_block_rsv *block_rsv, |
| 3372 | u64 num_bytes, int *retries) | 3647 | u64 num_bytes) |
| 3373 | { | 3648 | { |
| 3374 | int ret; | 3649 | int ret; |
| 3375 | 3650 | ||
| 3376 | if (num_bytes == 0) | 3651 | if (num_bytes == 0) |
| 3377 | return 0; | 3652 | return 0; |
| 3378 | again: | 3653 | |
| 3379 | ret = reserve_metadata_bytes(block_rsv, num_bytes); | 3654 | ret = reserve_metadata_bytes(trans, root, block_rsv, num_bytes, 1); |
| 3380 | if (!ret) { | 3655 | if (!ret) { |
| 3381 | block_rsv_add_bytes(block_rsv, num_bytes, 1); | 3656 | block_rsv_add_bytes(block_rsv, num_bytes, 1); |
| 3382 | return 0; | 3657 | return 0; |
| 3383 | } | 3658 | } |
| 3384 | 3659 | ||
| 3385 | ret = should_retry_reserve(trans, root, block_rsv, num_bytes, retries); | ||
| 3386 | if (ret > 0) | ||
| 3387 | goto again; | ||
| 3388 | |||
| 3389 | return ret; | 3660 | return ret; |
| 3390 | } | 3661 | } |
| 3391 | 3662 | ||
| @@ -3420,7 +3691,8 @@ int btrfs_block_rsv_check(struct btrfs_trans_handle *trans, | |||
| 3420 | return 0; | 3691 | return 0; |
| 3421 | 3692 | ||
| 3422 | if (block_rsv->refill_used) { | 3693 | if (block_rsv->refill_used) { |
| 3423 | ret = reserve_metadata_bytes(block_rsv, num_bytes); | 3694 | ret = reserve_metadata_bytes(trans, root, block_rsv, |
| 3695 | num_bytes, 0); | ||
| 3424 | if (!ret) { | 3696 | if (!ret) { |
| 3425 | block_rsv_add_bytes(block_rsv, num_bytes, 0); | 3697 | block_rsv_add_bytes(block_rsv, num_bytes, 0); |
| 3426 | return 0; | 3698 | return 0; |
| @@ -3499,6 +3771,8 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info) | |||
| 3499 | 3771 | ||
| 3500 | sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); | 3772 | sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); |
| 3501 | spin_lock(&sinfo->lock); | 3773 | spin_lock(&sinfo->lock); |
| 3774 | if (sinfo->flags & BTRFS_BLOCK_GROUP_DATA) | ||
| 3775 | data_used = 0; | ||
| 3502 | meta_used = sinfo->bytes_used; | 3776 | meta_used = sinfo->bytes_used; |
| 3503 | spin_unlock(&sinfo->lock); | 3777 | spin_unlock(&sinfo->lock); |
| 3504 | 3778 | ||
| @@ -3526,7 +3800,8 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info) | |||
| 3526 | block_rsv->size = num_bytes; | 3800 | block_rsv->size = num_bytes; |
| 3527 | 3801 | ||
| 3528 | num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + | 3802 | num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + |
| 3529 | sinfo->bytes_reserved + sinfo->bytes_readonly; | 3803 | sinfo->bytes_reserved + sinfo->bytes_readonly + |
| 3804 | sinfo->bytes_may_use; | ||
| 3530 | 3805 | ||
| 3531 | if (sinfo->total_bytes > num_bytes) { | 3806 | if (sinfo->total_bytes > num_bytes) { |
| 3532 | num_bytes = sinfo->total_bytes - num_bytes; | 3807 | num_bytes = sinfo->total_bytes - num_bytes; |
| @@ -3597,7 +3872,7 @@ static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items) | |||
| 3597 | 3872 | ||
| 3598 | int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, | 3873 | int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, |
| 3599 | struct btrfs_root *root, | 3874 | struct btrfs_root *root, |
| 3600 | int num_items, int *retries) | 3875 | int num_items) |
| 3601 | { | 3876 | { |
| 3602 | u64 num_bytes; | 3877 | u64 num_bytes; |
| 3603 | int ret; | 3878 | int ret; |
| @@ -3607,7 +3882,7 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, | |||
| 3607 | 3882 | ||
| 3608 | num_bytes = calc_trans_metadata_size(root, num_items); | 3883 | num_bytes = calc_trans_metadata_size(root, num_items); |
| 3609 | ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv, | 3884 | ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv, |
| 3610 | num_bytes, retries); | 3885 | num_bytes); |
| 3611 | if (!ret) { | 3886 | if (!ret) { |
| 3612 | trans->bytes_reserved += num_bytes; | 3887 | trans->bytes_reserved += num_bytes; |
| 3613 | trans->block_rsv = &root->fs_info->trans_block_rsv; | 3888 | trans->block_rsv = &root->fs_info->trans_block_rsv; |
| @@ -3681,14 +3956,13 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) | |||
| 3681 | struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv; | 3956 | struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv; |
| 3682 | u64 to_reserve; | 3957 | u64 to_reserve; |
| 3683 | int nr_extents; | 3958 | int nr_extents; |
| 3684 | int retries = 0; | ||
| 3685 | int ret; | 3959 | int ret; |
| 3686 | 3960 | ||
| 3687 | if (btrfs_transaction_in_commit(root->fs_info)) | 3961 | if (btrfs_transaction_in_commit(root->fs_info)) |
| 3688 | schedule_timeout(1); | 3962 | schedule_timeout(1); |
| 3689 | 3963 | ||
| 3690 | num_bytes = ALIGN(num_bytes, root->sectorsize); | 3964 | num_bytes = ALIGN(num_bytes, root->sectorsize); |
| 3691 | again: | 3965 | |
| 3692 | spin_lock(&BTRFS_I(inode)->accounting_lock); | 3966 | spin_lock(&BTRFS_I(inode)->accounting_lock); |
| 3693 | nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1; | 3967 | nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1; |
| 3694 | if (nr_extents > BTRFS_I(inode)->reserved_extents) { | 3968 | if (nr_extents > BTRFS_I(inode)->reserved_extents) { |
| @@ -3698,18 +3972,14 @@ again: | |||
| 3698 | nr_extents = 0; | 3972 | nr_extents = 0; |
| 3699 | to_reserve = 0; | 3973 | to_reserve = 0; |
| 3700 | } | 3974 | } |
| 3975 | spin_unlock(&BTRFS_I(inode)->accounting_lock); | ||
| 3701 | 3976 | ||
| 3702 | to_reserve += calc_csum_metadata_size(inode, num_bytes); | 3977 | to_reserve += calc_csum_metadata_size(inode, num_bytes); |
| 3703 | ret = reserve_metadata_bytes(block_rsv, to_reserve); | 3978 | ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1); |
| 3704 | if (ret) { | 3979 | if (ret) |
| 3705 | spin_unlock(&BTRFS_I(inode)->accounting_lock); | ||
| 3706 | ret = should_retry_reserve(NULL, root, block_rsv, to_reserve, | ||
| 3707 | &retries); | ||
| 3708 | if (ret > 0) | ||
| 3709 | goto again; | ||
| 3710 | return ret; | 3980 | return ret; |
| 3711 | } | ||
| 3712 | 3981 | ||
| 3982 | spin_lock(&BTRFS_I(inode)->accounting_lock); | ||
| 3713 | BTRFS_I(inode)->reserved_extents += nr_extents; | 3983 | BTRFS_I(inode)->reserved_extents += nr_extents; |
| 3714 | atomic_inc(&BTRFS_I(inode)->outstanding_extents); | 3984 | atomic_inc(&BTRFS_I(inode)->outstanding_extents); |
| 3715 | spin_unlock(&BTRFS_I(inode)->accounting_lock); | 3985 | spin_unlock(&BTRFS_I(inode)->accounting_lock); |
| @@ -3717,7 +3987,7 @@ again: | |||
| 3717 | block_rsv_add_bytes(block_rsv, to_reserve, 1); | 3987 | block_rsv_add_bytes(block_rsv, to_reserve, 1); |
| 3718 | 3988 | ||
| 3719 | if (block_rsv->size > 512 * 1024 * 1024) | 3989 | if (block_rsv->size > 512 * 1024 * 1024) |
| 3720 | shrink_delalloc(NULL, root, to_reserve); | 3990 | shrink_delalloc(NULL, root, to_reserve, 0); |
| 3721 | 3991 | ||
| 3722 | return 0; | 3992 | return 0; |
| 3723 | } | 3993 | } |
| @@ -3776,12 +4046,12 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
| 3776 | struct btrfs_root *root, | 4046 | struct btrfs_root *root, |
| 3777 | u64 bytenr, u64 num_bytes, int alloc) | 4047 | u64 bytenr, u64 num_bytes, int alloc) |
| 3778 | { | 4048 | { |
| 3779 | struct btrfs_block_group_cache *cache; | 4049 | struct btrfs_block_group_cache *cache = NULL; |
| 3780 | struct btrfs_fs_info *info = root->fs_info; | 4050 | struct btrfs_fs_info *info = root->fs_info; |
| 3781 | int factor; | ||
| 3782 | u64 total = num_bytes; | 4051 | u64 total = num_bytes; |
| 3783 | u64 old_val; | 4052 | u64 old_val; |
| 3784 | u64 byte_in_group; | 4053 | u64 byte_in_group; |
| 4054 | int factor; | ||
| 3785 | 4055 | ||
| 3786 | /* block accounting for super block */ | 4056 | /* block accounting for super block */ |
| 3787 | spin_lock(&info->delalloc_lock); | 4057 | spin_lock(&info->delalloc_lock); |
| @@ -3803,11 +4073,25 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
| 3803 | factor = 2; | 4073 | factor = 2; |
| 3804 | else | 4074 | else |
| 3805 | factor = 1; | 4075 | factor = 1; |
| 4076 | /* | ||
| 4077 | * If this block group has free space cache written out, we | ||
| 4078 | * need to make sure to load it if we are removing space. This | ||
| 4079 | * is because we need the unpinning stage to actually add the | ||
| 4080 | * space back to the block group, otherwise we will leak space. | ||
| 4081 | */ | ||
| 4082 | if (!alloc && cache->cached == BTRFS_CACHE_NO) | ||
| 4083 | cache_block_group(cache, trans, 1); | ||
| 4084 | |||
| 3806 | byte_in_group = bytenr - cache->key.objectid; | 4085 | byte_in_group = bytenr - cache->key.objectid; |
| 3807 | WARN_ON(byte_in_group > cache->key.offset); | 4086 | WARN_ON(byte_in_group > cache->key.offset); |
| 3808 | 4087 | ||
| 3809 | spin_lock(&cache->space_info->lock); | 4088 | spin_lock(&cache->space_info->lock); |
| 3810 | spin_lock(&cache->lock); | 4089 | spin_lock(&cache->lock); |
| 4090 | |||
| 4091 | if (btrfs_super_cache_generation(&info->super_copy) != 0 && | ||
| 4092 | cache->disk_cache_state < BTRFS_DC_CLEAR) | ||
| 4093 | cache->disk_cache_state = BTRFS_DC_CLEAR; | ||
| 4094 | |||
| 3811 | cache->dirty = 1; | 4095 | cache->dirty = 1; |
| 3812 | old_val = btrfs_block_group_used(&cache->item); | 4096 | old_val = btrfs_block_group_used(&cache->item); |
| 3813 | num_bytes = min(total, cache->key.offset - byte_in_group); | 4097 | num_bytes = min(total, cache->key.offset - byte_in_group); |
| @@ -4554,6 +4838,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, | |||
| 4554 | bool found_uncached_bg = false; | 4838 | bool found_uncached_bg = false; |
| 4555 | bool failed_cluster_refill = false; | 4839 | bool failed_cluster_refill = false; |
| 4556 | bool failed_alloc = false; | 4840 | bool failed_alloc = false; |
| 4841 | bool use_cluster = true; | ||
| 4557 | u64 ideal_cache_percent = 0; | 4842 | u64 ideal_cache_percent = 0; |
| 4558 | u64 ideal_cache_offset = 0; | 4843 | u64 ideal_cache_offset = 0; |
| 4559 | 4844 | ||
| @@ -4568,16 +4853,24 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, | |||
| 4568 | return -ENOSPC; | 4853 | return -ENOSPC; |
| 4569 | } | 4854 | } |
| 4570 | 4855 | ||
| 4856 | /* | ||
| 4857 | * If the space info is for both data and metadata it means we have a | ||
| 4858 | * small filesystem and we can't use the clustering stuff. | ||
| 4859 | */ | ||
| 4860 | if (btrfs_mixed_space_info(space_info)) | ||
| 4861 | use_cluster = false; | ||
| 4862 | |||
| 4571 | if (orig_root->ref_cows || empty_size) | 4863 | if (orig_root->ref_cows || empty_size) |
| 4572 | allowed_chunk_alloc = 1; | 4864 | allowed_chunk_alloc = 1; |
| 4573 | 4865 | ||
| 4574 | if (data & BTRFS_BLOCK_GROUP_METADATA) { | 4866 | if (data & BTRFS_BLOCK_GROUP_METADATA && use_cluster) { |
| 4575 | last_ptr = &root->fs_info->meta_alloc_cluster; | 4867 | last_ptr = &root->fs_info->meta_alloc_cluster; |
| 4576 | if (!btrfs_test_opt(root, SSD)) | 4868 | if (!btrfs_test_opt(root, SSD)) |
| 4577 | empty_cluster = 64 * 1024; | 4869 | empty_cluster = 64 * 1024; |
| 4578 | } | 4870 | } |
| 4579 | 4871 | ||
| 4580 | if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD)) { | 4872 | if ((data & BTRFS_BLOCK_GROUP_DATA) && use_cluster && |
| 4873 | btrfs_test_opt(root, SSD)) { | ||
| 4581 | last_ptr = &root->fs_info->data_alloc_cluster; | 4874 | last_ptr = &root->fs_info->data_alloc_cluster; |
| 4582 | } | 4875 | } |
| 4583 | 4876 | ||
| @@ -4641,6 +4934,10 @@ have_block_group: | |||
| 4641 | if (unlikely(block_group->cached == BTRFS_CACHE_NO)) { | 4934 | if (unlikely(block_group->cached == BTRFS_CACHE_NO)) { |
| 4642 | u64 free_percent; | 4935 | u64 free_percent; |
| 4643 | 4936 | ||
| 4937 | ret = cache_block_group(block_group, trans, 1); | ||
| 4938 | if (block_group->cached == BTRFS_CACHE_FINISHED) | ||
| 4939 | goto have_block_group; | ||
| 4940 | |||
| 4644 | free_percent = btrfs_block_group_used(&block_group->item); | 4941 | free_percent = btrfs_block_group_used(&block_group->item); |
| 4645 | free_percent *= 100; | 4942 | free_percent *= 100; |
| 4646 | free_percent = div64_u64(free_percent, | 4943 | free_percent = div64_u64(free_percent, |
| @@ -4661,7 +4958,7 @@ have_block_group: | |||
| 4661 | if (loop > LOOP_CACHING_NOWAIT || | 4958 | if (loop > LOOP_CACHING_NOWAIT || |
| 4662 | (loop > LOOP_FIND_IDEAL && | 4959 | (loop > LOOP_FIND_IDEAL && |
| 4663 | atomic_read(&space_info->caching_threads) < 2)) { | 4960 | atomic_read(&space_info->caching_threads) < 2)) { |
| 4664 | ret = cache_block_group(block_group); | 4961 | ret = cache_block_group(block_group, trans, 0); |
| 4665 | BUG_ON(ret); | 4962 | BUG_ON(ret); |
| 4666 | } | 4963 | } |
| 4667 | found_uncached_bg = true; | 4964 | found_uncached_bg = true; |
| @@ -5218,7 +5515,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, | |||
| 5218 | u64 num_bytes = ins->offset; | 5515 | u64 num_bytes = ins->offset; |
| 5219 | 5516 | ||
| 5220 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); | 5517 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); |
| 5221 | cache_block_group(block_group); | 5518 | cache_block_group(block_group, trans, 0); |
| 5222 | caching_ctl = get_caching_control(block_group); | 5519 | caching_ctl = get_caching_control(block_group); |
| 5223 | 5520 | ||
| 5224 | if (!caching_ctl) { | 5521 | if (!caching_ctl) { |
| @@ -5308,7 +5605,8 @@ use_block_rsv(struct btrfs_trans_handle *trans, | |||
| 5308 | block_rsv = get_block_rsv(trans, root); | 5605 | block_rsv = get_block_rsv(trans, root); |
| 5309 | 5606 | ||
| 5310 | if (block_rsv->size == 0) { | 5607 | if (block_rsv->size == 0) { |
| 5311 | ret = reserve_metadata_bytes(block_rsv, blocksize); | 5608 | ret = reserve_metadata_bytes(trans, root, block_rsv, |
| 5609 | blocksize, 0); | ||
| 5312 | if (ret) | 5610 | if (ret) |
| 5313 | return ERR_PTR(ret); | 5611 | return ERR_PTR(ret); |
| 5314 | return block_rsv; | 5612 | return block_rsv; |
| @@ -5318,11 +5616,6 @@ use_block_rsv(struct btrfs_trans_handle *trans, | |||
| 5318 | if (!ret) | 5616 | if (!ret) |
| 5319 | return block_rsv; | 5617 | return block_rsv; |
| 5320 | 5618 | ||
| 5321 | WARN_ON(1); | ||
| 5322 | printk(KERN_INFO"block_rsv size %llu reserved %llu freed %llu %llu\n", | ||
| 5323 | block_rsv->size, block_rsv->reserved, | ||
| 5324 | block_rsv->freed[0], block_rsv->freed[1]); | ||
| 5325 | |||
| 5326 | return ERR_PTR(-ENOSPC); | 5619 | return ERR_PTR(-ENOSPC); |
| 5327 | } | 5620 | } |
| 5328 | 5621 | ||
| @@ -5421,7 +5714,6 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans, | |||
| 5421 | u64 generation; | 5714 | u64 generation; |
| 5422 | u64 refs; | 5715 | u64 refs; |
| 5423 | u64 flags; | 5716 | u64 flags; |
| 5424 | u64 last = 0; | ||
| 5425 | u32 nritems; | 5717 | u32 nritems; |
| 5426 | u32 blocksize; | 5718 | u32 blocksize; |
| 5427 | struct btrfs_key key; | 5719 | struct btrfs_key key; |
| @@ -5489,7 +5781,6 @@ reada: | |||
| 5489 | generation); | 5781 | generation); |
| 5490 | if (ret) | 5782 | if (ret) |
| 5491 | break; | 5783 | break; |
| 5492 | last = bytenr + blocksize; | ||
| 5493 | nread++; | 5784 | nread++; |
| 5494 | } | 5785 | } |
| 5495 | wc->reada_slot = slot; | 5786 | wc->reada_slot = slot; |
| @@ -7813,6 +8104,40 @@ out: | |||
| 7813 | return ret; | 8104 | return ret; |
| 7814 | } | 8105 | } |
| 7815 | 8106 | ||
| 8107 | void btrfs_put_block_group_cache(struct btrfs_fs_info *info) | ||
| 8108 | { | ||
| 8109 | struct btrfs_block_group_cache *block_group; | ||
| 8110 | u64 last = 0; | ||
| 8111 | |||
| 8112 | while (1) { | ||
| 8113 | struct inode *inode; | ||
| 8114 | |||
| 8115 | block_group = btrfs_lookup_first_block_group(info, last); | ||
| 8116 | while (block_group) { | ||
| 8117 | spin_lock(&block_group->lock); | ||
| 8118 | if (block_group->iref) | ||
| 8119 | break; | ||
| 8120 | spin_unlock(&block_group->lock); | ||
| 8121 | block_group = next_block_group(info->tree_root, | ||
| 8122 | block_group); | ||
| 8123 | } | ||
| 8124 | if (!block_group) { | ||
| 8125 | if (last == 0) | ||
| 8126 | break; | ||
| 8127 | last = 0; | ||
| 8128 | continue; | ||
| 8129 | } | ||
| 8130 | |||
| 8131 | inode = block_group->inode; | ||
| 8132 | block_group->iref = 0; | ||
| 8133 | block_group->inode = NULL; | ||
| 8134 | spin_unlock(&block_group->lock); | ||
| 8135 | iput(inode); | ||
| 8136 | last = block_group->key.objectid + block_group->key.offset; | ||
| 8137 | btrfs_put_block_group(block_group); | ||
| 8138 | } | ||
| 8139 | } | ||
| 8140 | |||
| 7816 | int btrfs_free_block_groups(struct btrfs_fs_info *info) | 8141 | int btrfs_free_block_groups(struct btrfs_fs_info *info) |
| 7817 | { | 8142 | { |
| 7818 | struct btrfs_block_group_cache *block_group; | 8143 | struct btrfs_block_group_cache *block_group; |
| @@ -7896,6 +8221,8 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
| 7896 | struct btrfs_key key; | 8221 | struct btrfs_key key; |
| 7897 | struct btrfs_key found_key; | 8222 | struct btrfs_key found_key; |
| 7898 | struct extent_buffer *leaf; | 8223 | struct extent_buffer *leaf; |
| 8224 | int need_clear = 0; | ||
| 8225 | u64 cache_gen; | ||
| 7899 | 8226 | ||
| 7900 | root = info->extent_root; | 8227 | root = info->extent_root; |
| 7901 | key.objectid = 0; | 8228 | key.objectid = 0; |
| @@ -7905,6 +8232,15 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
| 7905 | if (!path) | 8232 | if (!path) |
| 7906 | return -ENOMEM; | 8233 | return -ENOMEM; |
| 7907 | 8234 | ||
| 8235 | cache_gen = btrfs_super_cache_generation(&root->fs_info->super_copy); | ||
| 8236 | if (cache_gen != 0 && | ||
| 8237 | btrfs_super_generation(&root->fs_info->super_copy) != cache_gen) | ||
| 8238 | need_clear = 1; | ||
| 8239 | if (btrfs_test_opt(root, CLEAR_CACHE)) | ||
| 8240 | need_clear = 1; | ||
| 8241 | if (!btrfs_test_opt(root, SPACE_CACHE) && cache_gen) | ||
| 8242 | printk(KERN_INFO "btrfs: disk space caching is enabled\n"); | ||
| 8243 | |||
| 7908 | while (1) { | 8244 | while (1) { |
| 7909 | ret = find_first_block_group(root, path, &key); | 8245 | ret = find_first_block_group(root, path, &key); |
| 7910 | if (ret > 0) | 8246 | if (ret > 0) |
| @@ -7927,6 +8263,9 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
| 7927 | INIT_LIST_HEAD(&cache->list); | 8263 | INIT_LIST_HEAD(&cache->list); |
| 7928 | INIT_LIST_HEAD(&cache->cluster_list); | 8264 | INIT_LIST_HEAD(&cache->cluster_list); |
| 7929 | 8265 | ||
| 8266 | if (need_clear) | ||
| 8267 | cache->disk_cache_state = BTRFS_DC_CLEAR; | ||
| 8268 | |||
| 7930 | /* | 8269 | /* |
| 7931 | * we only want to have 32k of ram per block group for keeping | 8270 | * we only want to have 32k of ram per block group for keeping |
| 7932 | * track of free space, and if we pass 1/2 of that we want to | 8271 | * track of free space, and if we pass 1/2 of that we want to |
| @@ -8031,6 +8370,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, | |||
| 8031 | cache->key.offset = size; | 8370 | cache->key.offset = size; |
| 8032 | cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; | 8371 | cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; |
| 8033 | cache->sectorsize = root->sectorsize; | 8372 | cache->sectorsize = root->sectorsize; |
| 8373 | cache->fs_info = root->fs_info; | ||
| 8034 | 8374 | ||
| 8035 | /* | 8375 | /* |
| 8036 | * we only want to have 32k of ram per block group for keeping track | 8376 | * we only want to have 32k of ram per block group for keeping track |
| @@ -8087,8 +8427,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | |||
| 8087 | struct btrfs_path *path; | 8427 | struct btrfs_path *path; |
| 8088 | struct btrfs_block_group_cache *block_group; | 8428 | struct btrfs_block_group_cache *block_group; |
| 8089 | struct btrfs_free_cluster *cluster; | 8429 | struct btrfs_free_cluster *cluster; |
| 8430 | struct btrfs_root *tree_root = root->fs_info->tree_root; | ||
| 8090 | struct btrfs_key key; | 8431 | struct btrfs_key key; |
| 8432 | struct inode *inode; | ||
| 8091 | int ret; | 8433 | int ret; |
| 8434 | int factor; | ||
| 8092 | 8435 | ||
| 8093 | root = root->fs_info->extent_root; | 8436 | root = root->fs_info->extent_root; |
| 8094 | 8437 | ||
| @@ -8097,6 +8440,12 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | |||
| 8097 | BUG_ON(!block_group->ro); | 8440 | BUG_ON(!block_group->ro); |
| 8098 | 8441 | ||
| 8099 | memcpy(&key, &block_group->key, sizeof(key)); | 8442 | memcpy(&key, &block_group->key, sizeof(key)); |
| 8443 | if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP | | ||
| 8444 | BTRFS_BLOCK_GROUP_RAID1 | | ||
| 8445 | BTRFS_BLOCK_GROUP_RAID10)) | ||
| 8446 | factor = 2; | ||
| 8447 | else | ||
| 8448 | factor = 1; | ||
| 8100 | 8449 | ||
| 8101 | /* make sure this block group isn't part of an allocation cluster */ | 8450 | /* make sure this block group isn't part of an allocation cluster */ |
| 8102 | cluster = &root->fs_info->data_alloc_cluster; | 8451 | cluster = &root->fs_info->data_alloc_cluster; |
| @@ -8116,6 +8465,40 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | |||
| 8116 | path = btrfs_alloc_path(); | 8465 | path = btrfs_alloc_path(); |
| 8117 | BUG_ON(!path); | 8466 | BUG_ON(!path); |
| 8118 | 8467 | ||
| 8468 | inode = lookup_free_space_inode(root, block_group, path); | ||
| 8469 | if (!IS_ERR(inode)) { | ||
| 8470 | btrfs_orphan_add(trans, inode); | ||
| 8471 | clear_nlink(inode); | ||
| 8472 | /* One for the block groups ref */ | ||
| 8473 | spin_lock(&block_group->lock); | ||
| 8474 | if (block_group->iref) { | ||
| 8475 | block_group->iref = 0; | ||
| 8476 | block_group->inode = NULL; | ||
| 8477 | spin_unlock(&block_group->lock); | ||
| 8478 | iput(inode); | ||
| 8479 | } else { | ||
| 8480 | spin_unlock(&block_group->lock); | ||
| 8481 | } | ||
| 8482 | /* One for our lookup ref */ | ||
| 8483 | iput(inode); | ||
| 8484 | } | ||
| 8485 | |||
| 8486 | key.objectid = BTRFS_FREE_SPACE_OBJECTID; | ||
| 8487 | key.offset = block_group->key.objectid; | ||
| 8488 | key.type = 0; | ||
| 8489 | |||
| 8490 | ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); | ||
| 8491 | if (ret < 0) | ||
| 8492 | goto out; | ||
| 8493 | if (ret > 0) | ||
| 8494 | btrfs_release_path(tree_root, path); | ||
| 8495 | if (ret == 0) { | ||
| 8496 | ret = btrfs_del_item(trans, tree_root, path); | ||
| 8497 | if (ret) | ||
| 8498 | goto out; | ||
| 8499 | btrfs_release_path(tree_root, path); | ||
| 8500 | } | ||
| 8501 | |||
| 8119 | spin_lock(&root->fs_info->block_group_cache_lock); | 8502 | spin_lock(&root->fs_info->block_group_cache_lock); |
| 8120 | rb_erase(&block_group->cache_node, | 8503 | rb_erase(&block_group->cache_node, |
| 8121 | &root->fs_info->block_group_cache_tree); | 8504 | &root->fs_info->block_group_cache_tree); |
| @@ -8137,8 +8520,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | |||
| 8137 | spin_lock(&block_group->space_info->lock); | 8520 | spin_lock(&block_group->space_info->lock); |
| 8138 | block_group->space_info->total_bytes -= block_group->key.offset; | 8521 | block_group->space_info->total_bytes -= block_group->key.offset; |
| 8139 | block_group->space_info->bytes_readonly -= block_group->key.offset; | 8522 | block_group->space_info->bytes_readonly -= block_group->key.offset; |
| 8523 | block_group->space_info->disk_total -= block_group->key.offset * factor; | ||
| 8140 | spin_unlock(&block_group->space_info->lock); | 8524 | spin_unlock(&block_group->space_info->lock); |
| 8141 | 8525 | ||
| 8526 | memcpy(&key, &block_group->key, sizeof(key)); | ||
| 8527 | |||
| 8142 | btrfs_clear_space_info_full(root->fs_info); | 8528 | btrfs_clear_space_info_full(root->fs_info); |
| 8143 | 8529 | ||
| 8144 | btrfs_put_block_group(block_group); | 8530 | btrfs_put_block_group(block_group); |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d74e6af9b53a..eac10e3260a9 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
| @@ -104,7 +104,7 @@ void extent_io_tree_init(struct extent_io_tree *tree, | |||
| 104 | struct address_space *mapping, gfp_t mask) | 104 | struct address_space *mapping, gfp_t mask) |
| 105 | { | 105 | { |
| 106 | tree->state = RB_ROOT; | 106 | tree->state = RB_ROOT; |
| 107 | tree->buffer = RB_ROOT; | 107 | INIT_RADIX_TREE(&tree->buffer, GFP_ATOMIC); |
| 108 | tree->ops = NULL; | 108 | tree->ops = NULL; |
| 109 | tree->dirty_bytes = 0; | 109 | tree->dirty_bytes = 0; |
| 110 | spin_lock_init(&tree->lock); | 110 | spin_lock_init(&tree->lock); |
| @@ -235,50 +235,6 @@ static inline struct rb_node *tree_search(struct extent_io_tree *tree, | |||
| 235 | return ret; | 235 | return ret; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | static struct extent_buffer *buffer_tree_insert(struct extent_io_tree *tree, | ||
| 239 | u64 offset, struct rb_node *node) | ||
| 240 | { | ||
| 241 | struct rb_root *root = &tree->buffer; | ||
| 242 | struct rb_node **p = &root->rb_node; | ||
| 243 | struct rb_node *parent = NULL; | ||
| 244 | struct extent_buffer *eb; | ||
| 245 | |||
| 246 | while (*p) { | ||
| 247 | parent = *p; | ||
| 248 | eb = rb_entry(parent, struct extent_buffer, rb_node); | ||
| 249 | |||
| 250 | if (offset < eb->start) | ||
| 251 | p = &(*p)->rb_left; | ||
| 252 | else if (offset > eb->start) | ||
| 253 | p = &(*p)->rb_right; | ||
| 254 | else | ||
| 255 | return eb; | ||
| 256 | } | ||
| 257 | |||
| 258 | rb_link_node(node, parent, p); | ||
| 259 | rb_insert_color(node, root); | ||
| 260 | return NULL; | ||
| 261 | } | ||
| 262 | |||
| 263 | static struct extent_buffer *buffer_search(struct extent_io_tree *tree, | ||
| 264 | u64 offset) | ||
| 265 | { | ||
| 266 | struct rb_root *root = &tree->buffer; | ||
| 267 | struct rb_node *n = root->rb_node; | ||
| 268 | struct extent_buffer *eb; | ||
| 269 | |||
| 270 | while (n) { | ||
| 271 | eb = rb_entry(n, struct extent_buffer, rb_node); | ||
| 272 | if (offset < eb->start) | ||
| 273 | n = n->rb_left; | ||
| 274 | else if (offset > eb->start) | ||
| 275 | n = n->rb_right; | ||
| 276 | else | ||
| 277 | return eb; | ||
| 278 | } | ||
| 279 | return NULL; | ||
| 280 | } | ||
| 281 | |||
| 282 | static void merge_cb(struct extent_io_tree *tree, struct extent_state *new, | 238 | static void merge_cb(struct extent_io_tree *tree, struct extent_state *new, |
| 283 | struct extent_state *other) | 239 | struct extent_state *other) |
| 284 | { | 240 | { |
| @@ -1901,10 +1857,8 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num, | |||
| 1901 | struct page *page = bvec->bv_page; | 1857 | struct page *page = bvec->bv_page; |
| 1902 | struct extent_io_tree *tree = bio->bi_private; | 1858 | struct extent_io_tree *tree = bio->bi_private; |
| 1903 | u64 start; | 1859 | u64 start; |
| 1904 | u64 end; | ||
| 1905 | 1860 | ||
| 1906 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + bvec->bv_offset; | 1861 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + bvec->bv_offset; |
| 1907 | end = start + bvec->bv_len - 1; | ||
| 1908 | 1862 | ||
| 1909 | bio->bi_private = NULL; | 1863 | bio->bi_private = NULL; |
| 1910 | 1864 | ||
| @@ -2204,7 +2158,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2204 | u64 last_byte = i_size_read(inode); | 2158 | u64 last_byte = i_size_read(inode); |
| 2205 | u64 block_start; | 2159 | u64 block_start; |
| 2206 | u64 iosize; | 2160 | u64 iosize; |
| 2207 | u64 unlock_start; | ||
| 2208 | sector_t sector; | 2161 | sector_t sector; |
| 2209 | struct extent_state *cached_state = NULL; | 2162 | struct extent_state *cached_state = NULL; |
| 2210 | struct extent_map *em; | 2163 | struct extent_map *em; |
| @@ -2329,7 +2282,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2329 | if (tree->ops && tree->ops->writepage_end_io_hook) | 2282 | if (tree->ops && tree->ops->writepage_end_io_hook) |
| 2330 | tree->ops->writepage_end_io_hook(page, start, | 2283 | tree->ops->writepage_end_io_hook(page, start, |
| 2331 | page_end, NULL, 1); | 2284 | page_end, NULL, 1); |
| 2332 | unlock_start = page_end + 1; | ||
| 2333 | goto done; | 2285 | goto done; |
| 2334 | } | 2286 | } |
| 2335 | 2287 | ||
| @@ -2340,7 +2292,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2340 | if (tree->ops && tree->ops->writepage_end_io_hook) | 2292 | if (tree->ops && tree->ops->writepage_end_io_hook) |
| 2341 | tree->ops->writepage_end_io_hook(page, cur, | 2293 | tree->ops->writepage_end_io_hook(page, cur, |
| 2342 | page_end, NULL, 1); | 2294 | page_end, NULL, 1); |
| 2343 | unlock_start = page_end + 1; | ||
| 2344 | break; | 2295 | break; |
| 2345 | } | 2296 | } |
| 2346 | em = epd->get_extent(inode, page, pg_offset, cur, | 2297 | em = epd->get_extent(inode, page, pg_offset, cur, |
| @@ -2387,7 +2338,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2387 | 2338 | ||
| 2388 | cur += iosize; | 2339 | cur += iosize; |
| 2389 | pg_offset += iosize; | 2340 | pg_offset += iosize; |
| 2390 | unlock_start = cur; | ||
| 2391 | continue; | 2341 | continue; |
| 2392 | } | 2342 | } |
| 2393 | /* leave this out until we have a page_mkwrite call */ | 2343 | /* leave this out until we have a page_mkwrite call */ |
| @@ -2473,7 +2423,6 @@ static int extent_write_cache_pages(struct extent_io_tree *tree, | |||
| 2473 | pgoff_t index; | 2423 | pgoff_t index; |
| 2474 | pgoff_t end; /* Inclusive */ | 2424 | pgoff_t end; /* Inclusive */ |
| 2475 | int scanned = 0; | 2425 | int scanned = 0; |
| 2476 | int range_whole = 0; | ||
| 2477 | 2426 | ||
| 2478 | pagevec_init(&pvec, 0); | 2427 | pagevec_init(&pvec, 0); |
| 2479 | if (wbc->range_cyclic) { | 2428 | if (wbc->range_cyclic) { |
| @@ -2482,8 +2431,6 @@ static int extent_write_cache_pages(struct extent_io_tree *tree, | |||
| 2482 | } else { | 2431 | } else { |
| 2483 | index = wbc->range_start >> PAGE_CACHE_SHIFT; | 2432 | index = wbc->range_start >> PAGE_CACHE_SHIFT; |
| 2484 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | 2433 | end = wbc->range_end >> PAGE_CACHE_SHIFT; |
| 2485 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) | ||
| 2486 | range_whole = 1; | ||
| 2487 | scanned = 1; | 2434 | scanned = 1; |
| 2488 | } | 2435 | } |
| 2489 | retry: | 2436 | retry: |
| @@ -2823,6 +2770,8 @@ int extent_prepare_write(struct extent_io_tree *tree, | |||
| 2823 | NULL, 1, | 2770 | NULL, 1, |
| 2824 | end_bio_extent_preparewrite, 0, | 2771 | end_bio_extent_preparewrite, 0, |
| 2825 | 0, 0); | 2772 | 0, 0); |
| 2773 | if (ret && !err) | ||
| 2774 | err = ret; | ||
| 2826 | iocount++; | 2775 | iocount++; |
| 2827 | block_start = block_start + iosize; | 2776 | block_start = block_start + iosize; |
| 2828 | } else { | 2777 | } else { |
| @@ -3104,6 +3053,39 @@ static void __free_extent_buffer(struct extent_buffer *eb) | |||
| 3104 | kmem_cache_free(extent_buffer_cache, eb); | 3053 | kmem_cache_free(extent_buffer_cache, eb); |
| 3105 | } | 3054 | } |
| 3106 | 3055 | ||
| 3056 | /* | ||
| 3057 | * Helper for releasing extent buffer page. | ||
| 3058 | */ | ||
| 3059 | static void btrfs_release_extent_buffer_page(struct extent_buffer *eb, | ||
| 3060 | unsigned long start_idx) | ||
| 3061 | { | ||
| 3062 | unsigned long index; | ||
| 3063 | struct page *page; | ||
| 3064 | |||
| 3065 | if (!eb->first_page) | ||
| 3066 | return; | ||
| 3067 | |||
| 3068 | index = num_extent_pages(eb->start, eb->len); | ||
| 3069 | if (start_idx >= index) | ||
| 3070 | return; | ||
| 3071 | |||
| 3072 | do { | ||
| 3073 | index--; | ||
| 3074 | page = extent_buffer_page(eb, index); | ||
| 3075 | if (page) | ||
| 3076 | page_cache_release(page); | ||
| 3077 | } while (index != start_idx); | ||
| 3078 | } | ||
| 3079 | |||
| 3080 | /* | ||
| 3081 | * Helper for releasing the extent buffer. | ||
| 3082 | */ | ||
| 3083 | static inline void btrfs_release_extent_buffer(struct extent_buffer *eb) | ||
| 3084 | { | ||
| 3085 | btrfs_release_extent_buffer_page(eb, 0); | ||
| 3086 | __free_extent_buffer(eb); | ||
| 3087 | } | ||
| 3088 | |||
| 3107 | struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | 3089 | struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, |
| 3108 | u64 start, unsigned long len, | 3090 | u64 start, unsigned long len, |
| 3109 | struct page *page0, | 3091 | struct page *page0, |
| @@ -3117,16 +3099,16 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
| 3117 | struct page *p; | 3099 | struct page *p; |
| 3118 | struct address_space *mapping = tree->mapping; | 3100 | struct address_space *mapping = tree->mapping; |
| 3119 | int uptodate = 1; | 3101 | int uptodate = 1; |
| 3102 | int ret; | ||
| 3120 | 3103 | ||
| 3121 | spin_lock(&tree->buffer_lock); | 3104 | rcu_read_lock(); |
| 3122 | eb = buffer_search(tree, start); | 3105 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 3123 | if (eb) { | 3106 | if (eb && atomic_inc_not_zero(&eb->refs)) { |
| 3124 | atomic_inc(&eb->refs); | 3107 | rcu_read_unlock(); |
| 3125 | spin_unlock(&tree->buffer_lock); | ||
| 3126 | mark_page_accessed(eb->first_page); | 3108 | mark_page_accessed(eb->first_page); |
| 3127 | return eb; | 3109 | return eb; |
| 3128 | } | 3110 | } |
| 3129 | spin_unlock(&tree->buffer_lock); | 3111 | rcu_read_unlock(); |
| 3130 | 3112 | ||
| 3131 | eb = __alloc_extent_buffer(tree, start, len, mask); | 3113 | eb = __alloc_extent_buffer(tree, start, len, mask); |
| 3132 | if (!eb) | 3114 | if (!eb) |
| @@ -3165,26 +3147,31 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
| 3165 | if (uptodate) | 3147 | if (uptodate) |
| 3166 | set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); | 3148 | set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); |
| 3167 | 3149 | ||
| 3150 | ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); | ||
| 3151 | if (ret) | ||
| 3152 | goto free_eb; | ||
| 3153 | |||
| 3168 | spin_lock(&tree->buffer_lock); | 3154 | spin_lock(&tree->buffer_lock); |
| 3169 | exists = buffer_tree_insert(tree, start, &eb->rb_node); | 3155 | ret = radix_tree_insert(&tree->buffer, start >> PAGE_CACHE_SHIFT, eb); |
| 3170 | if (exists) { | 3156 | if (ret == -EEXIST) { |
| 3157 | exists = radix_tree_lookup(&tree->buffer, | ||
| 3158 | start >> PAGE_CACHE_SHIFT); | ||
| 3171 | /* add one reference for the caller */ | 3159 | /* add one reference for the caller */ |
| 3172 | atomic_inc(&exists->refs); | 3160 | atomic_inc(&exists->refs); |
| 3173 | spin_unlock(&tree->buffer_lock); | 3161 | spin_unlock(&tree->buffer_lock); |
| 3162 | radix_tree_preload_end(); | ||
| 3174 | goto free_eb; | 3163 | goto free_eb; |
| 3175 | } | 3164 | } |
| 3176 | /* add one reference for the tree */ | 3165 | /* add one reference for the tree */ |
| 3177 | atomic_inc(&eb->refs); | 3166 | atomic_inc(&eb->refs); |
| 3178 | spin_unlock(&tree->buffer_lock); | 3167 | spin_unlock(&tree->buffer_lock); |
| 3168 | radix_tree_preload_end(); | ||
| 3179 | return eb; | 3169 | return eb; |
| 3180 | 3170 | ||
| 3181 | free_eb: | 3171 | free_eb: |
| 3182 | if (!atomic_dec_and_test(&eb->refs)) | 3172 | if (!atomic_dec_and_test(&eb->refs)) |
| 3183 | return exists; | 3173 | return exists; |
| 3184 | for (index = 1; index < i; index++) | 3174 | btrfs_release_extent_buffer(eb); |
| 3185 | page_cache_release(extent_buffer_page(eb, index)); | ||
| 3186 | page_cache_release(extent_buffer_page(eb, 0)); | ||
| 3187 | __free_extent_buffer(eb); | ||
| 3188 | return exists; | 3175 | return exists; |
| 3189 | } | 3176 | } |
| 3190 | 3177 | ||
| @@ -3194,16 +3181,16 @@ struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, | |||
| 3194 | { | 3181 | { |
| 3195 | struct extent_buffer *eb; | 3182 | struct extent_buffer *eb; |
| 3196 | 3183 | ||
| 3197 | spin_lock(&tree->buffer_lock); | 3184 | rcu_read_lock(); |
| 3198 | eb = buffer_search(tree, start); | 3185 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 3199 | if (eb) | 3186 | if (eb && atomic_inc_not_zero(&eb->refs)) { |
| 3200 | atomic_inc(&eb->refs); | 3187 | rcu_read_unlock(); |
| 3201 | spin_unlock(&tree->buffer_lock); | ||
| 3202 | |||
| 3203 | if (eb) | ||
| 3204 | mark_page_accessed(eb->first_page); | 3188 | mark_page_accessed(eb->first_page); |
| 3189 | return eb; | ||
| 3190 | } | ||
| 3191 | rcu_read_unlock(); | ||
| 3205 | 3192 | ||
| 3206 | return eb; | 3193 | return NULL; |
| 3207 | } | 3194 | } |
| 3208 | 3195 | ||
| 3209 | void free_extent_buffer(struct extent_buffer *eb) | 3196 | void free_extent_buffer(struct extent_buffer *eb) |
| @@ -3833,34 +3820,45 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, | |||
| 3833 | } | 3820 | } |
| 3834 | } | 3821 | } |
| 3835 | 3822 | ||
| 3823 | static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head) | ||
| 3824 | { | ||
| 3825 | struct extent_buffer *eb = | ||
| 3826 | container_of(head, struct extent_buffer, rcu_head); | ||
| 3827 | |||
| 3828 | btrfs_release_extent_buffer(eb); | ||
| 3829 | } | ||
| 3830 | |||
| 3836 | int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) | 3831 | int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) |
| 3837 | { | 3832 | { |
| 3838 | u64 start = page_offset(page); | 3833 | u64 start = page_offset(page); |
| 3839 | struct extent_buffer *eb; | 3834 | struct extent_buffer *eb; |
| 3840 | int ret = 1; | 3835 | int ret = 1; |
| 3841 | unsigned long i; | ||
| 3842 | unsigned long num_pages; | ||
| 3843 | 3836 | ||
| 3844 | spin_lock(&tree->buffer_lock); | 3837 | spin_lock(&tree->buffer_lock); |
| 3845 | eb = buffer_search(tree, start); | 3838 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 3846 | if (!eb) | 3839 | if (!eb) |
| 3847 | goto out; | 3840 | goto out; |
| 3848 | 3841 | ||
| 3849 | if (atomic_read(&eb->refs) > 1) { | 3842 | if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { |
| 3850 | ret = 0; | 3843 | ret = 0; |
| 3851 | goto out; | 3844 | goto out; |
| 3852 | } | 3845 | } |
| 3853 | if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { | 3846 | |
| 3847 | /* | ||
| 3848 | * set @eb->refs to 0 if it is already 1, and then release the @eb. | ||
| 3849 | * Or go back. | ||
| 3850 | */ | ||
| 3851 | if (atomic_cmpxchg(&eb->refs, 1, 0) != 1) { | ||
| 3854 | ret = 0; | 3852 | ret = 0; |
| 3855 | goto out; | 3853 | goto out; |
| 3856 | } | 3854 | } |
| 3857 | /* at this point we can safely release the extent buffer */ | 3855 | |
| 3858 | num_pages = num_extent_pages(eb->start, eb->len); | 3856 | radix_tree_delete(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 3859 | for (i = 0; i < num_pages; i++) | ||
| 3860 | page_cache_release(extent_buffer_page(eb, i)); | ||
| 3861 | rb_erase(&eb->rb_node, &tree->buffer); | ||
| 3862 | __free_extent_buffer(eb); | ||
| 3863 | out: | 3857 | out: |
| 3864 | spin_unlock(&tree->buffer_lock); | 3858 | spin_unlock(&tree->buffer_lock); |
| 3859 | |||
| 3860 | /* at this point we can safely release the extent buffer */ | ||
| 3861 | if (atomic_read(&eb->refs) == 0) | ||
| 3862 | call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu); | ||
| 3865 | return ret; | 3863 | return ret; |
| 3866 | } | 3864 | } |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 5691c7b590da..1c6d4f342ef7 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
| @@ -85,7 +85,7 @@ struct extent_io_ops { | |||
| 85 | 85 | ||
| 86 | struct extent_io_tree { | 86 | struct extent_io_tree { |
| 87 | struct rb_root state; | 87 | struct rb_root state; |
| 88 | struct rb_root buffer; | 88 | struct radix_tree_root buffer; |
| 89 | struct address_space *mapping; | 89 | struct address_space *mapping; |
| 90 | u64 dirty_bytes; | 90 | u64 dirty_bytes; |
| 91 | spinlock_t lock; | 91 | spinlock_t lock; |
| @@ -123,7 +123,7 @@ struct extent_buffer { | |||
| 123 | unsigned long bflags; | 123 | unsigned long bflags; |
| 124 | atomic_t refs; | 124 | atomic_t refs; |
| 125 | struct list_head leak_list; | 125 | struct list_head leak_list; |
| 126 | struct rb_node rb_node; | 126 | struct rcu_head rcu_head; |
| 127 | 127 | ||
| 128 | /* the spinlock is used to protect most operations */ | 128 | /* the spinlock is used to protect most operations */ |
| 129 | spinlock_t lock; | 129 | spinlock_t lock; |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 454ca52d6451..23cb8da3ff66 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
| @@ -335,7 +335,7 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | |||
| 335 | goto out; | 335 | goto out; |
| 336 | } | 336 | } |
| 337 | if (IS_ERR(rb_node)) { | 337 | if (IS_ERR(rb_node)) { |
| 338 | em = ERR_PTR(PTR_ERR(rb_node)); | 338 | em = ERR_CAST(rb_node); |
| 339 | goto out; | 339 | goto out; |
| 340 | } | 340 | } |
| 341 | em = rb_entry(rb_node, struct extent_map, rb_node); | 341 | em = rb_entry(rb_node, struct extent_map, rb_node); |
| @@ -384,7 +384,7 @@ struct extent_map *search_extent_mapping(struct extent_map_tree *tree, | |||
| 384 | goto out; | 384 | goto out; |
| 385 | } | 385 | } |
| 386 | if (IS_ERR(rb_node)) { | 386 | if (IS_ERR(rb_node)) { |
| 387 | em = ERR_PTR(PTR_ERR(rb_node)); | 387 | em = ERR_CAST(rb_node); |
| 388 | goto out; | 388 | goto out; |
| 389 | } | 389 | } |
| 390 | em = rb_entry(rb_node, struct extent_map, rb_node); | 390 | em = rb_entry(rb_node, struct extent_map, rb_node); |
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index f488fac04d99..22ee0dc2e6b8 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
| @@ -23,10 +23,761 @@ | |||
| 23 | #include "ctree.h" | 23 | #include "ctree.h" |
| 24 | #include "free-space-cache.h" | 24 | #include "free-space-cache.h" |
| 25 | #include "transaction.h" | 25 | #include "transaction.h" |
| 26 | #include "disk-io.h" | ||
| 26 | 27 | ||
| 27 | #define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8) | 28 | #define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8) |
| 28 | #define MAX_CACHE_BYTES_PER_GIG (32 * 1024) | 29 | #define MAX_CACHE_BYTES_PER_GIG (32 * 1024) |
| 29 | 30 | ||
| 31 | static void recalculate_thresholds(struct btrfs_block_group_cache | ||
| 32 | *block_group); | ||
| 33 | static int link_free_space(struct btrfs_block_group_cache *block_group, | ||
| 34 | struct btrfs_free_space *info); | ||
| 35 | |||
| 36 | struct inode *lookup_free_space_inode(struct btrfs_root *root, | ||
| 37 | struct btrfs_block_group_cache | ||
| 38 | *block_group, struct btrfs_path *path) | ||
| 39 | { | ||
| 40 | struct btrfs_key key; | ||
| 41 | struct btrfs_key location; | ||
| 42 | struct btrfs_disk_key disk_key; | ||
| 43 | struct btrfs_free_space_header *header; | ||
| 44 | struct extent_buffer *leaf; | ||
| 45 | struct inode *inode = NULL; | ||
| 46 | int ret; | ||
| 47 | |||
| 48 | spin_lock(&block_group->lock); | ||
| 49 | if (block_group->inode) | ||
| 50 | inode = igrab(block_group->inode); | ||
| 51 | spin_unlock(&block_group->lock); | ||
| 52 | if (inode) | ||
| 53 | return inode; | ||
| 54 | |||
| 55 | key.objectid = BTRFS_FREE_SPACE_OBJECTID; | ||
| 56 | key.offset = block_group->key.objectid; | ||
| 57 | key.type = 0; | ||
| 58 | |||
| 59 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
| 60 | if (ret < 0) | ||
| 61 | return ERR_PTR(ret); | ||
| 62 | if (ret > 0) { | ||
| 63 | btrfs_release_path(root, path); | ||
| 64 | return ERR_PTR(-ENOENT); | ||
| 65 | } | ||
| 66 | |||
| 67 | leaf = path->nodes[0]; | ||
| 68 | header = btrfs_item_ptr(leaf, path->slots[0], | ||
| 69 | struct btrfs_free_space_header); | ||
| 70 | btrfs_free_space_key(leaf, header, &disk_key); | ||
| 71 | btrfs_disk_key_to_cpu(&location, &disk_key); | ||
| 72 | btrfs_release_path(root, path); | ||
| 73 | |||
| 74 | inode = btrfs_iget(root->fs_info->sb, &location, root, NULL); | ||
| 75 | if (!inode) | ||
| 76 | return ERR_PTR(-ENOENT); | ||
| 77 | if (IS_ERR(inode)) | ||
| 78 | return inode; | ||
| 79 | if (is_bad_inode(inode)) { | ||
| 80 | iput(inode); | ||
| 81 | return ERR_PTR(-ENOENT); | ||
| 82 | } | ||
| 83 | |||
| 84 | spin_lock(&block_group->lock); | ||
| 85 | if (!root->fs_info->closing) { | ||
| 86 | block_group->inode = igrab(inode); | ||
| 87 | block_group->iref = 1; | ||
| 88 | } | ||
| 89 | spin_unlock(&block_group->lock); | ||
| 90 | |||
| 91 | return inode; | ||
| 92 | } | ||
| 93 | |||
| 94 | int create_free_space_inode(struct btrfs_root *root, | ||
| 95 | struct btrfs_trans_handle *trans, | ||
| 96 | struct btrfs_block_group_cache *block_group, | ||
| 97 | struct btrfs_path *path) | ||
| 98 | { | ||
| 99 | struct btrfs_key key; | ||
| 100 | struct btrfs_disk_key disk_key; | ||
| 101 | struct btrfs_free_space_header *header; | ||
| 102 | struct btrfs_inode_item *inode_item; | ||
| 103 | struct extent_buffer *leaf; | ||
| 104 | u64 objectid; | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | ret = btrfs_find_free_objectid(trans, root, 0, &objectid); | ||
| 108 | if (ret < 0) | ||
| 109 | return ret; | ||
| 110 | |||
| 111 | ret = btrfs_insert_empty_inode(trans, root, path, objectid); | ||
| 112 | if (ret) | ||
| 113 | return ret; | ||
| 114 | |||
| 115 | leaf = path->nodes[0]; | ||
| 116 | inode_item = btrfs_item_ptr(leaf, path->slots[0], | ||
| 117 | struct btrfs_inode_item); | ||
| 118 | btrfs_item_key(leaf, &disk_key, path->slots[0]); | ||
| 119 | memset_extent_buffer(leaf, 0, (unsigned long)inode_item, | ||
| 120 | sizeof(*inode_item)); | ||
| 121 | btrfs_set_inode_generation(leaf, inode_item, trans->transid); | ||
| 122 | btrfs_set_inode_size(leaf, inode_item, 0); | ||
| 123 | btrfs_set_inode_nbytes(leaf, inode_item, 0); | ||
| 124 | btrfs_set_inode_uid(leaf, inode_item, 0); | ||
| 125 | btrfs_set_inode_gid(leaf, inode_item, 0); | ||
| 126 | btrfs_set_inode_mode(leaf, inode_item, S_IFREG | 0600); | ||
| 127 | btrfs_set_inode_flags(leaf, inode_item, BTRFS_INODE_NOCOMPRESS | | ||
| 128 | BTRFS_INODE_PREALLOC | BTRFS_INODE_NODATASUM); | ||
| 129 | btrfs_set_inode_nlink(leaf, inode_item, 1); | ||
| 130 | btrfs_set_inode_transid(leaf, inode_item, trans->transid); | ||
| 131 | btrfs_set_inode_block_group(leaf, inode_item, | ||
| 132 | block_group->key.objectid); | ||
| 133 | btrfs_mark_buffer_dirty(leaf); | ||
| 134 | btrfs_release_path(root, path); | ||
| 135 | |||
| 136 | key.objectid = BTRFS_FREE_SPACE_OBJECTID; | ||
| 137 | key.offset = block_group->key.objectid; | ||
| 138 | key.type = 0; | ||
| 139 | |||
| 140 | ret = btrfs_insert_empty_item(trans, root, path, &key, | ||
| 141 | sizeof(struct btrfs_free_space_header)); | ||
| 142 | if (ret < 0) { | ||
| 143 | btrfs_release_path(root, path); | ||
| 144 | return ret; | ||
| 145 | } | ||
| 146 | leaf = path->nodes[0]; | ||
| 147 | header = btrfs_item_ptr(leaf, path->slots[0], | ||
| 148 | struct btrfs_free_space_header); | ||
| 149 | memset_extent_buffer(leaf, 0, (unsigned long)header, sizeof(*header)); | ||
| 150 | btrfs_set_free_space_key(leaf, header, &disk_key); | ||
| 151 | btrfs_mark_buffer_dirty(leaf); | ||
| 152 | btrfs_release_path(root, path); | ||
| 153 | |||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | int btrfs_truncate_free_space_cache(struct btrfs_root *root, | ||
| 158 | struct btrfs_trans_handle *trans, | ||
| 159 | struct btrfs_path *path, | ||
| 160 | struct inode *inode) | ||
| 161 | { | ||
| 162 | loff_t oldsize; | ||
| 163 | int ret = 0; | ||
| 164 | |||
| 165 | trans->block_rsv = root->orphan_block_rsv; | ||
| 166 | ret = btrfs_block_rsv_check(trans, root, | ||
| 167 | root->orphan_block_rsv, | ||
| 168 | 0, 5); | ||
| 169 | if (ret) | ||
| 170 | return ret; | ||
| 171 | |||
| 172 | oldsize = i_size_read(inode); | ||
| 173 | btrfs_i_size_write(inode, 0); | ||
| 174 | truncate_pagecache(inode, oldsize, 0); | ||
| 175 | |||
| 176 | /* | ||
| 177 | * We don't need an orphan item because truncating the free space cache | ||
| 178 | * will never be split across transactions. | ||
| 179 | */ | ||
| 180 | ret = btrfs_truncate_inode_items(trans, root, inode, | ||
| 181 | 0, BTRFS_EXTENT_DATA_KEY); | ||
| 182 | if (ret) { | ||
| 183 | WARN_ON(1); | ||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | |||
| 187 | return btrfs_update_inode(trans, root, inode); | ||
| 188 | } | ||
| 189 | |||
| 190 | static int readahead_cache(struct inode *inode) | ||
| 191 | { | ||
| 192 | struct file_ra_state *ra; | ||
| 193 | unsigned long last_index; | ||
| 194 | |||
| 195 | ra = kzalloc(sizeof(*ra), GFP_NOFS); | ||
| 196 | if (!ra) | ||
| 197 | return -ENOMEM; | ||
| 198 | |||
| 199 | file_ra_state_init(ra, inode->i_mapping); | ||
| 200 | last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; | ||
| 201 | |||
| 202 | page_cache_sync_readahead(inode->i_mapping, ra, NULL, 0, last_index); | ||
| 203 | |||
| 204 | kfree(ra); | ||
| 205 | |||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | |||
| 209 | int load_free_space_cache(struct btrfs_fs_info *fs_info, | ||
| 210 | struct btrfs_block_group_cache *block_group) | ||
| 211 | { | ||
| 212 | struct btrfs_root *root = fs_info->tree_root; | ||
| 213 | struct inode *inode; | ||
| 214 | struct btrfs_free_space_header *header; | ||
| 215 | struct extent_buffer *leaf; | ||
| 216 | struct page *page; | ||
| 217 | struct btrfs_path *path; | ||
| 218 | u32 *checksums = NULL, *crc; | ||
| 219 | char *disk_crcs = NULL; | ||
| 220 | struct btrfs_key key; | ||
| 221 | struct list_head bitmaps; | ||
| 222 | u64 num_entries; | ||
| 223 | u64 num_bitmaps; | ||
| 224 | u64 generation; | ||
| 225 | u32 cur_crc = ~(u32)0; | ||
| 226 | pgoff_t index = 0; | ||
| 227 | unsigned long first_page_offset; | ||
| 228 | int num_checksums; | ||
| 229 | int ret = 0; | ||
| 230 | |||
| 231 | /* | ||
| 232 | * If we're unmounting then just return, since this does a search on the | ||
| 233 | * normal root and not the commit root and we could deadlock. | ||
| 234 | */ | ||
| 235 | smp_mb(); | ||
| 236 | if (fs_info->closing) | ||
| 237 | return 0; | ||
| 238 | |||
| 239 | /* | ||
| 240 | * If this block group has been marked to be cleared for one reason or | ||
| 241 | * another then we can't trust the on disk cache, so just return. | ||
| 242 | */ | ||
| 243 | spin_lock(&block_group->lock); | ||
| 244 | if (block_group->disk_cache_state != BTRFS_DC_WRITTEN) { | ||
| 245 | spin_unlock(&block_group->lock); | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | spin_unlock(&block_group->lock); | ||
| 249 | |||
| 250 | INIT_LIST_HEAD(&bitmaps); | ||
| 251 | |||
| 252 | path = btrfs_alloc_path(); | ||
| 253 | if (!path) | ||
| 254 | return 0; | ||
| 255 | |||
| 256 | inode = lookup_free_space_inode(root, block_group, path); | ||
| 257 | if (IS_ERR(inode)) { | ||
| 258 | btrfs_free_path(path); | ||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | /* Nothing in the space cache, goodbye */ | ||
| 263 | if (!i_size_read(inode)) { | ||
| 264 | btrfs_free_path(path); | ||
| 265 | goto out; | ||
| 266 | } | ||
| 267 | |||
| 268 | key.objectid = BTRFS_FREE_SPACE_OBJECTID; | ||
| 269 | key.offset = block_group->key.objectid; | ||
| 270 | key.type = 0; | ||
| 271 | |||
| 272 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
| 273 | if (ret) { | ||
| 274 | btrfs_free_path(path); | ||
| 275 | goto out; | ||
| 276 | } | ||
| 277 | |||
| 278 | leaf = path->nodes[0]; | ||
| 279 | header = btrfs_item_ptr(leaf, path->slots[0], | ||
| 280 | struct btrfs_free_space_header); | ||
| 281 | num_entries = btrfs_free_space_entries(leaf, header); | ||
| 282 | num_bitmaps = btrfs_free_space_bitmaps(leaf, header); | ||
| 283 | generation = btrfs_free_space_generation(leaf, header); | ||
| 284 | btrfs_free_path(path); | ||
| 285 | |||
| 286 | if (BTRFS_I(inode)->generation != generation) { | ||
| 287 | printk(KERN_ERR "btrfs: free space inode generation (%llu) did" | ||
| 288 | " not match free space cache generation (%llu) for " | ||
| 289 | "block group %llu\n", | ||
| 290 | (unsigned long long)BTRFS_I(inode)->generation, | ||
| 291 | (unsigned long long)generation, | ||
| 292 | (unsigned long long)block_group->key.objectid); | ||
| 293 | goto out; | ||
| 294 | } | ||
| 295 | |||
| 296 | if (!num_entries) | ||
| 297 | goto out; | ||
| 298 | |||
| 299 | /* Setup everything for doing checksumming */ | ||
| 300 | num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE; | ||
| 301 | checksums = crc = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS); | ||
| 302 | if (!checksums) | ||
| 303 | goto out; | ||
| 304 | first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64); | ||
| 305 | disk_crcs = kzalloc(first_page_offset, GFP_NOFS); | ||
| 306 | if (!disk_crcs) | ||
| 307 | goto out; | ||
| 308 | |||
| 309 | ret = readahead_cache(inode); | ||
| 310 | if (ret) { | ||
| 311 | ret = 0; | ||
| 312 | goto out; | ||
| 313 | } | ||
| 314 | |||
| 315 | while (1) { | ||
| 316 | struct btrfs_free_space_entry *entry; | ||
| 317 | struct btrfs_free_space *e; | ||
| 318 | void *addr; | ||
| 319 | unsigned long offset = 0; | ||
| 320 | unsigned long start_offset = 0; | ||
| 321 | int need_loop = 0; | ||
| 322 | |||
| 323 | if (!num_entries && !num_bitmaps) | ||
| 324 | break; | ||
| 325 | |||
| 326 | if (index == 0) { | ||
| 327 | start_offset = first_page_offset; | ||
| 328 | offset = start_offset; | ||
| 329 | } | ||
| 330 | |||
| 331 | page = grab_cache_page(inode->i_mapping, index); | ||
| 332 | if (!page) { | ||
| 333 | ret = 0; | ||
| 334 | goto free_cache; | ||
| 335 | } | ||
| 336 | |||
| 337 | if (!PageUptodate(page)) { | ||
| 338 | btrfs_readpage(NULL, page); | ||
| 339 | lock_page(page); | ||
| 340 | if (!PageUptodate(page)) { | ||
| 341 | unlock_page(page); | ||
| 342 | page_cache_release(page); | ||
| 343 | printk(KERN_ERR "btrfs: error reading free " | ||
| 344 | "space cache: %llu\n", | ||
| 345 | (unsigned long long) | ||
| 346 | block_group->key.objectid); | ||
| 347 | goto free_cache; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | addr = kmap(page); | ||
| 351 | |||
| 352 | if (index == 0) { | ||
| 353 | u64 *gen; | ||
| 354 | |||
| 355 | memcpy(disk_crcs, addr, first_page_offset); | ||
| 356 | gen = addr + (sizeof(u32) * num_checksums); | ||
| 357 | if (*gen != BTRFS_I(inode)->generation) { | ||
| 358 | printk(KERN_ERR "btrfs: space cache generation" | ||
| 359 | " (%llu) does not match inode (%llu) " | ||
| 360 | "for block group %llu\n", | ||
| 361 | (unsigned long long)*gen, | ||
| 362 | (unsigned long long) | ||
| 363 | BTRFS_I(inode)->generation, | ||
| 364 | (unsigned long long) | ||
| 365 | block_group->key.objectid); | ||
| 366 | kunmap(page); | ||
| 367 | unlock_page(page); | ||
| 368 | page_cache_release(page); | ||
| 369 | goto free_cache; | ||
| 370 | } | ||
| 371 | crc = (u32 *)disk_crcs; | ||
| 372 | } | ||
| 373 | entry = addr + start_offset; | ||
| 374 | |||
| 375 | /* First lets check our crc before we do anything fun */ | ||
| 376 | cur_crc = ~(u32)0; | ||
| 377 | cur_crc = btrfs_csum_data(root, addr + start_offset, cur_crc, | ||
| 378 | PAGE_CACHE_SIZE - start_offset); | ||
| 379 | btrfs_csum_final(cur_crc, (char *)&cur_crc); | ||
| 380 | if (cur_crc != *crc) { | ||
| 381 | printk(KERN_ERR "btrfs: crc mismatch for page %lu in " | ||
| 382 | "block group %llu\n", index, | ||
| 383 | (unsigned long long)block_group->key.objectid); | ||
| 384 | kunmap(page); | ||
| 385 | unlock_page(page); | ||
| 386 | page_cache_release(page); | ||
| 387 | goto free_cache; | ||
| 388 | } | ||
| 389 | crc++; | ||
| 390 | |||
| 391 | while (1) { | ||
| 392 | if (!num_entries) | ||
| 393 | break; | ||
| 394 | |||
| 395 | need_loop = 1; | ||
| 396 | e = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS); | ||
| 397 | if (!e) { | ||
| 398 | kunmap(page); | ||
| 399 | unlock_page(page); | ||
| 400 | page_cache_release(page); | ||
| 401 | goto free_cache; | ||
| 402 | } | ||
| 403 | |||
| 404 | e->offset = le64_to_cpu(entry->offset); | ||
| 405 | e->bytes = le64_to_cpu(entry->bytes); | ||
| 406 | if (!e->bytes) { | ||
| 407 | kunmap(page); | ||
| 408 | kfree(e); | ||
| 409 | unlock_page(page); | ||
| 410 | page_cache_release(page); | ||
| 411 | goto free_cache; | ||
| 412 | } | ||
| 413 | |||
| 414 | if (entry->type == BTRFS_FREE_SPACE_EXTENT) { | ||
| 415 | spin_lock(&block_group->tree_lock); | ||
| 416 | ret = link_free_space(block_group, e); | ||
| 417 | spin_unlock(&block_group->tree_lock); | ||
| 418 | BUG_ON(ret); | ||
| 419 | } else { | ||
| 420 | e->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS); | ||
| 421 | if (!e->bitmap) { | ||
| 422 | kunmap(page); | ||
| 423 | kfree(e); | ||
| 424 | unlock_page(page); | ||
| 425 | page_cache_release(page); | ||
| 426 | goto free_cache; | ||
| 427 | } | ||
| 428 | spin_lock(&block_group->tree_lock); | ||
| 429 | ret = link_free_space(block_group, e); | ||
| 430 | block_group->total_bitmaps++; | ||
| 431 | recalculate_thresholds(block_group); | ||
| 432 | spin_unlock(&block_group->tree_lock); | ||
| 433 | list_add_tail(&e->list, &bitmaps); | ||
| 434 | } | ||
| 435 | |||
| 436 | num_entries--; | ||
| 437 | offset += sizeof(struct btrfs_free_space_entry); | ||
| 438 | if (offset + sizeof(struct btrfs_free_space_entry) >= | ||
| 439 | PAGE_CACHE_SIZE) | ||
| 440 | break; | ||
| 441 | entry++; | ||
| 442 | } | ||
| 443 | |||
| 444 | /* | ||
| 445 | * We read an entry out of this page, we need to move on to the | ||
| 446 | * next page. | ||
| 447 | */ | ||
| 448 | if (need_loop) { | ||
| 449 | kunmap(page); | ||
| 450 | goto next; | ||
| 451 | } | ||
| 452 | |||
| 453 | /* | ||
| 454 | * We add the bitmaps at the end of the entries in order that | ||
| 455 | * the bitmap entries are added to the cache. | ||
| 456 | */ | ||
| 457 | e = list_entry(bitmaps.next, struct btrfs_free_space, list); | ||
| 458 | list_del_init(&e->list); | ||
| 459 | memcpy(e->bitmap, addr, PAGE_CACHE_SIZE); | ||
| 460 | kunmap(page); | ||
| 461 | num_bitmaps--; | ||
| 462 | next: | ||
| 463 | unlock_page(page); | ||
| 464 | page_cache_release(page); | ||
| 465 | index++; | ||
| 466 | } | ||
| 467 | |||
| 468 | ret = 1; | ||
| 469 | out: | ||
| 470 | kfree(checksums); | ||
| 471 | kfree(disk_crcs); | ||
| 472 | iput(inode); | ||
| 473 | return ret; | ||
| 474 | |||
| 475 | free_cache: | ||
| 476 | /* This cache is bogus, make sure it gets cleared */ | ||
| 477 | spin_lock(&block_group->lock); | ||
| 478 | block_group->disk_cache_state = BTRFS_DC_CLEAR; | ||
| 479 | spin_unlock(&block_group->lock); | ||
| 480 | btrfs_remove_free_space_cache(block_group); | ||
| 481 | goto out; | ||
| 482 | } | ||
| 483 | |||
| 484 | int btrfs_write_out_cache(struct btrfs_root *root, | ||
| 485 | struct btrfs_trans_handle *trans, | ||
| 486 | struct btrfs_block_group_cache *block_group, | ||
| 487 | struct btrfs_path *path) | ||
| 488 | { | ||
| 489 | struct btrfs_free_space_header *header; | ||
| 490 | struct extent_buffer *leaf; | ||
| 491 | struct inode *inode; | ||
| 492 | struct rb_node *node; | ||
| 493 | struct list_head *pos, *n; | ||
| 494 | struct page *page; | ||
| 495 | struct extent_state *cached_state = NULL; | ||
| 496 | struct list_head bitmap_list; | ||
| 497 | struct btrfs_key key; | ||
| 498 | u64 bytes = 0; | ||
| 499 | u32 *crc, *checksums; | ||
| 500 | pgoff_t index = 0, last_index = 0; | ||
| 501 | unsigned long first_page_offset; | ||
| 502 | int num_checksums; | ||
| 503 | int entries = 0; | ||
| 504 | int bitmaps = 0; | ||
| 505 | int ret = 0; | ||
| 506 | |||
| 507 | root = root->fs_info->tree_root; | ||
| 508 | |||
| 509 | INIT_LIST_HEAD(&bitmap_list); | ||
| 510 | |||
| 511 | spin_lock(&block_group->lock); | ||
| 512 | if (block_group->disk_cache_state < BTRFS_DC_SETUP) { | ||
| 513 | spin_unlock(&block_group->lock); | ||
| 514 | return 0; | ||
| 515 | } | ||
| 516 | spin_unlock(&block_group->lock); | ||
| 517 | |||
| 518 | inode = lookup_free_space_inode(root, block_group, path); | ||
| 519 | if (IS_ERR(inode)) | ||
| 520 | return 0; | ||
| 521 | |||
| 522 | if (!i_size_read(inode)) { | ||
| 523 | iput(inode); | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; | ||
| 528 | filemap_write_and_wait(inode->i_mapping); | ||
| 529 | btrfs_wait_ordered_range(inode, inode->i_size & | ||
| 530 | ~(root->sectorsize - 1), (u64)-1); | ||
| 531 | |||
| 532 | /* We need a checksum per page. */ | ||
| 533 | num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE; | ||
| 534 | crc = checksums = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS); | ||
| 535 | if (!crc) { | ||
| 536 | iput(inode); | ||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 540 | /* Since the first page has all of our checksums and our generation we | ||
| 541 | * need to calculate the offset into the page that we can start writing | ||
| 542 | * our entries. | ||
| 543 | */ | ||
| 544 | first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64); | ||
| 545 | |||
| 546 | node = rb_first(&block_group->free_space_offset); | ||
| 547 | if (!node) | ||
| 548 | goto out_free; | ||
| 549 | |||
| 550 | /* | ||
| 551 | * Lock all pages first so we can lock the extent safely. | ||
| 552 | * | ||
| 553 | * NOTE: Because we hold the ref the entire time we're going to write to | ||
| 554 | * the page find_get_page should never fail, so we don't do a check | ||
| 555 | * after find_get_page at this point. Just putting this here so people | ||
| 556 | * know and don't freak out. | ||
| 557 | */ | ||
| 558 | while (index <= last_index) { | ||
| 559 | page = grab_cache_page(inode->i_mapping, index); | ||
| 560 | if (!page) { | ||
| 561 | pgoff_t i = 0; | ||
| 562 | |||
| 563 | while (i < index) { | ||
| 564 | page = find_get_page(inode->i_mapping, i); | ||
| 565 | unlock_page(page); | ||
| 566 | page_cache_release(page); | ||
| 567 | page_cache_release(page); | ||
| 568 | i++; | ||
| 569 | } | ||
| 570 | goto out_free; | ||
| 571 | } | ||
| 572 | index++; | ||
| 573 | } | ||
| 574 | |||
| 575 | index = 0; | ||
| 576 | lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, | ||
| 577 | 0, &cached_state, GFP_NOFS); | ||
| 578 | |||
| 579 | /* Write out the extent entries */ | ||
| 580 | do { | ||
| 581 | struct btrfs_free_space_entry *entry; | ||
| 582 | void *addr; | ||
| 583 | unsigned long offset = 0; | ||
| 584 | unsigned long start_offset = 0; | ||
| 585 | |||
| 586 | if (index == 0) { | ||
| 587 | start_offset = first_page_offset; | ||
| 588 | offset = start_offset; | ||
| 589 | } | ||
| 590 | |||
| 591 | page = find_get_page(inode->i_mapping, index); | ||
| 592 | |||
| 593 | addr = kmap(page); | ||
| 594 | entry = addr + start_offset; | ||
| 595 | |||
| 596 | memset(addr, 0, PAGE_CACHE_SIZE); | ||
| 597 | while (1) { | ||
| 598 | struct btrfs_free_space *e; | ||
| 599 | |||
| 600 | e = rb_entry(node, struct btrfs_free_space, offset_index); | ||
| 601 | entries++; | ||
| 602 | |||
| 603 | entry->offset = cpu_to_le64(e->offset); | ||
| 604 | entry->bytes = cpu_to_le64(e->bytes); | ||
| 605 | if (e->bitmap) { | ||
| 606 | entry->type = BTRFS_FREE_SPACE_BITMAP; | ||
| 607 | list_add_tail(&e->list, &bitmap_list); | ||
| 608 | bitmaps++; | ||
| 609 | } else { | ||
| 610 | entry->type = BTRFS_FREE_SPACE_EXTENT; | ||
| 611 | } | ||
| 612 | node = rb_next(node); | ||
| 613 | if (!node) | ||
| 614 | break; | ||
| 615 | offset += sizeof(struct btrfs_free_space_entry); | ||
| 616 | if (offset + sizeof(struct btrfs_free_space_entry) >= | ||
| 617 | PAGE_CACHE_SIZE) | ||
| 618 | break; | ||
| 619 | entry++; | ||
| 620 | } | ||
| 621 | *crc = ~(u32)0; | ||
| 622 | *crc = btrfs_csum_data(root, addr + start_offset, *crc, | ||
| 623 | PAGE_CACHE_SIZE - start_offset); | ||
| 624 | kunmap(page); | ||
| 625 | |||
| 626 | btrfs_csum_final(*crc, (char *)crc); | ||
| 627 | crc++; | ||
| 628 | |||
| 629 | bytes += PAGE_CACHE_SIZE; | ||
| 630 | |||
| 631 | ClearPageChecked(page); | ||
| 632 | set_page_extent_mapped(page); | ||
| 633 | SetPageUptodate(page); | ||
| 634 | set_page_dirty(page); | ||
| 635 | |||
| 636 | /* | ||
| 637 | * We need to release our reference we got for grab_cache_page, | ||
| 638 | * except for the first page which will hold our checksums, we | ||
| 639 | * do that below. | ||
| 640 | */ | ||
| 641 | if (index != 0) { | ||
| 642 | unlock_page(page); | ||
| 643 | page_cache_release(page); | ||
| 644 | } | ||
| 645 | |||
| 646 | page_cache_release(page); | ||
| 647 | |||
| 648 | index++; | ||
| 649 | } while (node); | ||
| 650 | |||
| 651 | /* Write out the bitmaps */ | ||
| 652 | list_for_each_safe(pos, n, &bitmap_list) { | ||
| 653 | void *addr; | ||
| 654 | struct btrfs_free_space *entry = | ||
| 655 | list_entry(pos, struct btrfs_free_space, list); | ||
| 656 | |||
| 657 | page = find_get_page(inode->i_mapping, index); | ||
| 658 | |||
| 659 | addr = kmap(page); | ||
| 660 | memcpy(addr, entry->bitmap, PAGE_CACHE_SIZE); | ||
| 661 | *crc = ~(u32)0; | ||
| 662 | *crc = btrfs_csum_data(root, addr, *crc, PAGE_CACHE_SIZE); | ||
| 663 | kunmap(page); | ||
| 664 | btrfs_csum_final(*crc, (char *)crc); | ||
| 665 | crc++; | ||
| 666 | bytes += PAGE_CACHE_SIZE; | ||
| 667 | |||
| 668 | ClearPageChecked(page); | ||
| 669 | set_page_extent_mapped(page); | ||
| 670 | SetPageUptodate(page); | ||
| 671 | set_page_dirty(page); | ||
| 672 | unlock_page(page); | ||
| 673 | page_cache_release(page); | ||
| 674 | page_cache_release(page); | ||
| 675 | list_del_init(&entry->list); | ||
| 676 | index++; | ||
| 677 | } | ||
| 678 | |||
| 679 | /* Zero out the rest of the pages just to make sure */ | ||
| 680 | while (index <= last_index) { | ||
| 681 | void *addr; | ||
| 682 | |||
| 683 | page = find_get_page(inode->i_mapping, index); | ||
| 684 | |||
| 685 | addr = kmap(page); | ||
| 686 | memset(addr, 0, PAGE_CACHE_SIZE); | ||
| 687 | kunmap(page); | ||
| 688 | ClearPageChecked(page); | ||
| 689 | set_page_extent_mapped(page); | ||
| 690 | SetPageUptodate(page); | ||
| 691 | set_page_dirty(page); | ||
| 692 | unlock_page(page); | ||
| 693 | page_cache_release(page); | ||
| 694 | page_cache_release(page); | ||
| 695 | bytes += PAGE_CACHE_SIZE; | ||
| 696 | index++; | ||
| 697 | } | ||
| 698 | |||
| 699 | btrfs_set_extent_delalloc(inode, 0, bytes - 1, &cached_state); | ||
| 700 | |||
| 701 | /* Write the checksums and trans id to the first page */ | ||
| 702 | { | ||
| 703 | void *addr; | ||
| 704 | u64 *gen; | ||
| 705 | |||
| 706 | page = find_get_page(inode->i_mapping, 0); | ||
| 707 | |||
| 708 | addr = kmap(page); | ||
| 709 | memcpy(addr, checksums, sizeof(u32) * num_checksums); | ||
| 710 | gen = addr + (sizeof(u32) * num_checksums); | ||
| 711 | *gen = trans->transid; | ||
| 712 | kunmap(page); | ||
| 713 | ClearPageChecked(page); | ||
| 714 | set_page_extent_mapped(page); | ||
| 715 | SetPageUptodate(page); | ||
| 716 | set_page_dirty(page); | ||
| 717 | unlock_page(page); | ||
| 718 | page_cache_release(page); | ||
| 719 | page_cache_release(page); | ||
| 720 | } | ||
| 721 | BTRFS_I(inode)->generation = trans->transid; | ||
| 722 | |||
| 723 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, | ||
| 724 | i_size_read(inode) - 1, &cached_state, GFP_NOFS); | ||
| 725 | |||
| 726 | filemap_write_and_wait(inode->i_mapping); | ||
| 727 | |||
| 728 | key.objectid = BTRFS_FREE_SPACE_OBJECTID; | ||
| 729 | key.offset = block_group->key.objectid; | ||
| 730 | key.type = 0; | ||
| 731 | |||
| 732 | ret = btrfs_search_slot(trans, root, &key, path, 1, 1); | ||
| 733 | if (ret < 0) { | ||
| 734 | ret = 0; | ||
| 735 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1, | ||
| 736 | EXTENT_DIRTY | EXTENT_DELALLOC | | ||
| 737 | EXTENT_DO_ACCOUNTING, 0, 0, NULL, GFP_NOFS); | ||
| 738 | goto out_free; | ||
| 739 | } | ||
| 740 | leaf = path->nodes[0]; | ||
| 741 | if (ret > 0) { | ||
| 742 | struct btrfs_key found_key; | ||
| 743 | BUG_ON(!path->slots[0]); | ||
| 744 | path->slots[0]--; | ||
| 745 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
| 746 | if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID || | ||
| 747 | found_key.offset != block_group->key.objectid) { | ||
| 748 | ret = 0; | ||
| 749 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1, | ||
| 750 | EXTENT_DIRTY | EXTENT_DELALLOC | | ||
| 751 | EXTENT_DO_ACCOUNTING, 0, 0, NULL, | ||
| 752 | GFP_NOFS); | ||
| 753 | btrfs_release_path(root, path); | ||
| 754 | goto out_free; | ||
| 755 | } | ||
| 756 | } | ||
| 757 | header = btrfs_item_ptr(leaf, path->slots[0], | ||
| 758 | struct btrfs_free_space_header); | ||
| 759 | btrfs_set_free_space_entries(leaf, header, entries); | ||
| 760 | btrfs_set_free_space_bitmaps(leaf, header, bitmaps); | ||
| 761 | btrfs_set_free_space_generation(leaf, header, trans->transid); | ||
| 762 | btrfs_mark_buffer_dirty(leaf); | ||
| 763 | btrfs_release_path(root, path); | ||
| 764 | |||
| 765 | ret = 1; | ||
| 766 | |||
| 767 | out_free: | ||
| 768 | if (ret == 0) { | ||
| 769 | invalidate_inode_pages2_range(inode->i_mapping, 0, index); | ||
| 770 | spin_lock(&block_group->lock); | ||
| 771 | block_group->disk_cache_state = BTRFS_DC_ERROR; | ||
| 772 | spin_unlock(&block_group->lock); | ||
| 773 | BTRFS_I(inode)->generation = 0; | ||
| 774 | } | ||
| 775 | kfree(checksums); | ||
| 776 | btrfs_update_inode(trans, root, inode); | ||
| 777 | iput(inode); | ||
| 778 | return ret; | ||
| 779 | } | ||
| 780 | |||
| 30 | static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize, | 781 | static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize, |
| 31 | u64 offset) | 782 | u64 offset) |
| 32 | { | 783 | { |
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h index 890a8e79011b..e49ca5c321b5 100644 --- a/fs/btrfs/free-space-cache.h +++ b/fs/btrfs/free-space-cache.h | |||
| @@ -27,6 +27,24 @@ struct btrfs_free_space { | |||
| 27 | struct list_head list; | 27 | struct list_head list; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | struct inode *lookup_free_space_inode(struct btrfs_root *root, | ||
| 31 | struct btrfs_block_group_cache | ||
| 32 | *block_group, struct btrfs_path *path); | ||
| 33 | int create_free_space_inode(struct btrfs_root *root, | ||
| 34 | struct btrfs_trans_handle *trans, | ||
| 35 | struct btrfs_block_group_cache *block_group, | ||
| 36 | struct btrfs_path *path); | ||
| 37 | |||
| 38 | int btrfs_truncate_free_space_cache(struct btrfs_root *root, | ||
| 39 | struct btrfs_trans_handle *trans, | ||
| 40 | struct btrfs_path *path, | ||
| 41 | struct inode *inode); | ||
| 42 | int load_free_space_cache(struct btrfs_fs_info *fs_info, | ||
| 43 | struct btrfs_block_group_cache *block_group); | ||
| 44 | int btrfs_write_out_cache(struct btrfs_root *root, | ||
| 45 | struct btrfs_trans_handle *trans, | ||
| 46 | struct btrfs_block_group_cache *block_group, | ||
| 47 | struct btrfs_path *path); | ||
| 30 | int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | 48 | int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, |
| 31 | u64 bytenr, u64 size); | 49 | u64 bytenr, u64 size); |
| 32 | int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, | 50 | int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 64f99cf69ce0..558cac2dfa54 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -319,8 +319,6 @@ static noinline int compress_file_range(struct inode *inode, | |||
| 319 | struct btrfs_root *root = BTRFS_I(inode)->root; | 319 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 320 | struct btrfs_trans_handle *trans; | 320 | struct btrfs_trans_handle *trans; |
| 321 | u64 num_bytes; | 321 | u64 num_bytes; |
| 322 | u64 orig_start; | ||
| 323 | u64 disk_num_bytes; | ||
| 324 | u64 blocksize = root->sectorsize; | 322 | u64 blocksize = root->sectorsize; |
| 325 | u64 actual_end; | 323 | u64 actual_end; |
| 326 | u64 isize = i_size_read(inode); | 324 | u64 isize = i_size_read(inode); |
| @@ -335,8 +333,6 @@ static noinline int compress_file_range(struct inode *inode, | |||
| 335 | int i; | 333 | int i; |
| 336 | int will_compress; | 334 | int will_compress; |
| 337 | 335 | ||
| 338 | orig_start = start; | ||
| 339 | |||
| 340 | actual_end = min_t(u64, isize, end + 1); | 336 | actual_end = min_t(u64, isize, end + 1); |
| 341 | again: | 337 | again: |
| 342 | will_compress = 0; | 338 | will_compress = 0; |
| @@ -371,7 +367,6 @@ again: | |||
| 371 | total_compressed = min(total_compressed, max_uncompressed); | 367 | total_compressed = min(total_compressed, max_uncompressed); |
| 372 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); | 368 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); |
| 373 | num_bytes = max(blocksize, num_bytes); | 369 | num_bytes = max(blocksize, num_bytes); |
| 374 | disk_num_bytes = num_bytes; | ||
| 375 | total_in = 0; | 370 | total_in = 0; |
| 376 | ret = 0; | 371 | ret = 0; |
| 377 | 372 | ||
| @@ -467,7 +462,6 @@ again: | |||
| 467 | if (total_compressed >= total_in) { | 462 | if (total_compressed >= total_in) { |
| 468 | will_compress = 0; | 463 | will_compress = 0; |
| 469 | } else { | 464 | } else { |
| 470 | disk_num_bytes = total_compressed; | ||
| 471 | num_bytes = total_in; | 465 | num_bytes = total_in; |
| 472 | } | 466 | } |
| 473 | } | 467 | } |
| @@ -757,20 +751,17 @@ static noinline int cow_file_range(struct inode *inode, | |||
| 757 | u64 disk_num_bytes; | 751 | u64 disk_num_bytes; |
| 758 | u64 cur_alloc_size; | 752 | u64 cur_alloc_size; |
| 759 | u64 blocksize = root->sectorsize; | 753 | u64 blocksize = root->sectorsize; |
| 760 | u64 actual_end; | ||
| 761 | u64 isize = i_size_read(inode); | ||
| 762 | struct btrfs_key ins; | 754 | struct btrfs_key ins; |
| 763 | struct extent_map *em; | 755 | struct extent_map *em; |
| 764 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 756 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
| 765 | int ret = 0; | 757 | int ret = 0; |
| 766 | 758 | ||
| 759 | BUG_ON(root == root->fs_info->tree_root); | ||
| 767 | trans = btrfs_join_transaction(root, 1); | 760 | trans = btrfs_join_transaction(root, 1); |
| 768 | BUG_ON(!trans); | 761 | BUG_ON(!trans); |
| 769 | btrfs_set_trans_block_group(trans, inode); | 762 | btrfs_set_trans_block_group(trans, inode); |
| 770 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; | 763 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; |
| 771 | 764 | ||
| 772 | actual_end = min_t(u64, isize, end + 1); | ||
| 773 | |||
| 774 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); | 765 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); |
| 775 | num_bytes = max(blocksize, num_bytes); | 766 | num_bytes = max(blocksize, num_bytes); |
| 776 | disk_num_bytes = num_bytes; | 767 | disk_num_bytes = num_bytes; |
| @@ -1035,10 +1026,16 @@ static noinline int run_delalloc_nocow(struct inode *inode, | |||
| 1035 | int type; | 1026 | int type; |
| 1036 | int nocow; | 1027 | int nocow; |
| 1037 | int check_prev = 1; | 1028 | int check_prev = 1; |
| 1029 | bool nolock = false; | ||
| 1038 | 1030 | ||
| 1039 | path = btrfs_alloc_path(); | 1031 | path = btrfs_alloc_path(); |
| 1040 | BUG_ON(!path); | 1032 | BUG_ON(!path); |
| 1041 | trans = btrfs_join_transaction(root, 1); | 1033 | if (root == root->fs_info->tree_root) { |
| 1034 | nolock = true; | ||
| 1035 | trans = btrfs_join_transaction_nolock(root, 1); | ||
| 1036 | } else { | ||
| 1037 | trans = btrfs_join_transaction(root, 1); | ||
| 1038 | } | ||
| 1042 | BUG_ON(!trans); | 1039 | BUG_ON(!trans); |
| 1043 | 1040 | ||
| 1044 | cow_start = (u64)-1; | 1041 | cow_start = (u64)-1; |
| @@ -1211,8 +1208,13 @@ out_check: | |||
| 1211 | BUG_ON(ret); | 1208 | BUG_ON(ret); |
| 1212 | } | 1209 | } |
| 1213 | 1210 | ||
| 1214 | ret = btrfs_end_transaction(trans, root); | 1211 | if (nolock) { |
| 1215 | BUG_ON(ret); | 1212 | ret = btrfs_end_transaction_nolock(trans, root); |
| 1213 | BUG_ON(ret); | ||
| 1214 | } else { | ||
| 1215 | ret = btrfs_end_transaction(trans, root); | ||
| 1216 | BUG_ON(ret); | ||
| 1217 | } | ||
| 1216 | btrfs_free_path(path); | 1218 | btrfs_free_path(path); |
| 1217 | return 0; | 1219 | return 0; |
| 1218 | } | 1220 | } |
| @@ -1289,6 +1291,8 @@ static int btrfs_set_bit_hook(struct inode *inode, | |||
| 1289 | if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) { | 1291 | if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) { |
| 1290 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1292 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 1291 | u64 len = state->end + 1 - state->start; | 1293 | u64 len = state->end + 1 - state->start; |
| 1294 | int do_list = (root->root_key.objectid != | ||
| 1295 | BTRFS_ROOT_TREE_OBJECTID); | ||
| 1292 | 1296 | ||
| 1293 | if (*bits & EXTENT_FIRST_DELALLOC) | 1297 | if (*bits & EXTENT_FIRST_DELALLOC) |
| 1294 | *bits &= ~EXTENT_FIRST_DELALLOC; | 1298 | *bits &= ~EXTENT_FIRST_DELALLOC; |
| @@ -1298,7 +1302,7 @@ static int btrfs_set_bit_hook(struct inode *inode, | |||
| 1298 | spin_lock(&root->fs_info->delalloc_lock); | 1302 | spin_lock(&root->fs_info->delalloc_lock); |
| 1299 | BTRFS_I(inode)->delalloc_bytes += len; | 1303 | BTRFS_I(inode)->delalloc_bytes += len; |
| 1300 | root->fs_info->delalloc_bytes += len; | 1304 | root->fs_info->delalloc_bytes += len; |
| 1301 | if (list_empty(&BTRFS_I(inode)->delalloc_inodes)) { | 1305 | if (do_list && list_empty(&BTRFS_I(inode)->delalloc_inodes)) { |
| 1302 | list_add_tail(&BTRFS_I(inode)->delalloc_inodes, | 1306 | list_add_tail(&BTRFS_I(inode)->delalloc_inodes, |
| 1303 | &root->fs_info->delalloc_inodes); | 1307 | &root->fs_info->delalloc_inodes); |
| 1304 | } | 1308 | } |
| @@ -1321,6 +1325,8 @@ static int btrfs_clear_bit_hook(struct inode *inode, | |||
| 1321 | if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) { | 1325 | if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) { |
| 1322 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1326 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 1323 | u64 len = state->end + 1 - state->start; | 1327 | u64 len = state->end + 1 - state->start; |
| 1328 | int do_list = (root->root_key.objectid != | ||
| 1329 | BTRFS_ROOT_TREE_OBJECTID); | ||
| 1324 | 1330 | ||
| 1325 | if (*bits & EXTENT_FIRST_DELALLOC) | 1331 | if (*bits & EXTENT_FIRST_DELALLOC) |
| 1326 | *bits &= ~EXTENT_FIRST_DELALLOC; | 1332 | *bits &= ~EXTENT_FIRST_DELALLOC; |
| @@ -1330,14 +1336,15 @@ static int btrfs_clear_bit_hook(struct inode *inode, | |||
| 1330 | if (*bits & EXTENT_DO_ACCOUNTING) | 1336 | if (*bits & EXTENT_DO_ACCOUNTING) |
| 1331 | btrfs_delalloc_release_metadata(inode, len); | 1337 | btrfs_delalloc_release_metadata(inode, len); |
| 1332 | 1338 | ||
| 1333 | if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) | 1339 | if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID |
| 1340 | && do_list) | ||
| 1334 | btrfs_free_reserved_data_space(inode, len); | 1341 | btrfs_free_reserved_data_space(inode, len); |
| 1335 | 1342 | ||
| 1336 | spin_lock(&root->fs_info->delalloc_lock); | 1343 | spin_lock(&root->fs_info->delalloc_lock); |
| 1337 | root->fs_info->delalloc_bytes -= len; | 1344 | root->fs_info->delalloc_bytes -= len; |
| 1338 | BTRFS_I(inode)->delalloc_bytes -= len; | 1345 | BTRFS_I(inode)->delalloc_bytes -= len; |
| 1339 | 1346 | ||
| 1340 | if (BTRFS_I(inode)->delalloc_bytes == 0 && | 1347 | if (do_list && BTRFS_I(inode)->delalloc_bytes == 0 && |
| 1341 | !list_empty(&BTRFS_I(inode)->delalloc_inodes)) { | 1348 | !list_empty(&BTRFS_I(inode)->delalloc_inodes)) { |
| 1342 | list_del_init(&BTRFS_I(inode)->delalloc_inodes); | 1349 | list_del_init(&BTRFS_I(inode)->delalloc_inodes); |
| 1343 | } | 1350 | } |
| @@ -1372,7 +1379,7 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | |||
| 1372 | 1379 | ||
| 1373 | if (map_length < length + size) | 1380 | if (map_length < length + size) |
| 1374 | return 1; | 1381 | return 1; |
| 1375 | return 0; | 1382 | return ret; |
| 1376 | } | 1383 | } |
| 1377 | 1384 | ||
| 1378 | /* | 1385 | /* |
| @@ -1426,7 +1433,10 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
| 1426 | 1433 | ||
| 1427 | skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 1434 | skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
| 1428 | 1435 | ||
| 1429 | ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); | 1436 | if (root == root->fs_info->tree_root) |
| 1437 | ret = btrfs_bio_wq_end_io(root->fs_info, bio, 2); | ||
| 1438 | else | ||
| 1439 | ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); | ||
| 1430 | BUG_ON(ret); | 1440 | BUG_ON(ret); |
| 1431 | 1441 | ||
| 1432 | if (!(rw & REQ_WRITE)) { | 1442 | if (!(rw & REQ_WRITE)) { |
| @@ -1662,6 +1672,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
| 1662 | struct extent_state *cached_state = NULL; | 1672 | struct extent_state *cached_state = NULL; |
| 1663 | int compressed = 0; | 1673 | int compressed = 0; |
| 1664 | int ret; | 1674 | int ret; |
| 1675 | bool nolock = false; | ||
| 1665 | 1676 | ||
| 1666 | ret = btrfs_dec_test_ordered_pending(inode, &ordered_extent, start, | 1677 | ret = btrfs_dec_test_ordered_pending(inode, &ordered_extent, start, |
| 1667 | end - start + 1); | 1678 | end - start + 1); |
| @@ -1669,11 +1680,17 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
| 1669 | return 0; | 1680 | return 0; |
| 1670 | BUG_ON(!ordered_extent); | 1681 | BUG_ON(!ordered_extent); |
| 1671 | 1682 | ||
| 1683 | nolock = (root == root->fs_info->tree_root); | ||
| 1684 | |||
| 1672 | if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { | 1685 | if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { |
| 1673 | BUG_ON(!list_empty(&ordered_extent->list)); | 1686 | BUG_ON(!list_empty(&ordered_extent->list)); |
| 1674 | ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); | 1687 | ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); |
| 1675 | if (!ret) { | 1688 | if (!ret) { |
| 1676 | trans = btrfs_join_transaction(root, 1); | 1689 | if (nolock) |
| 1690 | trans = btrfs_join_transaction_nolock(root, 1); | ||
| 1691 | else | ||
| 1692 | trans = btrfs_join_transaction(root, 1); | ||
| 1693 | BUG_ON(!trans); | ||
| 1677 | btrfs_set_trans_block_group(trans, inode); | 1694 | btrfs_set_trans_block_group(trans, inode); |
| 1678 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; | 1695 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; |
| 1679 | ret = btrfs_update_inode(trans, root, inode); | 1696 | ret = btrfs_update_inode(trans, root, inode); |
| @@ -1686,7 +1703,10 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
| 1686 | ordered_extent->file_offset + ordered_extent->len - 1, | 1703 | ordered_extent->file_offset + ordered_extent->len - 1, |
| 1687 | 0, &cached_state, GFP_NOFS); | 1704 | 0, &cached_state, GFP_NOFS); |
| 1688 | 1705 | ||
| 1689 | trans = btrfs_join_transaction(root, 1); | 1706 | if (nolock) |
| 1707 | trans = btrfs_join_transaction_nolock(root, 1); | ||
| 1708 | else | ||
| 1709 | trans = btrfs_join_transaction(root, 1); | ||
| 1690 | btrfs_set_trans_block_group(trans, inode); | 1710 | btrfs_set_trans_block_group(trans, inode); |
| 1691 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; | 1711 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; |
| 1692 | 1712 | ||
| @@ -1700,6 +1720,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
| 1700 | ordered_extent->len); | 1720 | ordered_extent->len); |
| 1701 | BUG_ON(ret); | 1721 | BUG_ON(ret); |
| 1702 | } else { | 1722 | } else { |
| 1723 | BUG_ON(root == root->fs_info->tree_root); | ||
| 1703 | ret = insert_reserved_file_extent(trans, inode, | 1724 | ret = insert_reserved_file_extent(trans, inode, |
| 1704 | ordered_extent->file_offset, | 1725 | ordered_extent->file_offset, |
| 1705 | ordered_extent->start, | 1726 | ordered_extent->start, |
| @@ -1724,9 +1745,15 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
| 1724 | ret = btrfs_update_inode(trans, root, inode); | 1745 | ret = btrfs_update_inode(trans, root, inode); |
| 1725 | BUG_ON(ret); | 1746 | BUG_ON(ret); |
| 1726 | out: | 1747 | out: |
| 1727 | btrfs_delalloc_release_metadata(inode, ordered_extent->len); | 1748 | if (nolock) { |
| 1728 | if (trans) | 1749 | if (trans) |
| 1729 | btrfs_end_transaction(trans, root); | 1750 | btrfs_end_transaction_nolock(trans, root); |
| 1751 | } else { | ||
| 1752 | btrfs_delalloc_release_metadata(inode, ordered_extent->len); | ||
| 1753 | if (trans) | ||
| 1754 | btrfs_end_transaction(trans, root); | ||
| 1755 | } | ||
| 1756 | |||
| 1730 | /* once for us */ | 1757 | /* once for us */ |
| 1731 | btrfs_put_ordered_extent(ordered_extent); | 1758 | btrfs_put_ordered_extent(ordered_extent); |
| 1732 | /* once for the tree */ | 1759 | /* once for the tree */ |
| @@ -2237,7 +2264,6 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2237 | { | 2264 | { |
| 2238 | struct btrfs_path *path; | 2265 | struct btrfs_path *path; |
| 2239 | struct extent_buffer *leaf; | 2266 | struct extent_buffer *leaf; |
| 2240 | struct btrfs_item *item; | ||
| 2241 | struct btrfs_key key, found_key; | 2267 | struct btrfs_key key, found_key; |
| 2242 | struct btrfs_trans_handle *trans; | 2268 | struct btrfs_trans_handle *trans; |
| 2243 | struct inode *inode; | 2269 | struct inode *inode; |
| @@ -2275,7 +2301,6 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2275 | 2301 | ||
| 2276 | /* pull out the item */ | 2302 | /* pull out the item */ |
| 2277 | leaf = path->nodes[0]; | 2303 | leaf = path->nodes[0]; |
| 2278 | item = btrfs_item_nr(leaf, path->slots[0]); | ||
| 2279 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 2304 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
| 2280 | 2305 | ||
| 2281 | /* make sure the item matches what we want */ | 2306 | /* make sure the item matches what we want */ |
| @@ -2651,7 +2676,8 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans, | |||
| 2651 | 2676 | ||
| 2652 | ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len, | 2677 | ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len, |
| 2653 | dir, index); | 2678 | dir, index); |
| 2654 | BUG_ON(ret); | 2679 | if (ret == -ENOENT) |
| 2680 | ret = 0; | ||
| 2655 | err: | 2681 | err: |
| 2656 | btrfs_free_path(path); | 2682 | btrfs_free_path(path); |
| 2657 | if (ret) | 2683 | if (ret) |
| @@ -2672,8 +2698,8 @@ static int check_path_shared(struct btrfs_root *root, | |||
| 2672 | { | 2698 | { |
| 2673 | struct extent_buffer *eb; | 2699 | struct extent_buffer *eb; |
| 2674 | int level; | 2700 | int level; |
| 2675 | int ret; | ||
| 2676 | u64 refs = 1; | 2701 | u64 refs = 1; |
| 2702 | int uninitialized_var(ret); | ||
| 2677 | 2703 | ||
| 2678 | for (level = 0; level < BTRFS_MAX_LEVEL; level++) { | 2704 | for (level = 0; level < BTRFS_MAX_LEVEL; level++) { |
| 2679 | if (!path->nodes[level]) | 2705 | if (!path->nodes[level]) |
| @@ -2686,7 +2712,7 @@ static int check_path_shared(struct btrfs_root *root, | |||
| 2686 | if (refs > 1) | 2712 | if (refs > 1) |
| 2687 | return 1; | 2713 | return 1; |
| 2688 | } | 2714 | } |
| 2689 | return 0; | 2715 | return ret; /* XXX callers? */ |
| 2690 | } | 2716 | } |
| 2691 | 2717 | ||
| 2692 | /* | 2718 | /* |
| @@ -3196,7 +3222,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, | |||
| 3196 | 3222 | ||
| 3197 | BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); | 3223 | BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); |
| 3198 | 3224 | ||
| 3199 | if (root->ref_cows) | 3225 | if (root->ref_cows || root == root->fs_info->tree_root) |
| 3200 | btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); | 3226 | btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); |
| 3201 | 3227 | ||
| 3202 | path = btrfs_alloc_path(); | 3228 | path = btrfs_alloc_path(); |
| @@ -3344,7 +3370,8 @@ delete: | |||
| 3344 | } else { | 3370 | } else { |
| 3345 | break; | 3371 | break; |
| 3346 | } | 3372 | } |
| 3347 | if (found_extent && root->ref_cows) { | 3373 | if (found_extent && (root->ref_cows || |
| 3374 | root == root->fs_info->tree_root)) { | ||
| 3348 | btrfs_set_path_blocking(path); | 3375 | btrfs_set_path_blocking(path); |
| 3349 | ret = btrfs_free_extent(trans, root, extent_start, | 3376 | ret = btrfs_free_extent(trans, root, extent_start, |
| 3350 | extent_num_bytes, 0, | 3377 | extent_num_bytes, 0, |
| @@ -3675,7 +3702,8 @@ void btrfs_evict_inode(struct inode *inode) | |||
| 3675 | int ret; | 3702 | int ret; |
| 3676 | 3703 | ||
| 3677 | truncate_inode_pages(&inode->i_data, 0); | 3704 | truncate_inode_pages(&inode->i_data, 0); |
| 3678 | if (inode->i_nlink && btrfs_root_refs(&root->root_item) != 0) | 3705 | if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 || |
| 3706 | root == root->fs_info->tree_root)) | ||
| 3679 | goto no_delete; | 3707 | goto no_delete; |
| 3680 | 3708 | ||
| 3681 | if (is_bad_inode(inode)) { | 3709 | if (is_bad_inode(inode)) { |
| @@ -3888,7 +3916,14 @@ static void inode_tree_del(struct inode *inode) | |||
| 3888 | } | 3916 | } |
| 3889 | spin_unlock(&root->inode_lock); | 3917 | spin_unlock(&root->inode_lock); |
| 3890 | 3918 | ||
| 3891 | if (empty && btrfs_root_refs(&root->root_item) == 0) { | 3919 | /* |
| 3920 | * Free space cache has inodes in the tree root, but the tree root has a | ||
| 3921 | * root_refs of 0, so this could end up dropping the tree root as a | ||
| 3922 | * snapshot, so we need the extra !root->fs_info->tree_root check to | ||
| 3923 | * make sure we don't drop it. | ||
| 3924 | */ | ||
| 3925 | if (empty && btrfs_root_refs(&root->root_item) == 0 && | ||
| 3926 | root != root->fs_info->tree_root) { | ||
| 3892 | synchronize_srcu(&root->fs_info->subvol_srcu); | 3927 | synchronize_srcu(&root->fs_info->subvol_srcu); |
| 3893 | spin_lock(&root->inode_lock); | 3928 | spin_lock(&root->inode_lock); |
| 3894 | empty = RB_EMPTY_ROOT(&root->inode_tree); | 3929 | empty = RB_EMPTY_ROOT(&root->inode_tree); |
| @@ -4282,14 +4317,24 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 4282 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4317 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 4283 | struct btrfs_trans_handle *trans; | 4318 | struct btrfs_trans_handle *trans; |
| 4284 | int ret = 0; | 4319 | int ret = 0; |
| 4320 | bool nolock = false; | ||
| 4285 | 4321 | ||
| 4286 | if (BTRFS_I(inode)->dummy_inode) | 4322 | if (BTRFS_I(inode)->dummy_inode) |
| 4287 | return 0; | 4323 | return 0; |
| 4288 | 4324 | ||
| 4325 | smp_mb(); | ||
| 4326 | nolock = (root->fs_info->closing && root == root->fs_info->tree_root); | ||
| 4327 | |||
| 4289 | if (wbc->sync_mode == WB_SYNC_ALL) { | 4328 | if (wbc->sync_mode == WB_SYNC_ALL) { |
| 4290 | trans = btrfs_join_transaction(root, 1); | 4329 | if (nolock) |
| 4330 | trans = btrfs_join_transaction_nolock(root, 1); | ||
| 4331 | else | ||
| 4332 | trans = btrfs_join_transaction(root, 1); | ||
| 4291 | btrfs_set_trans_block_group(trans, inode); | 4333 | btrfs_set_trans_block_group(trans, inode); |
| 4292 | ret = btrfs_commit_transaction(trans, root); | 4334 | if (nolock) |
| 4335 | ret = btrfs_end_transaction_nolock(trans, root); | ||
| 4336 | else | ||
| 4337 | ret = btrfs_commit_transaction(trans, root); | ||
| 4293 | } | 4338 | } |
| 4294 | return ret; | 4339 | return ret; |
| 4295 | } | 4340 | } |
| @@ -5645,7 +5690,6 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, | |||
| 5645 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5690 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 5646 | struct btrfs_dio_private *dip; | 5691 | struct btrfs_dio_private *dip; |
| 5647 | struct bio_vec *bvec = bio->bi_io_vec; | 5692 | struct bio_vec *bvec = bio->bi_io_vec; |
| 5648 | u64 start; | ||
| 5649 | int skip_sum; | 5693 | int skip_sum; |
| 5650 | int write = rw & REQ_WRITE; | 5694 | int write = rw & REQ_WRITE; |
| 5651 | int ret = 0; | 5695 | int ret = 0; |
| @@ -5671,7 +5715,6 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, | |||
| 5671 | dip->inode = inode; | 5715 | dip->inode = inode; |
| 5672 | dip->logical_offset = file_offset; | 5716 | dip->logical_offset = file_offset; |
| 5673 | 5717 | ||
| 5674 | start = dip->logical_offset; | ||
| 5675 | dip->bytes = 0; | 5718 | dip->bytes = 0; |
| 5676 | do { | 5719 | do { |
| 5677 | dip->bytes += bvec->bv_len; | 5720 | dip->bytes += bvec->bv_len; |
| @@ -6308,6 +6351,21 @@ void btrfs_destroy_inode(struct inode *inode) | |||
| 6308 | spin_unlock(&root->fs_info->ordered_extent_lock); | 6351 | spin_unlock(&root->fs_info->ordered_extent_lock); |
| 6309 | } | 6352 | } |
| 6310 | 6353 | ||
| 6354 | if (root == root->fs_info->tree_root) { | ||
| 6355 | struct btrfs_block_group_cache *block_group; | ||
| 6356 | |||
| 6357 | block_group = btrfs_lookup_block_group(root->fs_info, | ||
| 6358 | BTRFS_I(inode)->block_group); | ||
| 6359 | if (block_group && block_group->inode == inode) { | ||
| 6360 | spin_lock(&block_group->lock); | ||
| 6361 | block_group->inode = NULL; | ||
| 6362 | spin_unlock(&block_group->lock); | ||
| 6363 | btrfs_put_block_group(block_group); | ||
| 6364 | } else if (block_group) { | ||
| 6365 | btrfs_put_block_group(block_group); | ||
| 6366 | } | ||
| 6367 | } | ||
| 6368 | |||
| 6311 | spin_lock(&root->orphan_lock); | 6369 | spin_lock(&root->orphan_lock); |
| 6312 | if (!list_empty(&BTRFS_I(inode)->i_orphan)) { | 6370 | if (!list_empty(&BTRFS_I(inode)->i_orphan)) { |
| 6313 | printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n", | 6371 | printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n", |
| @@ -6340,7 +6398,8 @@ int btrfs_drop_inode(struct inode *inode) | |||
| 6340 | { | 6398 | { |
| 6341 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6399 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 6342 | 6400 | ||
| 6343 | if (btrfs_root_refs(&root->root_item) == 0) | 6401 | if (btrfs_root_refs(&root->root_item) == 0 && |
| 6402 | root != root->fs_info->tree_root) | ||
| 6344 | return 1; | 6403 | return 1; |
| 6345 | else | 6404 | else |
| 6346 | return generic_drop_inode(inode); | 6405 | return generic_drop_inode(inode); |
| @@ -6609,7 +6668,8 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) | |||
| 6609 | return 0; | 6668 | return 0; |
| 6610 | } | 6669 | } |
| 6611 | 6670 | ||
| 6612 | int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput) | 6671 | int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput, |
| 6672 | int sync) | ||
| 6613 | { | 6673 | { |
| 6614 | struct btrfs_inode *binode; | 6674 | struct btrfs_inode *binode; |
| 6615 | struct inode *inode = NULL; | 6675 | struct inode *inode = NULL; |
| @@ -6631,7 +6691,26 @@ int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput) | |||
| 6631 | spin_unlock(&root->fs_info->delalloc_lock); | 6691 | spin_unlock(&root->fs_info->delalloc_lock); |
| 6632 | 6692 | ||
| 6633 | if (inode) { | 6693 | if (inode) { |
| 6634 | write_inode_now(inode, 0); | 6694 | if (sync) { |
| 6695 | filemap_write_and_wait(inode->i_mapping); | ||
| 6696 | /* | ||
| 6697 | * We have to do this because compression doesn't | ||
| 6698 | * actually set PG_writeback until it submits the pages | ||
| 6699 | * for IO, which happens in an async thread, so we could | ||
| 6700 | * race and not actually wait for any writeback pages | ||
| 6701 | * because they've not been submitted yet. Technically | ||
| 6702 | * this could still be the case for the ordered stuff | ||
| 6703 | * since the async thread may not have started to do its | ||
| 6704 | * work yet. If this becomes the case then we need to | ||
| 6705 | * figure out a way to make sure that in writepage we | ||
| 6706 | * wait for any async pages to be submitted before | ||
| 6707 | * returning so that fdatawait does what its supposed to | ||
| 6708 | * do. | ||
| 6709 | */ | ||
| 6710 | btrfs_wait_ordered_range(inode, 0, (u64)-1); | ||
| 6711 | } else { | ||
| 6712 | filemap_flush(inode->i_mapping); | ||
| 6713 | } | ||
| 6635 | if (delay_iput) | 6714 | if (delay_iput) |
| 6636 | btrfs_add_delayed_iput(inode); | 6715 | btrfs_add_delayed_iput(inode); |
| 6637 | else | 6716 | else |
| @@ -6757,27 +6836,33 @@ out_unlock: | |||
| 6757 | return err; | 6836 | return err; |
| 6758 | } | 6837 | } |
| 6759 | 6838 | ||
| 6760 | int btrfs_prealloc_file_range(struct inode *inode, int mode, | 6839 | static int __btrfs_prealloc_file_range(struct inode *inode, int mode, |
| 6761 | u64 start, u64 num_bytes, u64 min_size, | 6840 | u64 start, u64 num_bytes, u64 min_size, |
| 6762 | loff_t actual_len, u64 *alloc_hint) | 6841 | loff_t actual_len, u64 *alloc_hint, |
| 6842 | struct btrfs_trans_handle *trans) | ||
| 6763 | { | 6843 | { |
| 6764 | struct btrfs_trans_handle *trans; | ||
| 6765 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6844 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 6766 | struct btrfs_key ins; | 6845 | struct btrfs_key ins; |
| 6767 | u64 cur_offset = start; | 6846 | u64 cur_offset = start; |
| 6768 | int ret = 0; | 6847 | int ret = 0; |
| 6848 | bool own_trans = true; | ||
| 6769 | 6849 | ||
| 6850 | if (trans) | ||
| 6851 | own_trans = false; | ||
| 6770 | while (num_bytes > 0) { | 6852 | while (num_bytes > 0) { |
| 6771 | trans = btrfs_start_transaction(root, 3); | 6853 | if (own_trans) { |
| 6772 | if (IS_ERR(trans)) { | 6854 | trans = btrfs_start_transaction(root, 3); |
| 6773 | ret = PTR_ERR(trans); | 6855 | if (IS_ERR(trans)) { |
| 6774 | break; | 6856 | ret = PTR_ERR(trans); |
| 6857 | break; | ||
| 6858 | } | ||
| 6775 | } | 6859 | } |
| 6776 | 6860 | ||
| 6777 | ret = btrfs_reserve_extent(trans, root, num_bytes, min_size, | 6861 | ret = btrfs_reserve_extent(trans, root, num_bytes, min_size, |
| 6778 | 0, *alloc_hint, (u64)-1, &ins, 1); | 6862 | 0, *alloc_hint, (u64)-1, &ins, 1); |
| 6779 | if (ret) { | 6863 | if (ret) { |
| 6780 | btrfs_end_transaction(trans, root); | 6864 | if (own_trans) |
| 6865 | btrfs_end_transaction(trans, root); | ||
| 6781 | break; | 6866 | break; |
| 6782 | } | 6867 | } |
| 6783 | 6868 | ||
| @@ -6810,11 +6895,30 @@ int btrfs_prealloc_file_range(struct inode *inode, int mode, | |||
| 6810 | ret = btrfs_update_inode(trans, root, inode); | 6895 | ret = btrfs_update_inode(trans, root, inode); |
| 6811 | BUG_ON(ret); | 6896 | BUG_ON(ret); |
| 6812 | 6897 | ||
| 6813 | btrfs_end_transaction(trans, root); | 6898 | if (own_trans) |
| 6899 | btrfs_end_transaction(trans, root); | ||
| 6814 | } | 6900 | } |
| 6815 | return ret; | 6901 | return ret; |
| 6816 | } | 6902 | } |
| 6817 | 6903 | ||
| 6904 | int btrfs_prealloc_file_range(struct inode *inode, int mode, | ||
| 6905 | u64 start, u64 num_bytes, u64 min_size, | ||
| 6906 | loff_t actual_len, u64 *alloc_hint) | ||
| 6907 | { | ||
| 6908 | return __btrfs_prealloc_file_range(inode, mode, start, num_bytes, | ||
| 6909 | min_size, actual_len, alloc_hint, | ||
| 6910 | NULL); | ||
| 6911 | } | ||
| 6912 | |||
| 6913 | int btrfs_prealloc_file_range_trans(struct inode *inode, | ||
| 6914 | struct btrfs_trans_handle *trans, int mode, | ||
| 6915 | u64 start, u64 num_bytes, u64 min_size, | ||
| 6916 | loff_t actual_len, u64 *alloc_hint) | ||
| 6917 | { | ||
| 6918 | return __btrfs_prealloc_file_range(inode, mode, start, num_bytes, | ||
| 6919 | min_size, actual_len, alloc_hint, trans); | ||
| 6920 | } | ||
| 6921 | |||
| 6818 | static long btrfs_fallocate(struct inode *inode, int mode, | 6922 | static long btrfs_fallocate(struct inode *inode, int mode, |
| 6819 | loff_t offset, loff_t len) | 6923 | loff_t offset, loff_t len) |
| 6820 | { | 6924 | { |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9254b3d58dbe..463d91b4dd3a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -224,7 +224,8 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg) | |||
| 224 | 224 | ||
| 225 | static noinline int create_subvol(struct btrfs_root *root, | 225 | static noinline int create_subvol(struct btrfs_root *root, |
| 226 | struct dentry *dentry, | 226 | struct dentry *dentry, |
| 227 | char *name, int namelen) | 227 | char *name, int namelen, |
| 228 | u64 *async_transid) | ||
| 228 | { | 229 | { |
| 229 | struct btrfs_trans_handle *trans; | 230 | struct btrfs_trans_handle *trans; |
| 230 | struct btrfs_key key; | 231 | struct btrfs_key key; |
| @@ -338,13 +339,19 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 338 | 339 | ||
| 339 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); | 340 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
| 340 | fail: | 341 | fail: |
| 341 | err = btrfs_commit_transaction(trans, root); | 342 | if (async_transid) { |
| 343 | *async_transid = trans->transid; | ||
| 344 | err = btrfs_commit_transaction_async(trans, root, 1); | ||
| 345 | } else { | ||
| 346 | err = btrfs_commit_transaction(trans, root); | ||
| 347 | } | ||
| 342 | if (err && !ret) | 348 | if (err && !ret) |
| 343 | ret = err; | 349 | ret = err; |
| 344 | return ret; | 350 | return ret; |
| 345 | } | 351 | } |
| 346 | 352 | ||
| 347 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) | 353 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
| 354 | char *name, int namelen, u64 *async_transid) | ||
| 348 | { | 355 | { |
| 349 | struct inode *inode; | 356 | struct inode *inode; |
| 350 | struct btrfs_pending_snapshot *pending_snapshot; | 357 | struct btrfs_pending_snapshot *pending_snapshot; |
| @@ -373,7 +380,14 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) | |||
| 373 | 380 | ||
| 374 | list_add(&pending_snapshot->list, | 381 | list_add(&pending_snapshot->list, |
| 375 | &trans->transaction->pending_snapshots); | 382 | &trans->transaction->pending_snapshots); |
| 376 | ret = btrfs_commit_transaction(trans, root->fs_info->extent_root); | 383 | if (async_transid) { |
| 384 | *async_transid = trans->transid; | ||
| 385 | ret = btrfs_commit_transaction_async(trans, | ||
| 386 | root->fs_info->extent_root, 1); | ||
| 387 | } else { | ||
| 388 | ret = btrfs_commit_transaction(trans, | ||
| 389 | root->fs_info->extent_root); | ||
| 390 | } | ||
| 377 | BUG_ON(ret); | 391 | BUG_ON(ret); |
| 378 | 392 | ||
| 379 | ret = pending_snapshot->error; | 393 | ret = pending_snapshot->error; |
| @@ -395,6 +409,76 @@ fail: | |||
| 395 | return ret; | 409 | return ret; |
| 396 | } | 410 | } |
| 397 | 411 | ||
| 412 | /* copy of check_sticky in fs/namei.c() | ||
| 413 | * It's inline, so penalty for filesystems that don't use sticky bit is | ||
| 414 | * minimal. | ||
| 415 | */ | ||
| 416 | static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode) | ||
| 417 | { | ||
| 418 | uid_t fsuid = current_fsuid(); | ||
| 419 | |||
| 420 | if (!(dir->i_mode & S_ISVTX)) | ||
| 421 | return 0; | ||
| 422 | if (inode->i_uid == fsuid) | ||
| 423 | return 0; | ||
| 424 | if (dir->i_uid == fsuid) | ||
| 425 | return 0; | ||
| 426 | return !capable(CAP_FOWNER); | ||
| 427 | } | ||
| 428 | |||
| 429 | /* copy of may_delete in fs/namei.c() | ||
| 430 | * Check whether we can remove a link victim from directory dir, check | ||
| 431 | * whether the type of victim is right. | ||
| 432 | * 1. We can't do it if dir is read-only (done in permission()) | ||
| 433 | * 2. We should have write and exec permissions on dir | ||
| 434 | * 3. We can't remove anything from append-only dir | ||
| 435 | * 4. We can't do anything with immutable dir (done in permission()) | ||
| 436 | * 5. If the sticky bit on dir is set we should either | ||
| 437 | * a. be owner of dir, or | ||
| 438 | * b. be owner of victim, or | ||
| 439 | * c. have CAP_FOWNER capability | ||
| 440 | * 6. If the victim is append-only or immutable we can't do antyhing with | ||
| 441 | * links pointing to it. | ||
| 442 | * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. | ||
| 443 | * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. | ||
| 444 | * 9. We can't remove a root or mountpoint. | ||
| 445 | * 10. We don't allow removal of NFS sillyrenamed files; it's handled by | ||
| 446 | * nfs_async_unlink(). | ||
| 447 | */ | ||
| 448 | |||
| 449 | static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir) | ||
| 450 | { | ||
| 451 | int error; | ||
| 452 | |||
| 453 | if (!victim->d_inode) | ||
| 454 | return -ENOENT; | ||
| 455 | |||
| 456 | BUG_ON(victim->d_parent->d_inode != dir); | ||
| 457 | audit_inode_child(victim, dir); | ||
| 458 | |||
| 459 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); | ||
| 460 | if (error) | ||
| 461 | return error; | ||
| 462 | if (IS_APPEND(dir)) | ||
| 463 | return -EPERM; | ||
| 464 | if (btrfs_check_sticky(dir, victim->d_inode)|| | ||
| 465 | IS_APPEND(victim->d_inode)|| | ||
| 466 | IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) | ||
| 467 | return -EPERM; | ||
| 468 | if (isdir) { | ||
| 469 | if (!S_ISDIR(victim->d_inode->i_mode)) | ||
| 470 | return -ENOTDIR; | ||
| 471 | if (IS_ROOT(victim)) | ||
| 472 | return -EBUSY; | ||
| 473 | } else if (S_ISDIR(victim->d_inode->i_mode)) | ||
| 474 | return -EISDIR; | ||
| 475 | if (IS_DEADDIR(dir)) | ||
| 476 | return -ENOENT; | ||
| 477 | if (victim->d_flags & DCACHE_NFSFS_RENAMED) | ||
| 478 | return -EBUSY; | ||
| 479 | return 0; | ||
| 480 | } | ||
| 481 | |||
| 398 | /* copy of may_create in fs/namei.c() */ | 482 | /* copy of may_create in fs/namei.c() */ |
| 399 | static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | 483 | static inline int btrfs_may_create(struct inode *dir, struct dentry *child) |
| 400 | { | 484 | { |
| @@ -412,7 +496,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
| 412 | */ | 496 | */ |
| 413 | static noinline int btrfs_mksubvol(struct path *parent, | 497 | static noinline int btrfs_mksubvol(struct path *parent, |
| 414 | char *name, int namelen, | 498 | char *name, int namelen, |
| 415 | struct btrfs_root *snap_src) | 499 | struct btrfs_root *snap_src, |
| 500 | u64 *async_transid) | ||
| 416 | { | 501 | { |
| 417 | struct inode *dir = parent->dentry->d_inode; | 502 | struct inode *dir = parent->dentry->d_inode; |
| 418 | struct dentry *dentry; | 503 | struct dentry *dentry; |
| @@ -443,10 +528,11 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
| 443 | goto out_up_read; | 528 | goto out_up_read; |
| 444 | 529 | ||
| 445 | if (snap_src) { | 530 | if (snap_src) { |
| 446 | error = create_snapshot(snap_src, dentry); | 531 | error = create_snapshot(snap_src, dentry, |
| 532 | name, namelen, async_transid); | ||
| 447 | } else { | 533 | } else { |
| 448 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 534 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
| 449 | name, namelen); | 535 | name, namelen, async_transid); |
| 450 | } | 536 | } |
| 451 | if (!error) | 537 | if (!error) |
| 452 | fsnotify_mkdir(dir, dentry); | 538 | fsnotify_mkdir(dir, dentry); |
| @@ -708,7 +794,6 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
| 708 | char *sizestr; | 794 | char *sizestr; |
| 709 | char *devstr = NULL; | 795 | char *devstr = NULL; |
| 710 | int ret = 0; | 796 | int ret = 0; |
| 711 | int namelen; | ||
| 712 | int mod = 0; | 797 | int mod = 0; |
| 713 | 798 | ||
| 714 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 799 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
| @@ -722,7 +807,6 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
| 722 | return PTR_ERR(vol_args); | 807 | return PTR_ERR(vol_args); |
| 723 | 808 | ||
| 724 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 809 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
| 725 | namelen = strlen(vol_args->name); | ||
| 726 | 810 | ||
| 727 | mutex_lock(&root->fs_info->volume_mutex); | 811 | mutex_lock(&root->fs_info->volume_mutex); |
| 728 | sizestr = vol_args->name; | 812 | sizestr = vol_args->name; |
| @@ -801,11 +885,13 @@ out_unlock: | |||
| 801 | return ret; | 885 | return ret; |
| 802 | } | 886 | } |
| 803 | 887 | ||
| 804 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 888 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, |
| 805 | void __user *arg, int subvol) | 889 | char *name, |
| 890 | unsigned long fd, | ||
| 891 | int subvol, | ||
| 892 | u64 *transid) | ||
| 806 | { | 893 | { |
| 807 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 894 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
| 808 | struct btrfs_ioctl_vol_args *vol_args; | ||
| 809 | struct file *src_file; | 895 | struct file *src_file; |
| 810 | int namelen; | 896 | int namelen; |
| 811 | int ret = 0; | 897 | int ret = 0; |
| @@ -813,23 +899,18 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
| 813 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 899 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
| 814 | return -EROFS; | 900 | return -EROFS; |
| 815 | 901 | ||
| 816 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 902 | namelen = strlen(name); |
| 817 | if (IS_ERR(vol_args)) | 903 | if (strchr(name, '/')) { |
| 818 | return PTR_ERR(vol_args); | ||
| 819 | |||
| 820 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
| 821 | namelen = strlen(vol_args->name); | ||
| 822 | if (strchr(vol_args->name, '/')) { | ||
| 823 | ret = -EINVAL; | 904 | ret = -EINVAL; |
| 824 | goto out; | 905 | goto out; |
| 825 | } | 906 | } |
| 826 | 907 | ||
| 827 | if (subvol) { | 908 | if (subvol) { |
| 828 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, | 909 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
| 829 | NULL); | 910 | NULL, transid); |
| 830 | } else { | 911 | } else { |
| 831 | struct inode *src_inode; | 912 | struct inode *src_inode; |
| 832 | src_file = fget(vol_args->fd); | 913 | src_file = fget(fd); |
| 833 | if (!src_file) { | 914 | if (!src_file) { |
| 834 | ret = -EINVAL; | 915 | ret = -EINVAL; |
| 835 | goto out; | 916 | goto out; |
| @@ -843,12 +924,56 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
| 843 | fput(src_file); | 924 | fput(src_file); |
| 844 | goto out; | 925 | goto out; |
| 845 | } | 926 | } |
| 846 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, | 927 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
| 847 | BTRFS_I(src_inode)->root); | 928 | BTRFS_I(src_inode)->root, |
| 929 | transid); | ||
| 848 | fput(src_file); | 930 | fput(src_file); |
| 849 | } | 931 | } |
| 850 | out: | 932 | out: |
| 933 | return ret; | ||
| 934 | } | ||
| 935 | |||
| 936 | static noinline int btrfs_ioctl_snap_create(struct file *file, | ||
| 937 | void __user *arg, int subvol, | ||
| 938 | int async) | ||
| 939 | { | ||
| 940 | struct btrfs_ioctl_vol_args *vol_args = NULL; | ||
| 941 | struct btrfs_ioctl_async_vol_args *async_vol_args = NULL; | ||
| 942 | char *name; | ||
| 943 | u64 fd; | ||
| 944 | u64 transid = 0; | ||
| 945 | int ret; | ||
| 946 | |||
| 947 | if (async) { | ||
| 948 | async_vol_args = memdup_user(arg, sizeof(*async_vol_args)); | ||
| 949 | if (IS_ERR(async_vol_args)) | ||
| 950 | return PTR_ERR(async_vol_args); | ||
| 951 | |||
| 952 | name = async_vol_args->name; | ||
| 953 | fd = async_vol_args->fd; | ||
| 954 | async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0'; | ||
| 955 | } else { | ||
| 956 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
| 957 | if (IS_ERR(vol_args)) | ||
| 958 | return PTR_ERR(vol_args); | ||
| 959 | name = vol_args->name; | ||
| 960 | fd = vol_args->fd; | ||
| 961 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
| 962 | } | ||
| 963 | |||
| 964 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
| 965 | subvol, &transid); | ||
| 966 | |||
| 967 | if (!ret && async) { | ||
| 968 | if (copy_to_user(arg + | ||
| 969 | offsetof(struct btrfs_ioctl_async_vol_args, | ||
| 970 | transid), &transid, sizeof(transid))) | ||
| 971 | return -EFAULT; | ||
| 972 | } | ||
| 973 | |||
| 851 | kfree(vol_args); | 974 | kfree(vol_args); |
| 975 | kfree(async_vol_args); | ||
| 976 | |||
| 852 | return ret; | 977 | return ret; |
| 853 | } | 978 | } |
| 854 | 979 | ||
| @@ -1073,14 +1198,10 @@ static noinline int btrfs_ioctl_tree_search(struct file *file, | |||
| 1073 | if (!capable(CAP_SYS_ADMIN)) | 1198 | if (!capable(CAP_SYS_ADMIN)) |
| 1074 | return -EPERM; | 1199 | return -EPERM; |
| 1075 | 1200 | ||
| 1076 | args = kmalloc(sizeof(*args), GFP_KERNEL); | 1201 | args = memdup_user(argp, sizeof(*args)); |
| 1077 | if (!args) | 1202 | if (IS_ERR(args)) |
| 1078 | return -ENOMEM; | 1203 | return PTR_ERR(args); |
| 1079 | 1204 | ||
| 1080 | if (copy_from_user(args, argp, sizeof(*args))) { | ||
| 1081 | kfree(args); | ||
| 1082 | return -EFAULT; | ||
| 1083 | } | ||
| 1084 | inode = fdentry(file)->d_inode; | 1205 | inode = fdentry(file)->d_inode; |
| 1085 | ret = search_ioctl(inode, args); | 1206 | ret = search_ioctl(inode, args); |
| 1086 | if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) | 1207 | if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) |
| @@ -1188,14 +1309,10 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file, | |||
| 1188 | if (!capable(CAP_SYS_ADMIN)) | 1309 | if (!capable(CAP_SYS_ADMIN)) |
| 1189 | return -EPERM; | 1310 | return -EPERM; |
| 1190 | 1311 | ||
| 1191 | args = kmalloc(sizeof(*args), GFP_KERNEL); | 1312 | args = memdup_user(argp, sizeof(*args)); |
| 1192 | if (!args) | 1313 | if (IS_ERR(args)) |
| 1193 | return -ENOMEM; | 1314 | return PTR_ERR(args); |
| 1194 | 1315 | ||
| 1195 | if (copy_from_user(args, argp, sizeof(*args))) { | ||
| 1196 | kfree(args); | ||
| 1197 | return -EFAULT; | ||
| 1198 | } | ||
| 1199 | inode = fdentry(file)->d_inode; | 1316 | inode = fdentry(file)->d_inode; |
| 1200 | 1317 | ||
| 1201 | if (args->treeid == 0) | 1318 | if (args->treeid == 0) |
| @@ -1227,9 +1344,6 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
| 1227 | int ret; | 1344 | int ret; |
| 1228 | int err = 0; | 1345 | int err = 0; |
| 1229 | 1346 | ||
| 1230 | if (!capable(CAP_SYS_ADMIN)) | ||
| 1231 | return -EPERM; | ||
| 1232 | |||
| 1233 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 1347 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
| 1234 | if (IS_ERR(vol_args)) | 1348 | if (IS_ERR(vol_args)) |
| 1235 | return PTR_ERR(vol_args); | 1349 | return PTR_ERR(vol_args); |
| @@ -1259,13 +1373,51 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
| 1259 | } | 1373 | } |
| 1260 | 1374 | ||
| 1261 | inode = dentry->d_inode; | 1375 | inode = dentry->d_inode; |
| 1376 | dest = BTRFS_I(inode)->root; | ||
| 1377 | if (!capable(CAP_SYS_ADMIN)){ | ||
| 1378 | /* | ||
| 1379 | * Regular user. Only allow this with a special mount | ||
| 1380 | * option, when the user has write+exec access to the | ||
| 1381 | * subvol root, and when rmdir(2) would have been | ||
| 1382 | * allowed. | ||
| 1383 | * | ||
| 1384 | * Note that this is _not_ check that the subvol is | ||
| 1385 | * empty or doesn't contain data that we wouldn't | ||
| 1386 | * otherwise be able to delete. | ||
| 1387 | * | ||
| 1388 | * Users who want to delete empty subvols should try | ||
| 1389 | * rmdir(2). | ||
| 1390 | */ | ||
| 1391 | err = -EPERM; | ||
| 1392 | if (!btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED)) | ||
| 1393 | goto out_dput; | ||
| 1394 | |||
| 1395 | /* | ||
| 1396 | * Do not allow deletion if the parent dir is the same | ||
| 1397 | * as the dir to be deleted. That means the ioctl | ||
| 1398 | * must be called on the dentry referencing the root | ||
| 1399 | * of the subvol, not a random directory contained | ||
| 1400 | * within it. | ||
| 1401 | */ | ||
| 1402 | err = -EINVAL; | ||
| 1403 | if (root == dest) | ||
| 1404 | goto out_dput; | ||
| 1405 | |||
| 1406 | err = inode_permission(inode, MAY_WRITE | MAY_EXEC); | ||
| 1407 | if (err) | ||
| 1408 | goto out_dput; | ||
| 1409 | |||
| 1410 | /* check if subvolume may be deleted by a non-root user */ | ||
| 1411 | err = btrfs_may_delete(dir, dentry, 1); | ||
| 1412 | if (err) | ||
| 1413 | goto out_dput; | ||
| 1414 | } | ||
| 1415 | |||
| 1262 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { | 1416 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { |
| 1263 | err = -EINVAL; | 1417 | err = -EINVAL; |
| 1264 | goto out_dput; | 1418 | goto out_dput; |
| 1265 | } | 1419 | } |
| 1266 | 1420 | ||
| 1267 | dest = BTRFS_I(inode)->root; | ||
| 1268 | |||
| 1269 | mutex_lock(&inode->i_mutex); | 1421 | mutex_lock(&inode->i_mutex); |
| 1270 | err = d_invalidate(dentry); | 1422 | err = d_invalidate(dentry); |
| 1271 | if (err) | 1423 | if (err) |
| @@ -1304,7 +1456,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
| 1304 | BUG_ON(ret); | 1456 | BUG_ON(ret); |
| 1305 | } | 1457 | } |
| 1306 | 1458 | ||
| 1307 | ret = btrfs_commit_transaction(trans, root); | 1459 | ret = btrfs_end_transaction(trans, root); |
| 1308 | BUG_ON(ret); | 1460 | BUG_ON(ret); |
| 1309 | inode->i_flags |= S_DEAD; | 1461 | inode->i_flags |= S_DEAD; |
| 1310 | out_up_write: | 1462 | out_up_write: |
| @@ -1502,11 +1654,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 1502 | path->reada = 2; | 1654 | path->reada = 2; |
| 1503 | 1655 | ||
| 1504 | if (inode < src) { | 1656 | if (inode < src) { |
| 1505 | mutex_lock(&inode->i_mutex); | 1657 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); |
| 1506 | mutex_lock(&src->i_mutex); | 1658 | mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD); |
| 1507 | } else { | 1659 | } else { |
| 1508 | mutex_lock(&src->i_mutex); | 1660 | mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT); |
| 1509 | mutex_lock(&inode->i_mutex); | 1661 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); |
| 1510 | } | 1662 | } |
| 1511 | 1663 | ||
| 1512 | /* determine range to clone */ | 1664 | /* determine range to clone */ |
| @@ -1530,13 +1682,15 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 1530 | while (1) { | 1682 | while (1) { |
| 1531 | struct btrfs_ordered_extent *ordered; | 1683 | struct btrfs_ordered_extent *ordered; |
| 1532 | lock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); | 1684 | lock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
| 1533 | ordered = btrfs_lookup_first_ordered_extent(inode, off+len); | 1685 | ordered = btrfs_lookup_first_ordered_extent(src, off+len); |
| 1534 | if (BTRFS_I(src)->delalloc_bytes == 0 && !ordered) | 1686 | if (!ordered && |
| 1687 | !test_range_bit(&BTRFS_I(src)->io_tree, off, off+len, | ||
| 1688 | EXTENT_DELALLOC, 0, NULL)) | ||
| 1535 | break; | 1689 | break; |
| 1536 | unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); | 1690 | unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
| 1537 | if (ordered) | 1691 | if (ordered) |
| 1538 | btrfs_put_ordered_extent(ordered); | 1692 | btrfs_put_ordered_extent(ordered); |
| 1539 | btrfs_wait_ordered_range(src, off, off+len); | 1693 | btrfs_wait_ordered_range(src, off, len); |
| 1540 | } | 1694 | } |
| 1541 | 1695 | ||
| 1542 | /* clone data */ | 1696 | /* clone data */ |
| @@ -1605,7 +1759,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 1605 | } | 1759 | } |
| 1606 | btrfs_release_path(root, path); | 1760 | btrfs_release_path(root, path); |
| 1607 | 1761 | ||
| 1608 | if (key.offset + datal < off || | 1762 | if (key.offset + datal <= off || |
| 1609 | key.offset >= off+len) | 1763 | key.offset >= off+len) |
| 1610 | goto next; | 1764 | goto next; |
| 1611 | 1765 | ||
| @@ -1879,6 +2033,22 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
| 1879 | return 0; | 2033 | return 0; |
| 1880 | } | 2034 | } |
| 1881 | 2035 | ||
| 2036 | static void get_block_group_info(struct list_head *groups_list, | ||
| 2037 | struct btrfs_ioctl_space_info *space) | ||
| 2038 | { | ||
| 2039 | struct btrfs_block_group_cache *block_group; | ||
| 2040 | |||
| 2041 | space->total_bytes = 0; | ||
| 2042 | space->used_bytes = 0; | ||
| 2043 | space->flags = 0; | ||
| 2044 | list_for_each_entry(block_group, groups_list, list) { | ||
| 2045 | space->flags = block_group->flags; | ||
| 2046 | space->total_bytes += block_group->key.offset; | ||
| 2047 | space->used_bytes += | ||
| 2048 | btrfs_block_group_used(&block_group->item); | ||
| 2049 | } | ||
| 2050 | } | ||
| 2051 | |||
| 1882 | long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | 2052 | long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) |
| 1883 | { | 2053 | { |
| 1884 | struct btrfs_ioctl_space_args space_args; | 2054 | struct btrfs_ioctl_space_args space_args; |
| @@ -1887,27 +2057,56 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | |||
| 1887 | struct btrfs_ioctl_space_info *dest_orig; | 2057 | struct btrfs_ioctl_space_info *dest_orig; |
| 1888 | struct btrfs_ioctl_space_info *user_dest; | 2058 | struct btrfs_ioctl_space_info *user_dest; |
| 1889 | struct btrfs_space_info *info; | 2059 | struct btrfs_space_info *info; |
| 2060 | u64 types[] = {BTRFS_BLOCK_GROUP_DATA, | ||
| 2061 | BTRFS_BLOCK_GROUP_SYSTEM, | ||
| 2062 | BTRFS_BLOCK_GROUP_METADATA, | ||
| 2063 | BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA}; | ||
| 2064 | int num_types = 4; | ||
| 1890 | int alloc_size; | 2065 | int alloc_size; |
| 1891 | int ret = 0; | 2066 | int ret = 0; |
| 1892 | int slot_count = 0; | 2067 | int slot_count = 0; |
| 2068 | int i, c; | ||
| 1893 | 2069 | ||
| 1894 | if (copy_from_user(&space_args, | 2070 | if (copy_from_user(&space_args, |
| 1895 | (struct btrfs_ioctl_space_args __user *)arg, | 2071 | (struct btrfs_ioctl_space_args __user *)arg, |
| 1896 | sizeof(space_args))) | 2072 | sizeof(space_args))) |
| 1897 | return -EFAULT; | 2073 | return -EFAULT; |
| 1898 | 2074 | ||
| 1899 | /* first we count slots */ | 2075 | for (i = 0; i < num_types; i++) { |
| 1900 | rcu_read_lock(); | 2076 | struct btrfs_space_info *tmp; |
| 1901 | list_for_each_entry_rcu(info, &root->fs_info->space_info, list) | 2077 | |
| 1902 | slot_count++; | 2078 | info = NULL; |
| 1903 | rcu_read_unlock(); | 2079 | rcu_read_lock(); |
| 2080 | list_for_each_entry_rcu(tmp, &root->fs_info->space_info, | ||
| 2081 | list) { | ||
| 2082 | if (tmp->flags == types[i]) { | ||
| 2083 | info = tmp; | ||
| 2084 | break; | ||
| 2085 | } | ||
| 2086 | } | ||
| 2087 | rcu_read_unlock(); | ||
| 2088 | |||
| 2089 | if (!info) | ||
| 2090 | continue; | ||
| 2091 | |||
| 2092 | down_read(&info->groups_sem); | ||
| 2093 | for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { | ||
| 2094 | if (!list_empty(&info->block_groups[c])) | ||
| 2095 | slot_count++; | ||
| 2096 | } | ||
| 2097 | up_read(&info->groups_sem); | ||
| 2098 | } | ||
| 1904 | 2099 | ||
| 1905 | /* space_slots == 0 means they are asking for a count */ | 2100 | /* space_slots == 0 means they are asking for a count */ |
| 1906 | if (space_args.space_slots == 0) { | 2101 | if (space_args.space_slots == 0) { |
| 1907 | space_args.total_spaces = slot_count; | 2102 | space_args.total_spaces = slot_count; |
| 1908 | goto out; | 2103 | goto out; |
| 1909 | } | 2104 | } |
| 2105 | |||
| 2106 | slot_count = min_t(int, space_args.space_slots, slot_count); | ||
| 2107 | |||
| 1910 | alloc_size = sizeof(*dest) * slot_count; | 2108 | alloc_size = sizeof(*dest) * slot_count; |
| 2109 | |||
| 1911 | /* we generally have at most 6 or so space infos, one for each raid | 2110 | /* we generally have at most 6 or so space infos, one for each raid |
| 1912 | * level. So, a whole page should be more than enough for everyone | 2111 | * level. So, a whole page should be more than enough for everyone |
| 1913 | */ | 2112 | */ |
| @@ -1921,27 +2120,34 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | |||
| 1921 | dest_orig = dest; | 2120 | dest_orig = dest; |
| 1922 | 2121 | ||
| 1923 | /* now we have a buffer to copy into */ | 2122 | /* now we have a buffer to copy into */ |
| 1924 | rcu_read_lock(); | 2123 | for (i = 0; i < num_types; i++) { |
| 1925 | list_for_each_entry_rcu(info, &root->fs_info->space_info, list) { | 2124 | struct btrfs_space_info *tmp; |
| 1926 | /* make sure we don't copy more than we allocated | 2125 | |
| 1927 | * in our buffer | 2126 | info = NULL; |
| 1928 | */ | 2127 | rcu_read_lock(); |
| 1929 | if (slot_count == 0) | 2128 | list_for_each_entry_rcu(tmp, &root->fs_info->space_info, |
| 1930 | break; | 2129 | list) { |
| 1931 | slot_count--; | 2130 | if (tmp->flags == types[i]) { |
| 1932 | 2131 | info = tmp; | |
| 1933 | /* make sure userland has enough room in their buffer */ | 2132 | break; |
| 1934 | if (space_args.total_spaces >= space_args.space_slots) | 2133 | } |
| 1935 | break; | 2134 | } |
| 2135 | rcu_read_unlock(); | ||
| 1936 | 2136 | ||
| 1937 | space.flags = info->flags; | 2137 | if (!info) |
| 1938 | space.total_bytes = info->total_bytes; | 2138 | continue; |
| 1939 | space.used_bytes = info->bytes_used; | 2139 | down_read(&info->groups_sem); |
| 1940 | memcpy(dest, &space, sizeof(space)); | 2140 | for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { |
| 1941 | dest++; | 2141 | if (!list_empty(&info->block_groups[c])) { |
| 1942 | space_args.total_spaces++; | 2142 | get_block_group_info(&info->block_groups[c], |
| 2143 | &space); | ||
| 2144 | memcpy(dest, &space, sizeof(space)); | ||
| 2145 | dest++; | ||
| 2146 | space_args.total_spaces++; | ||
| 2147 | } | ||
| 2148 | } | ||
| 2149 | up_read(&info->groups_sem); | ||
| 1943 | } | 2150 | } |
| 1944 | rcu_read_unlock(); | ||
| 1945 | 2151 | ||
| 1946 | user_dest = (struct btrfs_ioctl_space_info *) | 2152 | user_dest = (struct btrfs_ioctl_space_info *) |
| 1947 | (arg + sizeof(struct btrfs_ioctl_space_args)); | 2153 | (arg + sizeof(struct btrfs_ioctl_space_args)); |
| @@ -1984,6 +2190,36 @@ long btrfs_ioctl_trans_end(struct file *file) | |||
| 1984 | return 0; | 2190 | return 0; |
| 1985 | } | 2191 | } |
| 1986 | 2192 | ||
| 2193 | static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp) | ||
| 2194 | { | ||
| 2195 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; | ||
| 2196 | struct btrfs_trans_handle *trans; | ||
| 2197 | u64 transid; | ||
| 2198 | |||
| 2199 | trans = btrfs_start_transaction(root, 0); | ||
| 2200 | transid = trans->transid; | ||
| 2201 | btrfs_commit_transaction_async(trans, root, 0); | ||
| 2202 | |||
| 2203 | if (argp) | ||
| 2204 | if (copy_to_user(argp, &transid, sizeof(transid))) | ||
| 2205 | return -EFAULT; | ||
| 2206 | return 0; | ||
| 2207 | } | ||
| 2208 | |||
| 2209 | static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp) | ||
| 2210 | { | ||
| 2211 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; | ||
| 2212 | u64 transid; | ||
| 2213 | |||
| 2214 | if (argp) { | ||
| 2215 | if (copy_from_user(&transid, argp, sizeof(transid))) | ||
| 2216 | return -EFAULT; | ||
| 2217 | } else { | ||
| 2218 | transid = 0; /* current trans */ | ||
| 2219 | } | ||
| 2220 | return btrfs_wait_for_commit(root, transid); | ||
| 2221 | } | ||
| 2222 | |||
| 1987 | long btrfs_ioctl(struct file *file, unsigned int | 2223 | long btrfs_ioctl(struct file *file, unsigned int |
| 1988 | cmd, unsigned long arg) | 2224 | cmd, unsigned long arg) |
| 1989 | { | 2225 | { |
| @@ -1998,9 +2234,11 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 1998 | case FS_IOC_GETVERSION: | 2234 | case FS_IOC_GETVERSION: |
| 1999 | return btrfs_ioctl_getversion(file, argp); | 2235 | return btrfs_ioctl_getversion(file, argp); |
| 2000 | case BTRFS_IOC_SNAP_CREATE: | 2236 | case BTRFS_IOC_SNAP_CREATE: |
| 2001 | return btrfs_ioctl_snap_create(file, argp, 0); | 2237 | return btrfs_ioctl_snap_create(file, argp, 0, 0); |
| 2238 | case BTRFS_IOC_SNAP_CREATE_ASYNC: | ||
| 2239 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | ||
| 2002 | case BTRFS_IOC_SUBVOL_CREATE: | 2240 | case BTRFS_IOC_SUBVOL_CREATE: |
| 2003 | return btrfs_ioctl_snap_create(file, argp, 1); | 2241 | return btrfs_ioctl_snap_create(file, argp, 1, 0); |
| 2004 | case BTRFS_IOC_SNAP_DESTROY: | 2242 | case BTRFS_IOC_SNAP_DESTROY: |
| 2005 | return btrfs_ioctl_snap_destroy(file, argp); | 2243 | return btrfs_ioctl_snap_destroy(file, argp); |
| 2006 | case BTRFS_IOC_DEFAULT_SUBVOL: | 2244 | case BTRFS_IOC_DEFAULT_SUBVOL: |
| @@ -2034,6 +2272,10 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 2034 | case BTRFS_IOC_SYNC: | 2272 | case BTRFS_IOC_SYNC: |
| 2035 | btrfs_sync_fs(file->f_dentry->d_sb, 1); | 2273 | btrfs_sync_fs(file->f_dentry->d_sb, 1); |
| 2036 | return 0; | 2274 | return 0; |
| 2275 | case BTRFS_IOC_START_SYNC: | ||
| 2276 | return btrfs_ioctl_start_sync(file, argp); | ||
| 2277 | case BTRFS_IOC_WAIT_SYNC: | ||
| 2278 | return btrfs_ioctl_wait_sync(file, argp); | ||
| 2037 | } | 2279 | } |
| 2038 | 2280 | ||
| 2039 | return -ENOTTY; | 2281 | return -ENOTTY; |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 424694aa517f..17c99ebdf960 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
| @@ -22,14 +22,21 @@ | |||
| 22 | 22 | ||
| 23 | #define BTRFS_IOCTL_MAGIC 0x94 | 23 | #define BTRFS_IOCTL_MAGIC 0x94 |
| 24 | #define BTRFS_VOL_NAME_MAX 255 | 24 | #define BTRFS_VOL_NAME_MAX 255 |
| 25 | #define BTRFS_PATH_NAME_MAX 4087 | ||
| 26 | 25 | ||
| 27 | /* this should be 4k */ | 26 | /* this should be 4k */ |
| 27 | #define BTRFS_PATH_NAME_MAX 4087 | ||
| 28 | struct btrfs_ioctl_vol_args { | 28 | struct btrfs_ioctl_vol_args { |
| 29 | __s64 fd; | 29 | __s64 fd; |
| 30 | char name[BTRFS_PATH_NAME_MAX + 1]; | 30 | char name[BTRFS_PATH_NAME_MAX + 1]; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | #define BTRFS_SNAPSHOT_NAME_MAX 4079 | ||
| 34 | struct btrfs_ioctl_async_vol_args { | ||
| 35 | __s64 fd; | ||
| 36 | __u64 transid; | ||
| 37 | char name[BTRFS_SNAPSHOT_NAME_MAX + 1]; | ||
| 38 | }; | ||
| 39 | |||
| 33 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 | 40 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 |
| 34 | struct btrfs_ioctl_ino_lookup_args { | 41 | struct btrfs_ioctl_ino_lookup_args { |
| 35 | __u64 treeid; | 42 | __u64 treeid; |
| @@ -178,4 +185,8 @@ struct btrfs_ioctl_space_args { | |||
| 178 | #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64) | 185 | #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64) |
| 179 | #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ | 186 | #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ |
| 180 | struct btrfs_ioctl_space_args) | 187 | struct btrfs_ioctl_space_args) |
| 188 | #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) | ||
| 189 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) | ||
| 190 | #define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \ | ||
| 191 | struct btrfs_ioctl_async_vol_args) | ||
| 181 | #endif | 192 | #endif |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index e56c72bc5add..f4621f6deca1 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
| @@ -526,7 +526,6 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) | |||
| 526 | { | 526 | { |
| 527 | u64 end; | 527 | u64 end; |
| 528 | u64 orig_end; | 528 | u64 orig_end; |
| 529 | u64 wait_end; | ||
| 530 | struct btrfs_ordered_extent *ordered; | 529 | struct btrfs_ordered_extent *ordered; |
| 531 | int found; | 530 | int found; |
| 532 | 531 | ||
| @@ -537,7 +536,6 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) | |||
| 537 | if (orig_end > INT_LIMIT(loff_t)) | 536 | if (orig_end > INT_LIMIT(loff_t)) |
| 538 | orig_end = INT_LIMIT(loff_t); | 537 | orig_end = INT_LIMIT(loff_t); |
| 539 | } | 538 | } |
| 540 | wait_end = orig_end; | ||
| 541 | again: | 539 | again: |
| 542 | /* start IO across the range first to instantiate any delalloc | 540 | /* start IO across the range first to instantiate any delalloc |
| 543 | * extents | 541 | * extents |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b37d723b9d4a..045c9c2b2d7e 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "locking.h" | 29 | #include "locking.h" |
| 30 | #include "btrfs_inode.h" | 30 | #include "btrfs_inode.h" |
| 31 | #include "async-thread.h" | 31 | #include "async-thread.h" |
| 32 | #include "free-space-cache.h" | ||
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * backref_node, mapping_node and tree_block start with this | 35 | * backref_node, mapping_node and tree_block start with this |
| @@ -178,8 +179,6 @@ struct reloc_control { | |||
| 178 | u64 search_start; | 179 | u64 search_start; |
| 179 | u64 extents_found; | 180 | u64 extents_found; |
| 180 | 181 | ||
| 181 | int block_rsv_retries; | ||
| 182 | |||
| 183 | unsigned int stage:8; | 182 | unsigned int stage:8; |
| 184 | unsigned int create_reloc_tree:1; | 183 | unsigned int create_reloc_tree:1; |
| 185 | unsigned int merge_reloc_tree:1; | 184 | unsigned int merge_reloc_tree:1; |
| @@ -2133,7 +2132,6 @@ int prepare_to_merge(struct reloc_control *rc, int err) | |||
| 2133 | LIST_HEAD(reloc_roots); | 2132 | LIST_HEAD(reloc_roots); |
| 2134 | u64 num_bytes = 0; | 2133 | u64 num_bytes = 0; |
| 2135 | int ret; | 2134 | int ret; |
| 2136 | int retries = 0; | ||
| 2137 | 2135 | ||
| 2138 | mutex_lock(&root->fs_info->trans_mutex); | 2136 | mutex_lock(&root->fs_info->trans_mutex); |
| 2139 | rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2; | 2137 | rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2; |
| @@ -2143,7 +2141,7 @@ again: | |||
| 2143 | if (!err) { | 2141 | if (!err) { |
| 2144 | num_bytes = rc->merging_rsv_size; | 2142 | num_bytes = rc->merging_rsv_size; |
| 2145 | ret = btrfs_block_rsv_add(NULL, root, rc->block_rsv, | 2143 | ret = btrfs_block_rsv_add(NULL, root, rc->block_rsv, |
| 2146 | num_bytes, &retries); | 2144 | num_bytes); |
| 2147 | if (ret) | 2145 | if (ret) |
| 2148 | err = ret; | 2146 | err = ret; |
| 2149 | } | 2147 | } |
| @@ -2155,7 +2153,6 @@ again: | |||
| 2155 | btrfs_end_transaction(trans, rc->extent_root); | 2153 | btrfs_end_transaction(trans, rc->extent_root); |
| 2156 | btrfs_block_rsv_release(rc->extent_root, | 2154 | btrfs_block_rsv_release(rc->extent_root, |
| 2157 | rc->block_rsv, num_bytes); | 2155 | rc->block_rsv, num_bytes); |
| 2158 | retries = 0; | ||
| 2159 | goto again; | 2156 | goto again; |
| 2160 | } | 2157 | } |
| 2161 | } | 2158 | } |
| @@ -2405,15 +2402,13 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans, | |||
| 2405 | num_bytes = calcu_metadata_size(rc, node, 1) * 2; | 2402 | num_bytes = calcu_metadata_size(rc, node, 1) * 2; |
| 2406 | 2403 | ||
| 2407 | trans->block_rsv = rc->block_rsv; | 2404 | trans->block_rsv = rc->block_rsv; |
| 2408 | ret = btrfs_block_rsv_add(trans, root, rc->block_rsv, num_bytes, | 2405 | ret = btrfs_block_rsv_add(trans, root, rc->block_rsv, num_bytes); |
| 2409 | &rc->block_rsv_retries); | ||
| 2410 | if (ret) { | 2406 | if (ret) { |
| 2411 | if (ret == -EAGAIN) | 2407 | if (ret == -EAGAIN) |
| 2412 | rc->commit_transaction = 1; | 2408 | rc->commit_transaction = 1; |
| 2413 | return ret; | 2409 | return ret; |
| 2414 | } | 2410 | } |
| 2415 | 2411 | ||
| 2416 | rc->block_rsv_retries = 0; | ||
| 2417 | return 0; | 2412 | return 0; |
| 2418 | } | 2413 | } |
| 2419 | 2414 | ||
| @@ -3099,6 +3094,8 @@ static int add_tree_block(struct reloc_control *rc, | |||
| 3099 | BUG_ON(item_size != sizeof(struct btrfs_extent_item_v0)); | 3094 | BUG_ON(item_size != sizeof(struct btrfs_extent_item_v0)); |
| 3100 | ret = get_ref_objectid_v0(rc, path, extent_key, | 3095 | ret = get_ref_objectid_v0(rc, path, extent_key, |
| 3101 | &ref_owner, NULL); | 3096 | &ref_owner, NULL); |
| 3097 | if (ret < 0) | ||
| 3098 | return ret; | ||
| 3102 | BUG_ON(ref_owner >= BTRFS_MAX_LEVEL); | 3099 | BUG_ON(ref_owner >= BTRFS_MAX_LEVEL); |
| 3103 | level = (int)ref_owner; | 3100 | level = (int)ref_owner; |
| 3104 | /* FIXME: get real generation */ | 3101 | /* FIXME: get real generation */ |
| @@ -3191,6 +3188,54 @@ static int block_use_full_backref(struct reloc_control *rc, | |||
| 3191 | return ret; | 3188 | return ret; |
| 3192 | } | 3189 | } |
| 3193 | 3190 | ||
| 3191 | static int delete_block_group_cache(struct btrfs_fs_info *fs_info, | ||
| 3192 | struct inode *inode, u64 ino) | ||
| 3193 | { | ||
| 3194 | struct btrfs_key key; | ||
| 3195 | struct btrfs_path *path; | ||
| 3196 | struct btrfs_root *root = fs_info->tree_root; | ||
| 3197 | struct btrfs_trans_handle *trans; | ||
| 3198 | unsigned long nr; | ||
| 3199 | int ret = 0; | ||
| 3200 | |||
| 3201 | if (inode) | ||
| 3202 | goto truncate; | ||
| 3203 | |||
| 3204 | key.objectid = ino; | ||
| 3205 | key.type = BTRFS_INODE_ITEM_KEY; | ||
| 3206 | key.offset = 0; | ||
| 3207 | |||
| 3208 | inode = btrfs_iget(fs_info->sb, &key, root, NULL); | ||
| 3209 | if (!inode || IS_ERR(inode) || is_bad_inode(inode)) { | ||
| 3210 | if (inode && !IS_ERR(inode)) | ||
| 3211 | iput(inode); | ||
| 3212 | return -ENOENT; | ||
| 3213 | } | ||
| 3214 | |||
| 3215 | truncate: | ||
| 3216 | path = btrfs_alloc_path(); | ||
| 3217 | if (!path) { | ||
| 3218 | ret = -ENOMEM; | ||
| 3219 | goto out; | ||
| 3220 | } | ||
| 3221 | |||
| 3222 | trans = btrfs_join_transaction(root, 0); | ||
| 3223 | if (IS_ERR(trans)) { | ||
| 3224 | btrfs_free_path(path); | ||
| 3225 | goto out; | ||
| 3226 | } | ||
| 3227 | |||
| 3228 | ret = btrfs_truncate_free_space_cache(root, trans, path, inode); | ||
| 3229 | |||
| 3230 | btrfs_free_path(path); | ||
| 3231 | nr = trans->blocks_used; | ||
| 3232 | btrfs_end_transaction(trans, root); | ||
| 3233 | btrfs_btree_balance_dirty(root, nr); | ||
| 3234 | out: | ||
| 3235 | iput(inode); | ||
| 3236 | return ret; | ||
| 3237 | } | ||
| 3238 | |||
| 3194 | /* | 3239 | /* |
| 3195 | * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY | 3240 | * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY |
| 3196 | * this function scans fs tree to find blocks reference the data extent | 3241 | * this function scans fs tree to find blocks reference the data extent |
| @@ -3217,15 +3262,27 @@ static int find_data_references(struct reloc_control *rc, | |||
| 3217 | int counted; | 3262 | int counted; |
| 3218 | int ret; | 3263 | int ret; |
| 3219 | 3264 | ||
| 3220 | path = btrfs_alloc_path(); | ||
| 3221 | if (!path) | ||
| 3222 | return -ENOMEM; | ||
| 3223 | |||
| 3224 | ref_root = btrfs_extent_data_ref_root(leaf, ref); | 3265 | ref_root = btrfs_extent_data_ref_root(leaf, ref); |
| 3225 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); | 3266 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); |
| 3226 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); | 3267 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); |
| 3227 | ref_count = btrfs_extent_data_ref_count(leaf, ref); | 3268 | ref_count = btrfs_extent_data_ref_count(leaf, ref); |
| 3228 | 3269 | ||
| 3270 | /* | ||
| 3271 | * This is an extent belonging to the free space cache, lets just delete | ||
| 3272 | * it and redo the search. | ||
| 3273 | */ | ||
| 3274 | if (ref_root == BTRFS_ROOT_TREE_OBJECTID) { | ||
| 3275 | ret = delete_block_group_cache(rc->extent_root->fs_info, | ||
| 3276 | NULL, ref_objectid); | ||
| 3277 | if (ret != -ENOENT) | ||
| 3278 | return ret; | ||
| 3279 | ret = 0; | ||
| 3280 | } | ||
| 3281 | |||
| 3282 | path = btrfs_alloc_path(); | ||
| 3283 | if (!path) | ||
| 3284 | return -ENOMEM; | ||
| 3285 | |||
| 3229 | root = read_fs_root(rc->extent_root->fs_info, ref_root); | 3286 | root = read_fs_root(rc->extent_root->fs_info, ref_root); |
| 3230 | if (IS_ERR(root)) { | 3287 | if (IS_ERR(root)) { |
| 3231 | err = PTR_ERR(root); | 3288 | err = PTR_ERR(root); |
| @@ -3554,8 +3611,7 @@ int prepare_to_relocate(struct reloc_control *rc) | |||
| 3554 | * is no reservation in transaction handle. | 3611 | * is no reservation in transaction handle. |
| 3555 | */ | 3612 | */ |
| 3556 | ret = btrfs_block_rsv_add(NULL, rc->extent_root, rc->block_rsv, | 3613 | ret = btrfs_block_rsv_add(NULL, rc->extent_root, rc->block_rsv, |
| 3557 | rc->extent_root->nodesize * 256, | 3614 | rc->extent_root->nodesize * 256); |
| 3558 | &rc->block_rsv_retries); | ||
| 3559 | if (ret) | 3615 | if (ret) |
| 3560 | return ret; | 3616 | return ret; |
| 3561 | 3617 | ||
| @@ -3567,7 +3623,6 @@ int prepare_to_relocate(struct reloc_control *rc) | |||
| 3567 | rc->extents_found = 0; | 3623 | rc->extents_found = 0; |
| 3568 | rc->nodes_relocated = 0; | 3624 | rc->nodes_relocated = 0; |
| 3569 | rc->merging_rsv_size = 0; | 3625 | rc->merging_rsv_size = 0; |
| 3570 | rc->block_rsv_retries = 0; | ||
| 3571 | 3626 | ||
| 3572 | rc->create_reloc_tree = 1; | 3627 | rc->create_reloc_tree = 1; |
| 3573 | set_reloc_control(rc); | 3628 | set_reloc_control(rc); |
| @@ -3860,6 +3915,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
| 3860 | { | 3915 | { |
| 3861 | struct btrfs_fs_info *fs_info = extent_root->fs_info; | 3916 | struct btrfs_fs_info *fs_info = extent_root->fs_info; |
| 3862 | struct reloc_control *rc; | 3917 | struct reloc_control *rc; |
| 3918 | struct inode *inode; | ||
| 3919 | struct btrfs_path *path; | ||
| 3863 | int ret; | 3920 | int ret; |
| 3864 | int rw = 0; | 3921 | int rw = 0; |
| 3865 | int err = 0; | 3922 | int err = 0; |
| @@ -3882,6 +3939,26 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
| 3882 | rw = 1; | 3939 | rw = 1; |
| 3883 | } | 3940 | } |
| 3884 | 3941 | ||
| 3942 | path = btrfs_alloc_path(); | ||
| 3943 | if (!path) { | ||
| 3944 | err = -ENOMEM; | ||
| 3945 | goto out; | ||
| 3946 | } | ||
| 3947 | |||
| 3948 | inode = lookup_free_space_inode(fs_info->tree_root, rc->block_group, | ||
| 3949 | path); | ||
| 3950 | btrfs_free_path(path); | ||
| 3951 | |||
| 3952 | if (!IS_ERR(inode)) | ||
| 3953 | ret = delete_block_group_cache(fs_info, inode, 0); | ||
| 3954 | else | ||
| 3955 | ret = PTR_ERR(inode); | ||
| 3956 | |||
| 3957 | if (ret && ret != -ENOENT) { | ||
| 3958 | err = ret; | ||
| 3959 | goto out; | ||
| 3960 | } | ||
| 3961 | |||
| 3885 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); | 3962 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); |
| 3886 | if (IS_ERR(rc->data_inode)) { | 3963 | if (IS_ERR(rc->data_inode)) { |
| 3887 | err = PTR_ERR(rc->data_inode); | 3964 | err = PTR_ERR(rc->data_inode); |
| @@ -4143,7 +4220,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) | |||
| 4143 | btrfs_add_ordered_sum(inode, ordered, sums); | 4220 | btrfs_add_ordered_sum(inode, ordered, sums); |
| 4144 | } | 4221 | } |
| 4145 | btrfs_put_ordered_extent(ordered); | 4222 | btrfs_put_ordered_extent(ordered); |
| 4146 | return 0; | 4223 | return ret; |
| 4147 | } | 4224 | } |
| 4148 | 4225 | ||
| 4149 | void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, | 4226 | void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 2d958be761c8..6a1086e83ffc 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
| @@ -181,7 +181,6 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 181 | int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid) | 181 | int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid) |
| 182 | { | 182 | { |
| 183 | struct btrfs_root *dead_root; | 183 | struct btrfs_root *dead_root; |
| 184 | struct btrfs_item *item; | ||
| 185 | struct btrfs_root_item *ri; | 184 | struct btrfs_root_item *ri; |
| 186 | struct btrfs_key key; | 185 | struct btrfs_key key; |
| 187 | struct btrfs_key found_key; | 186 | struct btrfs_key found_key; |
| @@ -214,7 +213,6 @@ again: | |||
| 214 | nritems = btrfs_header_nritems(leaf); | 213 | nritems = btrfs_header_nritems(leaf); |
| 215 | slot = path->slots[0]; | 214 | slot = path->slots[0]; |
| 216 | } | 215 | } |
| 217 | item = btrfs_item_nr(leaf, slot); | ||
| 218 | btrfs_item_key_to_cpu(leaf, &key, slot); | 216 | btrfs_item_key_to_cpu(leaf, &key, slot); |
| 219 | if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY) | 217 | if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY) |
| 220 | goto next; | 218 | goto next; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ebe46c628748..8299a25ffc8f 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -61,6 +61,8 @@ static void btrfs_put_super(struct super_block *sb) | |||
| 61 | 61 | ||
| 62 | ret = close_ctree(root); | 62 | ret = close_ctree(root); |
| 63 | sb->s_fs_info = NULL; | 63 | sb->s_fs_info = NULL; |
| 64 | |||
| 65 | (void)ret; /* FIXME: need to fix VFS to return error? */ | ||
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | enum { | 68 | enum { |
| @@ -68,7 +70,8 @@ enum { | |||
| 68 | Opt_nodatacow, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, | 70 | Opt_nodatacow, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, |
| 69 | Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress, | 71 | Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress, |
| 70 | Opt_compress_force, Opt_notreelog, Opt_ratio, Opt_flushoncommit, | 72 | Opt_compress_force, Opt_notreelog, Opt_ratio, Opt_flushoncommit, |
| 71 | Opt_discard, Opt_err, | 73 | Opt_discard, Opt_space_cache, Opt_clear_cache, Opt_err, |
| 74 | Opt_user_subvol_rm_allowed, | ||
| 72 | }; | 75 | }; |
| 73 | 76 | ||
| 74 | static match_table_t tokens = { | 77 | static match_table_t tokens = { |
| @@ -92,6 +95,9 @@ static match_table_t tokens = { | |||
| 92 | {Opt_flushoncommit, "flushoncommit"}, | 95 | {Opt_flushoncommit, "flushoncommit"}, |
| 93 | {Opt_ratio, "metadata_ratio=%d"}, | 96 | {Opt_ratio, "metadata_ratio=%d"}, |
| 94 | {Opt_discard, "discard"}, | 97 | {Opt_discard, "discard"}, |
| 98 | {Opt_space_cache, "space_cache"}, | ||
| 99 | {Opt_clear_cache, "clear_cache"}, | ||
| 100 | {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"}, | ||
| 95 | {Opt_err, NULL}, | 101 | {Opt_err, NULL}, |
| 96 | }; | 102 | }; |
| 97 | 103 | ||
| @@ -235,6 +241,16 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) | |||
| 235 | case Opt_discard: | 241 | case Opt_discard: |
| 236 | btrfs_set_opt(info->mount_opt, DISCARD); | 242 | btrfs_set_opt(info->mount_opt, DISCARD); |
| 237 | break; | 243 | break; |
| 244 | case Opt_space_cache: | ||
| 245 | printk(KERN_INFO "btrfs: enabling disk space caching\n"); | ||
| 246 | btrfs_set_opt(info->mount_opt, SPACE_CACHE); | ||
| 247 | case Opt_clear_cache: | ||
| 248 | printk(KERN_INFO "btrfs: force clearing of disk cache\n"); | ||
| 249 | btrfs_set_opt(info->mount_opt, CLEAR_CACHE); | ||
| 250 | break; | ||
| 251 | case Opt_user_subvol_rm_allowed: | ||
| 252 | btrfs_set_opt(info->mount_opt, USER_SUBVOL_RM_ALLOWED); | ||
| 253 | break; | ||
| 238 | case Opt_err: | 254 | case Opt_err: |
| 239 | printk(KERN_INFO "btrfs: unrecognized mount option " | 255 | printk(KERN_INFO "btrfs: unrecognized mount option " |
| 240 | "'%s'\n", p); | 256 | "'%s'\n", p); |
| @@ -380,7 +396,7 @@ static struct dentry *get_default_root(struct super_block *sb, | |||
| 380 | find_root: | 396 | find_root: |
| 381 | new_root = btrfs_read_fs_root_no_name(root->fs_info, &location); | 397 | new_root = btrfs_read_fs_root_no_name(root->fs_info, &location); |
| 382 | if (IS_ERR(new_root)) | 398 | if (IS_ERR(new_root)) |
| 383 | return ERR_PTR(PTR_ERR(new_root)); | 399 | return ERR_CAST(new_root); |
| 384 | 400 | ||
| 385 | if (btrfs_root_refs(&new_root->root_item) == 0) | 401 | if (btrfs_root_refs(&new_root->root_item) == 0) |
| 386 | return ERR_PTR(-ENOENT); | 402 | return ERR_PTR(-ENOENT); |
| @@ -436,7 +452,6 @@ static int btrfs_fill_super(struct super_block *sb, | |||
| 436 | { | 452 | { |
| 437 | struct inode *inode; | 453 | struct inode *inode; |
| 438 | struct dentry *root_dentry; | 454 | struct dentry *root_dentry; |
| 439 | struct btrfs_super_block *disk_super; | ||
| 440 | struct btrfs_root *tree_root; | 455 | struct btrfs_root *tree_root; |
| 441 | struct btrfs_key key; | 456 | struct btrfs_key key; |
| 442 | int err; | 457 | int err; |
| @@ -458,7 +473,6 @@ static int btrfs_fill_super(struct super_block *sb, | |||
| 458 | return PTR_ERR(tree_root); | 473 | return PTR_ERR(tree_root); |
| 459 | } | 474 | } |
| 460 | sb->s_fs_info = tree_root; | 475 | sb->s_fs_info = tree_root; |
| 461 | disk_super = &tree_root->fs_info->super_copy; | ||
| 462 | 476 | ||
| 463 | key.objectid = BTRFS_FIRST_FREE_OBJECTID; | 477 | key.objectid = BTRFS_FIRST_FREE_OBJECTID; |
| 464 | key.type = BTRFS_INODE_ITEM_KEY; | 478 | key.type = BTRFS_INODE_ITEM_KEY; |
| @@ -571,7 +585,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
| 571 | char *subvol_name = NULL; | 585 | char *subvol_name = NULL; |
| 572 | u64 subvol_objectid = 0; | 586 | u64 subvol_objectid = 0; |
| 573 | int error = 0; | 587 | int error = 0; |
| 574 | int found = 0; | ||
| 575 | 588 | ||
| 576 | if (!(flags & MS_RDONLY)) | 589 | if (!(flags & MS_RDONLY)) |
| 577 | mode |= FMODE_WRITE; | 590 | mode |= FMODE_WRITE; |
| @@ -607,7 +620,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
| 607 | goto error_close_devices; | 620 | goto error_close_devices; |
| 608 | } | 621 | } |
| 609 | 622 | ||
| 610 | found = 1; | ||
| 611 | btrfs_close_devices(fs_devices); | 623 | btrfs_close_devices(fs_devices); |
| 612 | } else { | 624 | } else { |
| 613 | char b[BDEVNAME_SIZE]; | 625 | char b[BDEVNAME_SIZE]; |
| @@ -629,7 +641,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
| 629 | if (IS_ERR(root)) { | 641 | if (IS_ERR(root)) { |
| 630 | error = PTR_ERR(root); | 642 | error = PTR_ERR(root); |
| 631 | deactivate_locked_super(s); | 643 | deactivate_locked_super(s); |
| 632 | goto error; | 644 | goto error_free_subvol_name; |
| 633 | } | 645 | } |
| 634 | /* if they gave us a subvolume name bind mount into that */ | 646 | /* if they gave us a subvolume name bind mount into that */ |
| 635 | if (strcmp(subvol_name, ".")) { | 647 | if (strcmp(subvol_name, ".")) { |
| @@ -643,14 +655,14 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
| 643 | deactivate_locked_super(s); | 655 | deactivate_locked_super(s); |
| 644 | error = PTR_ERR(new_root); | 656 | error = PTR_ERR(new_root); |
| 645 | dput(root); | 657 | dput(root); |
| 646 | goto error_close_devices; | 658 | goto error_free_subvol_name; |
| 647 | } | 659 | } |
| 648 | if (!new_root->d_inode) { | 660 | if (!new_root->d_inode) { |
| 649 | dput(root); | 661 | dput(root); |
| 650 | dput(new_root); | 662 | dput(new_root); |
| 651 | deactivate_locked_super(s); | 663 | deactivate_locked_super(s); |
| 652 | error = -ENXIO; | 664 | error = -ENXIO; |
| 653 | goto error_close_devices; | 665 | goto error_free_subvol_name; |
| 654 | } | 666 | } |
| 655 | dput(root); | 667 | dput(root); |
| 656 | root = new_root; | 668 | root = new_root; |
| @@ -665,7 +677,6 @@ error_close_devices: | |||
| 665 | btrfs_close_devices(fs_devices); | 677 | btrfs_close_devices(fs_devices); |
| 666 | error_free_subvol_name: | 678 | error_free_subvol_name: |
| 667 | kfree(subvol_name); | 679 | kfree(subvol_name); |
| 668 | error: | ||
| 669 | return ERR_PTR(error); | 680 | return ERR_PTR(error); |
| 670 | } | 681 | } |
| 671 | 682 | ||
| @@ -713,18 +724,25 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 713 | struct list_head *head = &root->fs_info->space_info; | 724 | struct list_head *head = &root->fs_info->space_info; |
| 714 | struct btrfs_space_info *found; | 725 | struct btrfs_space_info *found; |
| 715 | u64 total_used = 0; | 726 | u64 total_used = 0; |
| 727 | u64 total_used_data = 0; | ||
| 716 | int bits = dentry->d_sb->s_blocksize_bits; | 728 | int bits = dentry->d_sb->s_blocksize_bits; |
| 717 | __be32 *fsid = (__be32 *)root->fs_info->fsid; | 729 | __be32 *fsid = (__be32 *)root->fs_info->fsid; |
| 718 | 730 | ||
| 719 | rcu_read_lock(); | 731 | rcu_read_lock(); |
| 720 | list_for_each_entry_rcu(found, head, list) | 732 | list_for_each_entry_rcu(found, head, list) { |
| 733 | if (found->flags & (BTRFS_BLOCK_GROUP_METADATA | | ||
| 734 | BTRFS_BLOCK_GROUP_SYSTEM)) | ||
| 735 | total_used_data += found->disk_total; | ||
| 736 | else | ||
| 737 | total_used_data += found->disk_used; | ||
| 721 | total_used += found->disk_used; | 738 | total_used += found->disk_used; |
| 739 | } | ||
| 722 | rcu_read_unlock(); | 740 | rcu_read_unlock(); |
| 723 | 741 | ||
| 724 | buf->f_namelen = BTRFS_NAME_LEN; | 742 | buf->f_namelen = BTRFS_NAME_LEN; |
| 725 | buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; | 743 | buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; |
| 726 | buf->f_bfree = buf->f_blocks - (total_used >> bits); | 744 | buf->f_bfree = buf->f_blocks - (total_used >> bits); |
| 727 | buf->f_bavail = buf->f_bfree; | 745 | buf->f_bavail = buf->f_blocks - (total_used_data >> bits); |
| 728 | buf->f_bsize = dentry->d_sb->s_blocksize; | 746 | buf->f_bsize = dentry->d_sb->s_blocksize; |
| 729 | buf->f_type = BTRFS_SUPER_MAGIC; | 747 | buf->f_type = BTRFS_SUPER_MAGIC; |
| 730 | 748 | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 66e4c66cc63b..1fffbc017bdf 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -163,6 +163,7 @@ enum btrfs_trans_type { | |||
| 163 | TRANS_START, | 163 | TRANS_START, |
| 164 | TRANS_JOIN, | 164 | TRANS_JOIN, |
| 165 | TRANS_USERSPACE, | 165 | TRANS_USERSPACE, |
| 166 | TRANS_JOIN_NOLOCK, | ||
| 166 | }; | 167 | }; |
| 167 | 168 | ||
| 168 | static int may_wait_transaction(struct btrfs_root *root, int type) | 169 | static int may_wait_transaction(struct btrfs_root *root, int type) |
| @@ -179,14 +180,14 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
| 179 | { | 180 | { |
| 180 | struct btrfs_trans_handle *h; | 181 | struct btrfs_trans_handle *h; |
| 181 | struct btrfs_transaction *cur_trans; | 182 | struct btrfs_transaction *cur_trans; |
| 182 | int retries = 0; | ||
| 183 | int ret; | 183 | int ret; |
| 184 | again: | 184 | again: |
| 185 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 185 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); |
| 186 | if (!h) | 186 | if (!h) |
| 187 | return ERR_PTR(-ENOMEM); | 187 | return ERR_PTR(-ENOMEM); |
| 188 | 188 | ||
| 189 | mutex_lock(&root->fs_info->trans_mutex); | 189 | if (type != TRANS_JOIN_NOLOCK) |
| 190 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 190 | if (may_wait_transaction(root, type)) | 191 | if (may_wait_transaction(root, type)) |
| 191 | wait_current_trans(root); | 192 | wait_current_trans(root); |
| 192 | 193 | ||
| @@ -195,7 +196,8 @@ again: | |||
| 195 | 196 | ||
| 196 | cur_trans = root->fs_info->running_transaction; | 197 | cur_trans = root->fs_info->running_transaction; |
| 197 | cur_trans->use_count++; | 198 | cur_trans->use_count++; |
| 198 | mutex_unlock(&root->fs_info->trans_mutex); | 199 | if (type != TRANS_JOIN_NOLOCK) |
| 200 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 199 | 201 | ||
| 200 | h->transid = cur_trans->transid; | 202 | h->transid = cur_trans->transid; |
| 201 | h->transaction = cur_trans; | 203 | h->transaction = cur_trans; |
| @@ -212,8 +214,7 @@ again: | |||
| 212 | } | 214 | } |
| 213 | 215 | ||
| 214 | if (num_items > 0) { | 216 | if (num_items > 0) { |
| 215 | ret = btrfs_trans_reserve_metadata(h, root, num_items, | 217 | ret = btrfs_trans_reserve_metadata(h, root, num_items); |
| 216 | &retries); | ||
| 217 | if (ret == -EAGAIN) { | 218 | if (ret == -EAGAIN) { |
| 218 | btrfs_commit_transaction(h, root); | 219 | btrfs_commit_transaction(h, root); |
| 219 | goto again; | 220 | goto again; |
| @@ -224,9 +225,11 @@ again: | |||
| 224 | } | 225 | } |
| 225 | } | 226 | } |
| 226 | 227 | ||
| 227 | mutex_lock(&root->fs_info->trans_mutex); | 228 | if (type != TRANS_JOIN_NOLOCK) |
| 229 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 228 | record_root_in_trans(h, root); | 230 | record_root_in_trans(h, root); |
| 229 | mutex_unlock(&root->fs_info->trans_mutex); | 231 | if (type != TRANS_JOIN_NOLOCK) |
| 232 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 230 | 233 | ||
| 231 | if (!current->journal_info && type != TRANS_USERSPACE) | 234 | if (!current->journal_info && type != TRANS_USERSPACE) |
| 232 | current->journal_info = h; | 235 | current->journal_info = h; |
| @@ -244,6 +247,12 @@ struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root, | |||
| 244 | return start_transaction(root, 0, TRANS_JOIN); | 247 | return start_transaction(root, 0, TRANS_JOIN); |
| 245 | } | 248 | } |
| 246 | 249 | ||
| 250 | struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root, | ||
| 251 | int num_blocks) | ||
| 252 | { | ||
| 253 | return start_transaction(root, 0, TRANS_JOIN_NOLOCK); | ||
| 254 | } | ||
| 255 | |||
| 247 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, | 256 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, |
| 248 | int num_blocks) | 257 | int num_blocks) |
| 249 | { | 258 | { |
| @@ -270,6 +279,58 @@ static noinline int wait_for_commit(struct btrfs_root *root, | |||
| 270 | return 0; | 279 | return 0; |
| 271 | } | 280 | } |
| 272 | 281 | ||
| 282 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | ||
| 283 | { | ||
| 284 | struct btrfs_transaction *cur_trans = NULL, *t; | ||
| 285 | int ret; | ||
| 286 | |||
| 287 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 288 | |||
| 289 | ret = 0; | ||
| 290 | if (transid) { | ||
| 291 | if (transid <= root->fs_info->last_trans_committed) | ||
| 292 | goto out_unlock; | ||
| 293 | |||
| 294 | /* find specified transaction */ | ||
| 295 | list_for_each_entry(t, &root->fs_info->trans_list, list) { | ||
| 296 | if (t->transid == transid) { | ||
| 297 | cur_trans = t; | ||
| 298 | break; | ||
| 299 | } | ||
| 300 | if (t->transid > transid) | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | ret = -EINVAL; | ||
| 304 | if (!cur_trans) | ||
| 305 | goto out_unlock; /* bad transid */ | ||
| 306 | } else { | ||
| 307 | /* find newest transaction that is committing | committed */ | ||
| 308 | list_for_each_entry_reverse(t, &root->fs_info->trans_list, | ||
| 309 | list) { | ||
| 310 | if (t->in_commit) { | ||
| 311 | if (t->commit_done) | ||
| 312 | goto out_unlock; | ||
| 313 | cur_trans = t; | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | if (!cur_trans) | ||
| 318 | goto out_unlock; /* nothing committing|committed */ | ||
| 319 | } | ||
| 320 | |||
| 321 | cur_trans->use_count++; | ||
| 322 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 323 | |||
| 324 | wait_for_commit(root, cur_trans); | ||
| 325 | |||
| 326 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 327 | put_transaction(cur_trans); | ||
| 328 | ret = 0; | ||
| 329 | out_unlock: | ||
| 330 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 331 | return ret; | ||
| 332 | } | ||
| 333 | |||
| 273 | #if 0 | 334 | #if 0 |
| 274 | /* | 335 | /* |
| 275 | * rate limit against the drop_snapshot code. This helps to slow down new | 336 | * rate limit against the drop_snapshot code. This helps to slow down new |
| @@ -348,7 +409,7 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | |||
| 348 | } | 409 | } |
| 349 | 410 | ||
| 350 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | 411 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, |
| 351 | struct btrfs_root *root, int throttle) | 412 | struct btrfs_root *root, int throttle, int lock) |
| 352 | { | 413 | { |
| 353 | struct btrfs_transaction *cur_trans = trans->transaction; | 414 | struct btrfs_transaction *cur_trans = trans->transaction; |
| 354 | struct btrfs_fs_info *info = root->fs_info; | 415 | struct btrfs_fs_info *info = root->fs_info; |
| @@ -376,26 +437,29 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
| 376 | 437 | ||
| 377 | btrfs_trans_release_metadata(trans, root); | 438 | btrfs_trans_release_metadata(trans, root); |
| 378 | 439 | ||
| 379 | if (!root->fs_info->open_ioctl_trans && | 440 | if (lock && !root->fs_info->open_ioctl_trans && |
| 380 | should_end_transaction(trans, root)) | 441 | should_end_transaction(trans, root)) |
| 381 | trans->transaction->blocked = 1; | 442 | trans->transaction->blocked = 1; |
| 382 | 443 | ||
| 383 | if (cur_trans->blocked && !cur_trans->in_commit) { | 444 | if (lock && cur_trans->blocked && !cur_trans->in_commit) { |
| 384 | if (throttle) | 445 | if (throttle) |
| 385 | return btrfs_commit_transaction(trans, root); | 446 | return btrfs_commit_transaction(trans, root); |
| 386 | else | 447 | else |
| 387 | wake_up_process(info->transaction_kthread); | 448 | wake_up_process(info->transaction_kthread); |
| 388 | } | 449 | } |
| 389 | 450 | ||
| 390 | mutex_lock(&info->trans_mutex); | 451 | if (lock) |
| 452 | mutex_lock(&info->trans_mutex); | ||
| 391 | WARN_ON(cur_trans != info->running_transaction); | 453 | WARN_ON(cur_trans != info->running_transaction); |
| 392 | WARN_ON(cur_trans->num_writers < 1); | 454 | WARN_ON(cur_trans->num_writers < 1); |
| 393 | cur_trans->num_writers--; | 455 | cur_trans->num_writers--; |
| 394 | 456 | ||
| 457 | smp_mb(); | ||
| 395 | if (waitqueue_active(&cur_trans->writer_wait)) | 458 | if (waitqueue_active(&cur_trans->writer_wait)) |
| 396 | wake_up(&cur_trans->writer_wait); | 459 | wake_up(&cur_trans->writer_wait); |
| 397 | put_transaction(cur_trans); | 460 | put_transaction(cur_trans); |
| 398 | mutex_unlock(&info->trans_mutex); | 461 | if (lock) |
| 462 | mutex_unlock(&info->trans_mutex); | ||
| 399 | 463 | ||
| 400 | if (current->journal_info == trans) | 464 | if (current->journal_info == trans) |
| 401 | current->journal_info = NULL; | 465 | current->journal_info = NULL; |
| @@ -411,13 +475,19 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
| 411 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | 475 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, |
| 412 | struct btrfs_root *root) | 476 | struct btrfs_root *root) |
| 413 | { | 477 | { |
| 414 | return __btrfs_end_transaction(trans, root, 0); | 478 | return __btrfs_end_transaction(trans, root, 0, 1); |
| 415 | } | 479 | } |
| 416 | 480 | ||
| 417 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | 481 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, |
| 418 | struct btrfs_root *root) | 482 | struct btrfs_root *root) |
| 419 | { | 483 | { |
| 420 | return __btrfs_end_transaction(trans, root, 1); | 484 | return __btrfs_end_transaction(trans, root, 1, 1); |
| 485 | } | ||
| 486 | |||
| 487 | int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans, | ||
| 488 | struct btrfs_root *root) | ||
| 489 | { | ||
| 490 | return __btrfs_end_transaction(trans, root, 0, 0); | ||
| 421 | } | 491 | } |
| 422 | 492 | ||
| 423 | /* | 493 | /* |
| @@ -836,7 +906,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 836 | struct extent_buffer *tmp; | 906 | struct extent_buffer *tmp; |
| 837 | struct extent_buffer *old; | 907 | struct extent_buffer *old; |
| 838 | int ret; | 908 | int ret; |
| 839 | int retries = 0; | ||
| 840 | u64 to_reserve = 0; | 909 | u64 to_reserve = 0; |
| 841 | u64 index = 0; | 910 | u64 index = 0; |
| 842 | u64 objectid; | 911 | u64 objectid; |
| @@ -858,7 +927,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 858 | 927 | ||
| 859 | if (to_reserve > 0) { | 928 | if (to_reserve > 0) { |
| 860 | ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv, | 929 | ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv, |
| 861 | to_reserve, &retries); | 930 | to_reserve); |
| 862 | if (ret) { | 931 | if (ret) { |
| 863 | pending->error = ret; | 932 | pending->error = ret; |
| 864 | goto fail; | 933 | goto fail; |
| @@ -966,6 +1035,8 @@ static void update_super_roots(struct btrfs_root *root) | |||
| 966 | super->root = root_item->bytenr; | 1035 | super->root = root_item->bytenr; |
| 967 | super->generation = root_item->generation; | 1036 | super->generation = root_item->generation; |
| 968 | super->root_level = root_item->level; | 1037 | super->root_level = root_item->level; |
| 1038 | if (super->cache_generation != 0 || btrfs_test_opt(root, SPACE_CACHE)) | ||
| 1039 | super->cache_generation = root_item->generation; | ||
| 969 | } | 1040 | } |
| 970 | 1041 | ||
| 971 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) | 1042 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) |
| @@ -988,11 +1059,127 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info) | |||
| 988 | return ret; | 1059 | return ret; |
| 989 | } | 1060 | } |
| 990 | 1061 | ||
| 1062 | /* | ||
| 1063 | * wait for the current transaction commit to start and block subsequent | ||
| 1064 | * transaction joins | ||
| 1065 | */ | ||
| 1066 | static void wait_current_trans_commit_start(struct btrfs_root *root, | ||
| 1067 | struct btrfs_transaction *trans) | ||
| 1068 | { | ||
| 1069 | DEFINE_WAIT(wait); | ||
| 1070 | |||
| 1071 | if (trans->in_commit) | ||
| 1072 | return; | ||
| 1073 | |||
| 1074 | while (1) { | ||
| 1075 | prepare_to_wait(&root->fs_info->transaction_blocked_wait, &wait, | ||
| 1076 | TASK_UNINTERRUPTIBLE); | ||
| 1077 | if (trans->in_commit) { | ||
| 1078 | finish_wait(&root->fs_info->transaction_blocked_wait, | ||
| 1079 | &wait); | ||
| 1080 | break; | ||
| 1081 | } | ||
| 1082 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 1083 | schedule(); | ||
| 1084 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 1085 | finish_wait(&root->fs_info->transaction_blocked_wait, &wait); | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | /* | ||
| 1090 | * wait for the current transaction to start and then become unblocked. | ||
| 1091 | * caller holds ref. | ||
| 1092 | */ | ||
| 1093 | static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root, | ||
| 1094 | struct btrfs_transaction *trans) | ||
| 1095 | { | ||
| 1096 | DEFINE_WAIT(wait); | ||
| 1097 | |||
| 1098 | if (trans->commit_done || (trans->in_commit && !trans->blocked)) | ||
| 1099 | return; | ||
| 1100 | |||
| 1101 | while (1) { | ||
| 1102 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | ||
| 1103 | TASK_UNINTERRUPTIBLE); | ||
| 1104 | if (trans->commit_done || | ||
| 1105 | (trans->in_commit && !trans->blocked)) { | ||
| 1106 | finish_wait(&root->fs_info->transaction_wait, | ||
| 1107 | &wait); | ||
| 1108 | break; | ||
| 1109 | } | ||
| 1110 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 1111 | schedule(); | ||
| 1112 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 1113 | finish_wait(&root->fs_info->transaction_wait, | ||
| 1114 | &wait); | ||
| 1115 | } | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | /* | ||
| 1119 | * commit transactions asynchronously. once btrfs_commit_transaction_async | ||
| 1120 | * returns, any subsequent transaction will not be allowed to join. | ||
| 1121 | */ | ||
| 1122 | struct btrfs_async_commit { | ||
| 1123 | struct btrfs_trans_handle *newtrans; | ||
| 1124 | struct btrfs_root *root; | ||
| 1125 | struct delayed_work work; | ||
| 1126 | }; | ||
| 1127 | |||
| 1128 | static void do_async_commit(struct work_struct *work) | ||
| 1129 | { | ||
| 1130 | struct btrfs_async_commit *ac = | ||
| 1131 | container_of(work, struct btrfs_async_commit, work.work); | ||
| 1132 | |||
| 1133 | btrfs_commit_transaction(ac->newtrans, ac->root); | ||
| 1134 | kfree(ac); | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | ||
| 1138 | struct btrfs_root *root, | ||
| 1139 | int wait_for_unblock) | ||
| 1140 | { | ||
| 1141 | struct btrfs_async_commit *ac; | ||
| 1142 | struct btrfs_transaction *cur_trans; | ||
| 1143 | |||
| 1144 | ac = kmalloc(sizeof(*ac), GFP_NOFS); | ||
| 1145 | BUG_ON(!ac); | ||
| 1146 | |||
| 1147 | INIT_DELAYED_WORK(&ac->work, do_async_commit); | ||
| 1148 | ac->root = root; | ||
| 1149 | ac->newtrans = btrfs_join_transaction(root, 0); | ||
| 1150 | |||
| 1151 | /* take transaction reference */ | ||
| 1152 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 1153 | cur_trans = trans->transaction; | ||
| 1154 | cur_trans->use_count++; | ||
| 1155 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 1156 | |||
| 1157 | btrfs_end_transaction(trans, root); | ||
| 1158 | schedule_delayed_work(&ac->work, 0); | ||
| 1159 | |||
| 1160 | /* wait for transaction to start and unblock */ | ||
| 1161 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 1162 | if (wait_for_unblock) | ||
| 1163 | wait_current_trans_commit_start_and_unblock(root, cur_trans); | ||
| 1164 | else | ||
| 1165 | wait_current_trans_commit_start(root, cur_trans); | ||
| 1166 | put_transaction(cur_trans); | ||
| 1167 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 1168 | |||
| 1169 | return 0; | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | /* | ||
| 1173 | * btrfs_transaction state sequence: | ||
| 1174 | * in_commit = 0, blocked = 0 (initial) | ||
| 1175 | * in_commit = 1, blocked = 1 | ||
| 1176 | * blocked = 0 | ||
| 1177 | * commit_done = 1 | ||
| 1178 | */ | ||
| 991 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 1179 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
| 992 | struct btrfs_root *root) | 1180 | struct btrfs_root *root) |
| 993 | { | 1181 | { |
| 994 | unsigned long joined = 0; | 1182 | unsigned long joined = 0; |
| 995 | unsigned long timeout = 1; | ||
| 996 | struct btrfs_transaction *cur_trans; | 1183 | struct btrfs_transaction *cur_trans; |
| 997 | struct btrfs_transaction *prev_trans = NULL; | 1184 | struct btrfs_transaction *prev_trans = NULL; |
| 998 | DEFINE_WAIT(wait); | 1185 | DEFINE_WAIT(wait); |
| @@ -1039,6 +1226,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1039 | 1226 | ||
| 1040 | trans->transaction->in_commit = 1; | 1227 | trans->transaction->in_commit = 1; |
| 1041 | trans->transaction->blocked = 1; | 1228 | trans->transaction->blocked = 1; |
| 1229 | wake_up(&root->fs_info->transaction_blocked_wait); | ||
| 1230 | |||
| 1042 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | 1231 | if (cur_trans->list.prev != &root->fs_info->trans_list) { |
| 1043 | prev_trans = list_entry(cur_trans->list.prev, | 1232 | prev_trans = list_entry(cur_trans->list.prev, |
| 1044 | struct btrfs_transaction, list); | 1233 | struct btrfs_transaction, list); |
| @@ -1063,11 +1252,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1063 | snap_pending = 1; | 1252 | snap_pending = 1; |
| 1064 | 1253 | ||
| 1065 | WARN_ON(cur_trans != trans->transaction); | 1254 | WARN_ON(cur_trans != trans->transaction); |
| 1066 | if (cur_trans->num_writers > 1) | ||
| 1067 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
| 1068 | else if (should_grow) | ||
| 1069 | timeout = 1; | ||
| 1070 | |||
| 1071 | mutex_unlock(&root->fs_info->trans_mutex); | 1255 | mutex_unlock(&root->fs_info->trans_mutex); |
| 1072 | 1256 | ||
| 1073 | if (flush_on_commit || snap_pending) { | 1257 | if (flush_on_commit || snap_pending) { |
| @@ -1089,8 +1273,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1089 | TASK_UNINTERRUPTIBLE); | 1273 | TASK_UNINTERRUPTIBLE); |
| 1090 | 1274 | ||
| 1091 | smp_mb(); | 1275 | smp_mb(); |
| 1092 | if (cur_trans->num_writers > 1 || should_grow) | 1276 | if (cur_trans->num_writers > 1) |
| 1093 | schedule_timeout(timeout); | 1277 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); |
| 1278 | else if (should_grow) | ||
| 1279 | schedule_timeout(1); | ||
| 1094 | 1280 | ||
| 1095 | mutex_lock(&root->fs_info->trans_mutex); | 1281 | mutex_lock(&root->fs_info->trans_mutex); |
| 1096 | finish_wait(&cur_trans->writer_wait, &wait); | 1282 | finish_wait(&cur_trans->writer_wait, &wait); |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index e104986d0bfd..f104b57ad4ef 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
| @@ -87,12 +87,17 @@ static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans, | |||
| 87 | 87 | ||
| 88 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | 88 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, |
| 89 | struct btrfs_root *root); | 89 | struct btrfs_root *root); |
| 90 | int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans, | ||
| 91 | struct btrfs_root *root); | ||
| 90 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | 92 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, |
| 91 | int num_items); | 93 | int num_items); |
| 92 | struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root, | 94 | struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root, |
| 93 | int num_blocks); | 95 | int num_blocks); |
| 96 | struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root, | ||
| 97 | int num_blocks); | ||
| 94 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, | 98 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, |
| 95 | int num_blocks); | 99 | int num_blocks); |
| 100 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); | ||
| 96 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | 101 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, |
| 97 | struct btrfs_root *root); | 102 | struct btrfs_root *root); |
| 98 | int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | 103 | int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, |
| @@ -104,6 +109,9 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly); | |||
| 104 | int btrfs_clean_old_snapshots(struct btrfs_root *root); | 109 | int btrfs_clean_old_snapshots(struct btrfs_root *root); |
| 105 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 110 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
| 106 | struct btrfs_root *root); | 111 | struct btrfs_root *root); |
| 112 | int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | ||
| 113 | struct btrfs_root *root, | ||
| 114 | int wait_for_unblock); | ||
| 107 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | 115 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, |
| 108 | struct btrfs_root *root); | 116 | struct btrfs_root *root); |
| 109 | int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | 117 | int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index f7ac8e013ed7..992ab425599d 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c | |||
| @@ -36,7 +36,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
| 36 | int ret = 0; | 36 | int ret = 0; |
| 37 | int wret; | 37 | int wret; |
| 38 | int level; | 38 | int level; |
| 39 | int orig_level; | ||
| 40 | int is_extent = 0; | 39 | int is_extent = 0; |
| 41 | int next_key_ret = 0; | 40 | int next_key_ret = 0; |
| 42 | u64 last_ret = 0; | 41 | u64 last_ret = 0; |
| @@ -64,7 +63,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
| 64 | return -ENOMEM; | 63 | return -ENOMEM; |
| 65 | 64 | ||
| 66 | level = btrfs_header_level(root->node); | 65 | level = btrfs_header_level(root->node); |
| 67 | orig_level = level; | ||
| 68 | 66 | ||
| 69 | if (level == 0) | 67 | if (level == 0) |
| 70 | goto out; | 68 | goto out; |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index fb102a9aee9c..a29f19384a27 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -786,7 +786,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | |||
| 786 | { | 786 | { |
| 787 | struct inode *dir; | 787 | struct inode *dir; |
| 788 | int ret; | 788 | int ret; |
| 789 | struct btrfs_key location; | ||
| 790 | struct btrfs_inode_ref *ref; | 789 | struct btrfs_inode_ref *ref; |
| 791 | struct btrfs_dir_item *di; | 790 | struct btrfs_dir_item *di; |
| 792 | struct inode *inode; | 791 | struct inode *inode; |
| @@ -795,10 +794,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | |||
| 795 | unsigned long ref_ptr; | 794 | unsigned long ref_ptr; |
| 796 | unsigned long ref_end; | 795 | unsigned long ref_end; |
| 797 | 796 | ||
| 798 | location.objectid = key->objectid; | ||
| 799 | location.type = BTRFS_INODE_ITEM_KEY; | ||
| 800 | location.offset = 0; | ||
| 801 | |||
| 802 | /* | 797 | /* |
| 803 | * it is possible that we didn't log all the parent directories | 798 | * it is possible that we didn't log all the parent directories |
| 804 | * for a given inode. If we don't find the dir, just don't | 799 | * for a given inode. If we don't find the dir, just don't |
| @@ -1583,7 +1578,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, | |||
| 1583 | struct btrfs_path *path; | 1578 | struct btrfs_path *path; |
| 1584 | struct btrfs_root *root = wc->replay_dest; | 1579 | struct btrfs_root *root = wc->replay_dest; |
| 1585 | struct btrfs_key key; | 1580 | struct btrfs_key key; |
| 1586 | u32 item_size; | ||
| 1587 | int level; | 1581 | int level; |
| 1588 | int i; | 1582 | int i; |
| 1589 | int ret; | 1583 | int ret; |
| @@ -1601,7 +1595,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, | |||
| 1601 | nritems = btrfs_header_nritems(eb); | 1595 | nritems = btrfs_header_nritems(eb); |
| 1602 | for (i = 0; i < nritems; i++) { | 1596 | for (i = 0; i < nritems; i++) { |
| 1603 | btrfs_item_key_to_cpu(eb, &key, i); | 1597 | btrfs_item_key_to_cpu(eb, &key, i); |
| 1604 | item_size = btrfs_item_size_nr(eb, i); | ||
| 1605 | 1598 | ||
| 1606 | /* inode keys are done during the first stage */ | 1599 | /* inode keys are done during the first stage */ |
| 1607 | if (key.type == BTRFS_INODE_ITEM_KEY && | 1600 | if (key.type == BTRFS_INODE_ITEM_KEY && |
| @@ -1668,7 +1661,6 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, | |||
| 1668 | struct walk_control *wc) | 1661 | struct walk_control *wc) |
| 1669 | { | 1662 | { |
| 1670 | u64 root_owner; | 1663 | u64 root_owner; |
| 1671 | u64 root_gen; | ||
| 1672 | u64 bytenr; | 1664 | u64 bytenr; |
| 1673 | u64 ptr_gen; | 1665 | u64 ptr_gen; |
| 1674 | struct extent_buffer *next; | 1666 | struct extent_buffer *next; |
| @@ -1698,7 +1690,6 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, | |||
| 1698 | 1690 | ||
| 1699 | parent = path->nodes[*level]; | 1691 | parent = path->nodes[*level]; |
| 1700 | root_owner = btrfs_header_owner(parent); | 1692 | root_owner = btrfs_header_owner(parent); |
| 1701 | root_gen = btrfs_header_generation(parent); | ||
| 1702 | 1693 | ||
| 1703 | next = btrfs_find_create_tree_block(root, bytenr, blocksize); | 1694 | next = btrfs_find_create_tree_block(root, bytenr, blocksize); |
| 1704 | 1695 | ||
| @@ -1749,7 +1740,6 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, | |||
| 1749 | struct walk_control *wc) | 1740 | struct walk_control *wc) |
| 1750 | { | 1741 | { |
| 1751 | u64 root_owner; | 1742 | u64 root_owner; |
| 1752 | u64 root_gen; | ||
| 1753 | int i; | 1743 | int i; |
| 1754 | int slot; | 1744 | int slot; |
| 1755 | int ret; | 1745 | int ret; |
| @@ -1757,8 +1747,6 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, | |||
| 1757 | for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { | 1747 | for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { |
| 1758 | slot = path->slots[i]; | 1748 | slot = path->slots[i]; |
| 1759 | if (slot + 1 < btrfs_header_nritems(path->nodes[i])) { | 1749 | if (slot + 1 < btrfs_header_nritems(path->nodes[i])) { |
| 1760 | struct extent_buffer *node; | ||
| 1761 | node = path->nodes[i]; | ||
| 1762 | path->slots[i]++; | 1750 | path->slots[i]++; |
| 1763 | *level = i; | 1751 | *level = i; |
| 1764 | WARN_ON(*level == 0); | 1752 | WARN_ON(*level == 0); |
| @@ -1771,7 +1759,6 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, | |||
| 1771 | parent = path->nodes[*level + 1]; | 1759 | parent = path->nodes[*level + 1]; |
| 1772 | 1760 | ||
| 1773 | root_owner = btrfs_header_owner(parent); | 1761 | root_owner = btrfs_header_owner(parent); |
| 1774 | root_gen = btrfs_header_generation(parent); | ||
| 1775 | wc->process_func(root, path->nodes[*level], wc, | 1762 | wc->process_func(root, path->nodes[*level], wc, |
| 1776 | btrfs_header_generation(path->nodes[*level])); | 1763 | btrfs_header_generation(path->nodes[*level])); |
| 1777 | if (wc->free) { | 1764 | if (wc->free) { |
| @@ -2273,7 +2260,7 @@ fail: | |||
| 2273 | } | 2260 | } |
| 2274 | btrfs_end_log_trans(root); | 2261 | btrfs_end_log_trans(root); |
| 2275 | 2262 | ||
| 2276 | return 0; | 2263 | return err; |
| 2277 | } | 2264 | } |
| 2278 | 2265 | ||
| 2279 | /* see comments for btrfs_del_dir_entries_in_log */ | 2266 | /* see comments for btrfs_del_dir_entries_in_log */ |
| @@ -2729,7 +2716,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
| 2729 | struct btrfs_key max_key; | 2716 | struct btrfs_key max_key; |
| 2730 | struct btrfs_root *log = root->log_root; | 2717 | struct btrfs_root *log = root->log_root; |
| 2731 | struct extent_buffer *src = NULL; | 2718 | struct extent_buffer *src = NULL; |
| 2732 | u32 size; | ||
| 2733 | int err = 0; | 2719 | int err = 0; |
| 2734 | int ret; | 2720 | int ret; |
| 2735 | int nritems; | 2721 | int nritems; |
| @@ -2793,7 +2779,6 @@ again: | |||
| 2793 | break; | 2779 | break; |
| 2794 | 2780 | ||
| 2795 | src = path->nodes[0]; | 2781 | src = path->nodes[0]; |
| 2796 | size = btrfs_item_size_nr(src, path->slots[0]); | ||
| 2797 | if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) { | 2782 | if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) { |
| 2798 | ins_nr++; | 2783 | ins_nr++; |
| 2799 | goto next_slot; | 2784 | goto next_slot; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e25e46a8b4e2..cc04dc1445d6 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -1898,7 +1898,6 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
| 1898 | u64 size_to_free; | 1898 | u64 size_to_free; |
| 1899 | struct btrfs_path *path; | 1899 | struct btrfs_path *path; |
| 1900 | struct btrfs_key key; | 1900 | struct btrfs_key key; |
| 1901 | struct btrfs_chunk *chunk; | ||
| 1902 | struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root; | 1901 | struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root; |
| 1903 | struct btrfs_trans_handle *trans; | 1902 | struct btrfs_trans_handle *trans; |
| 1904 | struct btrfs_key found_key; | 1903 | struct btrfs_key found_key; |
| @@ -1962,9 +1961,6 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
| 1962 | if (found_key.objectid != key.objectid) | 1961 | if (found_key.objectid != key.objectid) |
| 1963 | break; | 1962 | break; |
| 1964 | 1963 | ||
| 1965 | chunk = btrfs_item_ptr(path->nodes[0], | ||
| 1966 | path->slots[0], | ||
| 1967 | struct btrfs_chunk); | ||
| 1968 | /* chunk zero is special */ | 1964 | /* chunk zero is special */ |
| 1969 | if (found_key.offset == 0) | 1965 | if (found_key.offset == 0) |
| 1970 | break; | 1966 | break; |
| @@ -3031,8 +3027,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, | |||
| 3031 | } | 3027 | } |
| 3032 | bio->bi_sector = multi->stripes[dev_nr].physical >> 9; | 3028 | bio->bi_sector = multi->stripes[dev_nr].physical >> 9; |
| 3033 | dev = multi->stripes[dev_nr].dev; | 3029 | dev = multi->stripes[dev_nr].dev; |
| 3034 | BUG_ON(rw == WRITE && !dev->writeable); | 3030 | if (dev && dev->bdev && (rw != WRITE || dev->writeable)) { |
| 3035 | if (dev && dev->bdev) { | ||
| 3036 | bio->bi_bdev = dev->bdev; | 3031 | bio->bi_bdev = dev->bdev; |
| 3037 | if (async_submit) | 3032 | if (async_submit) |
| 3038 | schedule_bio(root, dev, rw, bio); | 3033 | schedule_bio(root, dev, rw, bio); |
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 88ecbb215878..698fdd2c739c 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c | |||
| @@ -178,7 +178,6 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
| 178 | struct inode *inode = dentry->d_inode; | 178 | struct inode *inode = dentry->d_inode; |
| 179 | struct btrfs_root *root = BTRFS_I(inode)->root; | 179 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 180 | struct btrfs_path *path; | 180 | struct btrfs_path *path; |
| 181 | struct btrfs_item *item; | ||
| 182 | struct extent_buffer *leaf; | 181 | struct extent_buffer *leaf; |
| 183 | struct btrfs_dir_item *di; | 182 | struct btrfs_dir_item *di; |
| 184 | int ret = 0, slot, advance; | 183 | int ret = 0, slot, advance; |
| @@ -234,7 +233,6 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
| 234 | } | 233 | } |
| 235 | advance = 1; | 234 | advance = 1; |
| 236 | 235 | ||
| 237 | item = btrfs_item_nr(leaf, slot); | ||
| 238 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | 236 | btrfs_item_key_to_cpu(leaf, &found_key, slot); |
| 239 | 237 | ||
| 240 | /* check to make sure this item is what we want */ | 238 | /* check to make sure this item is what we want */ |
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c index 3e2b90eaa239..b9cd5445f71c 100644 --- a/fs/btrfs/zlib.c +++ b/fs/btrfs/zlib.c | |||
| @@ -199,8 +199,6 @@ int btrfs_zlib_compress_pages(struct address_space *mapping, | |||
| 199 | int nr_pages = 0; | 199 | int nr_pages = 0; |
| 200 | struct page *in_page = NULL; | 200 | struct page *in_page = NULL; |
| 201 | struct page *out_page = NULL; | 201 | struct page *out_page = NULL; |
| 202 | int out_written = 0; | ||
| 203 | int in_read = 0; | ||
| 204 | unsigned long bytes_left; | 202 | unsigned long bytes_left; |
| 205 | 203 | ||
| 206 | *out_pages = 0; | 204 | *out_pages = 0; |
| @@ -233,9 +231,6 @@ int btrfs_zlib_compress_pages(struct address_space *mapping, | |||
| 233 | workspace->def_strm.avail_out = PAGE_CACHE_SIZE; | 231 | workspace->def_strm.avail_out = PAGE_CACHE_SIZE; |
| 234 | workspace->def_strm.avail_in = min(len, PAGE_CACHE_SIZE); | 232 | workspace->def_strm.avail_in = min(len, PAGE_CACHE_SIZE); |
| 235 | 233 | ||
| 236 | out_written = 0; | ||
| 237 | in_read = 0; | ||
| 238 | |||
| 239 | while (workspace->def_strm.total_in < len) { | 234 | while (workspace->def_strm.total_in < len) { |
| 240 | ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH); | 235 | ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH); |
| 241 | if (ret != Z_OK) { | 236 | if (ret != Z_OK) { |
diff --git a/fs/compat.c b/fs/compat.c index ff66c0d7583d..c580c322fa6b 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -49,6 +49,7 @@ | |||
| 49 | #include <linux/eventpoll.h> | 49 | #include <linux/eventpoll.h> |
| 50 | #include <linux/fs_struct.h> | 50 | #include <linux/fs_struct.h> |
| 51 | #include <linux/slab.h> | 51 | #include <linux/slab.h> |
| 52 | #include <linux/pagemap.h> | ||
| 52 | 53 | ||
| 53 | #include <asm/uaccess.h> | 54 | #include <asm/uaccess.h> |
| 54 | #include <asm/mmu_context.h> | 55 | #include <asm/mmu_context.h> |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index aed881a76b22..3d06ccc953aa 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -707,6 +707,17 @@ get_next_work_item(struct backing_dev_info *bdi) | |||
| 707 | return work; | 707 | return work; |
| 708 | } | 708 | } |
| 709 | 709 | ||
| 710 | /* | ||
| 711 | * Add in the number of potentially dirty inodes, because each inode | ||
| 712 | * write can dirty pagecache in the underlying blockdev. | ||
| 713 | */ | ||
| 714 | static unsigned long get_nr_dirty_pages(void) | ||
| 715 | { | ||
| 716 | return global_page_state(NR_FILE_DIRTY) + | ||
| 717 | global_page_state(NR_UNSTABLE_NFS) + | ||
| 718 | get_nr_dirty_inodes(); | ||
| 719 | } | ||
| 720 | |||
| 710 | static long wb_check_old_data_flush(struct bdi_writeback *wb) | 721 | static long wb_check_old_data_flush(struct bdi_writeback *wb) |
| 711 | { | 722 | { |
| 712 | unsigned long expired; | 723 | unsigned long expired; |
| @@ -724,13 +735,7 @@ static long wb_check_old_data_flush(struct bdi_writeback *wb) | |||
| 724 | return 0; | 735 | return 0; |
| 725 | 736 | ||
| 726 | wb->last_old_flush = jiffies; | 737 | wb->last_old_flush = jiffies; |
| 727 | /* | 738 | nr_pages = get_nr_dirty_pages(); |
| 728 | * Add in the number of potentially dirty inodes, because each inode | ||
| 729 | * write can dirty pagecache in the underlying blockdev. | ||
| 730 | */ | ||
| 731 | nr_pages = global_page_state(NR_FILE_DIRTY) + | ||
| 732 | global_page_state(NR_UNSTABLE_NFS) + | ||
| 733 | get_nr_dirty_inodes(); | ||
| 734 | 739 | ||
| 735 | if (nr_pages) { | 740 | if (nr_pages) { |
| 736 | struct wb_writeback_work work = { | 741 | struct wb_writeback_work work = { |
| @@ -1076,32 +1081,42 @@ static void wait_sb_inodes(struct super_block *sb) | |||
| 1076 | } | 1081 | } |
| 1077 | 1082 | ||
| 1078 | /** | 1083 | /** |
| 1079 | * writeback_inodes_sb - writeback dirty inodes from given super_block | 1084 | * writeback_inodes_sb_nr - writeback dirty inodes from given super_block |
| 1080 | * @sb: the superblock | 1085 | * @sb: the superblock |
| 1086 | * @nr: the number of pages to write | ||
| 1081 | * | 1087 | * |
| 1082 | * Start writeback on some inodes on this super_block. No guarantees are made | 1088 | * Start writeback on some inodes on this super_block. No guarantees are made |
| 1083 | * on how many (if any) will be written, and this function does not wait | 1089 | * on how many (if any) will be written, and this function does not wait |
| 1084 | * for IO completion of submitted IO. The number of pages submitted is | 1090 | * for IO completion of submitted IO. |
| 1085 | * returned. | ||
| 1086 | */ | 1091 | */ |
| 1087 | void writeback_inodes_sb(struct super_block *sb) | 1092 | void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr) |
| 1088 | { | 1093 | { |
| 1089 | unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); | ||
| 1090 | unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); | ||
| 1091 | DECLARE_COMPLETION_ONSTACK(done); | 1094 | DECLARE_COMPLETION_ONSTACK(done); |
| 1092 | struct wb_writeback_work work = { | 1095 | struct wb_writeback_work work = { |
| 1093 | .sb = sb, | 1096 | .sb = sb, |
| 1094 | .sync_mode = WB_SYNC_NONE, | 1097 | .sync_mode = WB_SYNC_NONE, |
| 1095 | .done = &done, | 1098 | .done = &done, |
| 1099 | .nr_pages = nr, | ||
| 1096 | }; | 1100 | }; |
| 1097 | 1101 | ||
| 1098 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 1102 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
| 1099 | |||
| 1100 | work.nr_pages = nr_dirty + nr_unstable + get_nr_dirty_inodes(); | ||
| 1101 | |||
| 1102 | bdi_queue_work(sb->s_bdi, &work); | 1103 | bdi_queue_work(sb->s_bdi, &work); |
| 1103 | wait_for_completion(&done); | 1104 | wait_for_completion(&done); |
| 1104 | } | 1105 | } |
| 1106 | EXPORT_SYMBOL(writeback_inodes_sb_nr); | ||
| 1107 | |||
| 1108 | /** | ||
| 1109 | * writeback_inodes_sb - writeback dirty inodes from given super_block | ||
| 1110 | * @sb: the superblock | ||
| 1111 | * | ||
| 1112 | * Start writeback on some inodes on this super_block. No guarantees are made | ||
| 1113 | * on how many (if any) will be written, and this function does not wait | ||
| 1114 | * for IO completion of submitted IO. | ||
| 1115 | */ | ||
| 1116 | void writeback_inodes_sb(struct super_block *sb) | ||
| 1117 | { | ||
| 1118 | return writeback_inodes_sb_nr(sb, get_nr_dirty_pages()); | ||
| 1119 | } | ||
| 1105 | EXPORT_SYMBOL(writeback_inodes_sb); | 1120 | EXPORT_SYMBOL(writeback_inodes_sb); |
| 1106 | 1121 | ||
| 1107 | /** | 1122 | /** |
| @@ -1124,6 +1139,27 @@ int writeback_inodes_sb_if_idle(struct super_block *sb) | |||
| 1124 | EXPORT_SYMBOL(writeback_inodes_sb_if_idle); | 1139 | EXPORT_SYMBOL(writeback_inodes_sb_if_idle); |
| 1125 | 1140 | ||
| 1126 | /** | 1141 | /** |
| 1142 | * writeback_inodes_sb_if_idle - start writeback if none underway | ||
| 1143 | * @sb: the superblock | ||
| 1144 | * @nr: the number of pages to write | ||
| 1145 | * | ||
| 1146 | * Invoke writeback_inodes_sb if no writeback is currently underway. | ||
| 1147 | * Returns 1 if writeback was started, 0 if not. | ||
| 1148 | */ | ||
| 1149 | int writeback_inodes_sb_nr_if_idle(struct super_block *sb, | ||
| 1150 | unsigned long nr) | ||
| 1151 | { | ||
| 1152 | if (!writeback_in_progress(sb->s_bdi)) { | ||
| 1153 | down_read(&sb->s_umount); | ||
| 1154 | writeback_inodes_sb_nr(sb, nr); | ||
| 1155 | up_read(&sb->s_umount); | ||
| 1156 | return 1; | ||
| 1157 | } else | ||
| 1158 | return 0; | ||
| 1159 | } | ||
| 1160 | EXPORT_SYMBOL(writeback_inodes_sb_nr_if_idle); | ||
| 1161 | |||
| 1162 | /** | ||
| 1127 | * sync_inodes_sb - sync sb inode pages | 1163 | * sync_inodes_sb - sync sb inode pages |
| 1128 | * @sb: the superblock | 1164 | * @sb: the superblock |
| 1129 | * | 1165 | * |
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index a906f538d11c..85c6be2db02f 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
| @@ -23,7 +23,7 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, | |||
| 23 | static inline struct jffs2_inode_cache * | 23 | static inline struct jffs2_inode_cache * |
| 24 | first_inode_chain(int *i, struct jffs2_sb_info *c) | 24 | first_inode_chain(int *i, struct jffs2_sb_info *c) |
| 25 | { | 25 | { |
| 26 | for (; *i < INOCACHE_HASHSIZE; (*i)++) { | 26 | for (; *i < c->inocache_hashsize; (*i)++) { |
| 27 | if (c->inocache_list[*i]) | 27 | if (c->inocache_list[*i]) |
| 28 | return c->inocache_list[*i]; | 28 | return c->inocache_list[*i]; |
| 29 | } | 29 | } |
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 617a1e5694c1..de4247021d25 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c | |||
| @@ -103,7 +103,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
| 103 | spin_unlock(&jffs2_compressor_list_lock); | 103 | spin_unlock(&jffs2_compressor_list_lock); |
| 104 | *datalen = orig_slen; | 104 | *datalen = orig_slen; |
| 105 | *cdatalen = orig_dlen; | 105 | *cdatalen = orig_dlen; |
| 106 | compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); | 106 | compr_ret = this->compress(data_in, output_buf, datalen, cdatalen); |
| 107 | spin_lock(&jffs2_compressor_list_lock); | 107 | spin_lock(&jffs2_compressor_list_lock); |
| 108 | this->usecount--; | 108 | this->usecount--; |
| 109 | if (!compr_ret) { | 109 | if (!compr_ret) { |
| @@ -152,7 +152,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
| 152 | spin_unlock(&jffs2_compressor_list_lock); | 152 | spin_unlock(&jffs2_compressor_list_lock); |
| 153 | *datalen = orig_slen; | 153 | *datalen = orig_slen; |
| 154 | *cdatalen = orig_dlen; | 154 | *cdatalen = orig_dlen; |
| 155 | compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); | 155 | compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen); |
| 156 | spin_lock(&jffs2_compressor_list_lock); | 156 | spin_lock(&jffs2_compressor_list_lock); |
| 157 | this->usecount--; | 157 | this->usecount--; |
| 158 | if (!compr_ret) { | 158 | if (!compr_ret) { |
| @@ -220,7 +220,7 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
| 220 | if (comprtype == this->compr) { | 220 | if (comprtype == this->compr) { |
| 221 | this->usecount++; | 221 | this->usecount++; |
| 222 | spin_unlock(&jffs2_compressor_list_lock); | 222 | spin_unlock(&jffs2_compressor_list_lock); |
| 223 | ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); | 223 | ret = this->decompress(cdata_in, data_out, cdatalen, datalen); |
| 224 | spin_lock(&jffs2_compressor_list_lock); | 224 | spin_lock(&jffs2_compressor_list_lock); |
| 225 | if (ret) { | 225 | if (ret) { |
| 226 | printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); | 226 | printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); |
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index e471a9106fd9..13bb7597ab39 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h | |||
| @@ -49,9 +49,9 @@ struct jffs2_compressor { | |||
| 49 | char *name; | 49 | char *name; |
| 50 | char compr; /* JFFS2_COMPR_XXX */ | 50 | char compr; /* JFFS2_COMPR_XXX */ |
| 51 | int (*compress)(unsigned char *data_in, unsigned char *cpage_out, | 51 | int (*compress)(unsigned char *data_in, unsigned char *cpage_out, |
| 52 | uint32_t *srclen, uint32_t *destlen, void *model); | 52 | uint32_t *srclen, uint32_t *destlen); |
| 53 | int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, | 53 | int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, |
| 54 | uint32_t cdatalen, uint32_t datalen, void *model); | 54 | uint32_t cdatalen, uint32_t datalen); |
| 55 | int usecount; | 55 | int usecount; |
| 56 | int disabled; /* if set the compressor won't compress */ | 56 | int disabled; /* if set the compressor won't compress */ |
| 57 | unsigned char *compr_buf; /* used by size compr. mode */ | 57 | unsigned char *compr_buf; /* used by size compr. mode */ |
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c index ed25ae7c98eb..af186ee674d8 100644 --- a/fs/jffs2/compr_lzo.c +++ b/fs/jffs2/compr_lzo.c | |||
| @@ -42,7 +42,7 @@ static int __init alloc_workspace(void) | |||
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, | 44 | static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, |
| 45 | uint32_t *sourcelen, uint32_t *dstlen, void *model) | 45 | uint32_t *sourcelen, uint32_t *dstlen) |
| 46 | { | 46 | { |
| 47 | size_t compress_size; | 47 | size_t compress_size; |
| 48 | int ret; | 48 | int ret; |
| @@ -67,7 +67,7 @@ static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, | |||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, | 69 | static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, |
| 70 | uint32_t srclen, uint32_t destlen, void *model) | 70 | uint32_t srclen, uint32_t destlen) |
| 71 | { | 71 | { |
| 72 | size_t dl = destlen; | 72 | size_t dl = destlen; |
| 73 | int ret; | 73 | int ret; |
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 9696ad9ef5f7..16a5047903a6 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c | |||
| @@ -31,8 +31,7 @@ | |||
| 31 | /* _compress returns the compressed size, -1 if bigger */ | 31 | /* _compress returns the compressed size, -1 if bigger */ |
| 32 | static int jffs2_rtime_compress(unsigned char *data_in, | 32 | static int jffs2_rtime_compress(unsigned char *data_in, |
| 33 | unsigned char *cpage_out, | 33 | unsigned char *cpage_out, |
| 34 | uint32_t *sourcelen, uint32_t *dstlen, | 34 | uint32_t *sourcelen, uint32_t *dstlen) |
| 35 | void *model) | ||
| 36 | { | 35 | { |
| 37 | short positions[256]; | 36 | short positions[256]; |
| 38 | int outpos = 0; | 37 | int outpos = 0; |
| @@ -73,8 +72,7 @@ static int jffs2_rtime_compress(unsigned char *data_in, | |||
| 73 | 72 | ||
| 74 | static int jffs2_rtime_decompress(unsigned char *data_in, | 73 | static int jffs2_rtime_decompress(unsigned char *data_in, |
| 75 | unsigned char *cpage_out, | 74 | unsigned char *cpage_out, |
| 76 | uint32_t srclen, uint32_t destlen, | 75 | uint32_t srclen, uint32_t destlen) |
| 77 | void *model) | ||
| 78 | { | 76 | { |
| 79 | short positions[256]; | 77 | short positions[256]; |
| 80 | int outpos = 0; | 78 | int outpos = 0; |
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index a12b4f763373..9e7cec808c4c 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c | |||
| @@ -298,7 +298,7 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, | |||
| 298 | #if 0 | 298 | #if 0 |
| 299 | /* _compress returns the compressed size, -1 if bigger */ | 299 | /* _compress returns the compressed size, -1 if bigger */ |
| 300 | int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, | 300 | int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, |
| 301 | uint32_t *sourcelen, uint32_t *dstlen, void *model) | 301 | uint32_t *sourcelen, uint32_t *dstlen) |
| 302 | { | 302 | { |
| 303 | return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, | 303 | return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, |
| 304 | cpage_out, sourcelen, dstlen); | 304 | cpage_out, sourcelen, dstlen); |
| @@ -306,8 +306,7 @@ int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, | |||
| 306 | #endif | 306 | #endif |
| 307 | static int jffs2_dynrubin_compress(unsigned char *data_in, | 307 | static int jffs2_dynrubin_compress(unsigned char *data_in, |
| 308 | unsigned char *cpage_out, | 308 | unsigned char *cpage_out, |
| 309 | uint32_t *sourcelen, uint32_t *dstlen, | 309 | uint32_t *sourcelen, uint32_t *dstlen) |
| 310 | void *model) | ||
| 311 | { | 310 | { |
| 312 | int bits[8]; | 311 | int bits[8]; |
| 313 | unsigned char histo[256]; | 312 | unsigned char histo[256]; |
| @@ -387,8 +386,7 @@ static void rubin_do_decompress(int bit_divider, int *bits, | |||
| 387 | 386 | ||
| 388 | static int jffs2_rubinmips_decompress(unsigned char *data_in, | 387 | static int jffs2_rubinmips_decompress(unsigned char *data_in, |
| 389 | unsigned char *cpage_out, | 388 | unsigned char *cpage_out, |
| 390 | uint32_t sourcelen, uint32_t dstlen, | 389 | uint32_t sourcelen, uint32_t dstlen) |
| 391 | void *model) | ||
| 392 | { | 390 | { |
| 393 | rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, | 391 | rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, |
| 394 | cpage_out, sourcelen, dstlen); | 392 | cpage_out, sourcelen, dstlen); |
| @@ -397,8 +395,7 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in, | |||
| 397 | 395 | ||
| 398 | static int jffs2_dynrubin_decompress(unsigned char *data_in, | 396 | static int jffs2_dynrubin_decompress(unsigned char *data_in, |
| 399 | unsigned char *cpage_out, | 397 | unsigned char *cpage_out, |
| 400 | uint32_t sourcelen, uint32_t dstlen, | 398 | uint32_t sourcelen, uint32_t dstlen) |
| 401 | void *model) | ||
| 402 | { | 399 | { |
| 403 | int bits[8]; | 400 | int bits[8]; |
| 404 | int c; | 401 | int c; |
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 97fc45de6f81..fd05a0b9431d 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c | |||
| @@ -68,8 +68,7 @@ static void free_workspaces(void) | |||
| 68 | 68 | ||
| 69 | static int jffs2_zlib_compress(unsigned char *data_in, | 69 | static int jffs2_zlib_compress(unsigned char *data_in, |
| 70 | unsigned char *cpage_out, | 70 | unsigned char *cpage_out, |
| 71 | uint32_t *sourcelen, uint32_t *dstlen, | 71 | uint32_t *sourcelen, uint32_t *dstlen) |
| 72 | void *model) | ||
| 73 | { | 72 | { |
| 74 | int ret; | 73 | int ret; |
| 75 | 74 | ||
| @@ -136,8 +135,7 @@ static int jffs2_zlib_compress(unsigned char *data_in, | |||
| 136 | 135 | ||
| 137 | static int jffs2_zlib_decompress(unsigned char *data_in, | 136 | static int jffs2_zlib_decompress(unsigned char *data_in, |
| 138 | unsigned char *cpage_out, | 137 | unsigned char *cpage_out, |
| 139 | uint32_t srclen, uint32_t destlen, | 138 | uint32_t srclen, uint32_t destlen) |
| 140 | void *model) | ||
| 141 | { | 139 | { |
| 142 | int ret; | 140 | int ret; |
| 143 | int wbits = MAX_WBITS; | 141 | int wbits = MAX_WBITS; |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 79121aa5858b..92978658ed18 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
| @@ -367,7 +367,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | /* We use f->target field to store the target path. */ | 369 | /* We use f->target field to store the target path. */ |
| 370 | f->target = kmalloc(targetlen + 1, GFP_KERNEL); | 370 | f->target = kmemdup(target, targetlen + 1, GFP_KERNEL); |
| 371 | if (!f->target) { | 371 | if (!f->target) { |
| 372 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); | 372 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); |
| 373 | mutex_unlock(&f->sem); | 373 | mutex_unlock(&f->sem); |
| @@ -376,7 +376,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 376 | goto fail; | 376 | goto fail; |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | memcpy(f->target, target, targetlen + 1); | ||
| 380 | D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target)); | 379 | D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target)); |
| 381 | 380 | ||
| 382 | /* No data here. Only a metadata node, which will be | 381 | /* No data here. Only a metadata node, which will be |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index abac961f617b..e513f1913c15 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
| @@ -151,7 +151,7 @@ int jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | /* Be nice */ | 153 | /* Be nice */ |
| 154 | yield(); | 154 | cond_resched(); |
| 155 | mutex_lock(&c->erase_free_sem); | 155 | mutex_lock(&c->erase_free_sem); |
| 156 | spin_lock(&c->erase_completion_lock); | 156 | spin_lock(&c->erase_completion_lock); |
| 157 | } | 157 | } |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index d9beb06e6fca..e896e67767eb 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
| @@ -474,6 +474,25 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i | |||
| 474 | return inode; | 474 | return inode; |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | static int calculate_inocache_hashsize(uint32_t flash_size) | ||
| 478 | { | ||
| 479 | /* | ||
| 480 | * Pick a inocache hash size based on the size of the medium. | ||
| 481 | * Count how many megabytes we're dealing with, apply a hashsize twice | ||
| 482 | * that size, but rounding down to the usual big powers of 2. And keep | ||
| 483 | * to sensible bounds. | ||
| 484 | */ | ||
| 485 | |||
| 486 | int size_mb = flash_size / 1024 / 1024; | ||
| 487 | int hashsize = (size_mb * 2) & ~0x3f; | ||
| 488 | |||
| 489 | if (hashsize < INOCACHE_HASHSIZE_MIN) | ||
| 490 | return INOCACHE_HASHSIZE_MIN; | ||
| 491 | if (hashsize > INOCACHE_HASHSIZE_MAX) | ||
| 492 | return INOCACHE_HASHSIZE_MAX; | ||
| 493 | |||
| 494 | return hashsize; | ||
| 495 | } | ||
| 477 | 496 | ||
| 478 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | 497 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) |
| 479 | { | 498 | { |
| @@ -520,7 +539,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
| 520 | if (ret) | 539 | if (ret) |
| 521 | return ret; | 540 | return ret; |
| 522 | 541 | ||
| 523 | c->inocache_list = kcalloc(INOCACHE_HASHSIZE, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); | 542 | c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); |
| 543 | c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); | ||
| 524 | if (!c->inocache_list) { | 544 | if (!c->inocache_list) { |
| 525 | ret = -ENOMEM; | 545 | ret = -ENOMEM; |
| 526 | goto out_wbuf; | 546 | goto out_wbuf; |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 846a79452497..31dce611337c 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
| @@ -219,13 +219,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
| 219 | if (!list_empty(&c->erase_complete_list) || | 219 | if (!list_empty(&c->erase_complete_list) || |
| 220 | !list_empty(&c->erase_pending_list)) { | 220 | !list_empty(&c->erase_pending_list)) { |
| 221 | spin_unlock(&c->erase_completion_lock); | 221 | spin_unlock(&c->erase_completion_lock); |
| 222 | mutex_unlock(&c->alloc_sem); | ||
| 222 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() erasing pending blocks\n")); | 223 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() erasing pending blocks\n")); |
| 223 | if (jffs2_erase_pending_blocks(c, 1)) { | 224 | if (jffs2_erase_pending_blocks(c, 1)) |
| 224 | mutex_unlock(&c->alloc_sem); | ||
| 225 | return 0; | 225 | return 0; |
| 226 | } | 226 | |
| 227 | D1(printk(KERN_DEBUG "No progress from erasing blocks; doing GC anyway\n")); | 227 | D1(printk(KERN_DEBUG "No progress from erasing blocks; doing GC anyway\n")); |
| 228 | spin_lock(&c->erase_completion_lock); | 228 | spin_lock(&c->erase_completion_lock); |
| 229 | mutex_lock(&c->alloc_sem); | ||
| 229 | } | 230 | } |
| 230 | 231 | ||
| 231 | /* First, work out which block we're garbage-collecting */ | 232 | /* First, work out which block we're garbage-collecting */ |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 6784bc89add1..f864005de64c 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
| @@ -100,6 +100,7 @@ struct jffs2_sb_info { | |||
| 100 | wait_queue_head_t erase_wait; /* For waiting for erases to complete */ | 100 | wait_queue_head_t erase_wait; /* For waiting for erases to complete */ |
| 101 | 101 | ||
| 102 | wait_queue_head_t inocache_wq; | 102 | wait_queue_head_t inocache_wq; |
| 103 | int inocache_hashsize; | ||
| 103 | struct jffs2_inode_cache **inocache_list; | 104 | struct jffs2_inode_cache **inocache_list; |
| 104 | spinlock_t inocache_lock; | 105 | spinlock_t inocache_lock; |
| 105 | 106 | ||
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index af02bd138469..5e03233c2363 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
| @@ -420,7 +420,7 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t | |||
| 420 | { | 420 | { |
| 421 | struct jffs2_inode_cache *ret; | 421 | struct jffs2_inode_cache *ret; |
| 422 | 422 | ||
| 423 | ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; | 423 | ret = c->inocache_list[ino % c->inocache_hashsize]; |
| 424 | while (ret && ret->ino < ino) { | 424 | while (ret && ret->ino < ino) { |
| 425 | ret = ret->next; | 425 | ret = ret->next; |
| 426 | } | 426 | } |
| @@ -441,7 +441,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new | |||
| 441 | 441 | ||
| 442 | dbg_inocache("add %p (ino #%u)\n", new, new->ino); | 442 | dbg_inocache("add %p (ino #%u)\n", new, new->ino); |
| 443 | 443 | ||
| 444 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; | 444 | prev = &c->inocache_list[new->ino % c->inocache_hashsize]; |
| 445 | 445 | ||
| 446 | while ((*prev) && (*prev)->ino < new->ino) { | 446 | while ((*prev) && (*prev)->ino < new->ino) { |
| 447 | prev = &(*prev)->next; | 447 | prev = &(*prev)->next; |
| @@ -462,7 +462,7 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) | |||
| 462 | dbg_inocache("del %p (ino #%u)\n", old, old->ino); | 462 | dbg_inocache("del %p (ino #%u)\n", old, old->ino); |
| 463 | spin_lock(&c->inocache_lock); | 463 | spin_lock(&c->inocache_lock); |
| 464 | 464 | ||
| 465 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; | 465 | prev = &c->inocache_list[old->ino % c->inocache_hashsize]; |
| 466 | 466 | ||
| 467 | while ((*prev) && (*prev)->ino < old->ino) { | 467 | while ((*prev) && (*prev)->ino < old->ino) { |
| 468 | prev = &(*prev)->next; | 468 | prev = &(*prev)->next; |
| @@ -487,7 +487,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) | |||
| 487 | int i; | 487 | int i; |
| 488 | struct jffs2_inode_cache *this, *next; | 488 | struct jffs2_inode_cache *this, *next; |
| 489 | 489 | ||
| 490 | for (i=0; i<INOCACHE_HASHSIZE; i++) { | 490 | for (i=0; i < c->inocache_hashsize; i++) { |
| 491 | this = c->inocache_list[i]; | 491 | this = c->inocache_list[i]; |
| 492 | while (this) { | 492 | while (this) { |
| 493 | next = this->next; | 493 | next = this->next; |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 523a91691052..5a53d9bdb2b5 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
| @@ -199,7 +199,8 @@ struct jffs2_inode_cache { | |||
| 199 | #define RAWNODE_CLASS_XATTR_DATUM 1 | 199 | #define RAWNODE_CLASS_XATTR_DATUM 1 |
| 200 | #define RAWNODE_CLASS_XATTR_REF 2 | 200 | #define RAWNODE_CLASS_XATTR_REF 2 |
| 201 | 201 | ||
| 202 | #define INOCACHE_HASHSIZE 128 | 202 | #define INOCACHE_HASHSIZE_MIN 128 |
| 203 | #define INOCACHE_HASHSIZE_MAX 1024 | ||
| 203 | 204 | ||
| 204 | #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size) | 205 | #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size) |
| 205 | 206 | ||
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 46f870d1cc36..b632dddcb482 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | #include "summary.h" | 20 | #include "summary.h" |
| 21 | #include "debug.h" | 21 | #include "debug.h" |
| 22 | 22 | ||
| 23 | #define DEFAULT_EMPTY_SCAN_SIZE 1024 | 23 | #define DEFAULT_EMPTY_SCAN_SIZE 256 |
| 24 | 24 | ||
| 25 | #define noisy_printk(noise, args...) do { \ | 25 | #define noisy_printk(noise, args...) do { \ |
| 26 | if (*(noise)) { \ | 26 | if (*(noise)) { \ |
| @@ -435,7 +435,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
| 435 | unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { | 435 | unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { |
| 436 | struct jffs2_unknown_node *node; | 436 | struct jffs2_unknown_node *node; |
| 437 | struct jffs2_unknown_node crcnode; | 437 | struct jffs2_unknown_node crcnode; |
| 438 | uint32_t ofs, prevofs; | 438 | uint32_t ofs, prevofs, max_ofs; |
| 439 | uint32_t hdr_crc, buf_ofs, buf_len; | 439 | uint32_t hdr_crc, buf_ofs, buf_len; |
| 440 | int err; | 440 | int err; |
| 441 | int noise = 0; | 441 | int noise = 0; |
| @@ -550,12 +550,12 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
| 550 | 550 | ||
| 551 | /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ | 551 | /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ |
| 552 | ofs = 0; | 552 | ofs = 0; |
| 553 | 553 | max_ofs = EMPTY_SCAN_SIZE(c->sector_size); | |
| 554 | /* Scan only 4KiB of 0xFF before declaring it's empty */ | 554 | /* Scan only EMPTY_SCAN_SIZE of 0xFF before declaring it's empty */ |
| 555 | while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) | 555 | while(ofs < max_ofs && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) |
| 556 | ofs += 4; | 556 | ofs += 4; |
| 557 | 557 | ||
| 558 | if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { | 558 | if (ofs == max_ofs) { |
| 559 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | 559 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
| 560 | if (jffs2_cleanmarker_oob(c)) { | 560 | if (jffs2_cleanmarker_oob(c)) { |
| 561 | /* scan oob, take care of cleanmarker */ | 561 | /* scan oob, take care of cleanmarker */ |
diff --git a/include/asm-generic/audit_change_attr.h b/include/asm-generic/audit_change_attr.h index 50764550a60c..bcbab3e4a3be 100644 --- a/include/asm-generic/audit_change_attr.h +++ b/include/asm-generic/audit_change_attr.h | |||
| @@ -20,3 +20,7 @@ __NR_chown32, | |||
| 20 | __NR_fchown32, | 20 | __NR_fchown32, |
| 21 | __NR_lchown32, | 21 | __NR_lchown32, |
| 22 | #endif | 22 | #endif |
| 23 | __NR_link, | ||
| 24 | #ifdef __NR_linkat | ||
| 25 | __NR_linkat, | ||
| 26 | #endif | ||
diff --git a/include/linux/audit.h b/include/linux/audit.h index e24afabc548f..8b5c0620abf9 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
| @@ -102,6 +102,7 @@ | |||
| 102 | #define AUDIT_EOE 1320 /* End of multi-record event */ | 102 | #define AUDIT_EOE 1320 /* End of multi-record event */ |
| 103 | #define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ | 103 | #define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ |
| 104 | #define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */ | 104 | #define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */ |
| 105 | #define AUDIT_MMAP 1323 /* Record showing descriptor and flags in mmap */ | ||
| 105 | 106 | ||
| 106 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | 107 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ |
| 107 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | 108 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ |
| @@ -478,6 +479,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, | |||
| 478 | const struct cred *new, | 479 | const struct cred *new, |
| 479 | const struct cred *old); | 480 | const struct cred *old); |
| 480 | extern void __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old); | 481 | extern void __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old); |
| 482 | extern void __audit_mmap_fd(int fd, int flags); | ||
| 481 | 483 | ||
| 482 | static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) | 484 | static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) |
| 483 | { | 485 | { |
| @@ -531,6 +533,12 @@ static inline void audit_log_capset(pid_t pid, const struct cred *new, | |||
| 531 | __audit_log_capset(pid, new, old); | 533 | __audit_log_capset(pid, new, old); |
| 532 | } | 534 | } |
| 533 | 535 | ||
| 536 | static inline void audit_mmap_fd(int fd, int flags) | ||
| 537 | { | ||
| 538 | if (unlikely(!audit_dummy_context())) | ||
| 539 | __audit_mmap_fd(fd, flags); | ||
| 540 | } | ||
| 541 | |||
| 534 | extern int audit_n_rules; | 542 | extern int audit_n_rules; |
| 535 | extern int audit_signals; | 543 | extern int audit_signals; |
| 536 | #else | 544 | #else |
| @@ -564,6 +572,7 @@ extern int audit_signals; | |||
| 564 | #define audit_mq_getsetattr(d,s) ((void)0) | 572 | #define audit_mq_getsetattr(d,s) ((void)0) |
| 565 | #define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; }) | 573 | #define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; }) |
| 566 | #define audit_log_capset(pid, ncr, ocr) ((void)0) | 574 | #define audit_log_capset(pid, ncr, ocr) ((void)0) |
| 575 | #define audit_mmap_fd(fd, flags) ((void)0) | ||
| 567 | #define audit_ptrace(t) ((void)0) | 576 | #define audit_ptrace(t) ((void)0) |
| 568 | #define audit_n_rules 0 | 577 | #define audit_n_rules 0 |
| 569 | #define audit_signals 0 | 578 | #define audit_signals 0 |
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index b67cb180e6e9..7880f18e4b86 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #ifndef _LINUX_JUMP_LABEL_H | 1 | #ifndef _LINUX_JUMP_LABEL_H |
| 2 | #define _LINUX_JUMP_LABEL_H | 2 | #define _LINUX_JUMP_LABEL_H |
| 3 | 3 | ||
| 4 | #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_HAVE_ARCH_JUMP_LABEL) | 4 | #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) |
| 5 | # include <asm/jump_label.h> | 5 | # include <asm/jump_label.h> |
| 6 | # define HAVE_JUMP_LABEL | 6 | # define HAVE_JUMP_LABEL |
| 7 | #endif | 7 | #endif |
| @@ -18,6 +18,8 @@ struct module; | |||
| 18 | extern struct jump_entry __start___jump_table[]; | 18 | extern struct jump_entry __start___jump_table[]; |
| 19 | extern struct jump_entry __stop___jump_table[]; | 19 | extern struct jump_entry __stop___jump_table[]; |
| 20 | 20 | ||
| 21 | extern void jump_label_lock(void); | ||
| 22 | extern void jump_label_unlock(void); | ||
| 21 | extern void arch_jump_label_transform(struct jump_entry *entry, | 23 | extern void arch_jump_label_transform(struct jump_entry *entry, |
| 22 | enum jump_label_type type); | 24 | enum jump_label_type type); |
| 23 | extern void arch_jump_label_text_poke_early(jump_label_t addr); | 25 | extern void arch_jump_label_text_poke_early(jump_label_t addr); |
| @@ -59,6 +61,9 @@ static inline int jump_label_text_reserved(void *start, void *end) | |||
| 59 | return 0; | 61 | return 0; |
| 60 | } | 62 | } |
| 61 | 63 | ||
| 64 | static inline void jump_label_lock(void) {} | ||
| 65 | static inline void jump_label_unlock(void) {} | ||
| 66 | |||
| 62 | #endif | 67 | #endif |
| 63 | 68 | ||
| 64 | #define COND_STMT(key, stmt) \ | 69 | #define COND_STMT(key, stmt) \ |
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 7fa20beb2ab9..57cc0e63714f 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h | |||
| @@ -84,7 +84,7 @@ struct nand_bbt_descr { | |||
| 84 | #define NAND_BBT_PERCHIP 0x00000080 | 84 | #define NAND_BBT_PERCHIP 0x00000080 |
| 85 | /* bbt has a version counter at offset veroffs */ | 85 | /* bbt has a version counter at offset veroffs */ |
| 86 | #define NAND_BBT_VERSION 0x00000100 | 86 | #define NAND_BBT_VERSION 0x00000100 |
| 87 | /* Create a bbt if none axists */ | 87 | /* Create a bbt if none exists */ |
| 88 | #define NAND_BBT_CREATE 0x00000200 | 88 | #define NAND_BBT_CREATE 0x00000200 |
| 89 | /* Search good / bad pattern through all pages of a block */ | 89 | /* Search good / bad pattern through all pages of a block */ |
| 90 | #define NAND_BBT_SCANALLPAGES 0x00000400 | 90 | #define NAND_BBT_SCANALLPAGES 0x00000400 |
| @@ -102,6 +102,8 @@ struct nand_bbt_descr { | |||
| 102 | #define NAND_BBT_SCANBYTE1AND6 0x00100000 | 102 | #define NAND_BBT_SCANBYTE1AND6 0x00100000 |
| 103 | /* The nand_bbt_descr was created dynamicaly and must be freed */ | 103 | /* The nand_bbt_descr was created dynamicaly and must be freed */ |
| 104 | #define NAND_BBT_DYNAMICSTRUCT 0x00200000 | 104 | #define NAND_BBT_DYNAMICSTRUCT 0x00200000 |
| 105 | /* The bad block table does not OOB for marker */ | ||
| 106 | #define NAND_BBT_NO_OOB 0x00400000 | ||
| 105 | 107 | ||
| 106 | /* The maximum number of blocks to scan for a bbt */ | 108 | /* The maximum number of blocks to scan for a bbt */ |
| 107 | #define NAND_BBT_SCAN_MAXBLOCKS 4 | 109 | #define NAND_BBT_SCAN_MAXBLOCKS 4 |
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index d2118b0eac9a..4dd0c2cd7659 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h | |||
| @@ -289,6 +289,7 @@ struct cfi_private { | |||
| 289 | must be of the same type. */ | 289 | must be of the same type. */ |
| 290 | int mfr, id; | 290 | int mfr, id; |
| 291 | int numchips; | 291 | int numchips; |
| 292 | map_word sector_erase_cmd; | ||
| 292 | unsigned long chipshift; /* Because they're of the same type */ | 293 | unsigned long chipshift; /* Because they're of the same type */ |
| 293 | const char *im_name; /* inter_module name for cmdset_setup */ | 294 | const char *im_name; /* inter_module name for cmdset_setup */ |
| 294 | struct flchip chips[0]; /* per-chip data structure for each chip */ | 295 | struct flchip chips[0]; /* per-chip data structure for each chip */ |
diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h new file mode 100644 index 000000000000..5d2556700ec2 --- /dev/null +++ b/include/linux/mtd/fsmc.h | |||
| @@ -0,0 +1,181 @@ | |||
| 1 | /* | ||
| 2 | * incude/mtd/fsmc.h | ||
| 3 | * | ||
| 4 | * ST Microelectronics | ||
| 5 | * Flexible Static Memory Controller (FSMC) | ||
| 6 | * platform data interface and header file | ||
| 7 | * | ||
| 8 | * Copyright © 2010 ST Microelectronics | ||
| 9 | * Vipin Kumar <vipin.kumar@st.com> | ||
| 10 | * | ||
| 11 | * This file is licensed under the terms of the GNU General Public | ||
| 12 | * License version 2. This program is licensed "as is" without any | ||
| 13 | * warranty of any kind, whether express or implied. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef __MTD_FSMC_H | ||
| 17 | #define __MTD_FSMC_H | ||
| 18 | |||
| 19 | #include <linux/platform_device.h> | ||
| 20 | #include <linux/mtd/physmap.h> | ||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/mtd/partitions.h> | ||
| 23 | #include <asm/param.h> | ||
| 24 | |||
| 25 | #define FSMC_NAND_BW8 1 | ||
| 26 | #define FSMC_NAND_BW16 2 | ||
| 27 | |||
| 28 | /* | ||
| 29 | * The placement of the Command Latch Enable (CLE) and | ||
| 30 | * Address Latch Enable (ALE) is twised around in the | ||
| 31 | * SPEAR310 implementation. | ||
| 32 | */ | ||
| 33 | #if defined(CONFIG_MACH_SPEAR310) | ||
| 34 | #define PLAT_NAND_CLE (1 << 17) | ||
| 35 | #define PLAT_NAND_ALE (1 << 16) | ||
| 36 | #else | ||
| 37 | #define PLAT_NAND_CLE (1 << 16) | ||
| 38 | #define PLAT_NAND_ALE (1 << 17) | ||
| 39 | #endif | ||
| 40 | |||
| 41 | #define FSMC_MAX_NOR_BANKS 4 | ||
| 42 | #define FSMC_MAX_NAND_BANKS 4 | ||
| 43 | |||
| 44 | #define FSMC_FLASH_WIDTH8 1 | ||
| 45 | #define FSMC_FLASH_WIDTH16 2 | ||
| 46 | |||
| 47 | struct fsmc_nor_bank_regs { | ||
| 48 | uint32_t ctrl; | ||
| 49 | uint32_t ctrl_tim; | ||
| 50 | }; | ||
| 51 | |||
| 52 | /* ctrl register definitions */ | ||
| 53 | #define BANK_ENABLE (1 << 0) | ||
| 54 | #define MUXED (1 << 1) | ||
| 55 | #define NOR_DEV (2 << 2) | ||
| 56 | #define WIDTH_8 (0 << 4) | ||
| 57 | #define WIDTH_16 (1 << 4) | ||
| 58 | #define RSTPWRDWN (1 << 6) | ||
| 59 | #define WPROT (1 << 7) | ||
| 60 | #define WRT_ENABLE (1 << 12) | ||
| 61 | #define WAIT_ENB (1 << 13) | ||
| 62 | |||
| 63 | /* ctrl_tim register definitions */ | ||
| 64 | |||
| 65 | struct fsms_nand_bank_regs { | ||
| 66 | uint32_t pc; | ||
| 67 | uint32_t sts; | ||
| 68 | uint32_t comm; | ||
| 69 | uint32_t attrib; | ||
| 70 | uint32_t ioata; | ||
| 71 | uint32_t ecc1; | ||
| 72 | uint32_t ecc2; | ||
| 73 | uint32_t ecc3; | ||
| 74 | }; | ||
| 75 | |||
| 76 | #define FSMC_NOR_REG_SIZE 0x40 | ||
| 77 | |||
| 78 | struct fsmc_regs { | ||
| 79 | struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS]; | ||
| 80 | uint8_t reserved_1[0x40 - 0x20]; | ||
| 81 | struct fsms_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS]; | ||
| 82 | uint8_t reserved_2[0xfe0 - 0xc0]; | ||
| 83 | uint32_t peripid0; /* 0xfe0 */ | ||
| 84 | uint32_t peripid1; /* 0xfe4 */ | ||
| 85 | uint32_t peripid2; /* 0xfe8 */ | ||
| 86 | uint32_t peripid3; /* 0xfec */ | ||
| 87 | uint32_t pcellid0; /* 0xff0 */ | ||
| 88 | uint32_t pcellid1; /* 0xff4 */ | ||
| 89 | uint32_t pcellid2; /* 0xff8 */ | ||
| 90 | uint32_t pcellid3; /* 0xffc */ | ||
| 91 | }; | ||
| 92 | |||
| 93 | #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ) | ||
| 94 | |||
| 95 | /* pc register definitions */ | ||
| 96 | #define FSMC_RESET (1 << 0) | ||
| 97 | #define FSMC_WAITON (1 << 1) | ||
| 98 | #define FSMC_ENABLE (1 << 2) | ||
| 99 | #define FSMC_DEVTYPE_NAND (1 << 3) | ||
| 100 | #define FSMC_DEVWID_8 (0 << 4) | ||
| 101 | #define FSMC_DEVWID_16 (1 << 4) | ||
| 102 | #define FSMC_ECCEN (1 << 6) | ||
| 103 | #define FSMC_ECCPLEN_512 (0 << 7) | ||
| 104 | #define FSMC_ECCPLEN_256 (1 << 7) | ||
| 105 | #define FSMC_TCLR_1 (1 << 9) | ||
| 106 | #define FSMC_TAR_1 (1 << 13) | ||
| 107 | |||
| 108 | /* sts register definitions */ | ||
| 109 | #define FSMC_CODE_RDY (1 << 15) | ||
| 110 | |||
| 111 | /* comm register definitions */ | ||
| 112 | #define FSMC_TSET_0 (0 << 0) | ||
| 113 | #define FSMC_TWAIT_6 (6 << 8) | ||
| 114 | #define FSMC_THOLD_4 (4 << 16) | ||
| 115 | #define FSMC_THIZ_1 (1 << 24) | ||
| 116 | |||
| 117 | /* peripid2 register definitions */ | ||
| 118 | #define FSMC_REVISION_MSK (0xf) | ||
| 119 | #define FSMC_REVISION_SHFT (0x4) | ||
| 120 | |||
| 121 | #define FSMC_VER1 1 | ||
| 122 | #define FSMC_VER2 2 | ||
| 123 | #define FSMC_VER3 3 | ||
| 124 | #define FSMC_VER4 4 | ||
| 125 | #define FSMC_VER5 5 | ||
| 126 | #define FSMC_VER6 6 | ||
| 127 | #define FSMC_VER7 7 | ||
| 128 | #define FSMC_VER8 8 | ||
| 129 | |||
| 130 | static inline uint32_t get_fsmc_version(struct fsmc_regs *regs) | ||
| 131 | { | ||
| 132 | return (readl(®s->peripid2) >> FSMC_REVISION_SHFT) & | ||
| 133 | FSMC_REVISION_MSK; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * There are 13 bytes of ecc for every 512 byte block in FSMC version 8 | ||
| 138 | * and it has to be read consecutively and immediately after the 512 | ||
| 139 | * byte data block for hardware to generate the error bit offsets | ||
| 140 | * Managing the ecc bytes in the following way is easier. This way is | ||
| 141 | * similar to oobfree structure maintained already in u-boot nand driver | ||
| 142 | */ | ||
| 143 | #define MAX_ECCPLACE_ENTRIES 32 | ||
| 144 | |||
| 145 | struct fsmc_nand_eccplace { | ||
| 146 | uint8_t offset; | ||
| 147 | uint8_t length; | ||
| 148 | }; | ||
| 149 | |||
| 150 | struct fsmc_eccplace { | ||
| 151 | struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES]; | ||
| 152 | }; | ||
| 153 | |||
| 154 | /** | ||
| 155 | * fsmc_nand_platform_data - platform specific NAND controller config | ||
| 156 | * @partitions: partition table for the platform, use a default fallback | ||
| 157 | * if this is NULL | ||
| 158 | * @nr_partitions: the number of partitions in the previous entry | ||
| 159 | * @options: different options for the driver | ||
| 160 | * @width: bus width | ||
| 161 | * @bank: default bank | ||
| 162 | * @select_bank: callback to select a certain bank, this is | ||
| 163 | * platform-specific. If the controller only supports one bank | ||
| 164 | * this may be set to NULL | ||
| 165 | */ | ||
| 166 | struct fsmc_nand_platform_data { | ||
| 167 | struct mtd_partition *partitions; | ||
| 168 | unsigned int nr_partitions; | ||
| 169 | unsigned int options; | ||
| 170 | unsigned int width; | ||
| 171 | unsigned int bank; | ||
| 172 | void (*select_bank)(uint32_t bank, uint32_t busw); | ||
| 173 | }; | ||
| 174 | |||
| 175 | extern int __init fsmc_nor_init(struct platform_device *pdev, | ||
| 176 | unsigned long base, uint32_t bank, uint32_t width); | ||
| 177 | extern void __init fsmc_init_board_info(struct platform_device *pdev, | ||
| 178 | struct mtd_partition *partitions, unsigned int nr_partitions, | ||
| 179 | unsigned int width); | ||
| 180 | |||
| 181 | #endif /* __MTD_FSMC_H */ | ||
diff --git a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h index 64ee53ce95a9..02cd5f9b79b8 100644 --- a/include/linux/mtd/inftl.h +++ b/include/linux/mtd/inftl.h | |||
| @@ -37,14 +37,14 @@ struct INFTLrecord { | |||
| 37 | __u16 firstEUN; | 37 | __u16 firstEUN; |
| 38 | __u16 lastEUN; | 38 | __u16 lastEUN; |
| 39 | __u16 numfreeEUNs; | 39 | __u16 numfreeEUNs; |
| 40 | __u16 LastFreeEUN; /* To speed up finding a free EUN */ | 40 | __u16 LastFreeEUN; /* To speed up finding a free EUN */ |
| 41 | int head,sect,cyl; | 41 | int head,sect,cyl; |
| 42 | __u16 *PUtable; /* Physical Unit Table */ | 42 | __u16 *PUtable; /* Physical Unit Table */ |
| 43 | __u16 *VUtable; /* Virtual Unit Table */ | 43 | __u16 *VUtable; /* Virtual Unit Table */ |
| 44 | unsigned int nb_blocks; /* number of physical blocks */ | 44 | unsigned int nb_blocks; /* number of physical blocks */ |
| 45 | unsigned int nb_boot_blocks; /* number of blocks used by the bios */ | 45 | unsigned int nb_boot_blocks; /* number of blocks used by the bios */ |
| 46 | struct erase_info instr; | 46 | struct erase_info instr; |
| 47 | struct nand_ecclayout oobinfo; | 47 | struct nand_ecclayout oobinfo; |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | int INFTL_mount(struct INFTLrecord *s); | 50 | int INFTL_mount(struct INFTLrecord *s); |
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 8485e42a9b09..fe8d77ebec13 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
| @@ -110,6 +110,21 @@ struct mtd_oob_ops { | |||
| 110 | uint8_t *oobbuf; | 110 | uint8_t *oobbuf; |
| 111 | }; | 111 | }; |
| 112 | 112 | ||
| 113 | #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 | ||
| 114 | #define MTD_MAX_ECCPOS_ENTRIES_LARGE 448 | ||
| 115 | /* | ||
| 116 | * Internal ECC layout control structure. For historical reasons, there is a | ||
| 117 | * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained | ||
| 118 | * for export to user-space via the ECCGETLAYOUT ioctl. | ||
| 119 | * nand_ecclayout should be expandable in the future simply by the above macros. | ||
| 120 | */ | ||
| 121 | struct nand_ecclayout { | ||
| 122 | __u32 eccbytes; | ||
| 123 | __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE]; | ||
| 124 | __u32 oobavail; | ||
| 125 | struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE]; | ||
| 126 | }; | ||
| 127 | |||
| 113 | struct mtd_info { | 128 | struct mtd_info { |
| 114 | u_char type; | 129 | u_char type; |
| 115 | uint32_t flags; | 130 | uint32_t flags; |
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 102e12c58cb3..63e17d01fde9 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
| @@ -27,15 +27,17 @@ | |||
| 27 | struct mtd_info; | 27 | struct mtd_info; |
| 28 | struct nand_flash_dev; | 28 | struct nand_flash_dev; |
| 29 | /* Scan and identify a NAND device */ | 29 | /* Scan and identify a NAND device */ |
| 30 | extern int nand_scan (struct mtd_info *mtd, int max_chips); | 30 | extern int nand_scan(struct mtd_info *mtd, int max_chips); |
| 31 | /* Separate phases of nand_scan(), allowing board driver to intervene | 31 | /* |
| 32 | * and override command or ECC setup according to flash type */ | 32 | * Separate phases of nand_scan(), allowing board driver to intervene |
| 33 | * and override command or ECC setup according to flash type. | ||
| 34 | */ | ||
| 33 | extern int nand_scan_ident(struct mtd_info *mtd, int max_chips, | 35 | extern int nand_scan_ident(struct mtd_info *mtd, int max_chips, |
| 34 | struct nand_flash_dev *table); | 36 | struct nand_flash_dev *table); |
| 35 | extern int nand_scan_tail(struct mtd_info *mtd); | 37 | extern int nand_scan_tail(struct mtd_info *mtd); |
| 36 | 38 | ||
| 37 | /* Free resources held by the NAND device */ | 39 | /* Free resources held by the NAND device */ |
| 38 | extern void nand_release (struct mtd_info *mtd); | 40 | extern void nand_release(struct mtd_info *mtd); |
| 39 | 41 | ||
| 40 | /* Internal helper for board drivers which need to override command function */ | 42 | /* Internal helper for board drivers which need to override command function */ |
| 41 | extern void nand_wait_ready(struct mtd_info *mtd); | 43 | extern void nand_wait_ready(struct mtd_info *mtd); |
| @@ -49,12 +51,13 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); | |||
| 49 | /* The maximum number of NAND chips in an array */ | 51 | /* The maximum number of NAND chips in an array */ |
| 50 | #define NAND_MAX_CHIPS 8 | 52 | #define NAND_MAX_CHIPS 8 |
| 51 | 53 | ||
| 52 | /* This constant declares the max. oobsize / page, which | 54 | /* |
| 55 | * This constant declares the max. oobsize / page, which | ||
| 53 | * is supported now. If you add a chip with bigger oobsize/page | 56 | * is supported now. If you add a chip with bigger oobsize/page |
| 54 | * adjust this accordingly. | 57 | * adjust this accordingly. |
| 55 | */ | 58 | */ |
| 56 | #define NAND_MAX_OOBSIZE 256 | 59 | #define NAND_MAX_OOBSIZE 576 |
| 57 | #define NAND_MAX_PAGESIZE 4096 | 60 | #define NAND_MAX_PAGESIZE 8192 |
| 58 | 61 | ||
| 59 | /* | 62 | /* |
| 60 | * Constants for hardware specific CLE/ALE/NCE function | 63 | * Constants for hardware specific CLE/ALE/NCE function |
| @@ -88,6 +91,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); | |||
| 88 | #define NAND_CMD_RNDIN 0x85 | 91 | #define NAND_CMD_RNDIN 0x85 |
| 89 | #define NAND_CMD_READID 0x90 | 92 | #define NAND_CMD_READID 0x90 |
| 90 | #define NAND_CMD_ERASE2 0xd0 | 93 | #define NAND_CMD_ERASE2 0xd0 |
| 94 | #define NAND_CMD_PARAM 0xec | ||
| 91 | #define NAND_CMD_RESET 0xff | 95 | #define NAND_CMD_RESET 0xff |
| 92 | 96 | ||
| 93 | #define NAND_CMD_LOCK 0x2a | 97 | #define NAND_CMD_LOCK 0x2a |
| @@ -152,9 +156,10 @@ typedef enum { | |||
| 152 | #define NAND_GET_DEVICE 0x80 | 156 | #define NAND_GET_DEVICE 0x80 |
| 153 | 157 | ||
| 154 | 158 | ||
| 155 | /* Option constants for bizarre disfunctionality and real | 159 | /* |
| 156 | * features | 160 | * Option constants for bizarre disfunctionality and real |
| 157 | */ | 161 | * features. |
| 162 | */ | ||
| 158 | /* Chip can not auto increment pages */ | 163 | /* Chip can not auto increment pages */ |
| 159 | #define NAND_NO_AUTOINCR 0x00000001 | 164 | #define NAND_NO_AUTOINCR 0x00000001 |
| 160 | /* Buswitdh is 16 bit */ | 165 | /* Buswitdh is 16 bit */ |
| @@ -165,19 +170,27 @@ typedef enum { | |||
| 165 | #define NAND_CACHEPRG 0x00000008 | 170 | #define NAND_CACHEPRG 0x00000008 |
| 166 | /* Chip has copy back function */ | 171 | /* Chip has copy back function */ |
| 167 | #define NAND_COPYBACK 0x00000010 | 172 | #define NAND_COPYBACK 0x00000010 |
| 168 | /* AND Chip which has 4 banks and a confusing page / block | 173 | /* |
| 169 | * assignment. See Renesas datasheet for further information */ | 174 | * AND Chip which has 4 banks and a confusing page / block |
| 175 | * assignment. See Renesas datasheet for further information. | ||
| 176 | */ | ||
| 170 | #define NAND_IS_AND 0x00000020 | 177 | #define NAND_IS_AND 0x00000020 |
| 171 | /* Chip has a array of 4 pages which can be read without | 178 | /* |
| 172 | * additional ready /busy waits */ | 179 | * Chip has a array of 4 pages which can be read without |
| 180 | * additional ready /busy waits. | ||
| 181 | */ | ||
| 173 | #define NAND_4PAGE_ARRAY 0x00000040 | 182 | #define NAND_4PAGE_ARRAY 0x00000040 |
| 174 | /* Chip requires that BBT is periodically rewritten to prevent | 183 | /* |
| 184 | * Chip requires that BBT is periodically rewritten to prevent | ||
| 175 | * bits from adjacent blocks from 'leaking' in altering data. | 185 | * bits from adjacent blocks from 'leaking' in altering data. |
| 176 | * This happens with the Renesas AG-AND chips, possibly others. */ | 186 | * This happens with the Renesas AG-AND chips, possibly others. |
| 187 | */ | ||
| 177 | #define BBT_AUTO_REFRESH 0x00000080 | 188 | #define BBT_AUTO_REFRESH 0x00000080 |
| 178 | /* Chip does not require ready check on read. True | 189 | /* |
| 190 | * Chip does not require ready check on read. True | ||
| 179 | * for all large page devices, as they do not support | 191 | * for all large page devices, as they do not support |
| 180 | * autoincrement.*/ | 192 | * autoincrement. |
| 193 | */ | ||
| 181 | #define NAND_NO_READRDY 0x00000100 | 194 | #define NAND_NO_READRDY 0x00000100 |
| 182 | /* Chip does not allow subpage writes */ | 195 | /* Chip does not allow subpage writes */ |
| 183 | #define NAND_NO_SUBPAGE_WRITE 0x00000200 | 196 | #define NAND_NO_SUBPAGE_WRITE 0x00000200 |
| @@ -205,16 +218,27 @@ typedef enum { | |||
| 205 | #define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) | 218 | #define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) |
| 206 | 219 | ||
| 207 | /* Non chip related options */ | 220 | /* Non chip related options */ |
| 208 | /* Use a flash based bad block table. This option is passed to the | 221 | /* |
| 209 | * default bad block table function. */ | 222 | * Use a flash based bad block table. OOB identifier is saved in OOB area. |
| 223 | * This option is passed to the default bad block table function. | ||
| 224 | */ | ||
| 210 | #define NAND_USE_FLASH_BBT 0x00010000 | 225 | #define NAND_USE_FLASH_BBT 0x00010000 |
| 211 | /* This option skips the bbt scan during initialization. */ | 226 | /* This option skips the bbt scan during initialization. */ |
| 212 | #define NAND_SKIP_BBTSCAN 0x00020000 | 227 | #define NAND_SKIP_BBTSCAN 0x00020000 |
| 213 | /* This option is defined if the board driver allocates its own buffers | 228 | /* |
| 214 | (e.g. because it needs them DMA-coherent */ | 229 | * This option is defined if the board driver allocates its own buffers |
| 230 | * (e.g. because it needs them DMA-coherent). | ||
| 231 | */ | ||
| 215 | #define NAND_OWN_BUFFERS 0x00040000 | 232 | #define NAND_OWN_BUFFERS 0x00040000 |
| 216 | /* Chip may not exist, so silence any errors in scan */ | 233 | /* Chip may not exist, so silence any errors in scan */ |
| 217 | #define NAND_SCAN_SILENT_NODEV 0x00080000 | 234 | #define NAND_SCAN_SILENT_NODEV 0x00080000 |
| 235 | /* | ||
| 236 | * If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch | ||
| 237 | * the OOB area. | ||
| 238 | */ | ||
| 239 | #define NAND_USE_FLASH_BBT_NO_OOB 0x00100000 | ||
| 240 | /* Create an empty BBT with no vendor information if the BBT is available */ | ||
| 241 | #define NAND_CREATE_EMPTY_BBT 0x00200000 | ||
| 218 | 242 | ||
| 219 | /* Options set by nand scan */ | 243 | /* Options set by nand scan */ |
| 220 | /* Nand scan has allocated controller struct */ | 244 | /* Nand scan has allocated controller struct */ |
| @@ -227,15 +251,80 @@ typedef enum { | |||
| 227 | /* Keep gcc happy */ | 251 | /* Keep gcc happy */ |
| 228 | struct nand_chip; | 252 | struct nand_chip; |
| 229 | 253 | ||
| 254 | struct nand_onfi_params { | ||
| 255 | /* rev info and features block */ | ||
| 256 | /* 'O' 'N' 'F' 'I' */ | ||
| 257 | u8 sig[4]; | ||
| 258 | __le16 revision; | ||
| 259 | __le16 features; | ||
| 260 | __le16 opt_cmd; | ||
| 261 | u8 reserved[22]; | ||
| 262 | |||
| 263 | /* manufacturer information block */ | ||
| 264 | char manufacturer[12]; | ||
| 265 | char model[20]; | ||
| 266 | u8 jedec_id; | ||
| 267 | __le16 date_code; | ||
| 268 | u8 reserved2[13]; | ||
| 269 | |||
| 270 | /* memory organization block */ | ||
| 271 | __le32 byte_per_page; | ||
| 272 | __le16 spare_bytes_per_page; | ||
| 273 | __le32 data_bytes_per_ppage; | ||
| 274 | __le16 spare_bytes_per_ppage; | ||
| 275 | __le32 pages_per_block; | ||
| 276 | __le32 blocks_per_lun; | ||
| 277 | u8 lun_count; | ||
| 278 | u8 addr_cycles; | ||
| 279 | u8 bits_per_cell; | ||
| 280 | __le16 bb_per_lun; | ||
| 281 | __le16 block_endurance; | ||
| 282 | u8 guaranteed_good_blocks; | ||
| 283 | __le16 guaranteed_block_endurance; | ||
| 284 | u8 programs_per_page; | ||
| 285 | u8 ppage_attr; | ||
| 286 | u8 ecc_bits; | ||
| 287 | u8 interleaved_bits; | ||
| 288 | u8 interleaved_ops; | ||
| 289 | u8 reserved3[13]; | ||
| 290 | |||
| 291 | /* electrical parameter block */ | ||
| 292 | u8 io_pin_capacitance_max; | ||
| 293 | __le16 async_timing_mode; | ||
| 294 | __le16 program_cache_timing_mode; | ||
| 295 | __le16 t_prog; | ||
| 296 | __le16 t_bers; | ||
| 297 | __le16 t_r; | ||
| 298 | __le16 t_ccs; | ||
| 299 | __le16 src_sync_timing_mode; | ||
| 300 | __le16 src_ssync_features; | ||
| 301 | __le16 clk_pin_capacitance_typ; | ||
| 302 | __le16 io_pin_capacitance_typ; | ||
| 303 | __le16 input_pin_capacitance_typ; | ||
| 304 | u8 input_pin_capacitance_max; | ||
| 305 | u8 driver_strenght_support; | ||
| 306 | __le16 t_int_r; | ||
| 307 | __le16 t_ald; | ||
| 308 | u8 reserved4[7]; | ||
| 309 | |||
| 310 | /* vendor */ | ||
| 311 | u8 reserved5[90]; | ||
| 312 | |||
| 313 | __le16 crc; | ||
| 314 | } __attribute__((packed)); | ||
| 315 | |||
| 316 | #define ONFI_CRC_BASE 0x4F4E | ||
| 317 | |||
| 230 | /** | 318 | /** |
| 231 | * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices | 319 | * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices |
| 232 | * @lock: protection lock | 320 | * @lock: protection lock |
| 233 | * @active: the mtd device which holds the controller currently | 321 | * @active: the mtd device which holds the controller currently |
| 234 | * @wq: wait queue to sleep on if a NAND operation is in progress | 322 | * @wq: wait queue to sleep on if a NAND operation is in |
| 235 | * used instead of the per chip wait queue when a hw controller is available | 323 | * progress used instead of the per chip wait queue |
| 324 | * when a hw controller is available. | ||
| 236 | */ | 325 | */ |
| 237 | struct nand_hw_control { | 326 | struct nand_hw_control { |
| 238 | spinlock_t lock; | 327 | spinlock_t lock; |
| 239 | struct nand_chip *active; | 328 | struct nand_chip *active; |
| 240 | wait_queue_head_t wq; | 329 | wait_queue_head_t wq; |
| 241 | }; | 330 | }; |
| @@ -256,51 +345,42 @@ struct nand_hw_control { | |||
| 256 | * @correct: function for ecc correction, matching to ecc generator (sw/hw) | 345 | * @correct: function for ecc correction, matching to ecc generator (sw/hw) |
| 257 | * @read_page_raw: function to read a raw page without ECC | 346 | * @read_page_raw: function to read a raw page without ECC |
| 258 | * @write_page_raw: function to write a raw page without ECC | 347 | * @write_page_raw: function to write a raw page without ECC |
| 259 | * @read_page: function to read a page according to the ecc generator requirements | 348 | * @read_page: function to read a page according to the ecc generator |
| 349 | * requirements. | ||
| 260 | * @read_subpage: function to read parts of the page covered by ECC. | 350 | * @read_subpage: function to read parts of the page covered by ECC. |
| 261 | * @write_page: function to write a page according to the ecc generator requirements | 351 | * @write_page: function to write a page according to the ecc generator |
| 352 | * requirements. | ||
| 262 | * @read_oob: function to read chip OOB data | 353 | * @read_oob: function to read chip OOB data |
| 263 | * @write_oob: function to write chip OOB data | 354 | * @write_oob: function to write chip OOB data |
| 264 | */ | 355 | */ |
| 265 | struct nand_ecc_ctrl { | 356 | struct nand_ecc_ctrl { |
| 266 | nand_ecc_modes_t mode; | 357 | nand_ecc_modes_t mode; |
| 267 | int steps; | 358 | int steps; |
| 268 | int size; | 359 | int size; |
| 269 | int bytes; | 360 | int bytes; |
| 270 | int total; | 361 | int total; |
| 271 | int prepad; | 362 | int prepad; |
| 272 | int postpad; | 363 | int postpad; |
| 273 | struct nand_ecclayout *layout; | 364 | struct nand_ecclayout *layout; |
| 274 | void (*hwctl)(struct mtd_info *mtd, int mode); | 365 | void (*hwctl)(struct mtd_info *mtd, int mode); |
| 275 | int (*calculate)(struct mtd_info *mtd, | 366 | int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, |
| 276 | const uint8_t *dat, | 367 | uint8_t *ecc_code); |
| 277 | uint8_t *ecc_code); | 368 | int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, |
| 278 | int (*correct)(struct mtd_info *mtd, uint8_t *dat, | 369 | uint8_t *calc_ecc); |
| 279 | uint8_t *read_ecc, | 370 | int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, |
| 280 | uint8_t *calc_ecc); | 371 | uint8_t *buf, int page); |
| 281 | int (*read_page_raw)(struct mtd_info *mtd, | 372 | void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, |
| 282 | struct nand_chip *chip, | 373 | const uint8_t *buf); |
| 283 | uint8_t *buf, int page); | 374 | int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, |
| 284 | void (*write_page_raw)(struct mtd_info *mtd, | 375 | uint8_t *buf, int page); |
| 285 | struct nand_chip *chip, | 376 | int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, |
| 286 | const uint8_t *buf); | 377 | uint32_t offs, uint32_t len, uint8_t *buf); |
| 287 | int (*read_page)(struct mtd_info *mtd, | 378 | void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, |
| 288 | struct nand_chip *chip, | 379 | const uint8_t *buf); |
| 289 | uint8_t *buf, int page); | 380 | int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page, |
| 290 | int (*read_subpage)(struct mtd_info *mtd, | 381 | int sndcmd); |
| 291 | struct nand_chip *chip, | 382 | int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, |
| 292 | uint32_t offs, uint32_t len, | 383 | int page); |
| 293 | uint8_t *buf); | ||
| 294 | void (*write_page)(struct mtd_info *mtd, | ||
| 295 | struct nand_chip *chip, | ||
| 296 | const uint8_t *buf); | ||
| 297 | int (*read_oob)(struct mtd_info *mtd, | ||
| 298 | struct nand_chip *chip, | ||
| 299 | int page, | ||
| 300 | int sndcmd); | ||
| 301 | int (*write_oob)(struct mtd_info *mtd, | ||
| 302 | struct nand_chip *chip, | ||
| 303 | int page); | ||
| 304 | }; | 384 | }; |
| 305 | 385 | ||
| 306 | /** | 386 | /** |
| @@ -320,102 +400,132 @@ struct nand_buffers { | |||
| 320 | 400 | ||
| 321 | /** | 401 | /** |
| 322 | * struct nand_chip - NAND Private Flash Chip Data | 402 | * struct nand_chip - NAND Private Flash Chip Data |
| 323 | * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device | 403 | * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the |
| 324 | * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device | 404 | * flash device |
| 405 | * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the | ||
| 406 | * flash device. | ||
| 325 | * @read_byte: [REPLACEABLE] read one byte from the chip | 407 | * @read_byte: [REPLACEABLE] read one byte from the chip |
| 326 | * @read_word: [REPLACEABLE] read one word from the chip | 408 | * @read_word: [REPLACEABLE] read one word from the chip |
| 327 | * @write_buf: [REPLACEABLE] write data from the buffer to the chip | 409 | * @write_buf: [REPLACEABLE] write data from the buffer to the chip |
| 328 | * @read_buf: [REPLACEABLE] read data from the chip into the buffer | 410 | * @read_buf: [REPLACEABLE] read data from the chip into the buffer |
| 329 | * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data | 411 | * @verify_buf: [REPLACEABLE] verify buffer contents against the chip |
| 412 | * data. | ||
| 330 | * @select_chip: [REPLACEABLE] select chip nr | 413 | * @select_chip: [REPLACEABLE] select chip nr |
| 331 | * @block_bad: [REPLACEABLE] check, if the block is bad | 414 | * @block_bad: [REPLACEABLE] check, if the block is bad |
| 332 | * @block_markbad: [REPLACEABLE] mark the block bad | 415 | * @block_markbad: [REPLACEABLE] mark the block bad |
| 333 | * @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific funtion for controlling | 416 | * @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific funtion for controlling |
| 334 | * ALE/CLE/nCE. Also used to write command and address | 417 | * ALE/CLE/nCE. Also used to write command and address |
| 335 | * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line | 418 | * @init_size: [BOARDSPECIFIC] hardwarespecific funtion for setting |
| 336 | * If set to NULL no access to ready/busy is available and the ready/busy information | 419 | * mtd->oobsize, mtd->writesize and so on. |
| 337 | * is read from the chip status register | 420 | * @id_data contains the 8 bytes values of NAND_CMD_READID. |
| 338 | * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip | 421 | * Return with the bus width. |
| 339 | * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready | 422 | * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing |
| 423 | * device ready/busy line. If set to NULL no access to | ||
| 424 | * ready/busy is available and the ready/busy information | ||
| 425 | * is read from the chip status register. | ||
| 426 | * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing | ||
| 427 | * commands to the chip. | ||
| 428 | * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on | ||
| 429 | * ready. | ||
| 340 | * @ecc: [BOARDSPECIFIC] ecc control ctructure | 430 | * @ecc: [BOARDSPECIFIC] ecc control ctructure |
| 341 | * @buffers: buffer structure for read/write | 431 | * @buffers: buffer structure for read/write |
| 342 | * @hwcontrol: platform-specific hardware control structure | 432 | * @hwcontrol: platform-specific hardware control structure |
| 343 | * @ops: oob operation operands | 433 | * @ops: oob operation operands |
| 344 | * @erase_cmd: [INTERN] erase command write function, selectable due to AND support | 434 | * @erase_cmd: [INTERN] erase command write function, selectable due |
| 435 | * to AND support. | ||
| 345 | * @scan_bbt: [REPLACEABLE] function to scan bad block table | 436 | * @scan_bbt: [REPLACEABLE] function to scan bad block table |
| 346 | * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) | 437 | * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering |
| 438 | * data from array to read regs (tR). | ||
| 347 | * @state: [INTERN] the current state of the NAND device | 439 | * @state: [INTERN] the current state of the NAND device |
| 348 | * @oob_poi: poison value buffer | 440 | * @oob_poi: poison value buffer |
| 349 | * @page_shift: [INTERN] number of address bits in a page (column address bits) | 441 | * @page_shift: [INTERN] number of address bits in a page (column |
| 442 | * address bits). | ||
| 350 | * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock | 443 | * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock |
| 351 | * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry | 444 | * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry |
| 352 | * @chip_shift: [INTERN] number of address bits in one chip | 445 | * @chip_shift: [INTERN] number of address bits in one chip |
| 353 | * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about | 446 | * @options: [BOARDSPECIFIC] various chip options. They can partly |
| 354 | * special functionality. See the defines for further explanation | 447 | * be set to inform nand_scan about special functionality. |
| 355 | * @badblockpos: [INTERN] position of the bad block marker in the oob area | 448 | * See the defines for further explanation. |
| 449 | * @badblockpos: [INTERN] position of the bad block marker in the oob | ||
| 450 | * area. | ||
| 356 | * @cellinfo: [INTERN] MLC/multichip data from chip ident | 451 | * @cellinfo: [INTERN] MLC/multichip data from chip ident |
| 357 | * @numchips: [INTERN] number of physical chips | 452 | * @numchips: [INTERN] number of physical chips |
| 358 | * @chipsize: [INTERN] the size of one chip for multichip arrays | 453 | * @chipsize: [INTERN] the size of one chip for multichip arrays |
| 359 | * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 | 454 | * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 |
| 360 | * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf | 455 | * @pagebuf: [INTERN] holds the pagenumber which is currently in |
| 456 | * data_buf. | ||
| 361 | * @subpagesize: [INTERN] holds the subpagesize | 457 | * @subpagesize: [INTERN] holds the subpagesize |
| 458 | * @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded), | ||
| 459 | * non 0 if ONFI supported. | ||
| 460 | * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is | ||
| 461 | * supported, 0 otherwise. | ||
| 362 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme | 462 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme |
| 363 | * @bbt: [INTERN] bad block table pointer | 463 | * @bbt: [INTERN] bad block table pointer |
| 364 | * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup | 464 | * @bbt_td: [REPLACEABLE] bad block table descriptor for flash |
| 465 | * lookup. | ||
| 365 | * @bbt_md: [REPLACEABLE] bad block table mirror descriptor | 466 | * @bbt_md: [REPLACEABLE] bad block table mirror descriptor |
| 366 | * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan | 467 | * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial |
| 367 | * @controller: [REPLACEABLE] a pointer to a hardware controller structure | 468 | * bad block scan. |
| 368 | * which is shared among multiple independend devices | 469 | * @controller: [REPLACEABLE] a pointer to a hardware controller |
| 470 | * structure which is shared among multiple independend | ||
| 471 | * devices. | ||
| 369 | * @priv: [OPTIONAL] pointer to private chip date | 472 | * @priv: [OPTIONAL] pointer to private chip date |
| 370 | * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks | 473 | * @errstat: [OPTIONAL] hardware specific function to perform |
| 371 | * (determine if errors are correctable) | 474 | * additional error status checks (determine if errors are |
| 475 | * correctable). | ||
| 372 | * @write_page: [REPLACEABLE] High-level page write function | 476 | * @write_page: [REPLACEABLE] High-level page write function |
| 373 | */ | 477 | */ |
| 374 | 478 | ||
| 375 | struct nand_chip { | 479 | struct nand_chip { |
| 376 | void __iomem *IO_ADDR_R; | 480 | void __iomem *IO_ADDR_R; |
| 377 | void __iomem *IO_ADDR_W; | 481 | void __iomem *IO_ADDR_W; |
| 378 | 482 | ||
| 379 | uint8_t (*read_byte)(struct mtd_info *mtd); | 483 | uint8_t (*read_byte)(struct mtd_info *mtd); |
| 380 | u16 (*read_word)(struct mtd_info *mtd); | 484 | u16 (*read_word)(struct mtd_info *mtd); |
| 381 | void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | 485 | void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); |
| 382 | void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); | 486 | void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); |
| 383 | int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | 487 | int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); |
| 384 | void (*select_chip)(struct mtd_info *mtd, int chip); | 488 | void (*select_chip)(struct mtd_info *mtd, int chip); |
| 385 | int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); | 489 | int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); |
| 386 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); | 490 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); |
| 387 | void (*cmd_ctrl)(struct mtd_info *mtd, int dat, | 491 | void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); |
| 388 | unsigned int ctrl); | 492 | int (*init_size)(struct mtd_info *mtd, struct nand_chip *this, |
| 389 | int (*dev_ready)(struct mtd_info *mtd); | 493 | u8 *id_data); |
| 390 | void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); | 494 | int (*dev_ready)(struct mtd_info *mtd); |
| 391 | int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); | 495 | void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, |
| 392 | void (*erase_cmd)(struct mtd_info *mtd, int page); | 496 | int page_addr); |
| 393 | int (*scan_bbt)(struct mtd_info *mtd); | 497 | int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); |
| 394 | int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); | 498 | void (*erase_cmd)(struct mtd_info *mtd, int page); |
| 395 | int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, | 499 | int (*scan_bbt)(struct mtd_info *mtd); |
| 396 | const uint8_t *buf, int page, int cached, int raw); | 500 | int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, |
| 397 | 501 | int status, int page); | |
| 398 | int chip_delay; | 502 | int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, |
| 399 | unsigned int options; | 503 | const uint8_t *buf, int page, int cached, int raw); |
| 400 | 504 | ||
| 401 | int page_shift; | 505 | int chip_delay; |
| 402 | int phys_erase_shift; | 506 | unsigned int options; |
| 403 | int bbt_erase_shift; | 507 | |
| 404 | int chip_shift; | 508 | int page_shift; |
| 405 | int numchips; | 509 | int phys_erase_shift; |
| 406 | uint64_t chipsize; | 510 | int bbt_erase_shift; |
| 407 | int pagemask; | 511 | int chip_shift; |
| 408 | int pagebuf; | 512 | int numchips; |
| 409 | int subpagesize; | 513 | uint64_t chipsize; |
| 410 | uint8_t cellinfo; | 514 | int pagemask; |
| 411 | int badblockpos; | 515 | int pagebuf; |
| 412 | int badblockbits; | 516 | int subpagesize; |
| 413 | 517 | uint8_t cellinfo; | |
| 414 | flstate_t state; | 518 | int badblockpos; |
| 415 | 519 | int badblockbits; | |
| 416 | uint8_t *oob_poi; | 520 | |
| 417 | struct nand_hw_control *controller; | 521 | int onfi_version; |
| 418 | struct nand_ecclayout *ecclayout; | 522 | struct nand_onfi_params onfi_params; |
| 523 | |||
| 524 | flstate_t state; | ||
| 525 | |||
| 526 | uint8_t *oob_poi; | ||
| 527 | struct nand_hw_control *controller; | ||
| 528 | struct nand_ecclayout *ecclayout; | ||
| 419 | 529 | ||
| 420 | struct nand_ecc_ctrl ecc; | 530 | struct nand_ecc_ctrl ecc; |
| 421 | struct nand_buffers *buffers; | 531 | struct nand_buffers *buffers; |
| @@ -423,13 +533,13 @@ struct nand_chip { | |||
| 423 | 533 | ||
| 424 | struct mtd_oob_ops ops; | 534 | struct mtd_oob_ops ops; |
| 425 | 535 | ||
| 426 | uint8_t *bbt; | 536 | uint8_t *bbt; |
| 427 | struct nand_bbt_descr *bbt_td; | 537 | struct nand_bbt_descr *bbt_td; |
| 428 | struct nand_bbt_descr *bbt_md; | 538 | struct nand_bbt_descr *bbt_md; |
| 429 | 539 | ||
| 430 | struct nand_bbt_descr *badblock_pattern; | 540 | struct nand_bbt_descr *badblock_pattern; |
| 431 | 541 | ||
| 432 | void *priv; | 542 | void *priv; |
| 433 | }; | 543 | }; |
| 434 | 544 | ||
| 435 | /* | 545 | /* |
| @@ -473,7 +583,7 @@ struct nand_flash_dev { | |||
| 473 | */ | 583 | */ |
| 474 | struct nand_manufacturers { | 584 | struct nand_manufacturers { |
| 475 | int id; | 585 | int id; |
| 476 | char * name; | 586 | char *name; |
| 477 | }; | 587 | }; |
| 478 | 588 | ||
| 479 | extern struct nand_flash_dev nand_flash_ids[]; | 589 | extern struct nand_flash_dev nand_flash_ids[]; |
| @@ -486,7 +596,7 @@ extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); | |||
| 486 | extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | 596 | extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, |
| 487 | int allowbbt); | 597 | int allowbbt); |
| 488 | extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | 598 | extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, |
| 489 | size_t * retlen, uint8_t * buf); | 599 | size_t *retlen, uint8_t *buf); |
| 490 | 600 | ||
| 491 | /** | 601 | /** |
| 492 | * struct platform_nand_chip - chip level device structure | 602 | * struct platform_nand_chip - chip level device structure |
| @@ -502,17 +612,16 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 502 | * @priv: hardware controller specific settings | 612 | * @priv: hardware controller specific settings |
| 503 | */ | 613 | */ |
| 504 | struct platform_nand_chip { | 614 | struct platform_nand_chip { |
| 505 | int nr_chips; | 615 | int nr_chips; |
| 506 | int chip_offset; | 616 | int chip_offset; |
| 507 | int nr_partitions; | 617 | int nr_partitions; |
| 508 | struct mtd_partition *partitions; | 618 | struct mtd_partition *partitions; |
| 509 | struct nand_ecclayout *ecclayout; | 619 | struct nand_ecclayout *ecclayout; |
| 510 | int chip_delay; | 620 | int chip_delay; |
| 511 | unsigned int options; | 621 | unsigned int options; |
| 512 | const char **part_probe_types; | 622 | const char **part_probe_types; |
| 513 | void (*set_parts)(uint64_t size, | 623 | void (*set_parts)(uint64_t size, struct platform_nand_chip *chip); |
| 514 | struct platform_nand_chip *chip); | 624 | void *priv; |
| 515 | void *priv; | ||
| 516 | }; | 625 | }; |
| 517 | 626 | ||
| 518 | /* Keep gcc happy */ | 627 | /* Keep gcc happy */ |
| @@ -534,18 +643,15 @@ struct platform_device; | |||
| 534 | * All fields are optional and depend on the hardware driver requirements | 643 | * All fields are optional and depend on the hardware driver requirements |
| 535 | */ | 644 | */ |
| 536 | struct platform_nand_ctrl { | 645 | struct platform_nand_ctrl { |
| 537 | int (*probe)(struct platform_device *pdev); | 646 | int (*probe)(struct platform_device *pdev); |
| 538 | void (*remove)(struct platform_device *pdev); | 647 | void (*remove)(struct platform_device *pdev); |
| 539 | void (*hwcontrol)(struct mtd_info *mtd, int cmd); | 648 | void (*hwcontrol)(struct mtd_info *mtd, int cmd); |
| 540 | int (*dev_ready)(struct mtd_info *mtd); | 649 | int (*dev_ready)(struct mtd_info *mtd); |
| 541 | void (*select_chip)(struct mtd_info *mtd, int chip); | 650 | void (*select_chip)(struct mtd_info *mtd, int chip); |
| 542 | void (*cmd_ctrl)(struct mtd_info *mtd, int dat, | 651 | void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); |
| 543 | unsigned int ctrl); | 652 | void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); |
| 544 | void (*write_buf)(struct mtd_info *mtd, | 653 | void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); |
| 545 | const uint8_t *buf, int len); | 654 | void *priv; |
| 546 | void (*read_buf)(struct mtd_info *mtd, | ||
| 547 | uint8_t *buf, int len); | ||
| 548 | void *priv; | ||
| 549 | }; | 655 | }; |
| 550 | 656 | ||
| 551 | /** | 657 | /** |
| @@ -554,8 +660,8 @@ struct platform_nand_ctrl { | |||
| 554 | * @ctrl: controller level device structure | 660 | * @ctrl: controller level device structure |
| 555 | */ | 661 | */ |
| 556 | struct platform_nand_data { | 662 | struct platform_nand_data { |
| 557 | struct platform_nand_chip chip; | 663 | struct platform_nand_chip chip; |
| 558 | struct platform_nand_ctrl ctrl; | 664 | struct platform_nand_ctrl ctrl; |
| 559 | }; | 665 | }; |
| 560 | 666 | ||
| 561 | /* Some helpers to access the data structures */ | 667 | /* Some helpers to access the data structures */ |
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 274b6196091d..2b54316591d2 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h | |||
| @@ -39,7 +39,7 @@ struct mtd_partition { | |||
| 39 | uint64_t size; /* partition size */ | 39 | uint64_t size; /* partition size */ |
| 40 | uint64_t offset; /* offset within the master MTD space */ | 40 | uint64_t offset; /* offset within the master MTD space */ |
| 41 | uint32_t mask_flags; /* master MTD flags to mask out for this partition */ | 41 | uint32_t mask_flags; /* master MTD flags to mask out for this partition */ |
| 42 | struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ | 42 | struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */ |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | #define MTDPART_OFS_NXTBLK (-2) | 45 | #define MTDPART_OFS_NXTBLK (-2) |
| @@ -89,4 +89,9 @@ static inline int mtd_has_cmdlinepart(void) { return 1; } | |||
| 89 | static inline int mtd_has_cmdlinepart(void) { return 0; } | 89 | static inline int mtd_has_cmdlinepart(void) { return 0; } |
| 90 | #endif | 90 | #endif |
| 91 | 91 | ||
| 92 | int mtd_is_master(struct mtd_info *mtd); | ||
| 93 | int mtd_add_partition(struct mtd_info *master, char *name, | ||
| 94 | long long offset, long long length); | ||
| 95 | int mtd_del_partition(struct mtd_info *master, int partno); | ||
| 96 | |||
| 92 | #endif | 97 | #endif |
diff --git a/include/linux/tty.h b/include/linux/tty.h index e500171c745f..2a754748dd5f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
| @@ -541,8 +541,8 @@ extern void tty_audit_exit(void); | |||
| 541 | extern void tty_audit_fork(struct signal_struct *sig); | 541 | extern void tty_audit_fork(struct signal_struct *sig); |
| 542 | extern void tty_audit_tiocsti(struct tty_struct *tty, char ch); | 542 | extern void tty_audit_tiocsti(struct tty_struct *tty, char ch); |
| 543 | extern void tty_audit_push(struct tty_struct *tty); | 543 | extern void tty_audit_push(struct tty_struct *tty); |
| 544 | extern void tty_audit_push_task(struct task_struct *tsk, | 544 | extern int tty_audit_push_task(struct task_struct *tsk, |
| 545 | uid_t loginuid, u32 sessionid); | 545 | uid_t loginuid, u32 sessionid); |
| 546 | #else | 546 | #else |
| 547 | static inline void tty_audit_add_data(struct tty_struct *tty, | 547 | static inline void tty_audit_add_data(struct tty_struct *tty, |
| 548 | unsigned char *data, size_t size) | 548 | unsigned char *data, size_t size) |
| @@ -560,9 +560,10 @@ static inline void tty_audit_fork(struct signal_struct *sig) | |||
| 560 | static inline void tty_audit_push(struct tty_struct *tty) | 560 | static inline void tty_audit_push(struct tty_struct *tty) |
| 561 | { | 561 | { |
| 562 | } | 562 | } |
| 563 | static inline void tty_audit_push_task(struct task_struct *tsk, | 563 | static inline int tty_audit_push_task(struct task_struct *tsk, |
| 564 | uid_t loginuid, u32 sessionid) | 564 | uid_t loginuid, u32 sessionid) |
| 565 | { | 565 | { |
| 566 | return 0; | ||
| 566 | } | 567 | } |
| 567 | #endif | 568 | #endif |
| 568 | 569 | ||
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 09eec350054d..0ead399e08b5 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
| @@ -58,7 +58,9 @@ struct writeback_control { | |||
| 58 | struct bdi_writeback; | 58 | struct bdi_writeback; |
| 59 | int inode_wait(void *); | 59 | int inode_wait(void *); |
| 60 | void writeback_inodes_sb(struct super_block *); | 60 | void writeback_inodes_sb(struct super_block *); |
| 61 | void writeback_inodes_sb_nr(struct super_block *, unsigned long nr); | ||
| 61 | int writeback_inodes_sb_if_idle(struct super_block *); | 62 | int writeback_inodes_sb_if_idle(struct super_block *); |
| 63 | int writeback_inodes_sb_nr_if_idle(struct super_block *, unsigned long nr); | ||
| 62 | void sync_inodes_sb(struct super_block *); | 64 | void sync_inodes_sb(struct super_block *); |
| 63 | void writeback_inodes_wb(struct bdi_writeback *wb, | 65 | void writeback_inodes_wb(struct bdi_writeback *wb, |
| 64 | struct writeback_control *wbc); | 66 | struct writeback_control *wbc); |
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 4debb4514634..2f7d45bcbd24 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h | |||
| @@ -52,6 +52,7 @@ struct mtd_oob_buf64 { | |||
| 52 | #define MTD_NANDFLASH 4 | 52 | #define MTD_NANDFLASH 4 |
| 53 | #define MTD_DATAFLASH 6 | 53 | #define MTD_DATAFLASH 6 |
| 54 | #define MTD_UBIVOLUME 7 | 54 | #define MTD_UBIVOLUME 7 |
| 55 | #define MTD_MLCNANDFLASH 8 | ||
| 55 | 56 | ||
| 56 | #define MTD_WRITEABLE 0x400 /* Device is writeable */ | 57 | #define MTD_WRITEABLE 0x400 /* Device is writeable */ |
| 57 | #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ | 58 | #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ |
| @@ -119,7 +120,7 @@ struct otp_info { | |||
| 119 | #define OTPGETREGIONCOUNT _IOW('M', 14, int) | 120 | #define OTPGETREGIONCOUNT _IOW('M', 14, int) |
| 120 | #define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) | 121 | #define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) |
| 121 | #define OTPLOCK _IOR('M', 16, struct otp_info) | 122 | #define OTPLOCK _IOR('M', 16, struct otp_info) |
| 122 | #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout) | 123 | #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user) |
| 123 | #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) | 124 | #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) |
| 124 | #define MTDFILEMODE _IO('M', 19) | 125 | #define MTDFILEMODE _IO('M', 19) |
| 125 | #define MEMERASE64 _IOW('M', 20, struct erase_info_user64) | 126 | #define MEMERASE64 _IOW('M', 20, struct erase_info_user64) |
| @@ -144,13 +145,18 @@ struct nand_oobfree { | |||
| 144 | }; | 145 | }; |
| 145 | 146 | ||
| 146 | #define MTD_MAX_OOBFREE_ENTRIES 8 | 147 | #define MTD_MAX_OOBFREE_ENTRIES 8 |
| 148 | #define MTD_MAX_ECCPOS_ENTRIES 64 | ||
| 147 | /* | 149 | /* |
| 148 | * ECC layout control structure. Exported to userspace for | 150 | * OBSOLETE: ECC layout control structure. Exported to user-space via ioctl |
| 149 | * diagnosis and to allow creation of raw images | 151 | * ECCGETLAYOUT for backwards compatbility and should not be mistaken as a |
| 152 | * complete set of ECC information. The ioctl truncates the larger internal | ||
| 153 | * structure to retain binary compatibility with the static declaration of the | ||
| 154 | * ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of | ||
| 155 | * the user struct, not the MAX size of the internal struct nand_ecclayout. | ||
| 150 | */ | 156 | */ |
| 151 | struct nand_ecclayout { | 157 | struct nand_ecclayout_user { |
| 152 | __u32 eccbytes; | 158 | __u32 eccbytes; |
| 153 | __u32 eccpos[64]; | 159 | __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES]; |
| 154 | __u32 oobavail; | 160 | __u32 oobavail; |
| 155 | struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; | 161 | struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; |
| 156 | }; | 162 | }; |
diff --git a/include/mtd/mtd-user.h b/include/mtd/mtd-user.h index aa3c2f86a913..83327c808c86 100644 --- a/include/mtd/mtd-user.h +++ b/include/mtd/mtd-user.h | |||
| @@ -29,6 +29,6 @@ typedef struct mtd_info_user mtd_info_t; | |||
| 29 | typedef struct erase_info_user erase_info_t; | 29 | typedef struct erase_info_user erase_info_t; |
| 30 | typedef struct region_info_user region_info_t; | 30 | typedef struct region_info_user region_info_t; |
| 31 | typedef struct nand_oobinfo nand_oobinfo_t; | 31 | typedef struct nand_oobinfo nand_oobinfo_t; |
| 32 | typedef struct nand_ecclayout nand_ecclayout_t; | 32 | typedef struct nand_ecclayout_user nand_ecclayout_t; |
| 33 | 33 | ||
| 34 | #endif /* __MTD_USER_H__ */ | 34 | #endif /* __MTD_USER_H__ */ |
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 55d700e8566e..daabae5817c6 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h | |||
| @@ -49,7 +49,9 @@ struct sh_mobile_lcdc_sys_bus_ops { | |||
| 49 | unsigned long (*read_data)(void *handle); | 49 | unsigned long (*read_data)(void *handle); |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | struct module; | ||
| 52 | struct sh_mobile_lcdc_board_cfg { | 53 | struct sh_mobile_lcdc_board_cfg { |
| 54 | struct module *owner; | ||
| 53 | void *board_data; | 55 | void *board_data; |
| 54 | int (*setup_sys)(void *board_data, void *sys_ops_handle, | 56 | int (*setup_sys)(void *board_data, void *sys_ops_handle, |
| 55 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); | 57 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); |
| @@ -70,7 +72,8 @@ struct sh_mobile_lcdc_chan_cfg { | |||
| 70 | int interface_type; /* selects RGBn or SYSn I/F, see above */ | 72 | int interface_type; /* selects RGBn or SYSn I/F, see above */ |
| 71 | int clock_divider; | 73 | int clock_divider; |
| 72 | unsigned long flags; /* LCDC_FLAGS_... */ | 74 | unsigned long flags; /* LCDC_FLAGS_... */ |
| 73 | struct fb_videomode lcd_cfg; | 75 | const struct fb_videomode *lcd_cfg; |
| 76 | int num_cfg; | ||
| 74 | struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; | 77 | struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; |
| 75 | struct sh_mobile_lcdc_board_cfg board_cfg; | 78 | struct sh_mobile_lcdc_board_cfg board_cfg; |
| 76 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ | 79 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ |
| @@ -479,6 +479,7 @@ static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ | |||
| 479 | { | 479 | { |
| 480 | struct shmid_ds out; | 480 | struct shmid_ds out; |
| 481 | 481 | ||
| 482 | memset(&out, 0, sizeof(out)); | ||
| 482 | ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm); | 483 | ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm); |
| 483 | out.shm_segsz = in->shm_segsz; | 484 | out.shm_segsz = in->shm_segsz; |
| 484 | out.shm_atime = in->shm_atime; | 485 | out.shm_atime = in->shm_atime; |
diff --git a/kernel/audit.c b/kernel/audit.c index d96045789b54..77770a034d59 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
| @@ -467,23 +467,16 @@ static int audit_prepare_user_tty(pid_t pid, uid_t loginuid, u32 sessionid) | |||
| 467 | struct task_struct *tsk; | 467 | struct task_struct *tsk; |
| 468 | int err; | 468 | int err; |
| 469 | 469 | ||
| 470 | read_lock(&tasklist_lock); | 470 | rcu_read_lock(); |
| 471 | tsk = find_task_by_vpid(pid); | 471 | tsk = find_task_by_vpid(pid); |
| 472 | err = -ESRCH; | 472 | if (!tsk) { |
| 473 | if (!tsk) | 473 | rcu_read_unlock(); |
| 474 | goto out; | 474 | return -ESRCH; |
| 475 | err = 0; | 475 | } |
| 476 | 476 | get_task_struct(tsk); | |
| 477 | spin_lock_irq(&tsk->sighand->siglock); | 477 | rcu_read_unlock(); |
| 478 | if (!tsk->signal->audit_tty) | 478 | err = tty_audit_push_task(tsk, loginuid, sessionid); |
| 479 | err = -EPERM; | 479 | put_task_struct(tsk); |
| 480 | spin_unlock_irq(&tsk->sighand->siglock); | ||
| 481 | if (err) | ||
| 482 | goto out; | ||
| 483 | |||
| 484 | tty_audit_push_task(tsk, loginuid, sessionid); | ||
| 485 | out: | ||
| 486 | read_unlock(&tasklist_lock); | ||
| 487 | return err; | 480 | return err; |
| 488 | } | 481 | } |
| 489 | 482 | ||
| @@ -506,7 +499,7 @@ int audit_send_list(void *_dest) | |||
| 506 | } | 499 | } |
| 507 | 500 | ||
| 508 | struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, | 501 | struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, |
| 509 | int multi, void *payload, int size) | 502 | int multi, const void *payload, int size) |
| 510 | { | 503 | { |
| 511 | struct sk_buff *skb; | 504 | struct sk_buff *skb; |
| 512 | struct nlmsghdr *nlh; | 505 | struct nlmsghdr *nlh; |
| @@ -555,8 +548,8 @@ static int audit_send_reply_thread(void *arg) | |||
| 555 | * Allocates an skb, builds the netlink message, and sends it to the pid. | 548 | * Allocates an skb, builds the netlink message, and sends it to the pid. |
| 556 | * No failure notifications. | 549 | * No failure notifications. |
| 557 | */ | 550 | */ |
| 558 | void audit_send_reply(int pid, int seq, int type, int done, int multi, | 551 | static void audit_send_reply(int pid, int seq, int type, int done, int multi, |
| 559 | void *payload, int size) | 552 | const void *payload, int size) |
| 560 | { | 553 | { |
| 561 | struct sk_buff *skb; | 554 | struct sk_buff *skb; |
| 562 | struct task_struct *tsk; | 555 | struct task_struct *tsk; |
| @@ -880,40 +873,40 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 880 | case AUDIT_TTY_GET: { | 873 | case AUDIT_TTY_GET: { |
| 881 | struct audit_tty_status s; | 874 | struct audit_tty_status s; |
| 882 | struct task_struct *tsk; | 875 | struct task_struct *tsk; |
| 876 | unsigned long flags; | ||
| 883 | 877 | ||
| 884 | read_lock(&tasklist_lock); | 878 | rcu_read_lock(); |
| 885 | tsk = find_task_by_vpid(pid); | 879 | tsk = find_task_by_vpid(pid); |
| 886 | if (!tsk) | 880 | if (tsk && lock_task_sighand(tsk, &flags)) { |
| 887 | err = -ESRCH; | ||
| 888 | else { | ||
| 889 | spin_lock_irq(&tsk->sighand->siglock); | ||
| 890 | s.enabled = tsk->signal->audit_tty != 0; | 881 | s.enabled = tsk->signal->audit_tty != 0; |
| 891 | spin_unlock_irq(&tsk->sighand->siglock); | 882 | unlock_task_sighand(tsk, &flags); |
| 892 | } | 883 | } else |
| 893 | read_unlock(&tasklist_lock); | 884 | err = -ESRCH; |
| 894 | audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_TTY_GET, 0, 0, | 885 | rcu_read_unlock(); |
| 895 | &s, sizeof(s)); | 886 | |
| 887 | if (!err) | ||
| 888 | audit_send_reply(NETLINK_CB(skb).pid, seq, | ||
| 889 | AUDIT_TTY_GET, 0, 0, &s, sizeof(s)); | ||
| 896 | break; | 890 | break; |
| 897 | } | 891 | } |
| 898 | case AUDIT_TTY_SET: { | 892 | case AUDIT_TTY_SET: { |
| 899 | struct audit_tty_status *s; | 893 | struct audit_tty_status *s; |
| 900 | struct task_struct *tsk; | 894 | struct task_struct *tsk; |
| 895 | unsigned long flags; | ||
| 901 | 896 | ||
| 902 | if (nlh->nlmsg_len < sizeof(struct audit_tty_status)) | 897 | if (nlh->nlmsg_len < sizeof(struct audit_tty_status)) |
| 903 | return -EINVAL; | 898 | return -EINVAL; |
| 904 | s = data; | 899 | s = data; |
| 905 | if (s->enabled != 0 && s->enabled != 1) | 900 | if (s->enabled != 0 && s->enabled != 1) |
| 906 | return -EINVAL; | 901 | return -EINVAL; |
| 907 | read_lock(&tasklist_lock); | 902 | rcu_read_lock(); |
| 908 | tsk = find_task_by_vpid(pid); | 903 | tsk = find_task_by_vpid(pid); |
| 909 | if (!tsk) | 904 | if (tsk && lock_task_sighand(tsk, &flags)) { |
| 910 | err = -ESRCH; | ||
| 911 | else { | ||
| 912 | spin_lock_irq(&tsk->sighand->siglock); | ||
| 913 | tsk->signal->audit_tty = s->enabled != 0; | 905 | tsk->signal->audit_tty = s->enabled != 0; |
| 914 | spin_unlock_irq(&tsk->sighand->siglock); | 906 | unlock_task_sighand(tsk, &flags); |
| 915 | } | 907 | } else |
| 916 | read_unlock(&tasklist_lock); | 908 | err = -ESRCH; |
| 909 | rcu_read_unlock(); | ||
| 917 | break; | 910 | break; |
| 918 | } | 911 | } |
| 919 | default: | 912 | default: |
diff --git a/kernel/audit.h b/kernel/audit.h index f7206db4e13d..91e7071c4d2c 100644 --- a/kernel/audit.h +++ b/kernel/audit.h | |||
| @@ -84,10 +84,7 @@ extern int audit_compare_dname_path(const char *dname, const char *path, | |||
| 84 | int *dirlen); | 84 | int *dirlen); |
| 85 | extern struct sk_buff * audit_make_reply(int pid, int seq, int type, | 85 | extern struct sk_buff * audit_make_reply(int pid, int seq, int type, |
| 86 | int done, int multi, | 86 | int done, int multi, |
| 87 | void *payload, int size); | 87 | const void *payload, int size); |
| 88 | extern void audit_send_reply(int pid, int seq, int type, | ||
| 89 | int done, int multi, | ||
| 90 | void *payload, int size); | ||
| 91 | extern void audit_panic(const char *message); | 88 | extern void audit_panic(const char *message); |
| 92 | 89 | ||
| 93 | struct audit_netlink_list { | 90 | struct audit_netlink_list { |
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 7f18d3a4527e..37b2bea170c8 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
| @@ -223,7 +223,7 @@ static void untag_chunk(struct node *p) | |||
| 223 | { | 223 | { |
| 224 | struct audit_chunk *chunk = find_chunk(p); | 224 | struct audit_chunk *chunk = find_chunk(p); |
| 225 | struct fsnotify_mark *entry = &chunk->mark; | 225 | struct fsnotify_mark *entry = &chunk->mark; |
| 226 | struct audit_chunk *new; | 226 | struct audit_chunk *new = NULL; |
| 227 | struct audit_tree *owner; | 227 | struct audit_tree *owner; |
| 228 | int size = chunk->count - 1; | 228 | int size = chunk->count - 1; |
| 229 | int i, j; | 229 | int i, j; |
| @@ -232,9 +232,14 @@ static void untag_chunk(struct node *p) | |||
| 232 | 232 | ||
| 233 | spin_unlock(&hash_lock); | 233 | spin_unlock(&hash_lock); |
| 234 | 234 | ||
| 235 | if (size) | ||
| 236 | new = alloc_chunk(size); | ||
| 237 | |||
| 235 | spin_lock(&entry->lock); | 238 | spin_lock(&entry->lock); |
| 236 | if (chunk->dead || !entry->i.inode) { | 239 | if (chunk->dead || !entry->i.inode) { |
| 237 | spin_unlock(&entry->lock); | 240 | spin_unlock(&entry->lock); |
| 241 | if (new) | ||
| 242 | free_chunk(new); | ||
| 238 | goto out; | 243 | goto out; |
| 239 | } | 244 | } |
| 240 | 245 | ||
| @@ -255,9 +260,9 @@ static void untag_chunk(struct node *p) | |||
| 255 | goto out; | 260 | goto out; |
| 256 | } | 261 | } |
| 257 | 262 | ||
| 258 | new = alloc_chunk(size); | ||
| 259 | if (!new) | 263 | if (!new) |
| 260 | goto Fallback; | 264 | goto Fallback; |
| 265 | |||
| 261 | fsnotify_duplicate_mark(&new->mark, entry); | 266 | fsnotify_duplicate_mark(&new->mark, entry); |
| 262 | if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { | 267 | if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { |
| 263 | free_chunk(new); | 268 | free_chunk(new); |
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index f0c9b2e7542d..d2e3c7866460 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c | |||
| @@ -60,7 +60,7 @@ struct audit_parent { | |||
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | /* fsnotify handle. */ | 62 | /* fsnotify handle. */ |
| 63 | struct fsnotify_group *audit_watch_group; | 63 | static struct fsnotify_group *audit_watch_group; |
| 64 | 64 | ||
| 65 | /* fsnotify events we care about. */ | 65 | /* fsnotify events we care about. */ |
| 66 | #define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\ | 66 | #define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\ |
| @@ -123,7 +123,7 @@ void audit_put_watch(struct audit_watch *watch) | |||
| 123 | } | 123 | } |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | void audit_remove_watch(struct audit_watch *watch) | 126 | static void audit_remove_watch(struct audit_watch *watch) |
| 127 | { | 127 | { |
| 128 | list_del(&watch->wlist); | 128 | list_del(&watch->wlist); |
| 129 | audit_put_parent(watch->parent); | 129 | audit_put_parent(watch->parent); |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index eb7675499fb5..add2819af71b 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
| @@ -1252,6 +1252,18 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb, | |||
| 1252 | case AUDIT_LOGINUID: | 1252 | case AUDIT_LOGINUID: |
| 1253 | result = audit_comparator(cb->loginuid, f->op, f->val); | 1253 | result = audit_comparator(cb->loginuid, f->op, f->val); |
| 1254 | break; | 1254 | break; |
| 1255 | case AUDIT_SUBJ_USER: | ||
| 1256 | case AUDIT_SUBJ_ROLE: | ||
| 1257 | case AUDIT_SUBJ_TYPE: | ||
| 1258 | case AUDIT_SUBJ_SEN: | ||
| 1259 | case AUDIT_SUBJ_CLR: | ||
| 1260 | if (f->lsm_rule) | ||
| 1261 | result = security_audit_rule_match(cb->sid, | ||
| 1262 | f->type, | ||
| 1263 | f->op, | ||
| 1264 | f->lsm_rule, | ||
| 1265 | NULL); | ||
| 1266 | break; | ||
| 1255 | } | 1267 | } |
| 1256 | 1268 | ||
| 1257 | if (!result) | 1269 | if (!result) |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 1b31c130d034..f49a0318c2ed 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -241,6 +241,10 @@ struct audit_context { | |||
| 241 | pid_t pid; | 241 | pid_t pid; |
| 242 | struct audit_cap_data cap; | 242 | struct audit_cap_data cap; |
| 243 | } capset; | 243 | } capset; |
| 244 | struct { | ||
| 245 | int fd; | ||
| 246 | int flags; | ||
| 247 | } mmap; | ||
| 244 | }; | 248 | }; |
| 245 | int fds[2]; | 249 | int fds[2]; |
| 246 | 250 | ||
| @@ -1305,6 +1309,10 @@ static void show_special(struct audit_context *context, int *call_panic) | |||
| 1305 | audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted); | 1309 | audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted); |
| 1306 | audit_log_cap(ab, "cap_pe", &context->capset.cap.effective); | 1310 | audit_log_cap(ab, "cap_pe", &context->capset.cap.effective); |
| 1307 | break; } | 1311 | break; } |
| 1312 | case AUDIT_MMAP: { | ||
| 1313 | audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd, | ||
| 1314 | context->mmap.flags); | ||
| 1315 | break; } | ||
| 1308 | } | 1316 | } |
| 1309 | audit_log_end(ab); | 1317 | audit_log_end(ab); |
| 1310 | } | 1318 | } |
| @@ -2476,6 +2484,14 @@ void __audit_log_capset(pid_t pid, | |||
| 2476 | context->type = AUDIT_CAPSET; | 2484 | context->type = AUDIT_CAPSET; |
| 2477 | } | 2485 | } |
| 2478 | 2486 | ||
| 2487 | void __audit_mmap_fd(int fd, int flags) | ||
| 2488 | { | ||
| 2489 | struct audit_context *context = current->audit_context; | ||
| 2490 | context->mmap.fd = fd; | ||
| 2491 | context->mmap.flags = flags; | ||
| 2492 | context->type = AUDIT_MMAP; | ||
| 2493 | } | ||
| 2494 | |||
| 2479 | /** | 2495 | /** |
| 2480 | * audit_core_dumps - record information about processes that end abnormally | 2496 | * audit_core_dumps - record information about processes that end abnormally |
| 2481 | * @signr: signal value | 2497 | * @signr: signal value |
diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 7be868bf25c6..3b79bd938330 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c | |||
| @@ -39,6 +39,16 @@ struct jump_label_module_entry { | |||
| 39 | struct module *mod; | 39 | struct module *mod; |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | void jump_label_lock(void) | ||
| 43 | { | ||
| 44 | mutex_lock(&jump_label_mutex); | ||
| 45 | } | ||
| 46 | |||
| 47 | void jump_label_unlock(void) | ||
| 48 | { | ||
| 49 | mutex_unlock(&jump_label_mutex); | ||
| 50 | } | ||
| 51 | |||
| 42 | static int jump_label_cmp(const void *a, const void *b) | 52 | static int jump_label_cmp(const void *a, const void *b) |
| 43 | { | 53 | { |
| 44 | const struct jump_entry *jea = a; | 54 | const struct jump_entry *jea = a; |
| @@ -152,7 +162,7 @@ void jump_label_update(unsigned long key, enum jump_label_type type) | |||
| 152 | struct jump_label_module_entry *e_module; | 162 | struct jump_label_module_entry *e_module; |
| 153 | int count; | 163 | int count; |
| 154 | 164 | ||
| 155 | mutex_lock(&jump_label_mutex); | 165 | jump_label_lock(); |
| 156 | entry = get_jump_label_entry((jump_label_t)key); | 166 | entry = get_jump_label_entry((jump_label_t)key); |
| 157 | if (entry) { | 167 | if (entry) { |
| 158 | count = entry->nr_entries; | 168 | count = entry->nr_entries; |
| @@ -168,13 +178,14 @@ void jump_label_update(unsigned long key, enum jump_label_type type) | |||
| 168 | count = e_module->nr_entries; | 178 | count = e_module->nr_entries; |
| 169 | iter = e_module->table; | 179 | iter = e_module->table; |
| 170 | while (count--) { | 180 | while (count--) { |
| 171 | if (kernel_text_address(iter->code)) | 181 | if (iter->key && |
| 182 | kernel_text_address(iter->code)) | ||
| 172 | arch_jump_label_transform(iter, type); | 183 | arch_jump_label_transform(iter, type); |
| 173 | iter++; | 184 | iter++; |
| 174 | } | 185 | } |
| 175 | } | 186 | } |
| 176 | } | 187 | } |
| 177 | mutex_unlock(&jump_label_mutex); | 188 | jump_label_unlock(); |
| 178 | } | 189 | } |
| 179 | 190 | ||
| 180 | static int addr_conflict(struct jump_entry *entry, void *start, void *end) | 191 | static int addr_conflict(struct jump_entry *entry, void *start, void *end) |
| @@ -231,6 +242,7 @@ out: | |||
| 231 | * overlaps with any of the jump label patch addresses. Code | 242 | * overlaps with any of the jump label patch addresses. Code |
| 232 | * that wants to modify kernel text should first verify that | 243 | * that wants to modify kernel text should first verify that |
| 233 | * it does not overlap with any of the jump label addresses. | 244 | * it does not overlap with any of the jump label addresses. |
| 245 | * Caller must hold jump_label_mutex. | ||
| 234 | * | 246 | * |
| 235 | * returns 1 if there is an overlap, 0 otherwise | 247 | * returns 1 if there is an overlap, 0 otherwise |
| 236 | */ | 248 | */ |
| @@ -241,7 +253,6 @@ int jump_label_text_reserved(void *start, void *end) | |||
| 241 | struct jump_entry *iter_stop = __start___jump_table; | 253 | struct jump_entry *iter_stop = __start___jump_table; |
| 242 | int conflict = 0; | 254 | int conflict = 0; |
| 243 | 255 | ||
| 244 | mutex_lock(&jump_label_mutex); | ||
| 245 | iter = iter_start; | 256 | iter = iter_start; |
| 246 | while (iter < iter_stop) { | 257 | while (iter < iter_stop) { |
| 247 | if (addr_conflict(iter, start, end)) { | 258 | if (addr_conflict(iter, start, end)) { |
| @@ -256,10 +267,16 @@ int jump_label_text_reserved(void *start, void *end) | |||
| 256 | conflict = module_conflict(start, end); | 267 | conflict = module_conflict(start, end); |
| 257 | #endif | 268 | #endif |
| 258 | out: | 269 | out: |
| 259 | mutex_unlock(&jump_label_mutex); | ||
| 260 | return conflict; | 270 | return conflict; |
| 261 | } | 271 | } |
| 262 | 272 | ||
| 273 | /* | ||
| 274 | * Not all archs need this. | ||
| 275 | */ | ||
| 276 | void __weak arch_jump_label_text_poke_early(jump_label_t addr) | ||
| 277 | { | ||
| 278 | } | ||
| 279 | |||
| 263 | static __init int init_jump_label(void) | 280 | static __init int init_jump_label(void) |
| 264 | { | 281 | { |
| 265 | int ret; | 282 | int ret; |
| @@ -267,7 +284,7 @@ static __init int init_jump_label(void) | |||
| 267 | struct jump_entry *iter_stop = __stop___jump_table; | 284 | struct jump_entry *iter_stop = __stop___jump_table; |
| 268 | struct jump_entry *iter; | 285 | struct jump_entry *iter; |
| 269 | 286 | ||
| 270 | mutex_lock(&jump_label_mutex); | 287 | jump_label_lock(); |
| 271 | ret = build_jump_label_hashtable(__start___jump_table, | 288 | ret = build_jump_label_hashtable(__start___jump_table, |
| 272 | __stop___jump_table); | 289 | __stop___jump_table); |
| 273 | iter = iter_start; | 290 | iter = iter_start; |
| @@ -275,7 +292,7 @@ static __init int init_jump_label(void) | |||
| 275 | arch_jump_label_text_poke_early(iter->code); | 292 | arch_jump_label_text_poke_early(iter->code); |
| 276 | iter++; | 293 | iter++; |
| 277 | } | 294 | } |
| 278 | mutex_unlock(&jump_label_mutex); | 295 | jump_label_unlock(); |
| 279 | return ret; | 296 | return ret; |
| 280 | } | 297 | } |
| 281 | early_initcall(init_jump_label); | 298 | early_initcall(init_jump_label); |
| @@ -366,6 +383,39 @@ static void remove_jump_label_module(struct module *mod) | |||
| 366 | } | 383 | } |
| 367 | } | 384 | } |
| 368 | 385 | ||
| 386 | static void remove_jump_label_module_init(struct module *mod) | ||
| 387 | { | ||
| 388 | struct hlist_head *head; | ||
| 389 | struct hlist_node *node, *node_next, *module_node, *module_node_next; | ||
| 390 | struct jump_label_entry *e; | ||
| 391 | struct jump_label_module_entry *e_module; | ||
| 392 | struct jump_entry *iter; | ||
| 393 | int i, count; | ||
| 394 | |||
| 395 | /* if the module doesn't have jump label entries, just return */ | ||
| 396 | if (!mod->num_jump_entries) | ||
| 397 | return; | ||
| 398 | |||
| 399 | for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) { | ||
| 400 | head = &jump_label_table[i]; | ||
| 401 | hlist_for_each_entry_safe(e, node, node_next, head, hlist) { | ||
| 402 | hlist_for_each_entry_safe(e_module, module_node, | ||
| 403 | module_node_next, | ||
| 404 | &(e->modules), hlist) { | ||
| 405 | if (e_module->mod != mod) | ||
| 406 | continue; | ||
| 407 | count = e_module->nr_entries; | ||
| 408 | iter = e_module->table; | ||
| 409 | while (count--) { | ||
| 410 | if (within_module_init(iter->code, mod)) | ||
| 411 | iter->key = 0; | ||
| 412 | iter++; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | } | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 369 | static int | 419 | static int |
| 370 | jump_label_module_notify(struct notifier_block *self, unsigned long val, | 420 | jump_label_module_notify(struct notifier_block *self, unsigned long val, |
| 371 | void *data) | 421 | void *data) |
| @@ -375,16 +425,21 @@ jump_label_module_notify(struct notifier_block *self, unsigned long val, | |||
| 375 | 425 | ||
| 376 | switch (val) { | 426 | switch (val) { |
| 377 | case MODULE_STATE_COMING: | 427 | case MODULE_STATE_COMING: |
| 378 | mutex_lock(&jump_label_mutex); | 428 | jump_label_lock(); |
| 379 | ret = add_jump_label_module(mod); | 429 | ret = add_jump_label_module(mod); |
| 380 | if (ret) | 430 | if (ret) |
| 381 | remove_jump_label_module(mod); | 431 | remove_jump_label_module(mod); |
| 382 | mutex_unlock(&jump_label_mutex); | 432 | jump_label_unlock(); |
| 383 | break; | 433 | break; |
| 384 | case MODULE_STATE_GOING: | 434 | case MODULE_STATE_GOING: |
| 385 | mutex_lock(&jump_label_mutex); | 435 | jump_label_lock(); |
| 386 | remove_jump_label_module(mod); | 436 | remove_jump_label_module(mod); |
| 387 | mutex_unlock(&jump_label_mutex); | 437 | jump_label_unlock(); |
| 438 | break; | ||
| 439 | case MODULE_STATE_LIVE: | ||
| 440 | jump_label_lock(); | ||
| 441 | remove_jump_label_module_init(mod); | ||
| 442 | jump_label_unlock(); | ||
| 388 | break; | 443 | break; |
| 389 | } | 444 | } |
| 390 | return ret; | 445 | return ret; |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 99865c33a60d..9737a76e106f 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -1145,14 +1145,13 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 1145 | if (ret) | 1145 | if (ret) |
| 1146 | return ret; | 1146 | return ret; |
| 1147 | 1147 | ||
| 1148 | jump_label_lock(); | ||
| 1148 | preempt_disable(); | 1149 | preempt_disable(); |
| 1149 | if (!kernel_text_address((unsigned long) p->addr) || | 1150 | if (!kernel_text_address((unsigned long) p->addr) || |
| 1150 | in_kprobes_functions((unsigned long) p->addr) || | 1151 | in_kprobes_functions((unsigned long) p->addr) || |
| 1151 | ftrace_text_reserved(p->addr, p->addr) || | 1152 | ftrace_text_reserved(p->addr, p->addr) || |
| 1152 | jump_label_text_reserved(p->addr, p->addr)) { | 1153 | jump_label_text_reserved(p->addr, p->addr)) |
| 1153 | preempt_enable(); | 1154 | goto fail_with_jump_label; |
| 1154 | return -EINVAL; | ||
| 1155 | } | ||
| 1156 | 1155 | ||
| 1157 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ | 1156 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ |
| 1158 | p->flags &= KPROBE_FLAG_DISABLED; | 1157 | p->flags &= KPROBE_FLAG_DISABLED; |
| @@ -1166,10 +1165,9 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 1166 | * We must hold a refcount of the probed module while updating | 1165 | * We must hold a refcount of the probed module while updating |
| 1167 | * its code to prohibit unexpected unloading. | 1166 | * its code to prohibit unexpected unloading. |
| 1168 | */ | 1167 | */ |
| 1169 | if (unlikely(!try_module_get(probed_mod))) { | 1168 | if (unlikely(!try_module_get(probed_mod))) |
| 1170 | preempt_enable(); | 1169 | goto fail_with_jump_label; |
| 1171 | return -EINVAL; | 1170 | |
| 1172 | } | ||
| 1173 | /* | 1171 | /* |
| 1174 | * If the module freed .init.text, we couldn't insert | 1172 | * If the module freed .init.text, we couldn't insert |
| 1175 | * kprobes in there. | 1173 | * kprobes in there. |
| @@ -1177,16 +1175,18 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 1177 | if (within_module_init((unsigned long)p->addr, probed_mod) && | 1175 | if (within_module_init((unsigned long)p->addr, probed_mod) && |
| 1178 | probed_mod->state != MODULE_STATE_COMING) { | 1176 | probed_mod->state != MODULE_STATE_COMING) { |
| 1179 | module_put(probed_mod); | 1177 | module_put(probed_mod); |
| 1180 | preempt_enable(); | 1178 | goto fail_with_jump_label; |
| 1181 | return -EINVAL; | ||
| 1182 | } | 1179 | } |
| 1183 | } | 1180 | } |
| 1184 | preempt_enable(); | 1181 | preempt_enable(); |
| 1182 | jump_label_unlock(); | ||
| 1185 | 1183 | ||
| 1186 | p->nmissed = 0; | 1184 | p->nmissed = 0; |
| 1187 | INIT_LIST_HEAD(&p->list); | 1185 | INIT_LIST_HEAD(&p->list); |
| 1188 | mutex_lock(&kprobe_mutex); | 1186 | mutex_lock(&kprobe_mutex); |
| 1189 | 1187 | ||
| 1188 | jump_label_lock(); /* needed to call jump_label_text_reserved() */ | ||
| 1189 | |||
| 1190 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ | 1190 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ |
| 1191 | mutex_lock(&text_mutex); | 1191 | mutex_lock(&text_mutex); |
| 1192 | 1192 | ||
| @@ -1214,12 +1214,18 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
| 1214 | out: | 1214 | out: |
| 1215 | mutex_unlock(&text_mutex); | 1215 | mutex_unlock(&text_mutex); |
| 1216 | put_online_cpus(); | 1216 | put_online_cpus(); |
| 1217 | jump_label_unlock(); | ||
| 1217 | mutex_unlock(&kprobe_mutex); | 1218 | mutex_unlock(&kprobe_mutex); |
| 1218 | 1219 | ||
| 1219 | if (probed_mod) | 1220 | if (probed_mod) |
| 1220 | module_put(probed_mod); | 1221 | module_put(probed_mod); |
| 1221 | 1222 | ||
| 1222 | return ret; | 1223 | return ret; |
| 1224 | |||
| 1225 | fail_with_jump_label: | ||
| 1226 | preempt_enable(); | ||
| 1227 | jump_label_unlock(); | ||
| 1228 | return -EINVAL; | ||
| 1223 | } | 1229 | } |
| 1224 | EXPORT_SYMBOL_GPL(register_kprobe); | 1230 | EXPORT_SYMBOL_GPL(register_kprobe); |
| 1225 | 1231 | ||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/rmap.h> | 28 | #include <linux/rmap.h> |
| 29 | #include <linux/mmu_notifier.h> | 29 | #include <linux/mmu_notifier.h> |
| 30 | #include <linux/perf_event.h> | 30 | #include <linux/perf_event.h> |
| 31 | #include <linux/audit.h> | ||
| 31 | 32 | ||
| 32 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
| 33 | #include <asm/cacheflush.h> | 34 | #include <asm/cacheflush.h> |
| @@ -1108,6 +1109,7 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, | |||
| 1108 | unsigned long retval = -EBADF; | 1109 | unsigned long retval = -EBADF; |
| 1109 | 1110 | ||
| 1110 | if (!(flags & MAP_ANONYMOUS)) { | 1111 | if (!(flags & MAP_ANONYMOUS)) { |
| 1112 | audit_mmap_fd(fd, flags); | ||
| 1111 | if (unlikely(flags & MAP_HUGETLB)) | 1113 | if (unlikely(flags & MAP_HUGETLB)) |
| 1112 | return -EINVAL; | 1114 | return -EINVAL; |
| 1113 | file = fget(fd); | 1115 | file = fget(fd); |
diff --git a/mm/nommu.c b/mm/nommu.c index 30b5c20eec15..3613517c7592 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/personality.h> | 29 | #include <linux/personality.h> |
| 30 | #include <linux/security.h> | 30 | #include <linux/security.h> |
| 31 | #include <linux/syscalls.h> | 31 | #include <linux/syscalls.h> |
| 32 | #include <linux/audit.h> | ||
| 32 | 33 | ||
| 33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
| 34 | #include <asm/tlb.h> | 35 | #include <asm/tlb.h> |
| @@ -1458,6 +1459,7 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, | |||
| 1458 | struct file *file = NULL; | 1459 | struct file *file = NULL; |
| 1459 | unsigned long retval = -EBADF; | 1460 | unsigned long retval = -EBADF; |
| 1460 | 1461 | ||
| 1462 | audit_mmap_fd(fd, flags); | ||
| 1461 | if (!(flags & MAP_ANONYMOUS)) { | 1463 | if (!(flags & MAP_ANONYMOUS)) { |
| 1462 | file = fget(fd); | 1464 | file = fget(fd); |
| 1463 | if (!file) | 1465 | if (!file) |
