Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfefe3c6 authored by Michael Hennerich's avatar Michael Hennerich Committed by Bryan Wu
Browse files

[Blackfin] arch: hook up set_irq_wake in Blackfin's irq code



 - Add support for irq_wake on system and gpio interrupts
 - Remove outdated kernel options
 - Add option to select default PM mode
 - Fix various places where SIC_IWRx was only handled partially

Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarBryan Wu <bryan.wu@analog.com>
parent 2c4f829b
Loading
Loading
Loading
Loading
+29 −20
Original line number Diff line number Diff line
@@ -904,29 +904,38 @@ config ARCH_SUSPEND_POSSIBLE
	depends on !SMP

choice
	prompt "Select PM Wakeup Event Source"
	default PM_WAKEUP_GPIO_BY_SIC_IWR
	prompt "Default Power Saving Mode"
	depends on PM
	help
	  If you have a GPIO already configured as input with the corresponding PORTx_MASK
	  bit set - "Specify Wakeup Event by SIC_IWR value"
	default PM_BFIN_SLEEP_DEEPER
config  PM_BFIN_SLEEP_DEEPER
	bool "Sleep Deeper"
	help
	  Sleep "Deeper" Mode (High Power Savings) - This mode reduces dynamic
	  power dissipation by disabling the clock to the processor core (CCLK).
	  Furthermore, Standby sets the internal power supply voltage (VDDINT)
	  to 0.85 V to provide the greatest power savings, while preserving the
	  processor state.
	  The PLL and system clock (SCLK) continue to operate at a very low
	  frequency of about 3.3 MHz. To preserve data integrity in the SDRAM,
	  the SDRAM is put into Self Refresh Mode. Typically an external event
	  such as GPIO interrupt or RTC activity wakes up the processor.
	  Various Peripherals such as UART, SPORT, PPI may not function as
	  normal during Sleep Deeper, due to the reduced SCLK frequency.
	  When in the sleep mode, system DMA access to L1 memory is not supported.

config  PM_BFIN_SLEEP
	bool "Sleep"
	help
	  Sleep Mode (High Power Savings) - The sleep mode reduces power
	  dissipation by disabling the clock to the processor core (CCLK).
	  The PLL and system clock (SCLK), however, continue to operate in
	  this mode. Typically an external event or RTC activity will wake
	  up the processor. When in the sleep mode,
	  system DMA access to L1 memory is not supported.
endchoice

config PM_WAKEUP_GPIO_BY_SIC_IWR
	bool "Specify Wakeup Event by SIC_IWR value"
config PM_WAKEUP_BY_GPIO
	bool "Cause Wakeup Event by GPIO"
config PM_WAKEUP_GPIO_API
	bool "Configure Wakeup Event by PM GPIO API"

endchoice

config PM_WAKEUP_SIC_IWR
	hex "Wakeup Events (SIC_IWR)"
	depends on PM_WAKEUP_GPIO_BY_SIC_IWR
	default 0x8 if (BF537 || BF536 || BF534)
	default 0x80 if (BF533 || BF532 || BF531)
	default 0x80 if (BF54x)
	default 0x80 if (BF52x)

config PM_WAKEUP_GPIO_NUMBER
	int "Wakeup GPIO number"
+8 −12
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ static struct str_ident {
	char name[RESOURCE_LABEL_SIZE];
} str_ident[MAX_RESOURCES];

#ifdef CONFIG_PM
#if defined(CONFIG_PM) && !defined(CONFIG_BF54x)
static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
@@ -696,9 +696,8 @@ static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type)
	return 0;
}

u32 gpio_pm_setup(void)
u32 bfin_pm_setup(void)
{
	u32 sic_iwr = 0;
	u16 bank, mask, i, gpio;

	for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
@@ -723,7 +722,8 @@ u32 gpio_pm_setup(void)
			gpio = i;

			while (mask) {
				if (mask & 1) {
				if ((mask & 1) && (wakeup_flags_map[gpio] !=
					PM_WAKE_IGNORE)) {
					reserved_gpio_map[gpio_bank(gpio)] |=
							gpio_bit(gpio);
					bfin_gpio_wakeup_type(gpio,
@@ -734,21 +734,17 @@ u32 gpio_pm_setup(void)
				mask >>= 1;
			}

			sic_iwr |= 1 <<
				(sic_iwr_irqs[bank] - (IRQ_CORETMR + 1));
			bfin_internal_set_wake(sic_iwr_irqs[bank], 1);
			gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)];
		}
	}

	AWA_DUMMY_READ(maskb_set);

	if (sic_iwr)
		return sic_iwr;
	else
		return IWR_ENABLE_ALL;
	return 0;
}

void gpio_pm_restore(void)
void bfin_pm_restore(void)
{
	u16 bank, mask, i;

@@ -768,7 +764,7 @@ void gpio_pm_restore(void)

			reserved_gpio_map[bank] =
					gpio_bank_saved[bank].reserved;

			bfin_internal_set_wake(sic_iwr_irqs[bank], 0);
		}

		gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
+31 −1
Original line number Diff line number Diff line
@@ -191,6 +191,9 @@ ENTRY(_sleep_mode)
	call _test_pll_locked;

	R0 = IWR_ENABLE(0);
	R1 = IWR_DISABLE_ALL;
	R2 = IWR_DISABLE_ALL;

	call _set_sic_iwr;

	P0.H = hi(PLL_CTL);
@@ -237,6 +240,10 @@ ENTRY(_deep_sleep)

	CLI R4;

	R0 = IWR_ENABLE(0);
	R1 = IWR_DISABLE_ALL;
	R2 = IWR_DISABLE_ALL;

	call _set_sic_iwr;

	call _set_dram_srfs;
@@ -261,6 +268,9 @@ ENTRY(_deep_sleep)
	call _test_pll_locked;

	R0 = IWR_ENABLE(0);
	R1 = IWR_DISABLE_ALL;
	R2 = IWR_DISABLE_ALL;

	call _set_sic_iwr;

	P0.H = hi(PLL_CTL);
@@ -286,7 +296,13 @@ ENTRY(_sleep_deeper)
	CLI R4;

	P3 = R0;
	P4 = R1;
	P5 = R2;

	R0 = IWR_ENABLE(0);
	R1 = IWR_DISABLE_ALL;
	R2 = IWR_DISABLE_ALL;

	call _set_sic_iwr;
	call _set_dram_srfs;	/* Set SDRAM Self Refresh */

@@ -327,6 +343,8 @@ ENTRY(_sleep_deeper)
	call _test_pll_locked;

	R0 = P3;
	R1 = P4;
	R3 = P5;
	call _set_sic_iwr;	/* Set Awake from IDLE */

	P0.H = hi(PLL_CTL);
@@ -340,6 +358,9 @@ ENTRY(_sleep_deeper)
	call _test_pll_locked;

	R0 = IWR_ENABLE(0);
	R1 = IWR_DISABLE_ALL;
	R2 = IWR_DISABLE_ALL;

	call _set_sic_iwr;	/* Set Awake from IDLE PLL */

	P0.H = hi(VR_CTL);
@@ -417,14 +438,23 @@ ENTRY(_unset_dram_srfs)
	RTS;

ENTRY(_set_sic_iwr)
#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)  || defined(CONFIG_BF561)
	P0.H = hi(SIC_IWR0);
	P0.L = lo(SIC_IWR0);
	P1.H = hi(SIC_IWR1);
	P1.L = lo(SIC_IWR1);
	[P1] = R1;
#if defined(CONFIG_BF54x)
	P1.H = hi(SIC_IWR2);
	P1.L = lo(SIC_IWR2);
	[P1] = R2;
#endif
#else
	P0.H = hi(SIC_IWR);
	P0.L = lo(SIC_IWR);
#endif
	[P0] = R0;

	SSYNC;
	RTS;

+121 −5
Original line number Diff line number Diff line
/*
 * File:         arch/blackfin/mach-common/ints-priority-sc.c
 * File:         arch/blackfin/mach-common/ints-priority.c
 * Based on:
 * Author:
 *
@@ -13,7 +13,7 @@
 *               2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
 *               2003 Metrowerks/Motorola
 *               2003 Bas Vermeulen <bas@buyways.nl>
 *               Copyright 2004-2007 Analog Devices Inc.
 *               Copyright 2004-2008 Analog Devices Inc.
 *
 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
 *
@@ -69,6 +69,10 @@ unsigned long irq_flags = 0x1f;
/* The number of spurious interrupts */
atomic_t num_spurious;

#ifdef CONFIG_PM
unsigned long bfin_sic_iwr[3];	/* Up to 3 SIC_IWRx registers */
#endif

struct ivgx {
	/* irq number for request_irq, available in mach-bf533/irq.h */
	unsigned int irqno;
@@ -178,6 +182,27 @@ static void bfin_internal_unmask_irq(unsigned int irq)
	SSYNC();
}

#ifdef CONFIG_PM
int bfin_internal_set_wake(unsigned int irq, unsigned int state)
{
	unsigned bank, bit;
	unsigned long flags;
	bank = (irq - (IRQ_CORETMR + 1)) / 32;
	bit = (irq - (IRQ_CORETMR + 1)) % 32;

	local_irq_save(flags);

	if (state)
		bfin_sic_iwr[bank] |= (1 << bit);
	else
		bfin_sic_iwr[bank] &= ~(1 << bit);

	local_irq_restore(flags);

	return 0;
}
#endif

static struct irq_chip bfin_core_irqchip = {
	.ack = ack_noop,
	.mask = bfin_core_mask_irq,
@@ -188,6 +213,9 @@ static struct irq_chip bfin_internal_irqchip = {
	.ack = ack_noop,
	.mask = bfin_internal_mask_irq,
	.unmask = bfin_internal_unmask_irq,
#ifdef CONFIG_PM
	.set_wake = bfin_internal_set_wake,
#endif
};

#ifdef BF537_GENERIC_ERROR_INT_DEMUX
@@ -434,6 +462,20 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
	return 0;
}

#ifdef CONFIG_PM
int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
{
	unsigned gpio = irq_to_gpio(irq);

	if (state)
		gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE);
	else
		gpio_pm_wakeup_free(gpio);

	return 0;
}
#endif

static struct irq_chip bfin_gpio_irqchip = {
	.ack = bfin_gpio_ack_irq,
	.mask = bfin_gpio_mask_irq,
@@ -441,7 +483,10 @@ static struct irq_chip bfin_gpio_irqchip = {
	.unmask = bfin_gpio_unmask_irq,
	.set_type = bfin_gpio_irq_type,
	.startup = bfin_gpio_irq_startup,
	.shutdown = bfin_gpio_irq_shutdown
	.shutdown = bfin_gpio_irq_shutdown,
#ifdef CONFIG_PM
	.set_wake = bfin_gpio_set_wake,
#endif
};

static void bfin_demux_gpio_irq(unsigned int inta_irq,
@@ -487,7 +532,7 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
	}

	if (search) {
		for (i = 0; i < MAX_BLACKFIN_GPIOS; i += 16) {
		for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
			irq += i;

			mask = get_gpiop_data(i) &
@@ -763,6 +808,74 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
	return 0;
}

#ifdef CONFIG_PM
u32 pint_saved_masks[NR_PINT_SYS_IRQS];
u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];

int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
{
	u32 pint_irq;
	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
	u32 bank = PINT_2_BANK(pint_val);
	u32 pintbit = PINT_BIT(pint_val);

	switch (bank) {
	case 0:
		pint_irq = IRQ_PINT0;
		break;
	case 2:
		pint_irq = IRQ_PINT2;
		break;
	case 3:
		pint_irq = IRQ_PINT3;
		break;
	case 1:
		pint_irq = IRQ_PINT1;
		break;
	default:
		return -EINVAL;
	}

	bfin_internal_set_wake(pint_irq, state);

	if (state)
		pint_wakeup_masks[bank] |= pintbit;
	else
		pint_wakeup_masks[bank] &= ~pintbit;

	return 0;
}

u32 bfin_pm_setup(void)
{
	u32 val, i;

	for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
		val = pint[i]->mask_clear;
		pint_saved_masks[i] = val;
		if (val ^ pint_wakeup_masks[i]) {
			pint[i]->mask_clear = val;
			pint[i]->mask_set = pint_wakeup_masks[i];
		}
	}

	return 0;
}

void bfin_pm_restore(void)
{
	u32 i, val;

	for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
		val = pint_saved_masks[i];
		if (val ^ pint_wakeup_masks[i]) {
			pint[i]->mask_clear = pint[i]->mask_clear;
			pint[i]->mask_set = val;
		}
	}
}
#endif

static struct irq_chip bfin_gpio_irqchip = {
	.ack = bfin_gpio_ack_irq,
	.mask = bfin_gpio_mask_irq,
@@ -770,7 +883,10 @@ static struct irq_chip bfin_gpio_irqchip = {
	.unmask = bfin_gpio_unmask_irq,
	.set_type = bfin_gpio_irq_type,
	.startup = bfin_gpio_irq_startup,
	.shutdown = bfin_gpio_irq_shutdown
	.shutdown = bfin_gpio_irq_shutdown,
#ifdef CONFIG_PM
	.set_wake = bfin_gpio_set_wake,
#endif
};

static void bfin_demux_gpio_irq(unsigned int inta_irq,
+16 −28
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 * Author:       Cliff Brake <cbrake@accelent.com> Copyright (c) 2001
 *
 * Created:      2001
 * Description:  Power management for the bfin
 * Description:  Blackfin power management
 *
 * Modified:     Nicolas Pitre - PXA250 support
 *                Copyright (c) 2002 Monta Vista Software, Inc.
@@ -12,7 +12,7 @@
 *                Copyright (c) 2002 Monta Vista Software, Inc.
 *               Dirk Behme <dirk.behme@de.bosch.com> - OMAP1510/1610
 *                Copyright 2004
 *               Copyright 2004-2006 Analog Devices Inc.
 *               Copyright 2004-2008 Analog Devices Inc.
 *
 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
 *
@@ -67,33 +67,20 @@ void bfin_pm_suspend_standby_enter(void)
	gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE);
#endif

#if defined(CONFIG_PM_WAKEUP_BY_GPIO) || defined(CONFIG_PM_WAKEUP_GPIO_API)
	{
	u32 flags;

	local_irq_save(flags);
	bfin_pm_setup();

		sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/

		gpio_pm_restore();

#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
		bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
		bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
# ifdef CONFIG_BF54x
		bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
# endif
#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
	sleep_deeper(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
#else
		bfin_write_SIC_IWR(IWR_ENABLE_ALL);
	sleep_mode(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
#endif

		local_irq_restore(flags);
	}
#endif
	bfin_pm_restore();

#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
	sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
# if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)  || defined(CONFIG_BF561)
	bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
	bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
# ifdef CONFIG_BF54x
@@ -102,7 +89,8 @@ void bfin_pm_suspend_standby_enter(void)
#else
	bfin_write_SIC_IWR(IWR_ENABLE_ALL);
#endif
#endif				/* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */

	local_irq_restore(flags);
}

/*
Loading