Merge branches 'misc', 'sa1100-for-next' and 'spectre' into for-linus
authorRussell King <rmk+kernel@armlinux.org.uk>
Wed, 2 Jan 2019 10:37:05 +0000 (10:37 +0000)
committerRussell King <rmk+kernel@armlinux.org.uk>
Wed, 2 Jan 2019 10:37:05 +0000 (10:37 +0000)
32 files changed:
arch/arm/common/sa1111.c
arch/arm/include/asm/cputype.h
arch/arm/include/asm/hardware/sa1111.h
arch/arm/include/asm/proc-fns.h
arch/arm/kernel/bugs.c
arch/arm/kernel/head-common.S
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/include/mach/mainstone.h
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-sa1100/Kconfig
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/h3100.c
arch/arm/mach-sa1100/jornada720.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mm/proc-macros.S
arch/arm/mm/proc-v7-bugs.c
arch/arm/mm/proc-v7.S
arch/arm/vfp/vfpmodule.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/max1600.c [new file with mode: 0644]
drivers/pcmcia/max1600.h [new file with mode: 0644]
drivers/pcmcia/pxa2xx_mainstone.c
drivers/pcmcia/sa1100_simpad.c
drivers/pcmcia/sa1111_jornada720.c
drivers/pcmcia/sa1111_lubbock.c
drivers/pcmcia/sa1111_neponset.c

index a2c8787..45412d2 100644 (file)
@@ -1282,65 +1282,6 @@ int sa1111_get_audio_rate(struct sa1111_dev *sadev)
 }
 EXPORT_SYMBOL(sa1111_get_audio_rate);
 
-void sa1111_set_io_dir(struct sa1111_dev *sadev,
-                      unsigned int bits, unsigned int dir,
-                      unsigned int sleep_dir)
-{
-       struct sa1111 *sachip = sa1111_chip_driver(sadev);
-       unsigned long flags;
-       unsigned int val;
-       void __iomem *gpio = sachip->base + SA1111_GPIO;
-
-#define MODIFY_BITS(port, mask, dir)           \
-       if (mask) {                             \
-               val = readl_relaxed(port);      \
-               val &= ~(mask);                 \
-               val |= (dir) & (mask);          \
-               writel_relaxed(val, port);      \
-       }
-
-       spin_lock_irqsave(&sachip->lock, flags);
-       MODIFY_BITS(gpio + SA1111_GPIO_PADDR, bits & 15, dir);
-       MODIFY_BITS(gpio + SA1111_GPIO_PBDDR, (bits >> 8) & 255, dir >> 8);
-       MODIFY_BITS(gpio + SA1111_GPIO_PCDDR, (bits >> 16) & 255, dir >> 16);
-
-       MODIFY_BITS(gpio + SA1111_GPIO_PASDR, bits & 15, sleep_dir);
-       MODIFY_BITS(gpio + SA1111_GPIO_PBSDR, (bits >> 8) & 255, sleep_dir >> 8);
-       MODIFY_BITS(gpio + SA1111_GPIO_PCSDR, (bits >> 16) & 255, sleep_dir >> 16);
-       spin_unlock_irqrestore(&sachip->lock, flags);
-}
-EXPORT_SYMBOL(sa1111_set_io_dir);
-
-void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v)
-{
-       struct sa1111 *sachip = sa1111_chip_driver(sadev);
-       unsigned long flags;
-       unsigned int val;
-       void __iomem *gpio = sachip->base + SA1111_GPIO;
-
-       spin_lock_irqsave(&sachip->lock, flags);
-       MODIFY_BITS(gpio + SA1111_GPIO_PADWR, bits & 15, v);
-       MODIFY_BITS(gpio + SA1111_GPIO_PBDWR, (bits >> 8) & 255, v >> 8);
-       MODIFY_BITS(gpio + SA1111_GPIO_PCDWR, (bits >> 16) & 255, v >> 16);
-       spin_unlock_irqrestore(&sachip->lock, flags);
-}
-EXPORT_SYMBOL(sa1111_set_io);
-
-void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v)
-{
-       struct sa1111 *sachip = sa1111_chip_driver(sadev);
-       unsigned long flags;
-       unsigned int val;
-       void __iomem *gpio = sachip->base + SA1111_GPIO;
-
-       spin_lock_irqsave(&sachip->lock, flags);
-       MODIFY_BITS(gpio + SA1111_GPIO_PASSR, bits & 15, v);
-       MODIFY_BITS(gpio + SA1111_GPIO_PBSSR, (bits >> 8) & 255, v >> 8);
-       MODIFY_BITS(gpio + SA1111_GPIO_PCSSR, (bits >> 16) & 255, v >> 16);
-       spin_unlock_irqrestore(&sachip->lock, flags);
-}
-EXPORT_SYMBOL(sa1111_set_sleep_io);
-
 /*
  * Individual device operations.
  */
index 0d28924..775cac3 100644 (file)
 #include <linux/kernel.h>
 
 extern unsigned int processor_id;
+struct proc_info_list *lookup_processor(u32 midr);
 
 #ifdef CONFIG_CPU_CP15
 #define read_cpuid(reg)                                                        \
index 798e520..d134b9a 100644 (file)
@@ -433,10 +433,6 @@ int sa1111_check_dma_bug(dma_addr_t addr);
 int sa1111_driver_register(struct sa1111_driver *);
 void sa1111_driver_unregister(struct sa1111_driver *);
 
-void sa1111_set_io_dir(struct sa1111_dev *sadev, unsigned int bits, unsigned int dir, unsigned int sleep_dir);
-void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v);
-void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v);
-
 struct sa1111_platform_data {
        int     irq_base;       /* base for cascaded on-chip IRQs */
        unsigned disable_devs;
index e25f439..e1b6f28 100644 (file)
@@ -23,7 +23,7 @@ struct mm_struct;
 /*
  * Don't change this structure - ASM code relies on it.
  */
-extern struct processor {
+struct processor {
        /* MISC
         * get data abort address/flags
         */
@@ -79,9 +79,13 @@ extern struct processor {
        unsigned int suspend_size;
        void (*do_suspend)(void *);
        void (*do_resume)(void *);
-} processor;
+};
 
 #ifndef MULTI_CPU
+static inline void init_proc_vtable(const struct processor *p)
+{
+}
+
 extern void cpu_proc_init(void);
 extern void cpu_proc_fin(void);
 extern int cpu_do_idle(void);
@@ -98,17 +102,50 @@ extern void cpu_reset(unsigned long addr, bool hvc) __attribute__((noreturn));
 extern void cpu_do_suspend(void *);
 extern void cpu_do_resume(void *);
 #else
-#define cpu_proc_init                  processor._proc_init
-#define cpu_proc_fin                   processor._proc_fin
-#define cpu_reset                      processor.reset
-#define cpu_do_idle                    processor._do_idle
-#define cpu_dcache_clean_area          processor.dcache_clean_area
-#define cpu_set_pte_ext                        processor.set_pte_ext
-#define cpu_do_switch_mm               processor.switch_mm
 
-/* These three are private to arch/arm/kernel/suspend.c */
-#define cpu_do_suspend                 processor.do_suspend
-#define cpu_do_resume                  processor.do_resume
+extern struct processor processor;
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+#include <linux/smp.h>
+/*
+ * This can't be a per-cpu variable because we need to access it before
+ * per-cpu has been initialised.  We have a couple of functions that are
+ * called in a pre-emptible context, and so can't use smp_processor_id()
+ * there, hence PROC_TABLE().  We insist in init_proc_vtable() that the
+ * function pointers for these are identical across all CPUs.
+ */
+extern struct processor *cpu_vtable[];
+#define PROC_VTABLE(f)                 cpu_vtable[smp_processor_id()]->f
+#define PROC_TABLE(f)                  cpu_vtable[0]->f
+static inline void init_proc_vtable(const struct processor *p)
+{
+       unsigned int cpu = smp_processor_id();
+       *cpu_vtable[cpu] = *p;
+       WARN_ON_ONCE(cpu_vtable[cpu]->dcache_clean_area !=
+                    cpu_vtable[0]->dcache_clean_area);
+       WARN_ON_ONCE(cpu_vtable[cpu]->set_pte_ext !=
+                    cpu_vtable[0]->set_pte_ext);
+}
+#else
+#define PROC_VTABLE(f)                 processor.f
+#define PROC_TABLE(f)                  processor.f
+static inline void init_proc_vtable(const struct processor *p)
+{
+       processor = *p;
+}
+#endif
+
+#define cpu_proc_init                  PROC_VTABLE(_proc_init)
+#define cpu_check_bugs                 PROC_VTABLE(check_bugs)
+#define cpu_proc_fin                   PROC_VTABLE(_proc_fin)
+#define cpu_reset                      PROC_VTABLE(reset)
+#define cpu_do_idle                    PROC_VTABLE(_do_idle)
+#define cpu_dcache_clean_area          PROC_TABLE(dcache_clean_area)
+#define cpu_set_pte_ext                        PROC_TABLE(set_pte_ext)
+#define cpu_do_switch_mm               PROC_VTABLE(switch_mm)
+
+/* These two are private to arch/arm/kernel/suspend.c */
+#define cpu_do_suspend                 PROC_VTABLE(do_suspend)
+#define cpu_do_resume                  PROC_VTABLE(do_resume)
 #endif
 
 extern void cpu_resume(void);
index 7be5113..d41d359 100644 (file)
@@ -6,8 +6,8 @@
 void check_other_bugs(void)
 {
 #ifdef MULTI_CPU
-       if (processor.check_bugs)
-               processor.check_bugs();
+       if (cpu_check_bugs)
+               cpu_check_bugs();
 #endif
 }
 
index 6e0375e..997b023 100644 (file)
@@ -145,6 +145,9 @@ __mmap_switched_data:
 #endif
        .size   __mmap_switched_data, . - __mmap_switched_data
 
+       __FINIT
+       .text
+
 /*
  * This provides a C-API version of __lookup_processor_type
  */
@@ -156,9 +159,6 @@ ENTRY(lookup_processor_type)
        ldmfd   sp!, {r4 - r6, r9, pc}
 ENDPROC(lookup_processor_type)
 
-       __FINIT
-       .text
-
 /*
  * Read processor ID register (CP#15, CR0), and look up in the linker-built
  * supported processor list.  Note that we can't use the absolute addresses
index ac7e088..375b13f 100644 (file)
@@ -114,6 +114,11 @@ EXPORT_SYMBOL(elf_hwcap2);
 
 #ifdef MULTI_CPU
 struct processor processor __ro_after_init;
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+struct processor *cpu_vtable[NR_CPUS] = {
+       [0] = &processor,
+};
+#endif
 #endif
 #ifdef MULTI_TLB
 struct cpu_tlb_fns cpu_tlb __ro_after_init;
@@ -666,28 +671,33 @@ static void __init smp_build_mpidr_hash(void)
 }
 #endif
 
-static void __init setup_processor(void)
+/*
+ * locate processor in the list of supported processor types.  The linker
+ * builds this table for us from the entries in arch/arm/mm/proc-*.S
+ */
+struct proc_info_list *lookup_processor(u32 midr)
 {
-       struct proc_info_list *list;
+       struct proc_info_list *list = lookup_processor_type(midr);
 
-       /*
-        * locate processor in the list of supported processor
-        * types.  The linker builds this table for us from the
-        * entries in arch/arm/mm/proc-*.S
-        */
-       list = lookup_processor_type(read_cpuid_id());
        if (!list) {
-               pr_err("CPU configuration botched (ID %08x), unable to continue.\n",
-                      read_cpuid_id());
-               while (1);
+               pr_err("CPU%u: configuration botched (ID %08x), CPU halted\n",
+                      smp_processor_id(), midr);
+               while (1)
+               /* can't use cpu_relax() here as it may require MMU setup */;
        }
 
+       return list;
+}
+
+static void __init setup_processor(void)
+{
+       unsigned int midr = read_cpuid_id();
+       struct proc_info_list *list = lookup_processor(midr);
+
        cpu_name = list->cpu_name;
        __cpu_architecture = __get_cpu_architecture();
 
-#ifdef MULTI_CPU
-       processor = *list->proc;
-#endif
+       init_proc_vtable(list->proc);
 #ifdef MULTI_TLB
        cpu_tlb = *list->tlb;
 #endif
@@ -699,7 +709,7 @@ static void __init setup_processor(void)
 #endif
 
        pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
-               cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
+               list->cpu_name, midr, midr & 15,
                proc_arch[cpu_architecture()], get_cr());
 
        snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
index f574a5e..3bf8223 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
+#include <asm/procinfo.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
@@ -102,6 +103,30 @@ static unsigned long get_arch_pgd(pgd_t *pgd)
 #endif
 }
 
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+static int secondary_biglittle_prepare(unsigned int cpu)
+{
+       if (!cpu_vtable[cpu])
+               cpu_vtable[cpu] = kzalloc(sizeof(*cpu_vtable[cpu]), GFP_KERNEL);
+
+       return cpu_vtable[cpu] ? 0 : -ENOMEM;
+}
+
+static void secondary_biglittle_init(void)
+{
+       init_proc_vtable(lookup_processor(read_cpuid_id())->proc);
+}
+#else
+static int secondary_biglittle_prepare(unsigned int cpu)
+{
+       return 0;
+}
+
+static void secondary_biglittle_init(void)
+{
+}
+#endif
+
 int __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
        int ret;
@@ -109,6 +134,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
        if (!smp_ops.smp_boot_secondary)
                return -ENOSYS;
 
+       ret = secondary_biglittle_prepare(cpu);
+       if (ret)
+               return ret;
+
        /*
         * We need to tell the secondary core where to find
         * its stack and the page tables.
@@ -359,6 +388,8 @@ asmlinkage void secondary_start_kernel(void)
        struct mm_struct *mm = &init_mm;
        unsigned int cpu;
 
+       secondary_biglittle_init();
+
        /*
         * The identity mapping is uncached (strongly ordered), so
         * switch away from it before attempting any exclusive accesses.
index 0853eb2..7298d07 100644 (file)
@@ -46,6 +46,7 @@ config ARCH_LUBBOCK
 
 config MACH_MAINSTONE
        bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
+       select GPIO_REG
        select PXA27x
 
 config MACH_ZYLONITE
index e82a7d3..474041a 100644 (file)
 #define MST_PCMCIA_PWR_VCC_33   0x8       /* voltage VCC = 3.3V */
 #define MST_PCMCIA_PWR_VCC_50   0x4       /* voltage VCC = 5.0V */
 
+#define MST_PCMCIA_INPUTS \
+       (MST_PCMCIA_nIRQ | MST_PCMCIA_nSPKR_BVD2 | MST_PCMCIA_nSTSCHG_BVD1 | \
+        MST_PCMCIA_nVS2 | MST_PCMCIA_nVS1 | MST_PCMCIA_nCD)
+
 /* board specific IRQs */
 #define MAINSTONE_NR_IRQS      IRQ_BOARD_START
 
index fe2ef9b..8e24455 100644 (file)
@@ -136,10 +136,26 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
        // no D+ pullup; lubbock can't connect/disconnect in software
 };
 
+/* GPIOs for SA1111 PCMCIA */
+static struct gpiod_lookup_table sa1111_pcmcia_gpio_table = {
+       .dev_id = "1800",
+       .table = {
+               { "sa1111", 0, "a0vpp", GPIO_ACTIVE_HIGH },
+               { "sa1111", 1, "a1vpp", GPIO_ACTIVE_HIGH },
+               { "sa1111", 2, "a0vcc", GPIO_ACTIVE_HIGH },
+               { "sa1111", 3, "a1vcc", GPIO_ACTIVE_HIGH },
+               { "lubbock", 14, "b0vcc", GPIO_ACTIVE_HIGH },
+               { "lubbock", 15, "b1vcc", GPIO_ACTIVE_HIGH },
+               { },
+       },
+};
+
 static void lubbock_init_pcmcia(void)
 {
        struct clk *clk;
 
+       gpiod_add_lookup_table(&sa1111_pcmcia_gpio_table);
+
        /* Add an alias for the SA1111 PCMCIA clock */
        clk = clk_get_sys("pxa2xx-pcmcia", NULL);
        if (!IS_ERR(clk)) {
index afd62a9..d40de19 100644 (file)
@@ -13,6 +13,7 @@
  *  published by the Free Software Foundation.
  */
 #include <linux/gpio.h>
+#include <linux/gpio/gpio-reg.h>
 #include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
@@ -507,12 +508,64 @@ static void __init mainstone_init_keypad(void)
 static inline void mainstone_init_keypad(void) {}
 #endif
 
+static int mst_pcmcia0_irqs[11] = {
+       [0 ... 10] = -1,
+       [5] = MAINSTONE_S0_CD_IRQ,
+       [8] = MAINSTONE_S0_STSCHG_IRQ,
+       [10] = MAINSTONE_S0_IRQ,
+};
+
+static int mst_pcmcia1_irqs[11] = {
+       [0 ... 10] = -1,
+       [5] = MAINSTONE_S1_CD_IRQ,
+       [8] = MAINSTONE_S1_STSCHG_IRQ,
+       [10] = MAINSTONE_S1_IRQ,
+};
+
+static struct gpiod_lookup_table mainstone_pcmcia_gpio_table = {
+       .dev_id = "pxa2xx-pcmcia",
+       .table = {
+               GPIO_LOOKUP("mst-pcmcia0",  0, "a0vpp",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia0",  1, "a1vpp",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia0",  2, "a0vcc",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia0",  3, "a1vcc",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia0",  4, "areset",  GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia0",  5, "adetect", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("mst-pcmcia0",  6, "avs1",    GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("mst-pcmcia0",  7, "avs2",    GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("mst-pcmcia0",  8, "abvd1",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia0",  9, "abvd2",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia0", 10, "aready",  GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1",  0, "b0vpp",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1",  1, "b1vpp",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1",  2, "b0vcc",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1",  3, "b1vcc",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1",  4, "breset",  GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1",  5, "bdetect", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("mst-pcmcia1",  6, "bvs1",    GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("mst-pcmcia1",  7, "bvs2",    GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("mst-pcmcia1",  8, "bbvd1",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1",  9, "bbvd2",   GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("mst-pcmcia1", 10, "bready",  GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init mainstone_init(void)
 {
        int SW7 = 0;  /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(mainstone_pin_config));
 
+       /* Register board control register(s) as GPIOs */
+       gpio_reg_init(NULL, (void __iomem *)&MST_PCMCIA0, -1, 11,
+                     "mst-pcmcia0", MST_PCMCIA_INPUTS, 0, NULL,
+                     NULL, mst_pcmcia0_irqs);
+       gpio_reg_init(NULL, (void __iomem *)&MST_PCMCIA1, -1, 11,
+                     "mst-pcmcia1", MST_PCMCIA_INPUTS, 0, NULL,
+                     NULL, mst_pcmcia1_irqs);
+       gpiod_add_lookup_table(&mainstone_pcmcia_gpio_table);
+
        pxa_set_ffuart_info(NULL);
        pxa_set_btuart_info(NULL);
        pxa_set_stuart_info(NULL);
index fde7ef1..af15ae5 100644 (file)
@@ -6,6 +6,7 @@ config SA1100_ASSABET
        bool "Assabet"
        select ARM_SA1110_CPUFREQ
        select GPIO_REG
+       select LEDS_GPIO_REGISTER
        select REGULATOR
        select REGULATOR_FIXED_VOLTAGE
        help
@@ -24,6 +25,7 @@ config ASSABET_NEPONSET
 config SA1100_CERF
        bool "CerfBoard"
        select ARM_SA1110_CPUFREQ
+       select LEDS_GPIO_REGISTER
        help
          The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
          More information is available at:
index 3e8c094..dfa4249 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/gpio/gpio-reg.h>
 #include <linux/gpio/machine.h>
+#include <linux/gpio_keys.h>
 #include <linux/ioport.h>
 #include <linux/platform_data/sa11x0-serial.h>
 #include <linux/regulator/fixed.h>
@@ -101,7 +102,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val)
 
        assabet_bcr_gc = gc;
 
-       return 0;
+       return gc->base;
 }
 
 /*
@@ -479,6 +480,49 @@ static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = {
        },
 };
 
+static struct gpio_led assabet_leds[] __initdata = {
+       {
+               .name = "assabet:red",
+               .default_trigger = "cpu0",
+               .active_low = 1,
+               .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+       }, {
+               .name = "assabet:green",
+               .default_trigger = "heartbeat",
+               .active_low = 1,
+               .default_state = LEDS_GPIO_DEFSTATE_KEEP,
+       },
+};
+
+static const struct gpio_led_platform_data assabet_leds_pdata __initconst = {
+       .num_leds = ARRAY_SIZE(assabet_leds),
+       .leds = assabet_leds,
+};
+
+static struct gpio_keys_button assabet_keys_buttons[] = {
+       {
+               .gpio = 0,
+               .irq = IRQ_GPIO0,
+               .desc = "gpio0",
+               .wakeup = 1,
+               .can_disable = 1,
+               .debounce_interval = 5,
+       }, {
+               .gpio = 1,
+               .irq = IRQ_GPIO1,
+               .desc = "gpio1",
+               .wakeup = 1,
+               .can_disable = 1,
+               .debounce_interval = 5,
+       },
+};
+
+static const struct gpio_keys_platform_data assabet_keys_pdata = {
+       .buttons = assabet_keys_buttons,
+       .nbuttons = ARRAY_SIZE(assabet_keys_buttons),
+       .rep = 0,
+};
+
 static void __init assabet_init(void)
 {
        /*
@@ -533,6 +577,13 @@ static void __init assabet_init(void)
 
        }
 
+       platform_device_register_resndata(NULL, "gpio-keys", 0,
+                                         NULL, 0,
+                                         &assabet_keys_pdata,
+                                         sizeof(assabet_keys_pdata));
+
+       gpio_led_register_device(-1, &assabet_leds_pdata);
+
 #ifndef ASSABET_PAL_VIDEO
        sa11x0_register_lcd(&lq039q2ds54_info);
 #else
@@ -726,92 +777,9 @@ static void __init assabet_map_io(void)
        sa1100_register_uart(2, 3);
 }
 
-/* LEDs */
-#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
-struct assabet_led {
-       struct led_classdev cdev;
-       u32 mask;
-};
-
-/*
- * The triggers lines up below will only be used if the
- * LED triggers are compiled in.
- */
-static const struct {
-       const char *name;
-       const char *trigger;
-} assabet_leds[] = {
-       { "assabet:red", "cpu0",},
-       { "assabet:green", "heartbeat", },
-};
-
-/*
- * The LED control in Assabet is reversed:
- *  - setting bit means turn off LED
- *  - clearing bit means turn on LED
- */
-static void assabet_led_set(struct led_classdev *cdev,
-               enum led_brightness b)
-{
-       struct assabet_led *led = container_of(cdev,
-                       struct assabet_led, cdev);
-
-       if (b != LED_OFF)
-               ASSABET_BCR_clear(led->mask);
-       else
-               ASSABET_BCR_set(led->mask);
-}
-
-static enum led_brightness assabet_led_get(struct led_classdev *cdev)
-{
-       struct assabet_led *led = container_of(cdev,
-                       struct assabet_led, cdev);
-
-       return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL;
-}
-
-static int __init assabet_leds_init(void)
-{
-       int i;
-
-       if (!machine_is_assabet())
-               return -ENODEV;
-
-       for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) {
-               struct assabet_led *led;
-
-               led = kzalloc(sizeof(*led), GFP_KERNEL);
-               if (!led)
-                       break;
-
-               led->cdev.name = assabet_leds[i].name;
-               led->cdev.brightness_set = assabet_led_set;
-               led->cdev.brightness_get = assabet_led_get;
-               led->cdev.default_trigger = assabet_leds[i].trigger;
-
-               if (!i)
-                       led->mask = ASSABET_BCR_LED_RED;
-               else
-                       led->mask = ASSABET_BCR_LED_GREEN;
-
-               if (led_classdev_register(NULL, &led->cdev) < 0) {
-                       kfree(led);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Since we may have triggers on any subsystem, defer registration
- * until after subsystem_init.
- */
-fs_initcall(assabet_leds_init);
-#endif
-
 void __init assabet_init_irq(void)
 {
+       unsigned int assabet_gpio_base;
        u32 def_val;
 
        sa1100_init_irq();
@@ -826,7 +794,10 @@ void __init assabet_init_irq(void)
         *
         * This must precede any driver calls to BCR_set() or BCR_clear().
         */
-       assabet_init_gpio((void *)&ASSABET_BCR, def_val);
+       assabet_gpio_base = assabet_init_gpio((void *)&ASSABET_BCR, def_val);
+
+       assabet_leds[0].gpio = assabet_gpio_base + 13;
+       assabet_leds[1].gpio = assabet_gpio_base + 14;
 }
 
 MACHINE_START(ASSABET, "Intel-Assabet")
index b2a4b41..88e5265 100644 (file)
@@ -89,18 +89,8 @@ static struct gpio_led_platform_data cerf_gpio_led_info = {
        .num_leds       = ARRAY_SIZE(cerf_gpio_leds),
 };
 
-static struct platform_device cerf_leds = {
-       .name   = "leds-gpio",
-       .id     = -1,
-       .dev    = {
-               .platform_data  = &cerf_gpio_led_info,
-       }
-};
-
-
 static struct platform_device *cerf_devices[] __initdata = {
        &cerfuart2_device,
-       &cerf_leds,
 };
 
 #ifdef CONFIG_SA1100_CERF_FLASH_32MB
@@ -176,6 +166,7 @@ static void __init cerf_init(void)
 {
        sa11x0_ppc_configure_mcp();
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
+       gpio_led_register_device(-1, &cerf_gpio_led_info);
        sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
        sa11x0_register_mcp(&cerf_mcp_data);
        sa11x0_register_pcmcia(1, &cerf_cf_gpio_table);
index 800321c..755290b 100644 (file)
@@ -235,18 +235,11 @@ void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
        sa11x0_register_device(&sa11x0fb_device, inf);
 }
 
-static bool sa11x0pcmcia_legacy = true;
-static struct platform_device sa11x0pcmcia_device = {
-       .name           = "sa11x0-pcmcia",
-       .id             = -1,
-};
-
 void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *table)
 {
        if (table)
                gpiod_add_lookup_table(table);
        platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0);
-       sa11x0pcmcia_legacy = false;
 }
 
 static struct platform_device sa11x0mtd_device = {
@@ -331,9 +324,6 @@ static int __init sa1100_init(void)
 {
        pm_power_off = sa1100_power_off;
 
-       if (sa11x0pcmcia_legacy)
-               platform_device_register(&sa11x0pcmcia_device);
-
        regulator_has_full_constraints();
 
        return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
index c6b4120..9dc5bcb 100644 (file)
@@ -126,6 +126,7 @@ static void __init h3100_mach_init(void)
 {
        h3xxx_mach_init();
 
+       sa11x0_register_pcmcia(-1, NULL);
        sa11x0_register_lcd(&h3100_lcd_info);
        sa11x0_register_irda(&h3100_irda_data);
 }
index 0a2ca9b..6298bad 100644 (file)
@@ -190,6 +190,17 @@ static struct platform_device s1d13xxxfb_device = {
        .resource       = s1d13xxxfb_resources,
 };
 
+static struct gpiod_lookup_table jornada_pcmcia_gpiod_table = {
+       .dev_id = "1800",
+       .table = {
+               GPIO_LOOKUP("sa1111", 0, "s0-power", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("sa1111", 1, "s1-power", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("sa1111", 2, "s0-3v", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("sa1111", 3, "s1-3v", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct resource sa1111_resources[] = {
        [0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
        [1] = DEFINE_RES_IRQ(IRQ_GPIO1),
@@ -265,6 +276,7 @@ static int __init jornada720_init(void)
                udelay(20);             /* give it some time to restart */
 
                gpiod_add_lookup_table(&jornada_ts_gpiod_table);
+               gpiod_add_lookup_table(&jornada_pcmcia_gpiod_table);
 
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
index b1823f4..eb60a71 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/err.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/gpio-reg.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
@@ -96,6 +97,19 @@ struct neponset_drvdata {
        struct gpio_chip *gpio[4];
 };
 
+static struct gpiod_lookup_table neponset_pcmcia_table = {
+       .dev_id = "1800",
+       .table = {
+               GPIO_LOOKUP("sa1111", 1, "a0vcc", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("sa1111", 0, "a1vcc", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("neponset-ncr", 5, "a0vpp", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("neponset-ncr", 6, "a1vpp", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("sa1111", 2, "b0vcc", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("sa1111", 3, "b1vcc", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct neponset_drvdata *nep;
 
 void neponset_ncr_frob(unsigned int mask, unsigned int val)
@@ -374,6 +388,8 @@ static int neponset_probe(struct platform_device *dev)
                           d->base + AUD_CTL, AUD_NGPIO, false,
                           neponset_aud_names);
 
+       gpiod_add_lookup_table(&neponset_pcmcia_table);
+
        /*
         * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
         * something on the Neponset activates this IRQ on sleep (eth?)
@@ -424,6 +440,9 @@ static int neponset_remove(struct platform_device *dev)
                platform_device_unregister(d->sa1111);
        if (!IS_ERR(d->smc91x))
                platform_device_unregister(d->smc91x);
+
+       gpiod_remove_lookup_table(&neponset_pcmcia_table);
+
        irq_set_chained_handler(irq, NULL);
        irq_free_descs(d->irq_base, NEP_IRQ_NR);
        nep = NULL;
index 81d0efb..5461d58 100644 (file)
        .endm
 
 .macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0, bugs=0
+/*
+ * If we are building for big.Little with branch predictor hardening,
+ * we need the processor function tables to remain available after boot.
+ */
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+       .section ".rodata"
+#endif
        .type   \name\()_processor_functions, #object
        .align 2
 ENTRY(\name\()_processor_functions)
@@ -309,6 +316,9 @@ ENTRY(\name\()_processor_functions)
        .endif
 
        .size   \name\()_processor_functions, . - \name\()_processor_functions
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+       .previous
+#endif
 .endm
 
 .macro define_cache_functions name:req
index 5544b82..9a07916 100644 (file)
@@ -52,8 +52,6 @@ static void cpu_v7_spectre_init(void)
        case ARM_CPU_PART_CORTEX_A17:
        case ARM_CPU_PART_CORTEX_A73:
        case ARM_CPU_PART_CORTEX_A75:
-               if (processor.switch_mm != cpu_v7_bpiall_switch_mm)
-                       goto bl_error;
                per_cpu(harden_branch_predictor_fn, cpu) =
                        harden_branch_predictor_bpiall;
                spectre_v2_method = "BPIALL";
@@ -61,8 +59,6 @@ static void cpu_v7_spectre_init(void)
 
        case ARM_CPU_PART_CORTEX_A15:
        case ARM_CPU_PART_BRAHMA_B15:
-               if (processor.switch_mm != cpu_v7_iciallu_switch_mm)
-                       goto bl_error;
                per_cpu(harden_branch_predictor_fn, cpu) =
                        harden_branch_predictor_iciallu;
                spectre_v2_method = "ICIALLU";
@@ -88,11 +84,9 @@ static void cpu_v7_spectre_init(void)
                                          ARM_SMCCC_ARCH_WORKAROUND_1, &res);
                        if ((int)res.a0 != 0)
                                break;
-                       if (processor.switch_mm != cpu_v7_hvc_switch_mm && cpu)
-                               goto bl_error;
                        per_cpu(harden_branch_predictor_fn, cpu) =
                                call_hvc_arch_workaround_1;
-                       processor.switch_mm = cpu_v7_hvc_switch_mm;
+                       cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
                        spectre_v2_method = "hypervisor";
                        break;
 
@@ -101,11 +95,9 @@ static void cpu_v7_spectre_init(void)
                                          ARM_SMCCC_ARCH_WORKAROUND_1, &res);
                        if ((int)res.a0 != 0)
                                break;
-                       if (processor.switch_mm != cpu_v7_smc_switch_mm && cpu)
-                               goto bl_error;
                        per_cpu(harden_branch_predictor_fn, cpu) =
                                call_smc_arch_workaround_1;
-                       processor.switch_mm = cpu_v7_smc_switch_mm;
+                       cpu_do_switch_mm = cpu_v7_smc_switch_mm;
                        spectre_v2_method = "firmware";
                        break;
 
@@ -119,11 +111,6 @@ static void cpu_v7_spectre_init(void)
        if (spectre_v2_method)
                pr_info("CPU%u: Spectre v2: using %s workaround\n",
                        smp_processor_id(), spectre_v2_method);
-       return;
-
-bl_error:
-       pr_err("CPU%u: Spectre v2: incorrect context switching function, system vulnerable\n",
-               cpu);
 }
 #else
 static void cpu_v7_spectre_init(void)
index 6fe5281..339eb17 100644 (file)
@@ -112,7 +112,7 @@ ENTRY(cpu_v7_hvc_switch_mm)
        hvc     #0
        ldmfd   sp!, {r0 - r3}
        b       cpu_v7_switch_mm
-ENDPROC(cpu_v7_smc_switch_mm)
+ENDPROC(cpu_v7_hvc_switch_mm)
 #endif
 ENTRY(cpu_v7_iciallu_switch_mm)
        mov     r3, #0
index aff6e6e..ee7b079 100644 (file)
@@ -573,7 +573,7 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp,
         */
        ufp_exc->fpexc = hwstate->fpexc;
        ufp_exc->fpinst = hwstate->fpinst;
-       ufp_exc->fpinst2 = ufp_exc->fpinst2;
+       ufp_exc->fpinst2 = hwstate->fpinst2;
 
        /* Ensure that VFP is disabled. */
        vfp_flush_hwstate(thread);
index cbbe4a2..d687a76 100644 (file)
@@ -63,6 +63,9 @@ config CARDBUS
 
          If unsure, say Y.
 
+config PCMCIA_MAX1600
+       tristate
+
 comment "PC-card bridges"
 
 config YENTA
@@ -191,6 +194,8 @@ config PCMCIA_SA1111
        select PCMCIA_SOC_COMMON
        select PCMCIA_SA11XX_BASE if ARCH_SA1100
        select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111
+       select PCMCIA_MAX1600 if ASSABET_NEPONSET
+       select PCMCIA_MAX1600 if ARCH_LUBBOCK && SA1111
        help
          Say Y  here to include support for SA1111-based PCMCIA or CF
          sockets, found on the Jornada 720, Graphicsmaster and other
@@ -207,6 +212,7 @@ config PCMCIA_PXA2XX
                    || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
                    || MACH_COLIBRI320 || MACH_H4700)
        select PCMCIA_SOC_COMMON
+       select PCMCIA_MAX1600 if MACH_MAINSTONE
        help
          Say Y here to include support for the PXA2xx PCMCIA controller
 
index 28502bd..01779c5 100644 (file)
@@ -35,6 +35,7 @@ obj-$(CONFIG_OMAP_CF)                         += omap_cf.o
 obj-$(CONFIG_AT91_CF)                          += at91_cf.o
 obj-$(CONFIG_ELECTRA_CF)                       += electra_cf.o
 obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD)          += db1xxx_ss.o
+obj-$(CONFIG_PCMCIA_MAX1600)                   += max1600.o
 
 sa1111_cs-y                                    += sa1111_generic.o
 sa1111_cs-$(CONFIG_ASSABET_NEPONSET)           += sa1111_neponset.o
diff --git a/drivers/pcmcia/max1600.c b/drivers/pcmcia/max1600.c
new file mode 100644 (file)
index 0000000..379875a
--- /dev/null
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MAX1600 PCMCIA power switch library
+ *
+ * Copyright (C) 2016 Russell King
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+#include "max1600.h"
+
+static const char *max1600_gpio_name[2][MAX1600_GPIO_MAX] = {
+       { "a0vcc", "a1vcc", "a0vpp", "a1vpp" },
+       { "b0vcc", "b1vcc", "b0vpp", "b1vpp" },
+};
+
+int max1600_init(struct device *dev, struct max1600 **ptr,
+       unsigned int channel, unsigned int code)
+{
+       struct max1600 *m;
+       int chan;
+       int i;
+
+       switch (channel) {
+       case MAX1600_CHAN_A:
+               chan = 0;
+               break;
+       case MAX1600_CHAN_B:
+               chan = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (code != MAX1600_CODE_LOW && code != MAX1600_CODE_HIGH)
+               return -EINVAL;
+
+       m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL);
+       if (!m)
+               return -ENOMEM;
+
+       m->dev = dev;
+       m->code = code;
+
+       for (i = 0; i < MAX1600_GPIO_MAX; i++) {
+               const char *name;
+
+               name = max1600_gpio_name[chan][i];
+               if (i != MAX1600_GPIO_0VPP) {
+                       m->gpio[i] = devm_gpiod_get(dev, name, GPIOD_OUT_LOW);
+               } else {
+                       m->gpio[i] = devm_gpiod_get_optional(dev, name,
+                                                            GPIOD_OUT_LOW);
+                       if (!m->gpio[i])
+                               break;
+               }
+               if (IS_ERR(m->gpio[i]))
+                       return PTR_ERR(m->gpio[i]);
+       }
+
+       *ptr = m;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max1600_init);
+
+int max1600_configure(struct max1600 *m, unsigned int vcc, unsigned int vpp)
+{
+       DECLARE_BITMAP(values, MAX1600_GPIO_MAX) = { 0, };
+       int n = MAX1600_GPIO_0VPP;
+
+       if (m->gpio[MAX1600_GPIO_0VPP]) {
+               if (vpp == 0) {
+                       __assign_bit(MAX1600_GPIO_0VPP, values, 0);
+                       __assign_bit(MAX1600_GPIO_1VPP, values, 0);
+               } else if (vpp == 120) {
+                       __assign_bit(MAX1600_GPIO_0VPP, values, 0);
+                       __assign_bit(MAX1600_GPIO_1VPP, values, 1);
+               } else if (vpp == vcc) {
+                       __assign_bit(MAX1600_GPIO_0VPP, values, 1);
+                       __assign_bit(MAX1600_GPIO_1VPP, values, 0);
+               } else {
+                       dev_err(m->dev, "unrecognised Vpp %u.%uV\n",
+                               vpp / 10, vpp % 10);
+                       return -EINVAL;
+               }
+               n = MAX1600_GPIO_MAX;
+       } else if (vpp != vcc && vpp != 0) {
+               dev_err(m->dev, "no VPP control\n");
+               return -EINVAL;
+       }
+
+       if (vcc == 0) {
+               __assign_bit(MAX1600_GPIO_0VCC, values, 0);
+               __assign_bit(MAX1600_GPIO_1VCC, values, 0);
+       } else if (vcc == 33) { /* VY */
+               __assign_bit(MAX1600_GPIO_0VCC, values, 1);
+               __assign_bit(MAX1600_GPIO_1VCC, values, 0);
+       } else if (vcc == 50) { /* VX */
+               __assign_bit(MAX1600_GPIO_0VCC, values, 0);
+               __assign_bit(MAX1600_GPIO_1VCC, values, 1);
+       } else {
+               dev_err(m->dev, "unrecognised Vcc %u.%uV\n",
+                       vcc / 10, vcc % 10);
+               return -EINVAL;
+       }
+
+       if (m->code == MAX1600_CODE_HIGH) {
+               /*
+                * Cirrus mode appears to be the same as Intel mode,
+                * except the VCC pins are inverted.
+                */
+               __change_bit(MAX1600_GPIO_0VCC, values);
+               __change_bit(MAX1600_GPIO_1VCC, values);
+       }
+
+       return gpiod_set_array_value_cansleep(n, m->gpio, NULL, values);
+}
+EXPORT_SYMBOL_GPL(max1600_configure);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pcmcia/max1600.h b/drivers/pcmcia/max1600.h
new file mode 100644 (file)
index 0000000..00bf1a0
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef MAX1600_H
+#define MAX1600_H
+
+struct gpio_desc;
+
+enum {
+       MAX1600_GPIO_0VCC = 0,
+       MAX1600_GPIO_1VCC,
+       MAX1600_GPIO_0VPP,
+       MAX1600_GPIO_1VPP,
+       MAX1600_GPIO_MAX,
+
+       MAX1600_CHAN_A,
+       MAX1600_CHAN_B,
+
+       MAX1600_CODE_LOW,
+       MAX1600_CODE_HIGH,
+};
+
+struct max1600 {
+       struct gpio_desc *gpio[MAX1600_GPIO_MAX];
+       struct device *dev;
+       unsigned int code;
+};
+
+int max1600_init(struct device *dev, struct max1600 **ptr,
+       unsigned int channel, unsigned int code);
+
+int max1600_configure(struct max1600 *, unsigned int vcc, unsigned int vpp);
+
+#endif
index 7e32e25..770c7bf 100644 (file)
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/interrupt.h>
 #include <linux/platform_device.h>
 
 #include <pcmcia/ss.h>
 
 #include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <mach/pxa2xx-regs.h>
-#include <mach/mainstone.h>
 
 #include "soc_common.h"
-
+#include "max1600.h"
 
 static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       /*
-        * Setup default state of GPIO outputs
-        * before we enable them as outputs.
-        */
-       if (skt->nr == 0) {
-               skt->socket.pci_irq = MAINSTONE_S0_IRQ;
-               skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ;
-               skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
-               skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ;
-               skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
-       } else {
-               skt->socket.pci_irq = MAINSTONE_S1_IRQ;
-               skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ;
-               skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
-               skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ;
-               skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
-       }
-       return 0;
+       struct device *dev = skt->socket.dev.parent;
+       struct max1600 *m;
+       int ret;
+
+       skt->stat[SOC_STAT_CD].name = skt->nr ? "bdetect" : "adetect";
+       skt->stat[SOC_STAT_BVD1].name = skt->nr ? "bbvd1" : "abvd1";
+       skt->stat[SOC_STAT_BVD2].name = skt->nr ? "bbvd2" : "abvd2";
+       skt->stat[SOC_STAT_RDY].name = skt->nr ? "bready" : "aready";
+       skt->stat[SOC_STAT_VS1].name = skt->nr ? "bvs1" : "avs1";
+       skt->stat[SOC_STAT_VS2].name = skt->nr ? "bvs2" : "avs2";
+
+       skt->gpio_reset = devm_gpiod_get(dev, skt->nr ? "breset" : "areset",
+                                        GPIOD_OUT_HIGH);
+       if (IS_ERR(skt->gpio_reset))
+               return PTR_ERR(skt->gpio_reset);
+
+       ret = max1600_init(dev, &m, skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
+                          MAX1600_CODE_HIGH);
+       if (ret)
+               return ret;
+
+       skt->driver_data = m;
+
+       return soc_pcmcia_request_gpiods(skt);
 }
 
-static unsigned long mst_pcmcia_status[2];
+static unsigned int mst_pcmcia_bvd1_status[2];
 
 static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                    struct pcmcia_state *state)
 {
-       unsigned long status, flip;
-
-       status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1;
-       flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1;
+       unsigned int flip = mst_pcmcia_bvd1_status[skt->nr] ^ state->bvd1;
 
        /*
         * Workaround for STSCHG which can't be deasserted:
@@ -68,62 +67,18 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
         * as needed to avoid IRQ locks.
         */
        if (flip) {
-               mst_pcmcia_status[skt->nr] = status;
-               if (status & MST_PCMCIA_nSTSCHG_BVD1)
-                       enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
-                                                  : MAINSTONE_S1_STSCHG_IRQ );
+               mst_pcmcia_bvd1_status[skt->nr] = state->bvd1;
+               if (state->bvd1)
+                       enable_irq(skt->stat[SOC_STAT_BVD1].irq);
                else
-                       disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
-                                                   : MAINSTONE_S1_STSCHG_IRQ );
+                       disable_irq(skt->stat[SOC_STAT_BVD2].irq);
        }
-
-       state->detect = (status & MST_PCMCIA_nCD) ? 0 : 1;
-       state->ready  = (status & MST_PCMCIA_nIRQ) ? 1 : 0;
-       state->bvd1   = (status & MST_PCMCIA_nSTSCHG_BVD1) ? 1 : 0;
-       state->bvd2   = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0;
-       state->vs_3v  = (status & MST_PCMCIA_nVS1) ? 0 : 1;
-       state->vs_Xv  = (status & MST_PCMCIA_nVS2) ? 0 : 1;
 }
 
 static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                                       const socket_state_t *state)
 {
-       unsigned long power = 0;
-       int ret = 0;
-
-       switch (state->Vcc) {
-       case 0:  power |= MST_PCMCIA_PWR_VCC_0;  break;
-       case 33: power |= MST_PCMCIA_PWR_VCC_33; break;
-       case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
-       default:
-                printk(KERN_ERR "%s(): bad Vcc %u\n",
-                                __func__, state->Vcc);
-                ret = -1;
-       }
-
-       switch (state->Vpp) {
-       case 0:   power |= MST_PCMCIA_PWR_VPP_0;   break;
-       case 120: power |= MST_PCMCIA_PWR_VPP_120; break;
-       default:
-                 if(state->Vpp == state->Vcc) {
-                         power |= MST_PCMCIA_PWR_VPP_VCC;
-                 } else {
-                         printk(KERN_ERR "%s(): bad Vpp %u\n",
-                                         __func__, state->Vpp);
-                         ret = -1;
-                 }
-       }
-
-       if (state->flags & SS_RESET)
-              power |= MST_PCMCIA_RESET;
-
-       switch (skt->nr) {
-       case 0:  MST_PCMCIA0 = power; break;
-       case 1:  MST_PCMCIA1 = power; break;
-       default: ret = -1;
-       }
-
-       return ret;
+       return max1600_configure(skt->driver_data, state->Vcc, state->Vpp);
 }
 
 static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
index e235ee1..e2e8729 100644 (file)
@@ -39,8 +39,8 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 {
        long cs3reg = simpad_get_cs3_ro();
 
-       state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */
-       state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */
+       /* bvd1 might be cs3reg & PCMCIA_BVD1 */
+       /* bvd2 might be cs3reg & PCMCIA_BVD2 */
 
        if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
                        (PCMCIA_VS1|PCMCIA_VS2)) {
index 3d4ca87..1083e1b 100644 (file)
@@ -6,29 +6,62 @@
  *
  */
 #include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/hardware/sa1111.h>
 #include <asm/mach-types.h>
 
 #include "sa1111_generic.h"
 
-/* Does SOCKET1_3V actually do anything? */
-#define SOCKET0_POWER  GPIO_GPIO0
-#define SOCKET0_3V     GPIO_GPIO2
-#define SOCKET1_POWER  (GPIO_GPIO1 | GPIO_GPIO3)
-#define SOCKET1_3V     GPIO_GPIO3
+/*
+ * Socket 0 power: GPIO A0
+ * Socket 0 3V: GPIO A2
+ * Socket 1 power: GPIO A1 & GPIO A3
+ * Socket 1 3V: GPIO A3
+ * Does Socket 1 3V actually do anything?
+ */
+enum {
+       J720_GPIO_PWR,
+       J720_GPIO_3V,
+       J720_GPIO_MAX,
+};
+struct jornada720_data {
+       struct gpio_desc *gpio[J720_GPIO_MAX];
+};
+
+static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+       struct device *dev = skt->socket.dev.parent;
+       struct jornada720_data *j;
+
+       j = devm_kzalloc(dev, sizeof(*j), GFP_KERNEL);
+       if (!j)
+               return -ENOMEM;
+
+       j->gpio[J720_GPIO_PWR] = devm_gpiod_get(dev, skt->nr ? "s1-power" :
+                                               "s0-power", GPIOD_OUT_LOW);
+       if (IS_ERR(j->gpio[J720_GPIO_PWR]))
+               return PTR_ERR(j->gpio[J720_GPIO_PWR]);
+
+       j->gpio[J720_GPIO_3V] = devm_gpiod_get(dev, skt->nr ? "s1-3v" :
+                                              "s0-3v", GPIOD_OUT_LOW);
+       if (IS_ERR(j->gpio[J720_GPIO_3V]))
+               return PTR_ERR(j->gpio[J720_GPIO_3V]);
+
+       skt->driver_data = j;
+
+       return 0;
+}
 
 static int
 jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
 {
-       struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned int pa_dwr_mask, pa_dwr_set;
+       struct jornada720_data *j = skt->driver_data;
+       DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
        int ret;
 
        printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
@@ -36,35 +69,34 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
 
        switch (skt->nr) {
        case 0:
-               pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
-
                switch (state->Vcc) {
                default:
                case  0:
-                       pa_dwr_set = 0;
+                       __assign_bit(J720_GPIO_PWR, values, 0);
+                       __assign_bit(J720_GPIO_3V, values, 0);
                        break;
                case 33:
-                       pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
+                       __assign_bit(J720_GPIO_PWR, values, 1);
+                       __assign_bit(J720_GPIO_3V, values, 1);
                        break;
                case 50:
-                       pa_dwr_set = SOCKET0_POWER;
+                       __assign_bit(J720_GPIO_PWR, values, 1);
+                       __assign_bit(J720_GPIO_3V, values, 0);
                        break;
                }
                break;
 
        case 1:
-               pa_dwr_mask = SOCKET1_POWER;
-
                switch (state->Vcc) {
                default:
                case 0:
-                       pa_dwr_set = 0;
+                       __assign_bit(J720_GPIO_PWR, values, 0);
+                       __assign_bit(J720_GPIO_3V, values, 0);
                        break;
                case 33:
-                       pa_dwr_set = SOCKET1_POWER;
-                       break;
                case 50:
-                       pa_dwr_set = SOCKET1_POWER;
+                       __assign_bit(J720_GPIO_PWR, values, 1);
+                       __assign_bit(J720_GPIO_3V, values, 1);
                        break;
                }
                break;
@@ -81,13 +113,15 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
 
        ret = sa1111_pcmcia_configure_socket(skt, state);
        if (ret == 0)
-               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+               ret = gpiod_set_array_value_cansleep(J720_GPIO_MAX, j->gpio,
+                                                    NULL, values);
 
        return ret;
 }
 
 static struct pcmcia_low_level jornada720_pcmcia_ops = {
        .owner                  = THIS_MODULE,
+       .hw_init                = jornada720_pcmcia_hw_init,
        .configure_socket       = jornada720_pcmcia_configure_socket,
        .first                  = 0,
        .nr                     = 2,
@@ -95,16 +129,9 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = {
 
 int pcmcia_jornada720_init(struct sa1111_dev *sadev)
 {
-       unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
-
        /* Fixme: why messing around with SA11x0's GPIO1? */
        GRER |= 0x00000002;
 
-       /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
-       sa1111_set_io_dir(sadev, pin, 0, 0);
-       sa1111_set_io(sadev, pin, 0);
-       sa1111_set_sleep_io(sadev, pin, 0);
-
        sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
        return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
                                 sa11xx_drv_pcmcia_add_one);
index e741f49..e3fc14c 100644 (file)
 #include <mach/hardware.h>
 #include <asm/hardware/sa1111.h>
 #include <asm/mach-types.h>
-#include <mach/lubbock.h>
 
 #include "sa1111_generic.h"
+#include "max1600.h"
+
+static int lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+       struct max1600 *m;
+       int ret;
+
+       ret = max1600_init(skt->socket.dev.parent, &m,
+                          skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
+                          MAX1600_CODE_HIGH);
+       if (ret == 0)
+               skt->driver_data = m;
+
+       return ret;
+}
 
 static int
 lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                                const socket_state_t *state)
 {
-       struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
+       struct max1600 *m = skt->driver_data;
        int ret = 0;
 
-       pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
-
        /* Lubbock uses the Maxim MAX1602, with the following connections:
         *
         * Socket 0 (PCMCIA):
@@ -71,74 +82,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
  again:
        switch (skt->nr) {
        case 0:
-               pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
-
-               switch (state->Vcc) {
-               case 0: /* Hi-Z */
-                       break;
-
-               case 33: /* VY */
-                       pa_dwr_set |= GPIO_A3;
-                       break;
-
-               case 50: /* VX */
-                       pa_dwr_set |= GPIO_A2;
-                       break;
-
-               default:
-                       printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                              __func__, state->Vcc);
-                       ret = -1;
-               }
-
-               switch (state->Vpp) {
-               case 0: /* Hi-Z */
-                       break;
-
-               case 120: /* 12IN */
-                       pa_dwr_set |= GPIO_A1;
-                       break;
-
-               default: /* VCC */
-                       if (state->Vpp == state->Vcc)
-                               pa_dwr_set |= GPIO_A0;
-                       else {
-                               printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
-                                      __func__, state->Vpp);
-                               ret = -1;
-                               break;
-                       }
-               }
-               break;
-
        case 1:
-               misc_mask = (1 << 15) | (1 << 14);
-
-               switch (state->Vcc) {
-               case 0: /* Hi-Z */
-                       break;
-
-               case 33: /* VY */
-                       misc_set |= 1 << 15;
-                       break;
-
-               case 50: /* VX */
-                       misc_set |= 1 << 14;
-                       break;
-
-               default:
-                       printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                              __func__, state->Vcc);
-                       ret = -1;
-                       break;
-               }
-
-               if (state->Vpp != state->Vcc && state->Vpp != 0) {
-                       printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
-                              __func__, state->Vpp);
-                       ret = -1;
-                       break;
-               }
                break;
 
        default:
@@ -147,11 +91,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
        if (ret == 0)
                ret = sa1111_pcmcia_configure_socket(skt, state);
-
-       if (ret == 0) {
-               lubbock_set_misc_wr(misc_mask, misc_set);
-               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-       }
+       if (ret == 0)
+               ret = max1600_configure(m, state->Vcc, state->Vpp);
 
 #if 1
        if (ret == 0 && state->Vcc == 33) {
@@ -175,8 +116,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                        /*
                         * Switch to 5V,  Configure socket with 5V voltage
                         */
-                       lubbock_set_misc_wr(misc_mask, 0);
-                       sa1111_set_io(s->dev, pa_dwr_mask, 0);
+                       max1600_configure(m, 0, 0);
 
                        /*
                         * It takes about 100ms to turn off Vcc.
@@ -201,6 +141,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
 static struct pcmcia_low_level lubbock_pcmcia_ops = {
        .owner                  = THIS_MODULE,
+       .hw_init                = lubbock_pcmcia_hw_init,
        .configure_socket       = lubbock_pcmcia_configure_socket,
        .first                  = 0,
        .nr                     = 2,
@@ -210,17 +151,6 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = {
 
 int pcmcia_lubbock_init(struct sa1111_dev *sadev)
 {
-       /*
-        * Set GPIO_A<3:0> to be outputs for the MAX1600,
-        * and switch to standby mode.
-        */
-       sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
-       sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-       sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-
-       /* Set CF Socket 1 power to standby mode. */
-       lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
-
        pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
        pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops);
        return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
index 0ccf05a..de0ce13 100644 (file)
 #include <linux/errno.h>
 #include <linux/init.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <mach/neponset.h>
-#include <asm/hardware/sa1111.h>
 
 #include "sa1111_generic.h"
+#include "max1600.h"
 
 /*
  * Neponset uses the Maxim MAX1600, with the following connections:
  * "Standard Intel code" mode. Refer to the Maxim data sheet for
  * the corresponding truth table.
  */
-
-static int
-neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+static int neponset_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
+       struct max1600 *m;
        int ret;
 
-       switch (skt->nr) {
-       case 0:
-               pa_dwr_mask = GPIO_A0 | GPIO_A1;
-               ncr_mask = NCR_A0VPP | NCR_A1VPP;
-
-               if (state->Vpp == 0)
-                       ncr_set = 0;
-               else if (state->Vpp == 120)
-                       ncr_set = NCR_A1VPP;
-               else if (state->Vpp == state->Vcc)
-                       ncr_set = NCR_A0VPP;
-               else {
-                       printk(KERN_ERR "%s(): unrecognized VPP %u\n",
-                              __func__, state->Vpp);
-                       return -1;
-               }
-               break;
-
-       case 1:
-               pa_dwr_mask = GPIO_A2 | GPIO_A3;
-               ncr_mask = 0;
-               ncr_set = 0;
-
-               if (state->Vpp != state->Vcc && state->Vpp != 0) {
-                       printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
-                              __func__, state->Vpp);
-                       return -1;
-               }
-               break;
+       ret = max1600_init(skt->socket.dev.parent, &m,
+                          skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
+                          MAX1600_CODE_LOW);
+       if (ret == 0)
+               skt->driver_data = m;
 
-       default:
-               return -1;
-       }
+       return ret;
+}
 
-       /*
-        * pa_dwr_set is the mask for selecting Vcc on both sockets.
-        * pa_dwr_mask selects which bits (and therefore socket) we change.
-        */
-       switch (state->Vcc) {
-       default:
-       case 0:  pa_dwr_set = 0;                break;
-       case 33: pa_dwr_set = GPIO_A1|GPIO_A2;  break;
-       case 50: pa_dwr_set = GPIO_A0|GPIO_A3;  break;
-       }
+static int
+neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+       struct max1600 *m = skt->driver_data;
+       int ret;
 
        ret = sa1111_pcmcia_configure_socket(skt, state);
-       if (ret == 0) {
-               neponset_ncr_frob(ncr_mask, ncr_set);
-               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-       }
+       if (ret == 0)
+               ret = max1600_configure(m, state->Vcc, state->Vpp);
 
        return ret;
 }
 
 static struct pcmcia_low_level neponset_pcmcia_ops = {
        .owner                  = THIS_MODULE,
+       .hw_init                = neponset_pcmcia_hw_init,
        .configure_socket       = neponset_pcmcia_configure_socket,
        .first                  = 0,
        .nr                     = 2,
@@ -111,13 +75,6 @@ static struct pcmcia_low_level neponset_pcmcia_ops = {
 
 int pcmcia_neponset_init(struct sa1111_dev *sadev)
 {
-       /*
-        * Set GPIO_A<3:0> to be outputs for the MAX1600,
-        * and switch to standby mode.
-        */
-       sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
-       sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-       sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
        sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
        return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
                                 sa11xx_drv_pcmcia_add_one);