Skip to content
Permalink
Browse files

drivers/gpio/gpio_intel_apl: remove dependency on shared interrupts

The GPIO driver for the Intel Apollo Lake has so many pins it has to
export ten devices to shoehorn its one device into the GPIO API. The
current implementation uses the shared IRQ driver because these
pseudodevices all share one IRQ. However, since the GPIO driver is
aware of all the possible interrupt sources, it's smaller and faster
(and not even messy) to handle it internally, so this patch eliminates
the dependency on the shared IRQ driver.

Signed-off-by: Charles E. Youse <charles.youse@intel.com>
  • Loading branch information...
Charles E. Youse authored and andrewboie committed Apr 22, 2019
1 parent 51a9e6f commit 6fc655351c980bc5d35845779b65d49606550443
@@ -15,13 +15,14 @@
* The GPIO controller has 245 pins divided into four sets.
* Each set has its own MMIO address space. Due to GPIO
* callback only allowing 32 pins (as a 32-bit mask) at once,
* each set is further sub-divided into multiple devices.
* Because of this, shared IRQ must be used.
* each set is further sub-divided into multiple devices, so
* we export GPIO_INTEL_APL_NR_SUBDEVS devices to the kernel.
*/

#define GPIO_INTEL_APL_NR_SUBDEVS 10

#include <errno.h>
#include <gpio.h>
#include <shared_irq.h>
#include <soc.h>
#include <sys_io.h>
#include <misc/__assert.h>
@@ -30,9 +31,12 @@

#include "gpio_utils.h"

#ifndef CONFIG_SHARED_IRQ
#error "Need CONFIG_SHARED_IRQ!"
#endif
/*
* only IRQ 14 is supported now. the docs say IRQ 15 is supported
* as well, but my (admitted cursory) testing disagrees.
*/

BUILD_ASSERT(DT_APL_GPIO_IRQ == 14);

#define REG_PAD_BASE_ADDR 0x000C

@@ -148,29 +152,45 @@ static bool check_perm(struct device *dev, u32_t raw_pin)
#define check_perm(...) (1)
#endif

/*
* as the kernel initializes the subdevices, we add them
* to the list of devices to check at ISR time.
*/

static int nr_isr_devs;

static struct device *isr_devs[GPIO_INTEL_APL_NR_SUBDEVS];

static int gpio_intel_apl_isr(struct device *dev)
{
const struct gpio_intel_apl_config *cfg = dev->config->config_info;
struct gpio_intel_apl_data *data = dev->driver_data;
const struct gpio_intel_apl_config *cfg;
struct gpio_intel_apl_data *data;
struct gpio_callback *cb, *tmp;
u32_t reg, int_sts, cur_mask, acc_mask;

reg = cfg->reg_base + REG_GPI_INT_STS_BASE
+ ((cfg->pin_offset >> 5) << 2);
int_sts = sys_read32(reg);
acc_mask = 0U;

SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&data->cb, cb, tmp, node) {
cur_mask = int_sts & cb->pin_mask;
acc_mask |= cur_mask;
if (cur_mask) {
__ASSERT(cb->handler, "No callback handler!");
cb->handler(dev, cb, cur_mask);
int isr_dev;

for (isr_dev = 0; isr_dev < nr_isr_devs; ++isr_dev) {
dev = isr_devs[isr_dev];
cfg = dev->config->config_info;
data = dev->driver_data;

reg = cfg->reg_base + REG_GPI_INT_STS_BASE
+ ((cfg->pin_offset >> 5) << 2);
int_sts = sys_read32(reg);
acc_mask = 0U;

SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&data->cb, cb, tmp, node) {
cur_mask = int_sts & cb->pin_mask;
acc_mask |= cur_mask;
if (cur_mask) {
__ASSERT(cb->handler, "No callback handler!");
cb->handler(dev, cb, cur_mask);
}
}
}

/* clear handled interrupt bits */
sys_write32(acc_mask, reg);
/* clear handled interrupt bits */
sys_write32(acc_mask, reg);
}

return 0;
}
@@ -432,18 +452,28 @@ static const struct gpio_driver_api gpio_intel_apl_api = {
.disable_callback = gpio_intel_apl_disable_callback,
};

static void gpio_intel_apl_irq_config(struct device *dev);

int gpio_intel_apl_init(struct device *dev)
{
const struct gpio_intel_apl_config *cfg = dev->config->config_info;
struct gpio_intel_apl_data *data = dev->driver_data;

gpio_intel_apl_irq_config(dev);

data->pad_base = sys_read32(cfg->reg_base + REG_PAD_BASE_ADDR);

/* Set to route interrupt through IRQ 14 */
__ASSERT(nr_isr_devs < GPIO_INTEL_APL_NR_SUBDEVS, "too many subdevs");

if (nr_isr_devs == 0) {
IRQ_CONNECT(DT_APL_GPIO_IRQ,
DT_APL_GPIO_IRQ_PRIORITY,
gpio_intel_apl_isr, NULL,
DT_APL_GPIO_IRQ_SENSE);

irq_enable(DT_APL_GPIO_IRQ);
}

isr_devs[nr_isr_devs++] = dev;

/* route to IRQ 14 */

sys_bitfield_clear_bit(data->pad_base + REG_MISCCFG,
MISCCFG_IRQ_ROUTE_POS);

@@ -470,6 +500,8 @@ DEVICE_AND_API_INIT(gpio_intel_apl_##dir_l##_##pos, \
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&gpio_intel_apl_api)

/* "sub" devices. no more than GPIO_INTEL_APL_NR_SUBDEVS of these! */

GPIO_INTEL_APL_DEV_CFG_DATA(n, N, 0, 0, 32);
GPIO_INTEL_APL_DEV_CFG_DATA(n, N, 1, 32, 32);
GPIO_INTEL_APL_DEV_CFG_DATA(n, N, 2, 32, 14);
@@ -483,15 +515,3 @@ GPIO_INTEL_APL_DEV_CFG_DATA(w, W, 1, 32, 15);

GPIO_INTEL_APL_DEV_CFG_DATA(sw, SW, 0, 0, 32);
GPIO_INTEL_APL_DEV_CFG_DATA(sw, SW, 1, 32, 11);

static void gpio_intel_apl_irq_config(struct device *dev)
{
struct device *irq_dev;

irq_dev = device_get_binding(DT_SHARED_IRQ_SHAREDIRQ0_LABEL);
__ASSERT(irq_dev != NULL,
"Failed to get shared IRQ device binding");

shared_irq_isr_register(irq_dev, gpio_intel_apl_isr, dev);
shared_irq_enable(irq_dev, dev);
}
@@ -30,6 +30,11 @@ properties:
description: Human readable string describing the device (used by Zephyr for API name)
generation: define

interrupts:
type: int
generation: define
category: required

cell_string: GPIO

"#cells":
@@ -50,21 +50,14 @@
<0xd0c40000 0x1000>,
<0xd0c70000 0x1000>,
<0xd0c00000 0x1000>;
label = "APL_GPIO";
interrupts = <14 IRQ_TYPE_LEVEL_LOW 3>;
interrupt-parent = <&intc>;

label = "APL_GPIO";
gpio-controller ;
#gpio-cells = <2>;

status = "disabled";
};
};

sharedirq0: sharedirq0 {
compatible = "shared-irq";
label = "APL_GPIO_IRQ";
interrupts = <14 IRQ_TYPE_LEVEL_LOW 3>;
interrupt-parent = <&intc>;

status = "ok";
};
};
@@ -62,15 +62,6 @@ if GPIO
config GPIO_INTEL_APL
default y

config SHARED_IRQ
default y if GPIO_INTEL_APL

config SHARED_IRQ_0
default y if SHARED_IRQ

config SHARED_IRQ_NUM_CLIENTS
default 10 if SHARED_IRQ

endif # GPIO

endif # SOC_APOLLO_LAKE
@@ -6,70 +6,35 @@

/* SoC level DTS fixup file */

#define DT_PHYS_RAM_ADDR CONFIG_SRAM_BASE_ADDRESS

#define DT_PHYS_LOAD_ADDR CONFIG_FLASH_BASE_ADDRESS

#define DT_RAM_SIZE CONFIG_SRAM_SIZE

#define DT_ROM_SIZE CONFIG_FLASH_SIZE

#define DT_IOAPIC_BASE_ADDRESS \
DT_INTEL_IOAPIC_FEC00000_BASE_ADDRESS

#define DT_APL_GPIO_BASE_ADDRESS_N \
DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_0

#define DT_APL_GPIO_BASE_ADDRESS_NW \
DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_1

#define DT_APL_GPIO_BASE_ADDRESS_W \
DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_2

#define DT_APL_GPIO_BASE_ADDRESS_SW \
DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_3

#define DT_APL_GPIO_IRQ DT_INTEL_APL_GPIO_D0C50000_IRQ_0

#define DT_APL_GPIO_IRQ_PRIORITY \
DT_INTEL_APL_GPIO_D0C50000_IRQ_0_PRIORITY

#define DT_APL_GPIO_IRQ_SENSE \
DT_INTEL_APL_GPIO_D0C50000_IRQ_0_SENSE

#define DT_APL_GPIO_MEM_SIZE_N DT_INTEL_APL_GPIO_D0C50000_SIZE_0
#define DT_APL_GPIO_MEM_SIZE_NW DT_INTEL_APL_GPIO_D0C50000_SIZE_1
#define DT_APL_GPIO_MEM_SIZE_W DT_INTEL_APL_GPIO_D0C50000_SIZE_2
#define DT_APL_GPIO_MEM_SIZE_SW DT_INTEL_APL_GPIO_D0C50000_SIZE_3

#define DT_APL_GPIO_LABEL_N_0 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_N_0"

#define DT_APL_GPIO_LABEL_N_1 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_N_1"

#define DT_APL_GPIO_LABEL_N_2 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_N_2"

#define DT_APL_GPIO_LABEL_NW_0 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_NW_0"

#define DT_APL_GPIO_LABEL_NW_1 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_NW_1"

#define DT_APL_GPIO_LABEL_NW_2 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_NW_2"

#define DT_APL_GPIO_LABEL_W_0 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_W_0"

#define DT_APL_GPIO_LABEL_W_1 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_W_1"

#define DT_APL_GPIO_LABEL_SW_0 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_SW_0"

#define DT_APL_GPIO_LABEL_SW_1 \
DT_INTEL_APL_GPIO_D0C50000_LABEL "_SW_1"
#define DT_PHYS_RAM_ADDR CONFIG_SRAM_BASE_ADDRESS
#define DT_PHYS_LOAD_ADDR CONFIG_FLASH_BASE_ADDRESS
#define DT_RAM_SIZE CONFIG_SRAM_SIZE
#define DT_ROM_SIZE CONFIG_FLASH_SIZE

#define DT_IOAPIC_BASE_ADDRESS DT_INTEL_IOAPIC_FEC00000_BASE_ADDRESS
#define DT_APL_GPIO_BASE_ADDRESS_N DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_0
#define DT_APL_GPIO_BASE_ADDRESS_NW DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_1
#define DT_APL_GPIO_BASE_ADDRESS_W DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_2
#define DT_APL_GPIO_BASE_ADDRESS_SW DT_INTEL_APL_GPIO_D0C50000_BASE_ADDRESS_3

#define DT_APL_GPIO_IRQ DT_INTEL_APL_GPIO_D0C50000_IRQ_0
#define DT_APL_GPIO_IRQ_PRIORITY DT_INTEL_APL_GPIO_D0C50000_IRQ_0_PRIORITY
#define DT_APL_GPIO_IRQ_SENSE DT_INTEL_APL_GPIO_D0C50000_IRQ_0_SENSE

#define DT_APL_GPIO_MEM_SIZE_N DT_INTEL_APL_GPIO_D0C50000_SIZE_0
#define DT_APL_GPIO_MEM_SIZE_NW DT_INTEL_APL_GPIO_D0C50000_SIZE_1
#define DT_APL_GPIO_MEM_SIZE_W DT_INTEL_APL_GPIO_D0C50000_SIZE_2
#define DT_APL_GPIO_MEM_SIZE_SW DT_INTEL_APL_GPIO_D0C50000_SIZE_3

#define DT_APL_GPIO_LABEL_N_0 DT_INTEL_APL_GPIO_D0C50000_LABEL "_N_0"
#define DT_APL_GPIO_LABEL_N_1 DT_INTEL_APL_GPIO_D0C50000_LABEL "_N_1"
#define DT_APL_GPIO_LABEL_N_2 DT_INTEL_APL_GPIO_D0C50000_LABEL "_N_2"
#define DT_APL_GPIO_LABEL_NW_0 DT_INTEL_APL_GPIO_D0C50000_LABEL "_NW_0"
#define DT_APL_GPIO_LABEL_NW_1 DT_INTEL_APL_GPIO_D0C50000_LABEL "_NW_1"
#define DT_APL_GPIO_LABEL_NW_2 DT_INTEL_APL_GPIO_D0C50000_LABEL "_NW_2"
#define DT_APL_GPIO_LABEL_W_0 DT_INTEL_APL_GPIO_D0C50000_LABEL "_W_0"
#define DT_APL_GPIO_LABEL_W_1 DT_INTEL_APL_GPIO_D0C50000_LABEL "_W_1"
#define DT_APL_GPIO_LABEL_SW_0 DT_INTEL_APL_GPIO_D0C50000_LABEL "_SW_0"
#define DT_APL_GPIO_LABEL_SW_1 DT_INTEL_APL_GPIO_D0C50000_LABEL "_SW_1"

/* End of SoC Level DTS fixup file */

0 comments on commit 6fc6553

Please sign in to comment.
You can’t perform that action at this time.