diff options
Diffstat (limited to 'target')
| -rw-r--r-- | target/linux/cns3xxx/base-files/lib/cns3xxx.sh | 22 | ||||
| -rw-r--r-- | target/linux/cns3xxx/base-files/lib/upgrade/platform.sh | 122 | ||||
| -rw-r--r-- | target/linux/cns3xxx/image/Makefile | 19 | ||||
| -rw-r--r-- | target/linux/cns3xxx/patches-3.3/300-laguna_support.patch | 18 | ||||
| -rw-r--r-- | target/linux/cns3xxx/patches-3.3/470-gpio_irq.patch | 536 | 
5 files changed, 712 insertions, 5 deletions
| diff --git a/target/linux/cns3xxx/base-files/lib/cns3xxx.sh b/target/linux/cns3xxx/base-files/lib/cns3xxx.sh new file mode 100644 index 000000000..d446777c0 --- /dev/null +++ b/target/linux/cns3xxx/base-files/lib/cns3xxx.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Copyright (C) 2012 OpenWrt.org +# + +cns3xxx_board_name() { +        local machine +        local name + +        machine=$(awk 'BEGIN{FS="[ \t]+:[ \t]"} /Hardware/ {print $2}' /proc/cpuinfo) + +        case "$machine" in +		"Gateworks Corporation Laguna"*) +			name="laguna" +			;; +		*) +			name="generic"; +			;; +	esac +	 +	echo $name +} diff --git a/target/linux/cns3xxx/base-files/lib/upgrade/platform.sh b/target/linux/cns3xxx/base-files/lib/upgrade/platform.sh new file mode 100644 index 000000000..599099181 --- /dev/null +++ b/target/linux/cns3xxx/base-files/lib/upgrade/platform.sh @@ -0,0 +1,122 @@ +. /lib/cns3xxx.sh + +RAMFS_COPY_DATA="/lib/cns3xxx.sh" + +CI_BLKSZ=65536 + +platform_find_partitions() { +	local first dev size erasesize name +	while read dev size erasesize name; do +		name=${name#'"'}; name=${name%'"'} +		case "$name" in +			vmlinux.bin.l7|kernel|linux|rootfs) +				if [ -z "$first" ]; then +					first="$name" +				else +					echo "$erasesize:$first:$name" +					break +				fi +			;; +		esac +	done < /proc/mtd +} + +platform_find_kernelpart() { +	local part +	for part in "${1%:*}" "${1#*:}"; do +		case "$part" in +			vmlinux.bin.l7|kernel|linux) +				echo "$part" +				break +			;; +		esac +	done +} + +platform_do_upgrade_combined() { +	local partitions=$(platform_find_partitions) +	local kernelpart=$(platform_find_kernelpart "${partitions#*:}") +	local erase_size=$((0x${partitions%%:*})); partitions="${partitions#*:}" +	local kern_length=0x$(dd if="$1" bs=2 skip=1 count=4 2>/dev/null) +	local kern_blocks=$(($kern_length / $CI_BLKSZ)) +	local root_blocks=$((0x$(dd if="$1" bs=2 skip=5 count=4 2>/dev/null) / $CI_BLKSZ)) + +	v "platform_do_upgrade_combined" +	v "partitions=$partitions" +	v "kernelpart=$kernelpart" +	v "erase_size=$erase_size"  +	v "kern_blocks=$kern_blocks" +	v "root_blocks=$root_blocks" + +	if [ -n "$partitions" ] && [ -n "$kernelpart" ] && \ +	   [ ${kern_blocks:-0} -gt 0 ] && \ +	   [ ${root_blocks:-0} -gt 0 ] && \ +	   [ ${erase_size:-0} -gt 0 ]; +	then +		local append="" +		[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 ] && append="-j $CONF_TAR" + +		dd if="$1" bs=$CI_BLKSZ skip=1 count=$kern_blocks 2>/dev/null | mtd write - kernel +		dd if="$1" bs=$CI_BLKSZ skip=$((1+$kern_blocks)) count=$root_blocks 2>/dev/null | \ +				 mtd -r $append write - rootfs +	else +		echo "invalid image" +	fi +} + +platform_check_image() { +	local board=$(cns3xxx_board_name) +	local magic="$(get_magic_word "$1")" +	local magic_long="$(get_magic_long "$1")" + +	[ "$ARGC" -gt 1 ] && return 1 + +	case "$board" in +	laguna) +		[ "$magic" != "4349" ] && { +			echo "Invalid image. Use *-sysupgrade.bin files on this board" +			return 1 +		} + +		local md5_img=$(dd if="$1" bs=2 skip=9 count=16 2>/dev/null) +		local md5_chk=$(dd if="$1" bs=$CI_BLKSZ skip=1 2>/dev/null | md5sum -); md5_chk="${md5_chk%% *}" + +		if [ -n "$md5_img" -a -n "$md5_chk" ] && [ "$md5_img" = "$md5_chk" ]; then +			return 0 +		else +			echo "Invalid image. Contents do not match checksum (image:$md5_img calculated:$md5_chk)" +			return 1 +		fi +		return 0 +		;; +	esac + +	echo "Sysupgrade is not yet supported on $board." +	return 1 +} + +platform_do_upgrade() { +	local board=$(cns3xxx_board_name) + +	v "board=$board" +	case "$board" in +	laguna) +		platform_do_upgrade_combined "$ARGV" +		;; +	*) +		default_do_upgrade "$ARGV" +		;; +	esac +} + +disable_watchdog() { +	v "killing watchdog" +	killall watchdog +	( ps | grep -v 'grep' | grep '/dev/watchdog' ) && { +		echo 'Could not disable watchdog' +		return 1 +	} +} + +# CONFIG_WATCHDOG_NOWAYOUT=y - can't kill watchdog unless kernel cmdline has a mpcore_wdt.nowayout=0 +#append sysupgrade_pre_upgrade disable_watchdog diff --git a/target/linux/cns3xxx/image/Makefile b/target/linux/cns3xxx/image/Makefile index 271d5ea19..05a0f4f7a 100644 --- a/target/linux/cns3xxx/image/Makefile +++ b/target/linux/cns3xxx/image/Makefile @@ -21,21 +21,32 @@ define Image/BuildKernel  	cp $(KDIR)/uImage-new $(BIN_DIR)/openwrt-$(BOARD)-uImage  endef +# Build sysupgrade image +define BuildFirmware/Generic +	dd if=$(BIN_DIR)/openwrt-$(BOARD)-uImage of=$(KDIR)/uImage.pad bs=64k conv=sync; \ +	dd if=$(KDIR)/root.$(1) of=$(KDIR)/root.$(1).pad bs=128k conv=sync; \ +	sh $(TOPDIR)/scripts/combined-image.sh \ +		$(KDIR)/uImage.pad \ +		$(KDIR)/root.$(1).pad \ +		$(BIN_DIR)/$(IMG_PREFIX)-$(patsubst jffs2-%,jffs2,$(patsubst squashfs-%,squashfs,$(1)))-sysupgrade.bin +endef +  define Image/Build  	$(call Image/Build/$(1),$(1)) +	$(call BuildFirmware/Generic,$(1))  endef  define Image/Build/jffs2-64k -	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=65536 conv=sync +	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=64k conv=sync  endef  define Image/Build/jffs2-128k -	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=131072 conv=sync +	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=128k conv=sync  endef  define Image/Build/squashfs -	$(call prepare_generic_squashfs,$(KDIR)/root.squashfs) -	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=131072 conv=sync +	$(call prepare_generic_squashfs,$(KDIR)/root.$(1)) +	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=128k conv=sync  endef  $(eval $(call BuildImage)) diff --git a/target/linux/cns3xxx/patches-3.3/300-laguna_support.patch b/target/linux/cns3xxx/patches-3.3/300-laguna_support.patch index 06f302a0d..7fe970a4d 100644 --- a/target/linux/cns3xxx/patches-3.3/300-laguna_support.patch +++ b/target/linux/cns3xxx/patches-3.3/300-laguna_support.patch @@ -1,6 +1,6 @@  --- /dev/null  +++ b/arch/arm/mach-cns3xxx/laguna.c -@@ -0,0 +1,919 @@ +@@ -0,0 +1,935 @@  +/*  + * Gateworks Corporation Laguna Platform  + * @@ -660,6 +660,16 @@  +	{ 108, GPIOF_IN           , "J9_DIOGSC0" },  +};  + ++static struct gpio laguna_gpio_gw2383[] = { ++	{   0, GPIOF_IN           , "*GPS_PPS" }, ++	{   1, GPIOF_IN           , "*GSC_IRQ#" }, ++	{   2, GPIOF_OUT_INIT_HIGH, "*PCIE_RST#" }, ++	{   3, GPIOF_IN           , "GPIO0" }, ++	{   8, GPIOF_IN           , "GPIO1" }, ++	{ 100, GPIOF_IN           , "DIO0" }, ++	{ 101, GPIOF_IN           , "DIO1" }, ++}; ++  +static struct gpio laguna_gpio_gw2382[] = {  +	{   0, GPIOF_IN           , "*GPS_PPS" },  +	{   1, GPIOF_IN           , "*GSC_IRQ#" }, @@ -882,6 +892,12 @@  +			laguna_register_gpio(ARRAY_AND_SIZE(laguna_gpio_gw2384));  +			// configure LED's  +			laguna_gpio_leds_data.num_leds = 1; ++		} else if (strncmp(laguna_info.model, "GW2383", 6) == 0) { ++			// configure GPIO's ++			laguna_register_gpio(ARRAY_AND_SIZE(laguna_gpio_gw2383)); ++			// configure LED's ++			laguna_gpio_leds[0].gpio = 107; ++			laguna_gpio_leds_data.num_leds = 1;  +		} else if (strncmp(laguna_info.model, "GW2382", 6) == 0) {  +			// configure GPIO's  +			laguna_register_gpio(ARRAY_AND_SIZE(laguna_gpio_gw2382)); diff --git a/target/linux/cns3xxx/patches-3.3/470-gpio_irq.patch b/target/linux/cns3xxx/patches-3.3/470-gpio_irq.patch new file mode 100644 index 000000000..c5de35fe4 --- /dev/null +++ b/target/linux/cns3xxx/patches-3.3/470-gpio_irq.patch @@ -0,0 +1,536 @@ +--- a/arch/arm/mach-cns3xxx/Makefile ++++ b/arch/arm/mach-cns3xxx/Makefile +@@ -1,4 +1,4 @@ +-obj-$(CONFIG_ARCH_CNS3XXX)		+= core.o pm.o devices.o ++obj-$(CONFIG_ARCH_CNS3XXX)		+= core.o gpio.o pm.o devices.o + obj-$(CONFIG_PCI)			+= pcie.o + obj-$(CONFIG_MACH_CNS3420VB)		+= cns3420vb.o + obj-$(CONFIG_MACH_GW2388)		+= laguna.o +--- a/arch/arm/mach-cns3xxx/cns3420vb.c ++++ b/arch/arm/mach-cns3xxx/cns3420vb.c +@@ -199,7 +199,10 @@ static void __init cns3420_init(void) +  + 	cns3xxx_ahci_init(); + 	cns3xxx_sdhci_init(); +- ++	cns3xxx_gpio_init( 0, 32, CNS3XXX_GPIOA_BASE_VIRT, IRQ_CNS3XXX_GPIOA, ++		NR_IRQS_CNS3XXX); ++	cns3xxx_gpio_init(32, 32, CNS3XXX_GPIOB_BASE_VIRT, IRQ_CNS3XXX_GPIOB, ++		NR_IRQS_CNS3XXX + 32); + 	cns3xxx_pcie_init(0x3); +  + 	pm_power_off = cns3xxx_power_off; +--- a/arch/arm/mach-cns3xxx/core.c ++++ b/arch/arm/mach-cns3xxx/core.c +@@ -21,7 +21,6 @@ + #include <asm/hardware/gic.h> + #include <asm/smp_twd.h> + #include <asm/hardware/cache-l2x0.h> +-#include <asm/gpio.h> + #include <mach/cns3xxx.h> + #include "core.h" +  +@@ -83,73 +82,12 @@ static struct map_desc cns3xxx_io_desc[] + 	}, + }; +  +-static inline void gpio_line_config(u8 line, u32 direction) +-{ +-	u32 reg; +-	if (direction) { +-		if (line < 32) { +-			reg = __raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); +-			reg |= (1 << line); +-			__raw_writel(reg, CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); +-		} else { +-			reg = __raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); +-			reg |= (1 << (line - 32)); +-			__raw_writel(reg, CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); +-		} +-	} else { +-		if (line < 32) { +-			reg = __raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); +-			reg &= ~(1 << line); +-			__raw_writel(reg, CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); +-		} else { +-			reg = __raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); +-			reg &= ~(1 << (line - 32)); +-			__raw_writel(reg, CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); +-		} +-	} +-} +- +-static int cns3xxx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +-{ +-	gpio_line_config(gpio, CNS3XXX_GPIO_IN); +-	return 0; +-} +- +-static int cns3xxx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level) +-{ +-	gpio_line_set(gpio, level); +-	gpio_line_config(gpio, CNS3XXX_GPIO_OUT); +-	return 0; +-} +- +-static int cns3xxx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +-{ +-	return gpio_get_value(gpio); +-} +- +-static void cns3xxx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +-{ +-	gpio_set_value(gpio, value); +-} +- +-static struct gpio_chip cns3xxx_gpio_chip = { +-	.label			= "CNS3XXX_GPIO_CHIP", +-	.direction_input	= cns3xxx_gpio_direction_input, +-	.direction_output	= cns3xxx_gpio_direction_output, +-	.get			= cns3xxx_gpio_get_value, +-	.set			= cns3xxx_gpio_set_value, +-	.base			= 0, +-	.ngpio			= 64, +-}; +- + void __init cns3xxx_common_init(void) + { + #ifdef CONFIG_LOCAL_TIMERS + 	twd_base = (void __iomem *) CNS3XXX_TC11MP_TWD_BASE_VIRT; + #endif + 	iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc)); +- +-	gpiochip_add(&cns3xxx_gpio_chip); + } +  + /* used by entry-macro.S */ +--- /dev/null ++++ b/arch/arm/mach-cns3xxx/gpio.c +@@ -0,0 +1,277 @@ ++/* ++ * Copyright 2012 Gateworks Corporation ++ *     Chris Lang <clang@gateworks.com> ++ *     Tim Harvey <tharvey@gateworks.com> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/gpio.h> ++#include <linux/irq.h> ++ ++#include <asm/mach/irq.h> ++ ++/* ++ * Registers ++ */ ++#define GPIO_INPUT                          0x04 ++#define GPIO_DIR                            0x08 ++#define GPIO_SET                            0x10 ++#define GPIO_CLEAR                          0x14 ++#define GPIO_INTERRUPT_ENABLE               0x20 ++#define GPIO_INTERRUPT_RAW_STATUS           0x24 ++#define GPIO_INTERRUPT_MASKED_STATUS        0x28 ++#define GPIO_INTERRUPT_MASK                 0x2C ++#define GPIO_INTERRUPT_CLEAR                0x30 ++#define GPIO_INTERRUPT_TRIGGER_METHOD       0x34 ++#define GPIO_INTERRUPT_TRIGGER_BOTH_EDGES   0x38 ++#define GPIO_INTERRUPT_TRIGGER_TYPE         0x3C ++ ++#define GPIO_INTERRUPT_TRIGGER_METHOD_EDGE  0 ++#define GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL 1 ++#define GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE  0 ++#define GPIO_INTERRUPT_TRIGGER_EDGE_BOTH    1 ++#define GPIO_INTERRUPT_TRIGGER_TYPE_RISING  0 ++#define GPIO_INTERRUPT_TRIGGER_TYPE_FALLING 1 ++#define GPIO_INTERRUPT_TRIGGER_TYPE_HIGH    0 ++#define GPIO_INTERRUPT_TRIGGER_TYPE_LOW     1 ++ ++struct cns3xxx_gpio_chip { ++	struct gpio_chip    chip; ++	spinlock_t          lock; ++	void __iomem        *base; ++	int                 secondary_irq_base; ++}; ++ ++static struct cns3xxx_gpio_chip cns3xxx_gpio_chips[2]; ++static int cns3xxx_gpio_chip_count; ++ ++static inline void ++__set_direction(struct cns3xxx_gpio_chip *cchip, unsigned pin, int input) ++{ ++	u32 reg; ++ ++	reg = __raw_readl(cchip->base + GPIO_DIR); ++	if (input) ++		reg |= 1 << pin; ++	else ++		reg &= !(1 << pin); ++	__raw_writel(reg, cchip->base + GPIO_DIR); ++} ++ ++/* ++ * GENERIC_GPIO primatives ++ */ ++static int cns3xxx_gpio_direction_input(struct gpio_chip *chip, unsigned pin) ++{ ++	struct cns3xxx_gpio_chip *cchip = ++		container_of(chip, struct cns3xxx_gpio_chip, chip); ++	unsigned long flags; ++ ++	spin_lock_irqsave(&cchip->lock, flags); ++	__set_direction(cchip, pin, 1); ++	spin_unlock_irqrestore(&cchip->lock, flags); ++ ++	return 0; ++} ++ ++static int cns3xxx_gpio_get(struct gpio_chip *chip, unsigned pin) ++{ ++	struct cns3xxx_gpio_chip *cchip = ++		container_of(chip, struct cns3xxx_gpio_chip, chip); ++	int val; ++ ++	val = ((__raw_readl(cchip->base + GPIO_INPUT) >> pin) & 0x1); ++ ++	return val; ++} ++ ++static int cns3xxx_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int level) ++{ ++	struct cns3xxx_gpio_chip *cchip = ++		container_of(chip, struct cns3xxx_gpio_chip, chip); ++	unsigned long flags; ++ ++	spin_lock_irqsave(&cchip->lock, flags); ++	if (level) ++		__raw_writel(1 << pin, cchip->base + GPIO_SET); ++	else ++		__raw_writel(1 << pin, cchip->base + GPIO_CLEAR); ++	__set_direction(cchip, pin, 0); ++	spin_unlock_irqrestore(&cchip->lock, flags); ++ ++	return 0; ++} ++ ++static void cns3xxx_gpio_set(struct gpio_chip *chip, unsigned pin, ++	int level) ++{ ++	struct cns3xxx_gpio_chip *cchip = ++		container_of(chip, struct cns3xxx_gpio_chip, chip); ++ ++	if (level) ++		__raw_writel(1 << pin, cchip->base + GPIO_SET); ++	else ++		__raw_writel(1 << pin, cchip->base + GPIO_CLEAR); ++} ++ ++static int cns3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned pin) ++{ ++	struct cns3xxx_gpio_chip *cchip = ++		container_of(chip, struct cns3xxx_gpio_chip, chip); ++ ++	return cchip->secondary_irq_base + pin; ++} ++ ++ ++/* ++ * IRQ support ++ */ ++ ++/* one interrupt per GPIO controller (GPIOA/GPIOB) ++ * this is called in task context, with IRQs enabled ++ */ ++static void cns3xxx_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++	struct cns3xxx_gpio_chip *cchip = irq_get_handler_data(irq); ++	struct irq_chip *chip = irq_get_chip(irq); ++	struct irq_chip_generic *gc = irq_desc_get_chip_data(desc); ++	struct irq_chip_type *ct = gc->chip_types; ++	u16 i; ++	u32 reg; ++ ++	chained_irq_enter(chip, desc); /* mask and ack the base interrupt */ ++ ++	/* see which pin(s) triggered the interrupt */ ++	reg = __raw_readl(cchip->base + GPIO_INTERRUPT_RAW_STATUS); ++	for (i = 0; i < 32; i++) { ++		if (reg & (1 << i)) { ++			/* let the generic IRQ layer handle an interrupt */ ++			generic_handle_irq(cchip->secondary_irq_base + i); ++		} ++	} ++ ++	chained_irq_exit(chip, desc); /* unmask the base interrupt */ ++} ++ ++static int cns3xxx_gpio_irq_set_type(struct irq_data *d, u32 irqtype) ++{ ++	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); ++	struct cns3xxx_gpio_chip *cchip = gc->private; ++	u32 gpio = d->irq - cchip->secondary_irq_base; ++	unsigned long flags; ++	u32 method, edges, type; ++ ++	spin_lock_irqsave(&cchip->lock, flags); ++	method = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_METHOD); ++	edges  = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_BOTH_EDGES); ++	type   = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_TYPE); ++	method &= ~(1 << gpio); ++	edges  &= ~(1 << gpio); ++	type   &= ~(1 << gpio); ++ ++	switch(irqtype) { ++	case IRQ_TYPE_EDGE_RISING: ++		method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio); ++		edges  |= (GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE << gpio); ++		type   |= (GPIO_INTERRUPT_TRIGGER_TYPE_RISING << gpio); ++		break; ++	case IRQ_TYPE_EDGE_FALLING: ++		method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio); ++		edges  |= (GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE << gpio); ++		type   |= (GPIO_INTERRUPT_TRIGGER_TYPE_FALLING << gpio); ++		break; ++	case IRQ_TYPE_EDGE_BOTH: ++		method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio); ++		edges  |= (GPIO_INTERRUPT_TRIGGER_EDGE_BOTH << gpio); ++		break; ++	case IRQ_TYPE_LEVEL_LOW: ++		method |= (GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL << gpio); ++		type   |= (GPIO_INTERRUPT_TRIGGER_TYPE_LOW << gpio); ++		break; ++	case IRQ_TYPE_LEVEL_HIGH: ++		method |= (GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL << gpio); ++		type   |= (GPIO_INTERRUPT_TRIGGER_TYPE_HIGH << gpio); ++		break; ++	default: ++		printk(KERN_WARNING "No irq type\n"); ++		spin_unlock_irqrestore(&cchip->lock, flags); ++		return -EINVAL; ++	} ++ ++	__raw_writel(method, cchip->base + GPIO_INTERRUPT_TRIGGER_METHOD); ++	__raw_writel(edges,  cchip->base + GPIO_INTERRUPT_TRIGGER_BOTH_EDGES); ++	__raw_writel(type,   cchip->base + GPIO_INTERRUPT_TRIGGER_TYPE); ++	spin_unlock_irqrestore(&cchip->lock, flags); ++ ++	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) ++		__irq_set_handler_locked(d->irq, handle_level_irq); ++	else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) ++		__irq_set_handler_locked(d->irq, handle_edge_irq); ++ ++	return 0; ++} ++ ++void __init cns3xxx_gpio_init(int gpio_base, int ngpio, ++	u32 base, int irq, int secondary_irq_base) ++{ ++	struct cns3xxx_gpio_chip *cchip; ++	struct irq_chip_generic *gc; ++	struct irq_chip_type *ct; ++	char gc_label[16]; ++ ++	if (cns3xxx_gpio_chip_count == ARRAY_SIZE(cns3xxx_gpio_chips)) ++		return; ++ ++	snprintf(gc_label, sizeof(gc_label), "cns3xxx_gpio%d", ++		cns3xxx_gpio_chip_count); ++ ++	cchip = cns3xxx_gpio_chips + cns3xxx_gpio_chip_count; ++	cchip->chip.label = kstrdup(gc_label, GFP_KERNEL); ++	cchip->chip.direction_input = cns3xxx_gpio_direction_input; ++	cchip->chip.get = cns3xxx_gpio_get; ++	cchip->chip.direction_output = cns3xxx_gpio_direction_output; ++	cchip->chip.set = cns3xxx_gpio_set; ++	cchip->chip.to_irq = cns3xxx_gpio_to_irq; ++	cchip->chip.base = gpio_base; ++	cchip->chip.ngpio = ngpio; ++	cchip->chip.can_sleep = 0; ++	spin_lock_init(&cchip->lock); ++	cchip->base = (void __iomem *)base; ++	cchip->secondary_irq_base = secondary_irq_base; ++ ++	BUG_ON(gpiochip_add(&cchip->chip) < 0); ++	cns3xxx_gpio_chip_count++; ++ ++	/* clear GPIO interrupts */ ++	__raw_writel(0xffff, cchip->base + GPIO_INTERRUPT_CLEAR); ++ ++	/* ++	 * IRQ chip init ++	 */ ++	gc = irq_alloc_generic_chip("cns3xxx_gpio_irq", 1, secondary_irq_base, ++		cchip->base, handle_edge_irq); ++	gc->private = cchip; ++ ++	ct = gc->chip_types; ++	ct->type = IRQ_TYPE_EDGE_FALLING; ++	ct->regs.ack = GPIO_INTERRUPT_CLEAR; ++	ct->regs.enable = GPIO_INTERRUPT_ENABLE; ++	ct->chip.irq_ack = irq_gc_ack_set_bit; ++	ct->chip.irq_enable = irq_gc_unmask_enable_reg; ++	ct->chip.irq_disable = irq_gc_mask_disable_reg; ++	ct->chip.irq_set_type = cns3xxx_gpio_irq_set_type; ++	ct->handler = handle_edge_irq; ++ ++	irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE, ++		IRQ_NOREQUEST, 0); ++ ++	irq_set_chained_handler(irq, cns3xxx_gpio_irq_handler); ++	irq_set_handler_data(irq, cchip); ++} +--- a/arch/arm/mach-cns3xxx/include/mach/gpio.h ++++ b/arch/arm/mach-cns3xxx/include/mach/gpio.h +@@ -1,98 +1,17 @@ + /* +  * arch/arm/mach-cns3xxx/include/mach/gpio.h +  * +- * CNS3xxx GPIO wrappers for arch-neutral GPIO calls +- * +- * Copyright 2011 Gateworks Corporation +- *		  Chris Lang <clang@gateworks.com> +- * +- * Based on IXP implementation by Milan Svoboda <msvoboda@ra.rockwell.com> +- * Based on PXA implementation by Philipp Zabel <philipp.zabel@gmail.com> +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2.  This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. +  * +  */ +- + #ifndef __ASM_ARCH_CNS3XXX_GPIO_H + #define __ASM_ARCH_CNS3XXX_GPIO_H +  + #include <linux/kernel.h> +-#include <linux/io.h> +-#include <mach/platform.h> +-#include <asm-generic/gpio.h>			/* cansleep wrappers */ +- +-#define NR_BUILTIN_GPIO 64 +- +-#define CNS3XXX_GPIO_IN    0x0 +-#define CNS3XXX_GPIO_OUT   0x1 +- +-#define CNS3XXX_GPIO_LO   0 +-#define CNS3XXX_GPIO_HI   1 +- +-#define CNS3XXX_GPIO_OUTPUT         0x00 +-#define CNS3XXX_GPIO_INPUT          0x04 +-#define CNS3XXX_GPIO_DIR            0x08 +-#define CNS3XXX_GPIO_SET            0x10 +-#define CNS3XXX_GPIO_CLEAR          0x14 +- +-static inline void gpio_line_get(u8 line, int *value) +-{ +-	if (line < 32) +-		*value = ((__raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_INPUT) >> line) & 0x1); +-	else +-		*value = ((__raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_INPUT) >> (line - 32)) & 0x1); +-} +- +-static inline void gpio_line_set(u8 line, int value) +-{ +-	if (line < 32) { +-		if (value) +-			__raw_writel((1 << line), CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_SET); +-		else +-			__raw_writel((1 << line), CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_CLEAR); +-	} else { +-		if (value) +-			__raw_writel((1 << line), CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_SET); +-		else +-			__raw_writel((1 << line), CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_CLEAR); +-	} +-} +- +-static inline int gpio_get_value(unsigned gpio) +-{ +-	if (gpio < NR_BUILTIN_GPIO) +-	{ +-		int value; +-		gpio_line_get(gpio, &value); +-		return value; +-	} +-	else +-		return __gpio_get_value(gpio); +-} +- +-static inline void gpio_set_value(unsigned gpio, int value) +-{ +-	if (gpio < NR_BUILTIN_GPIO) +-		gpio_line_set(gpio, value); +-	else +-		__gpio_set_value(gpio, value); +-} +- +-#define gpio_cansleep __gpio_cansleep +  +-extern int gpio_to_irq(int gpio); +-extern int irq_to_gpio(int gpio); ++extern void __init cns3xxx_gpio_init(int gpio_base, int ngpio, ++	u32 base, int irq, int secondary_irq_base); +  + #endif +--- a/arch/arm/mach-cns3xxx/laguna.c ++++ b/arch/arm/mach-cns3xxx/laguna.c +@@ -45,6 +45,7 @@ + #include <mach/irqs.h> + #include <mach/platform.h> + #include <mach/pm.h> ++#include <mach/gpio.h> + #include <asm/hardware/gic.h> + #include "core.h" + #include "devices.h" +@@ -759,6 +760,10 @@ static int __init laguna_model_setup(voi + 	u8 pcie_bitmap = 0; +  + 	printk("Running on Gateworks Laguna %s\n", laguna_info.model); ++	cns3xxx_gpio_init( 0, 32, CNS3XXX_GPIOA_BASE_VIRT, IRQ_CNS3XXX_GPIOA, ++		NR_IRQS_CNS3XXX); ++	cns3xxx_gpio_init(32, 32, CNS3XXX_GPIOB_BASE_VIRT, IRQ_CNS3XXX_GPIOB, ++		NR_IRQS_CNS3XXX + 32); +  + 	if (strncmp(laguna_info.model, "GW", 2) == 0) { + 		if (laguna_info.config_bitmap & ETH0_LOAD) +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -366,7 +366,8 @@ config ARCH_CLPS711X + config ARCH_CNS3XXX + 	bool "Cavium Networks CNS3XXX family" + 	select CPU_V6K +-	select ARCH_WANT_OPTIONAL_GPIOLIB ++	select ARCH_REQUIRE_GPIOLIB ++	select GENERIC_IRQ_CHIP + 	select GENERIC_CLOCKEVENTS + 	select ARM_GIC + 	select CLKDEV_LOOKUP +--- a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h ++++ b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h +@@ -627,7 +627,7 @@ int cns3xxx_cpu_clock(void); +  + #if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_CNS3XXX) + #undef NR_IRQS +-#define NR_IRQS				NR_IRQS_CNS3XXX ++#define NR_IRQS				(NR_IRQS_CNS3XXX + 64) + #endif +  + #endif	/* __MACH_BOARD_CNS3XXX_H */ | 
