gpio: aspeed: Fixes and support for sharing with co-processor
Subsystems (2)
cover gpio: aspeed: Fixes and support for sharing with co-processor
This series cleans up the register accessors a bit, adds missing ones, fixes the access to the write latch and finally adds an interface that a co-processor driver can use to change the owner of some of the GPIO lines and arbitrate access to shared GPIO banks.
PATCH 1/4 gpio: aspeed: Rework register type accessors
Use a single accessor function for all register types instead of several spread around. This will make it easier/cleaner to introduce new registers and keep the mechanism in one place.
The big switch/case is optimized at compile time since the switch value is a constant.
--- drivers/gpio/gpio-aspeed.c | 118 ++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 49 deletions(-)
drivers/gpio/gpio-aspeed.c +69 -49
@@ -127,12 +127,21 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, }; -#define GPIO_BANK (x) ((x) >> 5) -#define GPIO_OFFSET (x) ((x) & 0x1f) -#define GPIO_BIT (x) BIT(GPIO_OFFSET(x)) +enum aspeed_gpio_reg { + reg_val, + reg_dir, + reg_irq_enable, + reg_irq_type0, + reg_irq_type1, + reg_irq_type2, + reg_irq_status, + reg_debounce_sel1, + reg_debounce_sel2, + reg_tolerance, +}; -#define GPIO_DATA 0x00 -#define GPIO_DIR 0x04 +#define GPIO_VAL_VALUE 0x00 +#define GPIO_VAL_DIR 0x04#define GPIO_IRQ_ENABLE 0x00#define GPIO_IRQ_TYPE0 0x04
@@ -143,6 +152,40 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {#define GPIO_DEBOUNCE_SEL1 0x00#define GPIO_DEBOUNCE_SEL2 0x04 +/* This will be resolved at compile time */ +static inline void __iomem *bank_reg (struct aspeed_gpio *gpio, +const struct aspeed_gpio_bank *bank, +const enum aspeed_gpio_reg reg) +{ +switch (reg) { +case reg_val: +return gpio->base + bank->val_regs +GPIO_VAL_VALUE ; +case reg_dir: +return gpio->base + bank->val_regs +GPIO_VAL_DIR ; +case reg_irq_enable: +return gpio->base + bank->irq_regs +GPIO_IRQ_ENABLE ; +case reg_irq_type0: +return gpio->base + bank->irq_regs +GPIO_IRQ_TYPE0 ; +case reg_irq_type1: +return gpio->base + bank->irq_regs +GPIO_IRQ_TYPE1 ; +case reg_irq_type2: +return gpio->base + bank->irq_regs +GPIO_IRQ_TYPE2 ; +case reg_irq_status: +return gpio->base + bank->irq_regs +GPIO_IRQ_STATUS ; +case reg_debounce_sel1: +return gpio->base + bank->debounce_regs +GPIO_DEBOUNCE_SEL1 ; +case reg_debounce_sel2: +return gpio->base + bank->debounce_regs +GPIO_DEBOUNCE_SEL2 ; +case reg_tolerance: +return gpio->base + bank->tolerance_regs; + } +BUG_ON (1 ); +} + +#define GPIO_BANK (x) ((x) >> 5) +#define GPIO_OFFSET (x) ((x) & 0x1f) +#define GPIO_BIT (x) BIT(GPIO_OFFSET(x)) +#define _GPIO_SET_DEBOUNCE (t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o))#define GPIO_SET_DEBOUNCE1 (t, o) _GPIO_SET_DEBOUNCE(t, o, 1)#define GPIO_SET_DEBOUNCE2 (t, o) _GPIO_SET_DEBOUNCE(t, o, 0)
@@ -201,27 +244,12 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset)return !props || (props->output &GPIO_BIT (offset)); } -static void __iomem *bank_val_reg (struct aspeed_gpio *gpio, -const struct aspeed_gpio_bank *bank, -unsigned int reg) -{ -return gpio->base + bank->val_regs + reg; -} - -static void __iomem *bank_irq_reg (struct aspeed_gpio *gpio, -const struct aspeed_gpio_bank *bank, -unsigned int reg) -{ -return gpio->base + bank->irq_regs + reg; -} -static int aspeed_gpio_get (struct gpio_chip *gc,unsigned int offset) {struct aspeed_gpio *gpio =gpiochip_get_data (gc);const struct aspeed_gpio_bank *bank =to_bank (offset); -return !!(ioread32 (bank_val_reg (gpio, bank,GPIO_DATA )) - &GPIO_BIT (offset)); +return !!(ioread32 (bank_reg (gpio, bank, reg_val)) &GPIO_BIT (offset)); } static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,
@@ -232,7 +260,7 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,void __iomem *addr;u32 reg; - addr =bank_val_reg (gpio, bank,GPIO_DATA ); + addr =bank_reg (gpio, bank, reg_val); reg = gpio->dcache[GPIO_BANK (offset)];if (val)
@@ -269,8 +297,8 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)spin_lock_irqsave (&gpio->lock, flags); - reg =ioread32 (bank_val_reg (gpio, bank,GPIO_DIR )); -iowrite32 (reg & ~GPIO_BIT (offset),bank_val_reg (gpio, bank,GPIO_DIR )); + reg =ioread32 (bank_reg (gpio, bank, reg_dir)); +iowrite32 (reg & ~GPIO_BIT (offset),bank_reg (gpio, bank, reg_dir));spin_unlock_irqrestore (&gpio->lock, flags);
@@ -291,8 +319,8 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc,spin_lock_irqsave (&gpio->lock, flags);__aspeed_gpio_set (gc, offset, val); - reg =ioread32 (bank_val_reg (gpio, bank,GPIO_DIR )); -iowrite32 (reg |GPIO_BIT (offset),bank_val_reg (gpio, bank,GPIO_DIR )); + reg =ioread32 (bank_reg (gpio, bank, reg_dir)); +iowrite32 (reg |GPIO_BIT (offset),bank_reg (gpio, bank, reg_dir));spin_unlock_irqrestore (&gpio->lock, flags);
@@ -314,7 +342,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)spin_lock_irqsave (&gpio->lock, flags); - val =ioread32 (bank_val_reg (gpio, bank,GPIO_DIR )) &GPIO_BIT (offset); + val =ioread32 (bank_reg (gpio, bank, reg_dir)) &GPIO_BIT (offset);spin_unlock_irqrestore (&gpio->lock, flags);
@@ -358,7 +386,7 @@ static void aspeed_gpio_irq_ack(struct irq_data *d)if (rc)return ; - status_addr =bank_irq_reg (gpio, bank,GPIO_IRQ_STATUS ); + status_addr =bank_reg (gpio, bank, reg_irq_status);spin_lock_irqsave (&gpio->lock, flags);iowrite32 (bit, status_addr);
@@ -378,7 +406,7 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)if (rc)return ; - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_ENABLE ); + addr =bank_reg (gpio, bank, reg_irq_enable);spin_lock_irqsave (&gpio->lock, flags);
@@ -439,17 +467,17 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)spin_lock_irqsave (&gpio->lock, flags); - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_TYPE0 ); + addr =bank_reg (gpio, bank, reg_irq_type0); reg =ioread32 (addr); reg = (reg & ~bit) | type0;iowrite32 (reg, addr); - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_TYPE1 ); + addr =bank_reg (gpio, bank, reg_irq_type1); reg =ioread32 (addr); reg = (reg & ~bit) | type1;iowrite32 (reg, addr); - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_TYPE2 ); + addr =bank_reg (gpio, bank, reg_irq_type2); reg =ioread32 (addr); reg = (reg & ~bit) | type2;iowrite32 (reg, addr);
@@ -474,7 +502,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)for (i =0 ; i <ARRAY_SIZE (aspeed_gpio_banks); i++) {const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - reg =ioread32 (bank_irq_reg (data, bank,GPIO_IRQ_STATUS )); + reg =ioread32 (bank_reg (data, bank, reg_irq_status));for_each_set_bit (p, ®,32 ) { girq =irq_find_mapping (gc->irqdomain, i *32 + p);
@@ -546,21 +574,21 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, unsigned int offset, bool enable) {struct aspeed_gpio *gpio =gpiochip_get_data (chip); -const struct aspeed_gpio_bank *bank;unsigned long flags; +void __iomem *treg;u32 val; - bank =to_bank (offset); + treg =bank_reg (gpio,to_bank (offset), reg_tolerance);spin_lock_irqsave (&gpio->lock, flags); - val =readl (gpio->base + bank->tolerance_regs); + val =readl (treg);if (enable) val |=GPIO_BIT (offset);else val &= ~GPIO_BIT (offset); -writel (val, gpio->base + bank->tolerance_regs); +writel (val, treg);spin_unlock_irqrestore (&gpio->lock, flags);return 0 ;
@@ -579,13 +607,6 @@ static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset)pinctrl_free_gpio (chip->base + offset); } -static inline void __iomem *bank_debounce_reg (struct aspeed_gpio *gpio, -const struct aspeed_gpio_bank *bank, -unsigned int reg) -{ -return gpio->base + bank->debounce_regs + reg; -} -static int usecs_to_cycles (struct aspeed_gpio *gpio,unsigned long usecs,u32 *cycles) {
@@ -663,11 +684,11 @@ static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset,void __iomem *addr;u32 val; - addr =bank_debounce_reg (gpio, bank,GPIO_DEBOUNCE_SEL1 ); + addr =bank_reg (gpio, bank, reg_debounce_sel1); val =ioread32 (addr);iowrite32 ((val & ~mask) |GPIO_SET_DEBOUNCE1 (timer, offset), addr); - addr =bank_debounce_reg (gpio, bank,GPIO_DEBOUNCE_SEL2 ); + addr =bank_reg (gpio, bank, reg_debounce_sel2); val =ioread32 (addr);iowrite32 ((val & ~mask) |GPIO_SET_DEBOUNCE2 (timer, offset), addr); }
@@ -901,9 +922,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)/* Populate it with initial values read from the HW */ for (i =0 ; i < banks; i++) { -const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - gpio->dcache[i] =ioread32 (gpio->base + bank->val_regs + -GPIO_DATA ); +void __iomem *addr =bank_reg (gpio, &aspeed_gpio_banks[i], reg_val); + gpio->dcache[i] =ioread32 (addr); } rc =devm_gpiochip_add_data (&pdev->dev, &gpio->chip, gpio);
Signature · 1 line
2.17.0
PATCH 1/4 gpio: aspeed: Rework register type accessors
Quoted 7 lines · Benjamin Herrenschmidt
Use a single accessor function for all register types instead of several spread around. This will make it easier/cleaner to introduce new registers and keep the mechanism in one place.
The big switch/case is optimized at compile time since the switch value is a constant.
The patches were accidentally sent based on an older internal tree, not 4.17. I'll send a v2 properly rebased later, that shouldn't prevent reviews.
Linus, let me know what you think of 4/4, it implements what we discussed for arbitrating with the coprocessor. This is tested and solid now, but it does contain some less than savoury bits such as #include <linux/gpio/consumer.h>...
Cheers,
Ben.
Quoted 260 lines
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- drivers/gpio/gpio-aspeed.c | 118 ++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 49 deletions(-)drivers/gpio/gpio-aspeed.c +69
-49@@ -127,12 +127,21 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, }; -#define GPIO_BANK (x) ((x) >> 5) -#define GPIO_OFFSET (x) ((x) & 0x1f) -#define GPIO_BIT (x) BIT(GPIO_OFFSET(x)) +enum aspeed_gpio_reg { + reg_val, + reg_dir, + reg_irq_enable, + reg_irq_type0, + reg_irq_type1, + reg_irq_type2, + reg_irq_status, + reg_debounce_sel1, + reg_debounce_sel2, + reg_tolerance, +}; -#define GPIO_DATA 0x00 -#define GPIO_DIR 0x04 +#define GPIO_VAL_VALUE 0x00 +#define GPIO_VAL_DIR 0x04#define GPIO_IRQ_ENABLE 0x00#define GPIO_IRQ_TYPE0 0x04@@ -143,6 +152,40 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {#define GPIO_DEBOUNCE_SEL1 0x00#define GPIO_DEBOUNCE_SEL2 0x04 +/* This will be resolved at compile time */ +static inline void __iomem *bank_reg (struct aspeed_gpio *gpio, +const struct aspeed_gpio_bank *bank, +const enum aspeed_gpio_reg reg) +{ +switch (reg) { +case reg_val: +return gpio->base + bank->val_regs +GPIO_VAL_VALUE ; +case reg_dir: +return gpio->base + bank->val_regs +GPIO_VAL_DIR ; +case reg_irq_enable: +return gpio->base + bank->irq_regs +GPIO_IRQ_ENABLE ; +case reg_irq_type0: +return gpio->base + bank->irq_regs +GPIO_IRQ_TYPE0 ; +case reg_irq_type1: +return gpio->base + bank->irq_regs +GPIO_IRQ_TYPE1 ; +case reg_irq_type2: +return gpio->base + bank->irq_regs +GPIO_IRQ_TYPE2 ; +case reg_irq_status: +return gpio->base + bank->irq_regs +GPIO_IRQ_STATUS ; +case reg_debounce_sel1: +return gpio->base + bank->debounce_regs +GPIO_DEBOUNCE_SEL1 ; +case reg_debounce_sel2: +return gpio->base + bank->debounce_regs +GPIO_DEBOUNCE_SEL2 ; +case reg_tolerance: +return gpio->base + bank->tolerance_regs; + } +BUG_ON (1 ); +} + +#define GPIO_BANK (x) ((x) >> 5) +#define GPIO_OFFSET (x) ((x) & 0x1f) +#define GPIO_BIT (x) BIT(GPIO_OFFSET(x)) +#define _GPIO_SET_DEBOUNCE (t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o))#define GPIO_SET_DEBOUNCE1 (t, o) _GPIO_SET_DEBOUNCE(t, o, 1)#define GPIO_SET_DEBOUNCE2 (t, o) _GPIO_SET_DEBOUNCE(t, o, 0)@@ -201,27 +244,12 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset)return !props || (props->output &GPIO_BIT (offset)); } -static void __iomem *bank_val_reg (struct aspeed_gpio *gpio, -const struct aspeed_gpio_bank *bank, -unsigned int reg) -{ -return gpio->base + bank->val_regs + reg; -} - -static void __iomem *bank_irq_reg (struct aspeed_gpio *gpio, -const struct aspeed_gpio_bank *bank, -unsigned int reg) -{ -return gpio->base + bank->irq_regs + reg; -} -static int aspeed_gpio_get (struct gpio_chip *gc,unsigned int offset) {struct aspeed_gpio *gpio =gpiochip_get_data (gc);const struct aspeed_gpio_bank *bank =to_bank (offset); -return !!(ioread32 (bank_val_reg (gpio, bank,GPIO_DATA )) - &GPIO_BIT (offset)); +return !!(ioread32 (bank_reg (gpio, bank, reg_val)) &GPIO_BIT (offset)); } static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,@@ -232,7 +260,7 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,void __iomem *addr;u32 reg; - addr =bank_val_reg (gpio, bank,GPIO_DATA ); + addr =bank_reg (gpio, bank, reg_val); reg = gpio->dcache[GPIO_BANK (offset)];if (val)@@ -269,8 +297,8 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)spin_lock_irqsave (&gpio->lock, flags); - reg =ioread32 (bank_val_reg (gpio, bank,GPIO_DIR )); -iowrite32 (reg & ~GPIO_BIT (offset),bank_val_reg (gpio, bank,GPIO_DIR )); + reg =ioread32 (bank_reg (gpio, bank, reg_dir)); +iowrite32 (reg & ~GPIO_BIT (offset),bank_reg (gpio, bank, reg_dir));spin_unlock_irqrestore (&gpio->lock, flags);@@ -291,8 +319,8 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc,spin_lock_irqsave (&gpio->lock, flags);__aspeed_gpio_set (gc, offset, val); - reg =ioread32 (bank_val_reg (gpio, bank,GPIO_DIR )); -iowrite32 (reg |GPIO_BIT (offset),bank_val_reg (gpio, bank,GPIO_DIR )); + reg =ioread32 (bank_reg (gpio, bank, reg_dir)); +iowrite32 (reg |GPIO_BIT (offset),bank_reg (gpio, bank, reg_dir));spin_unlock_irqrestore (&gpio->lock, flags);@@ -314,7 +342,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)spin_lock_irqsave (&gpio->lock, flags); - val =ioread32 (bank_val_reg (gpio, bank,GPIO_DIR )) &GPIO_BIT (offset); + val =ioread32 (bank_reg (gpio, bank, reg_dir)) &GPIO_BIT (offset);spin_unlock_irqrestore (&gpio->lock, flags);@@ -358,7 +386,7 @@ static void aspeed_gpio_irq_ack(struct irq_data *d)if (rc)return ; - status_addr =bank_irq_reg (gpio, bank,GPIO_IRQ_STATUS ); + status_addr =bank_reg (gpio, bank, reg_irq_status);spin_lock_irqsave (&gpio->lock, flags);iowrite32 (bit, status_addr);@@ -378,7 +406,7 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)if (rc)return ; - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_ENABLE ); + addr =bank_reg (gpio, bank, reg_irq_enable);spin_lock_irqsave (&gpio->lock, flags);@@ -439,17 +467,17 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)spin_lock_irqsave (&gpio->lock, flags); - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_TYPE0 ); + addr =bank_reg (gpio, bank, reg_irq_type0); reg =ioread32 (addr); reg = (reg & ~bit) | type0;iowrite32 (reg, addr); - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_TYPE1 ); + addr =bank_reg (gpio, bank, reg_irq_type1); reg =ioread32 (addr); reg = (reg & ~bit) | type1;iowrite32 (reg, addr); - addr =bank_irq_reg (gpio, bank,GPIO_IRQ_TYPE2 ); + addr =bank_reg (gpio, bank, reg_irq_type2); reg =ioread32 (addr); reg = (reg & ~bit) | type2;iowrite32 (reg, addr);@@ -474,7 +502,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)for (i =0 ; i <ARRAY_SIZE (aspeed_gpio_banks); i++) {const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - reg =ioread32 (bank_irq_reg (data, bank,GPIO_IRQ_STATUS )); + reg =ioread32 (bank_reg (data, bank, reg_irq_status));for_each_set_bit (p, ®,32 ) { girq =irq_find_mapping (gc->irqdomain, i *32 + p);@@ -546,21 +574,21 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, unsigned int offset, bool enable) {struct aspeed_gpio *gpio =gpiochip_get_data (chip); -const struct aspeed_gpio_bank *bank;unsigned long flags; +void __iomem *treg;u32 val; - bank =to_bank (offset); + treg =bank_reg (gpio,to_bank (offset), reg_tolerance);spin_lock_irqsave (&gpio->lock, flags); - val =readl (gpio->base + bank->tolerance_regs); + val =readl (treg);if (enable) val |=GPIO_BIT (offset);else val &= ~GPIO_BIT (offset); -writel (val, gpio->base + bank->tolerance_regs); +writel (val, treg);spin_unlock_irqrestore (&gpio->lock, flags);return 0 ;@@ -579,13 +607,6 @@ static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset)pinctrl_free_gpio (chip->base + offset); } -static inline void __iomem *bank_debounce_reg (struct aspeed_gpio *gpio, -const struct aspeed_gpio_bank *bank, -unsigned int reg) -{ -return gpio->base + bank->debounce_regs + reg; -} -static int usecs_to_cycles (struct aspeed_gpio *gpio,unsigned long usecs,u32 *cycles) {@@ -663,11 +684,11 @@ static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset,void __iomem *addr;u32 val; - addr =bank_debounce_reg (gpio, bank,GPIO_DEBOUNCE_SEL1 ); + addr =bank_reg (gpio, bank, reg_debounce_sel1); val =ioread32 (addr);iowrite32 ((val & ~mask) |GPIO_SET_DEBOUNCE1 (timer, offset), addr); - addr =bank_debounce_reg (gpio, bank,GPIO_DEBOUNCE_SEL2 ); + addr =bank_reg (gpio, bank, reg_debounce_sel2); val =ioread32 (addr);iowrite32 ((val & ~mask) |GPIO_SET_DEBOUNCE2 (timer, offset), addr); }@@ -901,9 +922,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)/* Populate it with initial values read from the HW */ for (i =0 ; i < banks; i++) { -const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - gpio->dcache[i] =ioread32 (gpio->base + bank->val_regs + -GPIO_DATA ); +void __iomem *addr =bank_reg (gpio, &aspeed_gpio_banks[i], reg_val); + gpio->dcache[i] =ioread32 (addr); } rc =devm_gpiochip_add_data (&pdev->dev, &gpio->chip, gpio);
PATCH 2/4 gpio: aspeed: Add "Read Data" register to read the write latch
In reply to Benjamin HerrenschmidtThe Aspeed GPIO hardware has a quirk: the value register, for an output GPIO, doesn't contain the last value written (the write latch content) but the sampled input value.
This means that when reading back shortly after writing, you can get an incorrect value as the input value is delayed by a few synchronizers.
The HW supports a separate read-only register "Data Read Register" which allows you to read the write latch instead.
This adds the definition for it, and uses it for the initial population of the GPIO value cache. It will be used more in subsequent patches.
can be
--- drivers/gpio/gpio-aspeed.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
drivers/gpio/gpio-aspeed.c +15 -2
@@ -59,7 +59,10 @@ struct aspeed_gpio { };struct aspeed_gpio_bank { -uint16_t val_regs; +uint16_t val_regs;/* 0: Wr: set write latch, Rd: read input value (*) +* 4: Direction (0=in, 1=out) +*/ +uint16_t rdata_reg;/* Wr: <none> Rd: read write latch */ uint16_t irq_regs;uint16_t debounce_regs;uint16_t tolerance_regs;
@@ -71,6 +74,7 @@ static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 };static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs =0x0000 , + .rdata_reg =0x00c0 , .irq_regs =0x0008 , .debounce_regs =0x0040 , .tolerance_regs =0x001c ,
@@ -78,6 +82,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0020, + .rdata_reg = 0x00c4, .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c,
@@ -85,6 +90,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0070, + .rdata_reg = 0x00c8, .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac,
@@ -92,6 +98,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0078, + .rdata_reg = 0x00d0, .irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc,
@@ -106,6 +113,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0088, + .rdata_reg = 0x00d4, .irq_regs = 0x0148, .debounce_regs = 0x0160, .tolerance_regs = 0x015c,
@@ -113,6 +121,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x01E0, + .rdata_reg = 0x00d4, .irq_regs = 0x0178, .debounce_regs = 0x0190, .tolerance_regs = 0x018c,
@@ -120,6 +129,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x01e8, + .rdata_reg = 0x00d8, .irq_regs = 0x01a8, .debounce_regs = 0x01c0, .tolerance_regs = 0x01bc,
@@ -129,6 +139,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {enum aspeed_gpio_reg { reg_val, + reg_rdata, reg_dir, reg_irq_enable, reg_irq_type0,
@@ -160,6 +171,8 @@ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio,switch (reg) {case reg_val:return gpio->base + bank->val_regs +GPIO_VAL_VALUE ; +case reg_rdata: +return gpio->base + bank->rdata_reg;case reg_dir:return gpio->base + bank->val_regs +GPIO_VAL_DIR ;case reg_irq_enable:
@@ -922,7 +935,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)/* Populate it with initial values read from the HW */ for (i =0 ; i < banks; i++) { -void __iomem *addr =bank_reg (gpio, &aspeed_gpio_banks[i], reg_val); +void __iomem *addr =bank_reg (gpio, &aspeed_gpio_banks[i], reg_rdata); gpio->dcache[i] =ioread32 (addr); }
Signature · 1 line
2.17.0
Joel Stanley
maintainerPATCH 2/4 gpio: aspeed: Add "Read Data" register to read the write latch
Quoted 26 lines · Benjamin Herrenschmidt
The Aspeed GPIO hardware has a quirk: the value register, for an output GPIO, doesn't contain the last value written (the write latch content) but the sampled input value.
This means that when reading back shortly after writing, you can get an incorrect value as the input value is delayed by a few synchronizers.
The HW supports a separate read-only register "Data Read Register" which allows you to read the write latch instead.
This adds the definition for it, and uses it for the initial population of the GPIO value cache. It will be used more in subsequent patches.
can beSigned-off-by Benjamin Herrenschmidt <[email protected]>--- drivers/gpio/gpio-aspeed.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)drivers/gpio/gpio-aspeed.c +0
-0
drivers/gpio/gpio-aspeed.c struct aspeed_gpio { · line 65
Quoted 8 lines
drivers/gpio/gpio-aspeed.c +4
-1@@ -59,7 +59,10 @@ struct aspeed_gpio { };struct aspeed_gpio_bank { -uint16_t val_regs; +uint16_t val_regs;/* 0: Wr: set write latch, Rd: read input value (*) +* 4: Direction (0=in, 1=out) +*/ +uint16_t rdata_reg;/* Wr: <none> Rd: read write latch */
The numbers weren't immediately obvious to me.
Quoted 28 lines
drivers/gpio/gpio-aspeed.c +3
-0uint16_t irq_regs;uint16_t debounce_regs;uint16_t tolerance_regs;@@ -71,6 +74,7 @@ static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 };static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs =0x0000 , + .rdata_reg =0x00c0 , .irq_regs =0x0008 , .debounce_regs =0x0040 , .tolerance_regs =0x001c ,@@ -78,6 +82,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0020, + .rdata_reg = 0x00c4, .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c,@@ -85,6 +90,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0070, + .rdata_reg = 0x00c8, .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac,
drivers/gpio/gpio-aspeed.c static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { · line 101
Quoted 4 lines
drivers/gpio/gpio-aspeed.c +1
-0@@ -92,6 +98,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0078, + .rdata_reg = 0x00d0,
0x00cc?
I was really confused for a second, as I'd applied the series to my tree for testing, and my source as correct. It looks like you fixed these in patch 3.
Quoted 3 lines
drivers/gpio/gpio-aspeed.c +0
-0.irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc,
PATCH 2/4 gpio: aspeed: Add "Read Data" register to read the write latch
Quoted 74 lines · Joel Stanley
Quoted 26 lines · Benjamin Herrenschmidt
The Aspeed GPIO hardware has a quirk: the value register, for an output GPIO, doesn't contain the last value written (the write latch content) but the sampled input value.
This means that when reading back shortly after writing, you can get an incorrect value as the input value is delayed by a few synchronizers.
The HW supports a separate read-only register "Data Read Register" which allows you to read the write latch instead.
This adds the definition for it, and uses it for the initial population of the GPIO value cache. It will be used more in subsequent patches.
can beSigned-off-by Benjamin Herrenschmidt <[email protected]>--- drivers/gpio/gpio-aspeed.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)drivers/gpio/gpio-aspeed.c +0
-0drivers/gpio/gpio-aspeed.c struct aspeed_gpio { · line 65
Quoted 8 lines
drivers/gpio/gpio-aspeed.c +4
-1@@ -59,7 +59,10 @@ struct aspeed_gpio { };struct aspeed_gpio_bank { -uint16_t val_regs; +uint16_t val_regs;/* 0: Wr: set write latch, Rd: read input value (*) +* 4: Direction (0=in, 1=out) +*/ +uint16_t rdata_reg;/* Wr: <none> Rd: read write latch */ The numbers weren't immediately obvious to me.
Quoted 28 lines
drivers/gpio/gpio-aspeed.c +3
-0uint16_t irq_regs;uint16_t debounce_regs;uint16_t tolerance_regs;@@ -71,6 +74,7 @@ static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 };static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs =0x0000 , + .rdata_reg =0x00c0 , .irq_regs =0x0008 , .debounce_regs =0x0040 , .tolerance_regs =0x001c ,@@ -78,6 +82,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0020, + .rdata_reg = 0x00c4, .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c,@@ -85,6 +90,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0070, + .rdata_reg = 0x00c8, .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac,drivers/gpio/gpio-aspeed.c static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { · line 101
Quoted 4 lines
drivers/gpio/gpio-aspeed.c +1
-0@@ -92,6 +98,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0078, + .rdata_reg = 0x00d0,
0x00cc?
Quoted 3 lines
I was really confused for a second, as I'd applied the series to my tree for testing, and my source as correct. It looks like you fixed these in patch 3.
Ah yes, patch splitting mistake. I'll fix that up, thanks.
Quoted 3 lines
Quoted 3 lines
drivers/gpio/gpio-aspeed.c +0
-0.irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc,
PATCH 3/4 gpio: aspeed: Add command source registers
In reply to Benjamin HerrenschmidtThis adds the definitions for the command source registers and a helper to set them.
Those registers allow to control which bus master on the SoC is allowed to modify a given bank of GPIOs and will be used by subsequent patches.
--- drivers/gpio/gpio-aspeed.c | 55 +++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-)
drivers/gpio/gpio-aspeed.c +52 -3
@@ -66,6 +66,7 @@ struct aspeed_gpio_bank {uint16_t irq_regs;uint16_t debounce_regs;uint16_t tolerance_regs; +uint16_t cmdsrc_regs;const char names[4 ][3 ]; };
@@ -78,6 +79,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0008, .debounce_regs = 0x0040, .tolerance_regs = 0x001c, + .cmdsrc_regs = 0x0060, .names = { "A", "B", "C", "D" }, }, {
@@ -86,6 +88,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c, + .cmdsrc_regs = 0x0068, .names = { "E", "F", "G", "H" }, }, {
@@ -94,21 +97,25 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac, + .cmdsrc_regs = 0x0090, .names = { "I", "J", "K", "L" }, }, { .val_regs =0x0078 , - .rdata_reg = 0x00d0, + .rdata_reg = 0x00cc, .irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc, + .cmdsrc_regs = 0x00e0, .names = { "M", "N", "O", "P" }, }, { .val_regs =0x0080 , + .rdata_reg = 0x00d0, .irq_regs = 0x0118, .debounce_regs = 0x0130, .tolerance_regs = 0x012c, + .cmdsrc_regs = 0x0110, .names = { "Q", "R", "S", "T" }, }, {
@@ -117,22 +124,25 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0148, .debounce_regs = 0x0160, .tolerance_regs = 0x015c, + .cmdsrc_regs = 0x0140, .names = { "U", "V", "W", "X" }, }, { .val_regs =0x01E0 , - .rdata_reg = 0x00d4, + .rdata_reg = 0x00d8, .irq_regs = 0x0178, .debounce_regs = 0x0190, .tolerance_regs = 0x018c, + .cmdsrc_regs = 0x0170, .names = { "Y", "Z", "AA", "AB" }, }, { .val_regs =0x01e8 , - .rdata_reg = 0x00d8, + .rdata_reg = 0x00dc, .irq_regs = 0x01a8, .debounce_regs = 0x01c0, .tolerance_regs = 0x01bc, + .cmdsrc_regs = 0x01a0, .names = { "AC", "", "", "" }, }, };
@@ -149,6 +159,8 @@ enum aspeed_gpio_reg { reg_debounce_sel1, reg_debounce_sel2, reg_tolerance, + reg_cmdsrc0, + reg_cmdsrc1, };#define GPIO_VAL_VALUE 0x00
@@ -163,6 +175,12 @@ enum aspeed_gpio_reg {#define GPIO_DEBOUNCE_SEL1 0x00#define GPIO_DEBOUNCE_SEL2 0x04 +#define GPIO_CMDSRC_0 0x00 +#define GPIO_CMDSRC_1 0x04 +#define GPIO_CMDSRC_ARM 0 +#define GPIO_CMDSRC_LPC 1 +#define GPIO_CMDSRC_COLDFIRE 2 +/* This will be resolved at compile time */ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, const struct aspeed_gpio_bank *bank,
@@ -191,6 +209,10 @@ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio,return gpio->base + bank->debounce_regs +GPIO_DEBOUNCE_SEL2 ;case reg_tolerance:return gpio->base + bank->tolerance_regs; +case reg_cmdsrc0: +return gpio->base + bank->cmdsrc_regs +GPIO_CMDSRC_0 ; +case reg_cmdsrc1: +return gpio->base + bank->cmdsrc_regs +GPIO_CMDSRC_1 ; }BUG_ON (1 ); }
@@ -257,6 +279,33 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset)return !props || (props->output &GPIO_BIT (offset)); } +static void aspeed_gpio_change_cmd_source (struct aspeed_gpio *gpio, +const struct aspeed_gpio_bank *bank, +int bindex,int cmdsrc) +{ +void __iomem *c0 =bank_reg (gpio, bank, reg_cmdsrc0); +void __iomem *c1 =bank_reg (gpio, bank, reg_cmdsrc1); +u32 bit, reg; + + bit =1u << ((bindex &3 ) <<3 ); + +/* Source 1 first to avoid illegal 11 combination */ + reg =ioread32 (c1); +if (cmdsrc &2 ) + reg |= bit; +else + reg &= ~bit; +iowrite32 (reg, c1); + +/* Then Source 0 */ + reg =ioread32 (c0); +if (cmdsrc &1 ) + reg |= bit; +else + reg &= ~bit; +iowrite32 (reg, c0); +} +static int aspeed_gpio_get (struct gpio_chip *gc,unsigned int offset) {struct aspeed_gpio *gpio =gpiochip_get_data (gc);
Signature · 1 line
2.17.0
Joel Stanley
maintainerPATCH 3/4 gpio: aspeed: Add command source registers
Quoted 50 lines · Benjamin Herrenschmidt
This adds the definitions for the command source registers and a helper to set them.
Those registers allow to control which bus master on the SoC is allowed to modify a given bank of GPIOs and will be used by subsequent patches.
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- drivers/gpio/gpio-aspeed.c | 55 +++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-)drivers/gpio/gpio-aspeed.c +4
-1@@ -66,6 +66,7 @@ struct aspeed_gpio_bank {uint16_t irq_regs;uint16_t debounce_regs;uint16_t tolerance_regs; +uint16_t cmdsrc_regs;const char names[4 ][3 ]; };@@ -78,6 +79,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0008, .debounce_regs = 0x0040, .tolerance_regs = 0x001c, + .cmdsrc_regs = 0x0060, .names = { "A", "B", "C", "D" }, }, {@@ -86,6 +88,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c, + .cmdsrc_regs = 0x0068, .names = { "E", "F", "G", "H" }, }, {@@ -94,21 +97,25 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac, + .cmdsrc_regs = 0x0090, .names = { "I", "J", "K", "L" }, }, { .val_regs = 0x0078, - .rdata_reg = 0x00d0,
drivers/gpio/gpio-aspeed.c static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { · line 114
Quoted 10 lines
drivers/gpio/gpio-aspeed.c +3
-0+ .rdata_reg = 0x00cc, .irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc, + .cmdsrc_regs = 0x00e0, .names = { "M", "N", "O", "P" }, }, { .val_regs =0x0080 , + .rdata_reg = 0x00d0,
See the comments in patch 2.
Quoted 45 lines
drivers/gpio/gpio-aspeed.c +8
-2.irq_regs = 0x0118, .debounce_regs = 0x0130, .tolerance_regs = 0x012c, + .cmdsrc_regs = 0x0110, .names = { "Q", "R", "S", "T" }, }, {@@ -117,22 +124,25 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0148, .debounce_regs = 0x0160, .tolerance_regs = 0x015c, + .cmdsrc_regs = 0x0140, .names = { "U", "V", "W", "X" }, }, { .val_regs =0x01E0 , - .rdata_reg = 0x00d4, + .rdata_reg = 0x00d8, .irq_regs = 0x0178, .debounce_regs = 0x0190, .tolerance_regs = 0x018c, + .cmdsrc_regs = 0x0170, .names = { "Y", "Z", "AA", "AB" }, }, { .val_regs =0x01e8 , - .rdata_reg = 0x00d8, + .rdata_reg = 0x00dc, .irq_regs = 0x01a8, .debounce_regs = 0x01c0, .tolerance_regs = 0x01bc, + .cmdsrc_regs = 0x01a0, .names = { "AC", "", "", "" }, }, };@@ -149,6 +159,8 @@ enum aspeed_gpio_reg { reg_debounce_sel1, reg_debounce_sel2, reg_tolerance, + reg_cmdsrc0, + reg_cmdsrc1, };#define GPIO_VAL_VALUE 0x00
drivers/gpio/gpio-aspeed.c enum aspeed_gpio_reg { · line 182
Quoted 8 lines
drivers/gpio/gpio-aspeed.c +5
-0@@ -163,6 +175,12 @@ enum aspeed_gpio_reg {#define GPIO_DEBOUNCE_SEL1 0x00#define GPIO_DEBOUNCE_SEL2 0x04 +#define GPIO_CMDSRC_0 0x00 +#define GPIO_CMDSRC_1 0x04 +#define GPIO_CMDSRC_ARM 0 +#define GPIO_CMDSRC_LPC 1 +#define GPIO_CMDSRC_COLDFIRE 2
Something like this to document that 0b11 is illegal, for people who don't have the datasheet handy?
#define GPIO_CMDSRC_RESERVED 3
Quoted 18 lines
drivers/gpio/gpio-aspeed.c +5
-0+/* This will be resolved at compile time */ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, const struct aspeed_gpio_bank *bank,@@ -191,6 +209,10 @@ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio,return gpio->base + bank->debounce_regs +GPIO_DEBOUNCE_SEL2 ;case reg_tolerance:return gpio->base + bank->tolerance_regs; +case reg_cmdsrc0: +return gpio->base + bank->cmdsrc_regs +GPIO_CMDSRC_0 ; +case reg_cmdsrc1: +return gpio->base + bank->cmdsrc_regs +GPIO_CMDSRC_1 ; }BUG_ON (1 ); }@@ -257,6 +279,33 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset)return !props || (props->output &GPIO_BIT (offset)); }
drivers/gpio/gpio-aspeed.c static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset) · line 290
Quoted 10 lines
drivers/gpio/gpio-aspeed.c +9
-0+static void aspeed_gpio_change_cmd_source (struct aspeed_gpio *gpio, +const struct aspeed_gpio_bank *bank, +int bindex,int cmdsrc) +{ +void __iomem *c0 =bank_reg (gpio, bank, reg_cmdsrc0); +void __iomem *c1 =bank_reg (gpio, bank, reg_cmdsrc1); +u32 bit, reg; + + bit =1u << ((bindex &3 ) <<3 );
I didn't follow this on first go. If you can think of a way to make it clearer that the first 3 is just to mask off the first two bits that would be handy.
And perhaps this?
bit = BIT((bindex & 3) << 3);
Quoted 24 lines
drivers/gpio/gpio-aspeed.c +18
-1+ +/* Source 1 first to avoid illegal 11 combination */ + reg =ioread32 (c1); +if (cmdsrc &2 ) + reg |= bit; +else + reg &= ~bit; +iowrite32 (reg, c1); + +/* Then Source 0 */ + reg =ioread32 (c0); +if (cmdsrc &1 ) + reg |= bit; +else + reg &= ~bit; +iowrite32 (reg, c0); +} +static int aspeed_gpio_get (struct gpio_chip *gc,unsigned int offset) {struct aspeed_gpio *gpio =gpiochip_get_data (gc); --2.17.0
PATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
In reply to Benjamin HerrenschmidtOn the Aspeed chip, the GPIOs can be under control of the ARM chip or of the ColdFire coprocessor. (There's a third command source, the LPC bus, which we don't use or support yet).
The control of which master is allowed to modify a given GPIO is per-bank (8 GPIOs).
Unfortunately, systems already exist for which we want to use GPIOs of both sources in the same bank.
This provides an API exported by the gpio-aspeed driver that an aspeed coprocessor driver can use to "grab" some GPIOs for use by the coprocessor, and allow the coprocessor driver to provide callbacks for arbitrating access.
Once at least one GPIO of a given bank has been "grabbed" by the coprocessor, the entire bank is marked as being under coprocessor control. It's command source is switched to the coprocessor.
If the ARM then tries to write to a GPIO in such a marked bank, the provided callbacks are used to request access from the coprocessor driver, which is responsible to doing whatever is necessary to "pause" the coprocessor or prevent it from trying to use the GPIOs while the ARM is doing its accesses.
During that time, the command source for the bank is temporarily switched back to the ARM.
--- drivers/gpio/gpio-aspeed.c | 235 +++++++++++++++++++++++++++++++++--- include/linux/gpio/aspeed.h | 14 +++ 2 files changed, 229 insertions(+), 20 deletions(-) create mode 100644 include/linux/gpio/aspeed.h
drivers/gpio/gpio-aspeed.c +215 -20
@@ -12,6 +12,8 @@#include <asm/div64.h> #include <linux/clk.h> #include <linux/gpio/driver.h> +#include <linux/gpio/aspeed.h> +#include <linux/gpio/consumer.h> #include <linux/hashtable.h> #include <linux/init.h> #include <linux/io.h>
@@ -22,6 +24,8 @@#include <linux/spinlock.h> #include <linux/string.h> +#include "gpiolib.h" +struct aspeed_bank_props {unsigned int bank;u32 input;
@@ -56,6 +60,7 @@ struct aspeed_gpio {struct clk *clk;u32 *dcache; +u8 *cf_copro_bankmap; };struct aspeed_gpio_bank {
@@ -72,6 +77,9 @@ struct aspeed_gpio_bank {static const int debounce_timers[4 ] = {0x00 ,0x50 ,0x54 ,0x58 }; +static const struct aspeed_gpio_copro_ops *copro_ops; +static void *copro_data; +static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs =0x0000 ,
@@ -306,6 +314,50 @@ static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio,iowrite32 (reg, c0); } +static bool aspeed_gpio_copro_request (struct aspeed_gpio *gpio, +unsigned int offset) +{ +const struct aspeed_gpio_bank *bank =to_bank (offset); + +if (!copro_ops || !gpio->cf_copro_bankmap) +return false; +if (!gpio->cf_copro_bankmap[offset >>3 ]) +return false; +if (!copro_ops->request_access) +return false; + +/* Pause the coprocessor */ + copro_ops->request_access (copro_data); + +/* Change command source back to ARM */ +aspeed_gpio_change_cmd_source (gpio, bank, offset >>3 ,GPIO_CMDSRC_ARM ); + +/* Update cache */ + gpio->dcache[GPIO_BANK (offset)] =ioread32 (bank_reg (gpio, bank, reg_rdata)); + +return true; +} + +static void aspeed_gpio_copro_release (struct aspeed_gpio *gpio, +unsigned int offset) +{ +const struct aspeed_gpio_bank *bank =to_bank (offset); + +if (!copro_ops || !gpio->cf_copro_bankmap) +return ; +if (!gpio->cf_copro_bankmap[offset >>3 ]) +return ; +if (!copro_ops->release_access) +return ; + +/* Change command source back to ColdFire */ +aspeed_gpio_change_cmd_source (gpio, bank, offset >>3 , +GPIO_CMDSRC_COLDFIRE ); + +/* Restart the coprocessor */ + copro_ops->release_access (copro_data); +} +static int aspeed_gpio_get (struct gpio_chip *gc,unsigned int offset) {struct aspeed_gpio *gpio =gpiochip_get_data (gc);
@@ -339,11 +391,15 @@ static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, {struct aspeed_gpio *gpio =gpiochip_get_data (gc);unsigned long flags; +bool copro;spin_lock_irqsave (&gpio->lock, flags); + copro =aspeed_gpio_copro_request (gpio, offset);__aspeed_gpio_set (gc, offset, val); +if (copro) +aspeed_gpio_copro_release (gpio, offset);spin_unlock_irqrestore (&gpio->lock, flags); }
@@ -351,7 +407,9 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) {struct aspeed_gpio *gpio =gpiochip_get_data (gc);const struct aspeed_gpio_bank *bank =to_bank (offset); +void __iomem *addr =bank_reg (gpio, bank, reg_dir);unsigned long flags; +bool copro;u32 reg;if (!have_input (gpio, offset))
@@ -359,8 +417,13 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)spin_lock_irqsave (&gpio->lock, flags); - reg =ioread32 (bank_reg (gpio, bank, reg_dir)); -iowrite32 (reg & ~GPIO_BIT (offset),bank_reg (gpio, bank, reg_dir)); + reg =ioread32 (addr); + reg &= ~GPIO_BIT (offset); + + copro =aspeed_gpio_copro_request (gpio, offset); +iowrite32 (reg, addr); +if (copro) +aspeed_gpio_copro_release (gpio, offset);spin_unlock_irqrestore (&gpio->lock, flags);
@@ -372,7 +435,9 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, {struct aspeed_gpio *gpio =gpiochip_get_data (gc);const struct aspeed_gpio_bank *bank =to_bank (offset); +void __iomem *addr =bank_reg (gpio, bank, reg_dir);unsigned long flags; +bool copro;u32 reg;if (!have_output (gpio, offset))
@@ -380,10 +445,15 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc,spin_lock_irqsave (&gpio->lock, flags); + reg =ioread32 (addr); + reg |=GPIO_BIT (offset); + + copro =aspeed_gpio_copro_request (gpio, offset);__aspeed_gpio_set (gc, offset, val); - reg =ioread32 (bank_reg (gpio, bank, reg_dir)); -iowrite32 (reg |GPIO_BIT (offset),bank_reg (gpio, bank, reg_dir)); +iowrite32 (reg, addr); +if (copro) +aspeed_gpio_copro_release (gpio, offset);spin_unlock_irqrestore (&gpio->lock, flags);return 0 ;
@@ -413,24 +483,23 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) }static inline int irqd_to_aspeed_gpio_data (struct irq_data *d, -struct aspeed_gpio **gpio, -const struct aspeed_gpio_bank **bank, -u32 *bit) +struct aspeed_gpio **gpio, +const struct aspeed_gpio_bank **bank, +u32 *bit,int *offset) { -int offset;struct aspeed_gpio *internal; - offset =irqd_to_hwirq (d); + *offset =irqd_to_hwirq (d); internal =irq_data_get_irq_chip_data (d);/* This might be a bit of a questionable place to check */ -if (!have_irq (internal, offset)) +if (!have_irq (internal, *offset))return -ENOTSUPP ; *gpio = internal; - *bank =to_bank (offset); - *bit =GPIO_BIT (offset); + *bank =to_bank (*offset); + *bit =GPIO_BIT (*offset);return 0 ; }
@@ -441,17 +510,23 @@ static void aspeed_gpio_irq_ack(struct irq_data *d)struct aspeed_gpio *gpio;unsigned long flags;void __iomem *status_addr; +int rc, offset; +bool copro;u32 bit; -int rc; - rc =irqd_to_aspeed_gpio_data (d, &gpio, &bank, &bit); + rc =irqd_to_aspeed_gpio_data (d, &gpio, &bank, &bit, &offset);if (rc)return ; status_addr =bank_reg (gpio, bank, reg_irq_status);spin_lock_irqsave (&gpio->lock, flags); + copro =aspeed_gpio_copro_request (gpio, offset); +iowrite32 (bit, status_addr); + +if (copro) +aspeed_gpio_copro_release (gpio, offset);spin_unlock_irqrestore (&gpio->lock, flags); }
@@ -462,15 +537,17 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)unsigned long flags;u32 reg, bit;void __iomem *addr; -int rc; +int rc, offset; +bool copro; - rc =irqd_to_aspeed_gpio_data (d, &gpio, &bank, &bit); + rc =irqd_to_aspeed_gpio_data (d, &gpio, &bank, &bit, &offset);if (rc)return ; addr =bank_reg (gpio, bank, reg_irq_enable);spin_lock_irqsave (&gpio->lock, flags); + copro =aspeed_gpio_copro_request (gpio, offset); reg =ioread32 (addr);if (set)
@@ -479,6 +556,8 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) reg &= bit;iowrite32 (reg, addr); +if (copro) +aspeed_gpio_copro_release (gpio, offset);spin_unlock_irqrestore (&gpio->lock, flags); }
@@ -503,9 +582,10 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)struct aspeed_gpio *gpio;unsigned long flags;void __iomem *addr; -int rc; +int rc, offset; +bool copro; - rc =irqd_to_aspeed_gpio_data (d, &gpio, &bank, &bit); + rc =irqd_to_aspeed_gpio_data (d, &gpio, &bank, &bit, &offset);if (rc)return -EINVAL ;
@@ -528,6 +608,7 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) }spin_lock_irqsave (&gpio->lock, flags); + copro =aspeed_gpio_copro_request (gpio, offset); addr =bank_reg (gpio, bank, reg_irq_type0); reg =ioread32 (addr);
@@ -544,6 +625,8 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) reg = (reg & ~bit) | type2;iowrite32 (reg, addr); +if (copro) +aspeed_gpio_copro_release (gpio, offset);spin_unlock_irqrestore (&gpio->lock, flags);irq_set_handler_locked (d, handler);
@@ -638,11 +721,14 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip,struct aspeed_gpio *gpio =gpiochip_get_data (chip);unsigned long flags;void __iomem *treg; +bool copro;u32 val; treg =bank_reg (gpio,to_bank (offset), reg_tolerance);spin_lock_irqsave (&gpio->lock, flags); + copro =aspeed_gpio_copro_request (gpio, offset); + val =readl (treg);if (enable)
@@ -651,6 +737,9 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, val &= ~GPIO_BIT (offset);writel (val, treg); + +if (copro) +aspeed_gpio_copro_release (gpio, offset);spin_unlock_irqrestore (&gpio->lock, flags);return 0 ;
@@ -746,6 +835,9 @@ static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset,void __iomem *addr;u32 val; +/* Note: Debounce timer isn't under control of the command +* source registers, so no need to sync with the coprocessor +*/ addr =bank_reg (gpio, bank, reg_debounce_sel1); val =ioread32 (addr);iowrite32 ((val & ~mask) |GPIO_SET_DEBOUNCE1 (timer, offset), addr);
@@ -892,6 +984,101 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset,return -ENOTSUPP ; } +/** +* aspeed_gpio_copro_set_ops - Sets the callbacks used for handhsaking with +* the coprocessor for shared GPIO banks +* @ops: The callbacks +* @data: Pointer passed back to the callbacks +*/ +int aspeed_gpio_copro_set_ops (const struct aspeed_gpio_copro_ops *ops,void *data) +{ + copro_data = data; + copro_ops = ops; + +return 0 ; +} +EXPORT_SYMBOL_GPL (aspeed_gpio_copro_set_ops); + +/** +* aspeed_gpio_copro_grab_gpio - Mark a GPIO used by the coprocessor. The entire +* bank gets marked and any access from the ARM will +* result in handshaking via callbacks. +* @desc: The GPIO to be marked +*/ +int aspeed_gpio_copro_grab_gpio (struct gpio_desc *desc) +{ +struct gpio_chip *chip =gpiod_to_chip (desc); +struct aspeed_gpio *gpio =gpiochip_get_data (chip); +int rc =0 , bindex, offset =gpio_chip_hwgpio (desc); +const struct aspeed_gpio_bank *bank =to_bank (offset); +unsigned long flags; + +if (!gpio->cf_copro_bankmap) + gpio->cf_copro_bankmap =kzalloc (gpio->config->nr_gpios >>3 ,GFP_KERNEL ); +if (!gpio->cf_copro_bankmap) +return -ENOMEM ; +if (offset <0 || offset > gpio->config->nr_gpios) +return -EINVAL ; + bindex = offset >>3 ; + +spin_lock_irqsave (&gpio->lock, flags); + +/* Sanity check, this shouldn't happen */ +if (gpio->cf_copro_bankmap[bindex] ==0xff ) { + rc = -EIO ; + goto bail; + } + gpio->cf_copro_bankmap[bindex]++; + +/* Switch command source */ +if (gpio->cf_copro_bankmap[bindex] ==1 ) +aspeed_gpio_change_cmd_source (gpio, bank, bindex, +GPIO_CMDSRC_COLDFIRE ); + + bail: +spin_unlock_irqrestore (&gpio->lock, flags); +return rc; +} +EXPORT_SYMBOL_GPL (aspeed_gpio_copro_grab_gpio); + +/** +* aspeed_gpio_copro_release_gpio - Unmark a GPIO used by the coprocessor. +* @desc: The GPIO to be marked +*/ +int aspeed_gpio_copro_release_gpio (struct gpio_desc *desc) +{ +struct gpio_chip *chip =gpiod_to_chip (desc); +struct aspeed_gpio *gpio =gpiochip_get_data (chip); +int rc =0 , bindex, offset =gpio_chip_hwgpio (desc); +const struct aspeed_gpio_bank *bank =to_bank (offset); +unsigned long flags; + +if (!gpio->cf_copro_bankmap) +return -ENXIO ; + +if (offset <0 || offset > gpio->config->nr_gpios) +return -EINVAL ; + bindex = offset >>3 ; + +spin_lock_irqsave (&gpio->lock, flags); + +/* Sanity check, this shouldn't happen */ +if (gpio->cf_copro_bankmap[bindex] ==0 ) { + rc = -EIO ; + goto bail; + } + gpio->cf_copro_bankmap[bindex]--; + +/* Switch command source */ +if (gpio->cf_copro_bankmap[bindex] ==0 ) +aspeed_gpio_change_cmd_source (gpio, bank, bindex, +GPIO_CMDSRC_ARM ); + bail: +spin_unlock_irqrestore (&gpio->lock, flags); +return rc; +} +EXPORT_SYMBOL_GPL (aspeed_gpio_copro_release_gpio); +/* * Any banks not specified in a struct aspeed_bank_props array are assumed to * have the properties:
@@ -982,10 +1169,18 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)if (!gpio->dcache)return -ENOMEM ; -/* Populate it with initial values read from the HW */ +/* +* Populate it with initial values read from the HW and switch +* all command sources to the ARM by default +*/ for (i =0 ; i < banks; i++) { -void __iomem *addr =bank_reg (gpio, &aspeed_gpio_banks[i], reg_rdata); +const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; +void __iomem *addr =bank_reg (gpio, bank, reg_rdata); gpio->dcache[i] =ioread32 (addr); +aspeed_gpio_change_cmd_source (gpio, bank,0 ,GPIO_CMDSRC_ARM ); +aspeed_gpio_change_cmd_source (gpio, bank,1 ,GPIO_CMDSRC_ARM ); +aspeed_gpio_change_cmd_source (gpio, bank,2 ,GPIO_CMDSRC_ARM ); +aspeed_gpio_change_cmd_source (gpio, bank,3 ,GPIO_CMDSRC_ARM ); } rc =devm_gpiochip_add_data (&pdev->dev, &gpio->chip, gpio);
include/linux/gpio/aspeed.h new file +14 -0
@@ -0,0 +1,14 @@ +#ifndef __GPIO_ASPEED_H +#define __GPIO_ASPEED_H + +struct aspeed_gpio_copro_ops { +int (*request_access)(void *data); +int (*release_access)(void *data); +}; + +int aspeed_gpio_copro_grab_gpio (struct gpio_desc *desc); +int aspeed_gpio_copro_release_gpio (struct gpio_desc *desc); +int aspeed_gpio_copro_set_ops (const struct aspeed_gpio_copro_ops *ops,void *data); + + +#endif /* __GPIO_ASPEED_H */
Signature · 1 line
2.17.0
Joel Stanley
maintainerPATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
Quoted 26 lines · Benjamin Herrenschmidt
On the Aspeed chip, the GPIOs can be under control of the ARM chip or of the ColdFire coprocessor. (There's a third command source, the LPC bus, which we don't use or support yet).
The control of which master is allowed to modify a given GPIO is per-bank (8 GPIOs).
Unfortunately, systems already exist for which we want to use GPIOs of both sources in the same bank.
This provides an API exported by the gpio-aspeed driver that an aspeed coprocessor driver can use to "grab" some GPIOs for use by the coprocessor, and allow the coprocessor driver to provide callbacks for arbitrating access.
Once at least one GPIO of a given bank has been "grabbed" by the coprocessor, the entire bank is marked as being under coprocessor control. It's command source is switched to the coprocessor.
If the ARM then tries to write to a GPIO in such a marked bank, the provided callbacks are used to request access from the coprocessor driver, which is responsible to doing whatever is necessary to "pause" the coprocessor or prevent it from trying to use the GPIOs while the ARM is doing its accesses.
Quoted 4 lines
During that time, the command source for the bank is temporarily switched back to the ARM.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Looks okay to me. Just need to deal with the memory allocated.
Quoted 7 lines
drivers/gpio/gpio-aspeed.c +7
-0+ +/** +* aspeed_gpio_copro_grab_gpio - Mark a GPIO used by the coprocessor. The entire +* bank gets marked and any access from the ARM will +* result in handshaking via callbacks. +* @desc: The GPIO to be marked +*/
drivers/gpio/gpio-aspeed.c static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, · line 1017
Quoted 10 lines
drivers/gpio/gpio-aspeed.c +10
-0+int aspeed_gpio_copro_grab_gpio (struct gpio_desc *desc) +{ +struct gpio_chip *chip =gpiod_to_chip (desc); +struct aspeed_gpio *gpio =gpiochip_get_data (chip); +int rc =0 , bindex, offset =gpio_chip_hwgpio (desc); +const struct aspeed_gpio_bank *bank =to_bank (offset); +unsigned long flags; + +if (!gpio->cf_copro_bankmap) + gpio->cf_copro_bankmap =kzalloc (gpio->config->nr_gpios >>3 ,GFP_KERNEL );
Someone should free this.
Quoted 25 lines
drivers/gpio/gpio-aspeed.c +25
-0+if (!gpio->cf_copro_bankmap) +return -ENOMEM ; +if (offset <0 || offset > gpio->config->nr_gpios) +return -EINVAL ; + bindex = offset >>3 ; + +spin_lock_irqsave (&gpio->lock, flags); + +/* Sanity check, this shouldn't happen */ +if (gpio->cf_copro_bankmap[bindex] ==0xff ) { + rc = -EIO ; + goto bail; + } + gpio->cf_copro_bankmap[bindex]++; + +/* Switch command source */ +if (gpio->cf_copro_bankmap[bindex] ==1 ) +aspeed_gpio_change_cmd_source (gpio, bank, bindex, +GPIO_CMDSRC_COLDFIRE ); + + bail: +spin_unlock_irqrestore (&gpio->lock, flags); +return rc; +} +EXPORT_SYMBOL_GPL (aspeed_gpio_copro_grab_gpio);
PATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
Quoted 46 lines · Joel Stanley
Quoted 26 lines · Benjamin Herrenschmidt
On the Aspeed chip, the GPIOs can be under control of the ARM chip or of the ColdFire coprocessor. (There's a third command source, the LPC bus, which we don't use or support yet).
The control of which master is allowed to modify a given GPIO is per-bank (8 GPIOs).
Unfortunately, systems already exist for which we want to use GPIOs of both sources in the same bank.
This provides an API exported by the gpio-aspeed driver that an aspeed coprocessor driver can use to "grab" some GPIOs for use by the coprocessor, and allow the coprocessor driver to provide callbacks for arbitrating access.
Once at least one GPIO of a given bank has been "grabbed" by the coprocessor, the entire bank is marked as being under coprocessor control. It's command source is switched to the coprocessor.
If the ARM then tries to write to a GPIO in such a marked bank, the provided callbacks are used to request access from the coprocessor driver, which is responsible to doing whatever is necessary to "pause" the coprocessor or prevent it from trying to use the GPIOs while the ARM is doing its accesses.
Quoted 4 lines
During that time, the command source for the bank is temporarily switched back to the ARM.
Signed-off-by Benjamin Herrenschmidt <[email protected]>Looks okay to me. Just need to deal with the memory allocated.
Quoted 11 lines
drivers/gpio/gpio-aspeed.c +11
-0+ +/** +* aspeed_gpio_copro_grab_gpio - Mark a GPIO used by the coprocessor. The entire +* bank gets marked and any access from the ARM will +* result in handshaking via callbacks. +* @desc: The GPIO to be marked +*/ +int aspeed_gpio_copro_grab_gpio (struct gpio_desc *desc) +{ +struct gpio_chip *chip =gpiod_to_chip (desc); +struct aspeed_gpio *gpio =gpiochip_get_data (chip);
Quoted 8 lines
drivers/gpio/gpio-aspeed.c static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, · line 1017
Quoted 6 lines
drivers/gpio/gpio-aspeed.c +6
-0+int rc =0 , bindex, offset =gpio_chip_hwgpio (desc); +const struct aspeed_gpio_bank *bank =to_bank (offset); +unsigned long flags; + +if (!gpio->cf_copro_bankmap) + gpio->cf_copro_bankmap =kzalloc (gpio->config->nr_gpios >>3 ,GFP_KERNEL );Someone should free this.
Right, I'll probably just make it a devm_kzalloc
Quoted 25 lines
Quoted 25 lines
drivers/gpio/gpio-aspeed.c +25
-0+if (!gpio->cf_copro_bankmap) +return -ENOMEM ; +if (offset <0 || offset > gpio->config->nr_gpios) +return -EINVAL ; + bindex = offset >>3 ; + +spin_lock_irqsave (&gpio->lock, flags); + +/* Sanity check, this shouldn't happen */ +if (gpio->cf_copro_bankmap[bindex] ==0xff ) { + rc = -EIO ; + goto bail; + } + gpio->cf_copro_bankmap[bindex]++; + +/* Switch command source */ +if (gpio->cf_copro_bankmap[bindex] ==1 ) +aspeed_gpio_change_cmd_source (gpio, bank, bindex, +GPIO_CMDSRC_COLDFIRE ); + + bail: +spin_unlock_irqrestore (&gpio->lock, flags); +return rc; +} +EXPORT_SYMBOL_GPL (aspeed_gpio_copro_grab_gpio);
PATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
In reply to Joel StanleyQuoted 12 lines
Quoted 12 lines
drivers/gpio/gpio-aspeed.c +11
-0+ +/** +* aspeed_gpio_copro_grab_gpio - Mark a GPIO used by the coprocessor. The entire +* bank gets marked and any access from the ARM will +* result in handshaking via callbacks. +* @desc: The GPIO to be marked +*/ +int aspeed_gpio_copro_grab_gpio (struct gpio_desc *desc) +{ +struct gpio_chip *chip =gpiod_to_chip (desc); +struct aspeed_gpio *gpio =gpiochip_get_data (chip);
Quoted 8 lines
drivers/gpio/gpio-aspeed.c static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, · line 1017
Quoted 6 lines
drivers/gpio/gpio-aspeed.c +6
-0+int rc =0 , bindex, offset =gpio_chip_hwgpio (desc); +const struct aspeed_gpio_bank *bank =to_bank (offset); +unsigned long flags; + +if (!gpio->cf_copro_bankmap) + gpio->cf_copro_bankmap =kzalloc (gpio->config->nr_gpios >>3 ,GFP_KERNEL );Someone should free this.
Actually no. The driver doesn't have a remove(), so it doesn't.
Cheers,
Ben.
PATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
In reply to Benjamin HerrenschmidtQuoted 26 lines · Benjamin Herrenschmidt
On the Aspeed chip, the GPIOs can be under control of the ARM chip or of the ColdFire coprocessor. (There's a third command source, the LPC bus, which we don't use or support yet).
The control of which master is allowed to modify a given GPIO is per-bank (8 GPIOs).
Unfortunately, systems already exist for which we want to use GPIOs of both sources in the same bank.
This provides an API exported by the gpio-aspeed driver that an aspeed coprocessor driver can use to "grab" some GPIOs for use by the coprocessor, and allow the coprocessor driver to provide callbacks for arbitrating access.
Once at least one GPIO of a given bank has been "grabbed" by the coprocessor, the entire bank is marked as being under coprocessor control. It's command source is switched to the coprocessor.
If the ARM then tries to write to a GPIO in such a marked bank, the provided callbacks are used to request access from the coprocessor driver, which is responsible to doing whatever is necessary to "pause" the coprocessor or prevent it from trying to use the GPIOs while the ARM is doing its accesses.
Quoted 4 lines
During that time, the command source for the bank is temporarily switched back to the ARM.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Overall looks fine!
You definately need something like this for handling this special case.
Quoted 1 line
+#include <
linux/gpio/consumer.h>
Why do you need this?
I don't see that you use any functions from it.
Quoted 1 line
+#include "
gpiolib.h"
I'm not so happy about this either, what is this needed for?
It seems to me you can remove both includes, but admittedly I miss fine details all the time.
Yours,
Linus Walleij
PATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
Quoted 9 lines · Linus Walleij
Overall looks fine!
You definately need something like this for handling this special case.
Quoted 1 line
+#include <
linux/gpio/consumer.h>Why do you need this?
Quoted 8 lines
I don't see that you use any functions from it.
Quoted 1 line
+#include "
gpiolib.h"I'm not so happy about this either, what is this needed for?
It seems to me you can remove both includes, but admittedly I miss fine details all the time.
I wish I could :-) This is the main wart in there to be honest.
consumer.h is needed to build gpiolib.h
gpiolib.h is needed for gpio_chip_hwgpio() which needs the definition of gpio_desc, etc...
I didn't find a simple way out if it... the "API" I expose to the copro driver takes a gpio_desc which is the clean thing to do but I can't get to the underlying GPIO number without gpiolib.
Cheers,
Ben.
PATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
Quoted 19 lines · Benjamin Herrenschmidt
Quoted 9 lines · Linus Walleij
Overall looks fine!
You definately need something like this for handling this special case.
Quoted 1 line
+#include <
linux/gpio/consumer.h>Why do you need this?
Quoted 8 lines
I don't see that you use any functions from it.
Quoted 1 line
+#include "
gpiolib.h"I'm not so happy about this either, what is this needed for?
It seems to me you can remove both includes, but admittedly I miss fine details all the time.
Quoted 6 lines
I wish I could :-) This is the main wart in there to be honest.
consumer.his needed to buildgpiolib.h
gpiolib.his needed forgpio_chip_hwgpio()which needs the definition ofgpio_desc, etc...
Aha I see, you need that because while normally the gpiolib does the conversion of desc -> offset this is needed here in a driver.
Maybe we should just name it gpiod_to_offset() or something and make it a public API.
But this is actually OK, you definately need it here, toss in some comment or so about what is going on and why this is included so we know in the future.
Yours,
Linus Walleij
PATCH 4/4 gpio: aspeed: Add interfaces for co-processor to grab GPIOs
Quoted 11 lines · Linus Walleij
Aha I see, you need that because while normally the gpiolib does the conversion of desc -> offset this is needed here in a driver.
Maybe we should just name it
gpiod_to_offset()or something and make it a public API.But this is actually OK, you definately need it here, toss in some comment or so about what is going on and why this is included so we know in the future.
Ok, I'll spin a v4 with the interface addition I need to pass the offsets to the coprocessor and will add that comment some time today.
Cheers,
Ben.
cover gpio: aspeed: Fixes and support for sharing with co-processor
In reply to Benjamin HerrenschmidtQuoted 4 lines · Benjamin Herrenschmidt
This series cleans up the register accessors a bit, adds missing ones, fixes the access to the write latch and finally adds an interface that a co-processor driver can use to change the owner of some of the GPIO lines and arbitrate access to shared GPIO banks.
I'm pretty happy with the series as long as they have Joel's consent/ACK which seems doable. See comment about using gpiolib internals which I do not think is necessary.
Yours,
Linus Walleij
cover gpio: aspeed: Fixes and support for sharing with co-processor
Quoted 11 lines · Linus Walleij
Quoted 4 lines · Benjamin Herrenschmidt
This series cleans up the register accessors a bit, adds missing ones, fixes the access to the write latch and finally adds an interface that a co-processor driver can use to change the owner of some of the GPIO lines and arbitrate access to shared GPIO banks.
I'm pretty happy with the series as long as they have Joel's consent/ACK which seems doable. See comment about using gpiolib internals which I do not think is necessary.
Thanks. Yes I need to address Joel's comments, I was waiting for your review before posting a v2.
As for the gpiolib internals, it's unfortunate, see my other email, I'm happy to change that if you can suggest an alternative approach...
Cheers,
Ben.