pinctrl: Align Cannon Lake GPIO number space with Windows
Subsystems (4)
Mika Westerberg
maintainercover pinctrl: Align Cannon Lake GPIO number space with Windows
Hi,
It turns out that the Cannon Lake GPIO driver in Windows uses different GPIO numbering scheme than what Linux uses. Instead of hardware numbers it has "banks" of 32 pins even if the hardware group actually does not have that many pins. This is problematic for Linux because BIOS uses the same Windows numbering scheme in ACPI GpioIo/GpioInt resources, making Linux to pick a wrong pin.
For example the SD card detection GPIO resource in BIOS ACPI tables looks like:
GpioInt (...) {231} // vSD3_CD_B
Where the real hardware number would be 180 instead of 231.
Unfortunately changing the BIOS and the Windows driver is not possible for Cannon Lake anymore so we need to handle it in Linux instead. This should be done properly in future platforms.
The patch series updates the Intel pinctrl driver to allow passing custom GPIO number space, taking advantage of pin ranges supported by the pinctrl core. However, before we can add these pin ranges we need to drop the custom Cherryview GPIO/ACPI translation first and make the driver to use direct mapping instead (which turns out to be much simpler).
Once that is done we update the Cannon Lake pinctrl driver to align with the Windows GPIO driver numbering scheme.
Mika Westerberg (3):
gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation
pinctrl: intel: Allow custom GPIO base for pad groups
pinctrl: cannonlake: Align GPIO number space with Windows
drivers/gpio/gpiolib-acpi.c | 75 +------------- drivers/pinctrl/intel/pinctrl-cannonlake.c | 65 ++++++------ drivers/pinctrl/intel/pinctrl-cherryview.c | 59 ++++------- drivers/pinctrl/intel/pinctrl-intel.c | 156 +++++++++++++++++++++-------- drivers/pinctrl/intel/pinctrl-intel.h | 3 + 5 files changed, 176 insertions(+), 182 deletions(-)
Signature · 1 line
2.15.0
Mika Westerberg
maintainerPATCH 1/3 gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation
We added acpi_gpiochip_pin_to_gpio_offset() because there was a need to translate from ACPI GpioIo/GpioInt number to Linux GPIO number in the Cherryview pinctrl driver. This translation is necessary because Cherryview has gaps in the pin list and the driver used continuous GPIO number space in Linux side as follows:
created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 8->19 ==> INT33FF:03 PIN 15->26 created GPIO range 20->25 ==> INT33FF:03 PIN 30->35 created GPIO range 26->33 ==> INT33FF:03 PIN 45->52 created GPIO range 34->43 ==> INT33FF:03 PIN 60->69 created GPIO range 44->54 ==> INT33FF:03 PIN 75->85
For example when ACPI GpioInt resource refers to GPIO 81 (SDMMC3_CD_B) we translate from pin 81 to the corresponding Linux GPIO number, which is 50. This number is then used when the GPIO is accessed through gpiolib.
It turns out, this is not necessary at all. We can just pass 1:1 mapping between Linux GPIO numbers and pin numbers (including gaps) and the pinctrl core handles all the details automatically:
created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 15->26 ==> INT33FF:03 PIN 15->26 created GPIO range 30->35 ==> INT33FF:03 PIN 30->35 created GPIO range 45->52 ==> INT33FF:03 PIN 45->52 created GPIO range 60->69 ==> INT33FF:03 PIN 60->69 created GPIO range 75->85 ==> INT33FF:03 PIN 75->85
Here GPIO 81 is exactly same than the hardware pin 81 (SDMMC3_CD_B).
As an added bonus this simplifies both the ACPI GPIO core code and the Cherryview pinctrl driver.
--- drivers/gpio/gpiolib-acpi.c | 75 +----------------------------- drivers/pinctrl/intel/pinctrl-cherryview.c | 59 ++++++++--------------- 2 files changed, 22 insertions(+), 112 deletions(-)
drivers/gpio/gpiolib-acpi.c +2 -73
@@ -58,58 +58,6 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)return ACPI_HANDLE (gc->parent) == data; } -#ifdef CONFIG_PINCTRL -/** -* acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO -* @gdev: GPIO device -* @pin: ACPI GPIO pin number from GpioIo/GpioInt resource -* -* Function takes ACPI GpioIo/GpioInt pin number as a parameter and -* translates it to a corresponding offset suitable to be passed to a -* GPIO controller driver. -* -* Typically the returned offset is same as @pin, but if the GPIO -* controller uses pin controller and the mapping is not contiguous the -* offset might be different. -*/ -static int acpi_gpiochip_pin_to_gpio_offset (struct gpio_device *gdev,int pin) -{ -struct gpio_pin_range *pin_range; - -/* If there are no ranges in this chip, use 1:1 mapping */ -if (list_empty (&gdev->pin_ranges)) -return pin; - -list_for_each_entry (pin_range, &gdev->pin_ranges, node) { -const struct pinctrl_gpio_range *range = &pin_range->range; -int i; - -if (range->pins) { -for (i =0 ; i < range->npins; i++) { -if (range->pins[i] == pin) -return range->base + i - gdev->base; - } - }else { -if (pin >= range->pin_base && - pin < range->pin_base + range->npins) { -unsigned gpio_base; - - gpio_base = range->base - gdev->base; -return gpio_base + pin - range->pin_base; - } - } - } - -return -EINVAL ; -} -#else -static inline int acpi_gpiochip_pin_to_gpio_offset (struct gpio_device *gdev, -int pin) -{ -return pin; -} -#endif -/** * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
@@ -125,7 +73,6 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)struct gpio_chip *chip;acpi_handle handle;acpi_status status; -int offset; status =acpi_get_handle (NULL , path, &handle);if (ACPI_FAILURE (status))
@@ -135,11 +82,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)if (!chip)return ERR_PTR (-EPROBE_DEFER ); - offset =acpi_gpiochip_pin_to_gpio_offset (chip->gpiodev, pin); -if (offset <0 ) -return ERR_PTR (offset); - -return gpiochip_get_desc (chip, offset); +return gpiochip_get_desc (chip, pin); }static irqreturn_t acpi_gpio_irq_handler (int irq,void *data)
@@ -216,10 +159,6 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,if (!handler)return AE_OK ; - pin =acpi_gpiochip_pin_to_gpio_offset (chip->gpiodev, pin); -if (pin <0 ) -return AE_BAD_PARAMETER ; - desc =gpiochip_request_own_desc (chip, pin,"ACPI:Event" );if (IS_ERR (desc)) {dev_err (chip->parent,"Failed to request GPIO\n" );
@@ -852,12 +791,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,struct gpio_desc *desc;bool found; - pin =acpi_gpiochip_pin_to_gpio_offset (chip->gpiodev, pin); -if (pin <0 ) { - status =AE_BAD_PARAMETER ; - goto out; - } -mutex_lock (&achip->conn_lock); found = false;
@@ -990,11 +923,7 @@ static struct gpio_desc *acpi_gpiochip_parse_own_gpio(if (ret <0 )return ERR_PTR (ret); - ret =acpi_gpiochip_pin_to_gpio_offset (chip->gpiodev, gpios[0 ]); -if (ret <0 ) -return ERR_PTR (ret); - - desc =gpiochip_get_desc (chip, ret); + desc =gpiochip_get_desc (chip, gpios[0 ]);if (IS_ERR (desc))return desc;
drivers/pinctrl/intel/pinctrl-cherryview.c +20 -39
198 lines not on this page · raw message
Signature · 1 line
2.15.0
Re: [PATCH 1/3] gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation
Quoted 28 lines · Mika Westerberg
We added
acpi_gpiochip_pin_to_gpio_offset()because there was a need to translate from ACPI GpioIo/GpioInt number to Linux GPIO number in the Cherryview pinctrl driver. This translation is necessary because Cherryview has gaps in the pin list and the driver used continuous GPIO number space in Linux side as follows:created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 8->19 ==> INT33FF:03 PIN 15->26 created GPIO range 20->25 ==> INT33FF:03 PIN 30->35 created GPIO range 26->33 ==> INT33FF:03 PIN 45->52 created GPIO range 34->43 ==> INT33FF:03 PIN 60->69 created GPIO range 44->54 ==> INT33FF:03 PIN 75->85
For example when ACPI GpioInt resource refers to GPIO 81 (
SDMMC3_CD_B) we translate from pin 81 to the corresponding Linux GPIO number, which is 50. This number is then used when the GPIO is accessed through gpiolib.It turns out, this is not necessary at all. We can just pass 1:1 mapping between Linux GPIO numbers and pin numbers (including gaps) and the pinctrl core handles all the details automatically:
created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 15->26 ==> INT33FF:03 PIN 15->26 created GPIO range 30->35 ==> INT33FF:03 PIN 30->35 created GPIO range 45->52 ==> INT33FF:03 PIN 45->52 created GPIO range 60->69 ==> INT33FF:03 PIN 60->69 created GPIO range 75->85 ==> INT33FF:03 PIN 75->85
Quoted 4 lines
Here GPIO 81 is exactly same than the hardware pin 81 (
SDMMC3_CD_B).As an added bonus this simplifies both the ACPI GPIO core code and the Cherryview pinctrl driver.
Cool!
Re: [PATCH 1/3] gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation
In reply to Mika WesterbergQuoted 28 lines · Mika Westerberg
We added
acpi_gpiochip_pin_to_gpio_offset()because there was a need to translate from ACPI GpioIo/GpioInt number to Linux GPIO number in the Cherryview pinctrl driver. This translation is necessary because Cherryview has gaps in the pin list and the driver used continuous GPIO number space in Linux side as follows:created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 8->19 ==> INT33FF:03 PIN 15->26 created GPIO range 20->25 ==> INT33FF:03 PIN 30->35 created GPIO range 26->33 ==> INT33FF:03 PIN 45->52 created GPIO range 34->43 ==> INT33FF:03 PIN 60->69 created GPIO range 44->54 ==> INT33FF:03 PIN 75->85
For example when ACPI GpioInt resource refers to GPIO 81 (
SDMMC3_CD_B) we translate from pin 81 to the corresponding Linux GPIO number, which is 50. This number is then used when the GPIO is accessed through gpiolib.It turns out, this is not necessary at all. We can just pass 1:1 mapping between Linux GPIO numbers and pin numbers (including gaps) and the pinctrl core handles all the details automatically:
created GPIO range 0->7 ==> INT33FF:03 PIN 0->7 created GPIO range 15->26 ==> INT33FF:03 PIN 15->26 created GPIO range 30->35 ==> INT33FF:03 PIN 30->35 created GPIO range 45->52 ==> INT33FF:03 PIN 45->52 created GPIO range 60->69 ==> INT33FF:03 PIN 60->69 created GPIO range 75->85 ==> INT33FF:03 PIN 75->85
Quoted 6 lines
Here GPIO 81 is exactly same than the hardware pin 81 (
SDMMC3_CD_B).As an added bonus this simplifies both the ACPI GPIO core code and the Cherryview pinctrl driver.
Signed-off-by Mika Westerberg <[email protected]>
I optimistically applied this with the ACKs to the pinctrl tree hoping it does not
clash with Andy's refactorings that I applied to the GPIO tree.
Let's see what happens.
Yours,
Linus Walleij
Mika Westerberg
maintainerPATCH 2/3 pinctrl: intel: Allow custom GPIO base for pad groups
In reply to Mika WesterbergCurrently we always have direct mapping between GPIO numbers and the hardware pin numbers. However, there are cases where that's not the case anymore (more about this in the next patch). Instead we need to be able to specify custom GPIO base for certain pad groups.
To support this, add a new field (gpio_base) to the pad group structure and update the core Intel pinctrl driver to handle this accordingly. Passing 0 as gpio_base will use direct mapping so the existing drivers do not need to be modified. Passing -1 excludes the whole pad group from having GPIO mapping.
--- drivers/pinctrl/intel/pinctrl-intel.c | 156 +++++++++++++++++++++++++--------- drivers/pinctrl/intel/pinctrl-intel.h | 3 + 2 files changed, 120 insertions(+), 39 deletions(-)
drivers/pinctrl/intel/pinctrl-intel.c +117 -39
@@ -811,22 +811,63 @@ static const struct gpio_chip intel_gpio_chip = { .set_config = gpiochip_generic_config, }; +/** +* intel_gpio_to_pin() - Translate from GPIO offset to pin number +* @pctrl: Pinctrl structure +* @offset: GPIO offset from gpiolib +* @commmunity: Community is filled here if not %NULL +* @padgrp: Pad group is filled here if not %NULL +* +* When coming through gpiolib irqchip, the GPIO offset is not +* automatically translated to pinctrl pin number. This function can be +* used to find out the corresponding pinctrl pin. +*/ +static int intel_gpio_to_pin (struct intel_pinctrl *pctrl,unsigned offset, +const struct intel_community **community, +const struct intel_padgroup **padgrp) +{ +int i; + +for (i =0 ; i < pctrl->ncommunities; i++) { +const struct intel_community *comm = &pctrl->communities[i]; +int j; + +for (j =0 ; j < comm->ngpps; j++) { +const struct intel_padgroup *pgrp = &comm->gpps[j]; + +if (pgrp->gpio_base <0 ) +continue ; + +if (offset >= pgrp->gpio_base && + offset < pgrp->gpio_base + pgrp->size) { +int pin; + + pin = pgrp->base + offset - pgrp->gpio_base; +if (community) + *community = comm; +if (padgrp) + *padgrp = pgrp; + +return pin; + } + } + } + +return -EINVAL ; +} +static void intel_gpio_irq_ack (struct irq_data *d) {struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct intel_pinctrl *pctrl =gpiochip_get_data (gc);const struct intel_community *community; -unsigned pin =irqd_to_hwirq (d); +const struct intel_padgroup *padgrp; +int pin; - community =intel_get_community (pctrl, pin); -if (community) { -const struct intel_padgroup *padgrp; + pin =intel_gpio_to_pin (pctrl,irqd_to_hwirq (d), &community, &padgrp); +if (pin >=0 ) {unsigned gpp, gpp_offset, is_offset; - padgrp =intel_community_get_padgroup (community, pin); -if (!padgrp) -return ; - gpp = padgrp->reg_num; gpp_offset =padgroup_offset (padgrp, pin); is_offset = community->is_offset + gpp *4 ;
@@ -842,19 +883,15 @@ static void intel_gpio_irq_enable(struct irq_data *d)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct intel_pinctrl *pctrl =gpiochip_get_data (gc);const struct intel_community *community; -unsigned pin =irqd_to_hwirq (d); +const struct intel_padgroup *padgrp; +int pin; - community =intel_get_community (pctrl, pin); -if (community) { -const struct intel_padgroup *padgrp; + pin =intel_gpio_to_pin (pctrl,irqd_to_hwirq (d), &community, &padgrp); +if (pin >=0 ) {unsigned gpp, gpp_offset, is_offset;unsigned long flags;u32 value; - padgrp =intel_community_get_padgroup (community, pin); -if (!padgrp) -return ; - gpp = padgrp->reg_num; gpp_offset =padgroup_offset (padgrp, pin); is_offset = community->is_offset + gpp *4 ;
@@ -875,20 +912,16 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct intel_pinctrl *pctrl =gpiochip_get_data (gc);const struct intel_community *community; -unsigned pin =irqd_to_hwirq (d); +const struct intel_padgroup *padgrp; +int pin; - community =intel_get_community (pctrl, pin); -if (community) { -const struct intel_padgroup *padgrp; + pin =intel_gpio_to_pin (pctrl,irqd_to_hwirq (d), &community, &padgrp); +if (pin >=0 ) {unsigned gpp, gpp_offset;unsigned long flags;void __iomem *reg;u32 value; - padgrp =intel_community_get_padgroup (community, pin); -if (!padgrp) -return ; - gpp = padgrp->reg_num; gpp_offset =padgroup_offset (padgrp, pin);
@@ -919,7 +952,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) {struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct intel_pinctrl *pctrl =gpiochip_get_data (gc); -unsigned pin =irqd_to_hwirq (d); +unsigned pin =intel_gpio_to_pin (pctrl,irqd_to_hwirq (d),NULL ,NULL );unsigned long flags;void __iomem *reg;u32 value;
@@ -976,7 +1009,7 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) {struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct intel_pinctrl *pctrl =gpiochip_get_data (gc); -unsigned pin =irqd_to_hwirq (d); +unsigned pin =intel_gpio_to_pin (pctrl,irqd_to_hwirq (d),NULL ,NULL );if (on)enable_irq_wake (pctrl->irq);
@@ -1007,14 +1040,10 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, pending &= enabled;for_each_set_bit (gpp_offset, &pending, padgrp->size) { -unsigned padno, irq; - - padno = padgrp->base - community->pin_base + gpp_offset; -if (padno >= community->npins) -break ; +unsigned irq; irq =irq_find_mapping (gc->irq.domain, - community->pin_base + padno); + padgrp->gpio_base + gpp_offset);generic_handle_irq (irq); ret |=IRQ_HANDLED ;
@@ -1051,13 +1080,56 @@ static struct irq_chip intel_gpio_irqchip = { .flags = IRQCHIP_MASK_ON_SUSPEND, }; +static int intel_gpio_add_pin_ranges (struct intel_pinctrl *pctrl, +const struct intel_community *community) +{ +int ret, i; + +for (i =0 ; i < community->ngpps; i++) { +const struct intel_padgroup *gpp = &community->gpps[i]; + +if (gpp->gpio_base <0 ) +continue ; + + ret =gpiochip_add_pin_range (&pctrl->chip,dev_name (pctrl->dev), + gpp->gpio_base, gpp->base, + gpp->size); +if (ret) +return ret; + } + +return ret; +} + +static unsigned intel_gpio_ngpio (const struct intel_pinctrl *pctrl) +{ +const struct intel_community *community; +unsigned ngpio =0 ; +int i, j; + +for (i =0 ; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; +for (j =0 ; j < community->ngpps; j++) { +const struct intel_padgroup *gpp = &community->gpps[j]; + +if (gpp->gpio_base <0 ) +continue ; + +if (gpp->gpio_base + gpp->size > ngpio) + ngpio = gpp->gpio_base + gpp->size; + } + } + +return ngpio; +} +static int intel_gpio_probe (struct intel_pinctrl *pctrl,int irq) { -int ret; +int ret, i; pctrl->chip = intel_gpio_chip; - pctrl->chip.ngpio = pctrl->soc->npins; + pctrl->chip.ngpio =intel_gpio_ngpio (pctrl); pctrl->chip.label =dev_name (pctrl->dev); pctrl->chip.parent = pctrl->dev; pctrl->chip.base =-1 ;
@@ -1069,11 +1141,14 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)return ret; } - ret =gpiochip_add_pin_range (&pctrl->chip,dev_name (pctrl->dev), -0 ,0 , pctrl->soc->npins); -if (ret) { -dev_err (pctrl->dev,"failed to add GPIO pin range\n" ); -return ret; +for (i =0 ; i < pctrl->ncommunities; i++) { +struct intel_community *community = &pctrl->communities[i]; + + ret =intel_gpio_add_pin_ranges (pctrl, community); +if (ret) { +dev_err (pctrl->dev,"failed to add GPIO pin range\n" ); +return ret; + } }/*
@@ -1133,6 +1208,9 @@ static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl,if (gpps[i].size >32 )return -EINVAL ; +if (!gpps[i].gpio_base) + gpps[i].gpio_base = gpps[i].base; + gpps[i].padown_num = padown_num;/*
drivers/pinctrl/intel/pinctrl-intel.h +3 -0
@@ -51,6 +51,8 @@ struct intel_function {* @reg_num: GPI_IS register number * @base: Starting pin of this group * @size: Size of this group (maximum is 32). +* @gpio_base: Starting GPIO base of this group (%0 if matches with @base, +* and %-1 if no GPIO mapping should be created) * @padown_num: PAD_OWN register number (assigned by the core driver) * * If pad groups of a community are not the same size, use this structure
@@ -60,6 +62,7 @@ struct intel_padgroup {unsigned reg_num;unsigned base;unsigned size; +int gpio_base;unsigned padown_num; };
Signature · 1 line
2.15.0
Re: [PATCH 2/3] pinctrl: intel: Allow custom GPIO base for pad groups
Quoted 5 lines · Mika Westerberg
Currently we always have direct mapping between GPIO numbers and the hardware pin numbers. However, there are cases where that's not the case anymore (more about this in the next patch). Instead we need to be able to specify custom GPIO base for certain pad groups.
Quoted 7 lines
To support this, add a new field (
gpio_base) to the pad group structure and update the core Intel pinctrl driver to handle this accordingly. Passing 0 asgpio_basewill use direct mapping so the existing drivers do not need to be modified. Passing -1 excludes the whole pad group from having GPIO mapping.Signed-off-by Mika Westerberg <[email protected]>
Patch applied with Andy's ACK.
Yours,
Linus Walleij
Mika Westerberg
maintainerPATCH 3/3 pinctrl: cannonlake: Align GPIO number space with Windows
In reply to Mika WesterbergThe Cannon Lake Windows GPIO driver always exposes 32 pins per "bank" regardless of whether the hardware actually has that many pins in a pad group. This means that there are gaps in the GPIO number space even if such gaps do not exist in the real hardware. To make things worse the BIOS is also using the same scheme, so for example on Cannon Lake-LP vGPIO 39 (vSD3_CD_B) the ACPI GpioInt resource has number 231 instead of the expected 180 (which would be the hardware number).
To make SD card detection and other GPIOs working properly in Linux we align the pinctrl-cannonlake GPIO numbering to follow the Windows GPIO driver numbering taking advantage of the gpio_base field introduced in the previous patch.
--- drivers/pinctrl/intel/pinctrl-cannonlake.c | 65 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 31 deletions(-)
drivers/pinctrl/intel/pinctrl-cannonlake.c +34 -31
@@ -23,13 +23,16 @@#define CNL_HOSTSW_OWN 0x0b0#define CNL_GPI_IE 0x120 -#define CNL_GPP (r, s, e) \ +#define CNL_GPP (r, s, e, g) \ { \ .reg_num = (r), \ .base = (s), \ .size = ((e) - (s) + 1), \ + .gpio_base = (g), \ } +#define CNL_NO_GPIO -1 +#define CNL_COMMUNITY (b, s, e, g) \ { \ .barno = (b), \
@@ -363,32 +366,32 @@ static const struct pinctrl_pin_desc cnlh_pins[] = { };static const struct intel_padgroup cnlh_community0_gpps[] = { -CNL_GPP (0 ,0 ,24 ),/* GPP_A */ -CNL_GPP (1 ,25 ,50 ),/* GPP_B */ +CNL_GPP (0 ,0 ,24 ,0 ),/* GPP_A */ +CNL_GPP (1 ,25 ,50 ,32 ),/* GPP_B */ };static const struct intel_padgroup cnlh_community1_gpps[] = { -CNL_GPP (0 ,51 ,74 ),/* GPP_C */ -CNL_GPP (1 ,75 ,98 ),/* GPP_D */ -CNL_GPP (2 ,99 ,106 ),/* GPP_G */ -CNL_GPP (3 ,107 ,114 ),/* AZA */ -CNL_GPP (4 ,115 ,146 ),/* vGPIO_0 */ -CNL_GPP (5 ,147 ,154 ),/* vGPIO_1 */ +CNL_GPP (0 ,51 ,74 ,64 ),/* GPP_C */ +CNL_GPP (1 ,75 ,98 ,96 ),/* GPP_D */ +CNL_GPP (2 ,99 ,106 ,128 ),/* GPP_G */ +CNL_GPP (3 ,107 ,114 ,CNL_NO_GPIO ),/* AZA */ +CNL_GPP (4 ,115 ,146 ,160 ),/* vGPIO_0 */ +CNL_GPP (5 ,147 ,154 ,CNL_NO_GPIO ),/* vGPIO_1 */ };static const struct intel_padgroup cnlh_community3_gpps[] = { -CNL_GPP (0 ,155 ,178 ),/* GPP_K */ -CNL_GPP (1 ,179 ,202 ),/* GPP_H */ -CNL_GPP (2 ,203 ,215 ),/* GPP_E */ -CNL_GPP (3 ,216 ,239 ),/* GPP_F */ -CNL_GPP (4 ,240 ,248 ),/* SPI */ +CNL_GPP (0 ,155 ,178 ,192 ),/* GPP_K */ +CNL_GPP (1 ,179 ,202 ,224 ),/* GPP_H */ +CNL_GPP (2 ,203 ,215 ,258 ),/* GPP_E */ +CNL_GPP (3 ,216 ,239 ,288 ),/* GPP_F */ +CNL_GPP (4 ,240 ,248 ,CNL_NO_GPIO ),/* SPI */ };static const struct intel_padgroup cnlh_community4_gpps[] = { -CNL_GPP (0 ,249 ,259 ),/* CPU */ -CNL_GPP (1 ,260 ,268 ),/* JTAG */ -CNL_GPP (2 ,269 ,286 ),/* GPP_I */ -CNL_GPP (3 ,287 ,298 ),/* GPP_J */ +CNL_GPP (0 ,249 ,259 ,CNL_NO_GPIO ),/* CPU */ +CNL_GPP (1 ,260 ,268 ,CNL_NO_GPIO ),/* JTAG */ +CNL_GPP (2 ,269 ,286 ,320 ),/* GPP_I */ +CNL_GPP (3 ,287 ,298 ,352 ),/* GPP_J */ };static const unsigned int cnlh_spi0_pins[] = {40 ,41 ,42 ,43 };
@@ -785,25 +788,25 @@ static const struct intel_function cnllp_functions[] = { };static const struct intel_padgroup cnllp_community0_gpps[] = { -CNL_GPP (0 ,0 ,24 ),/* GPP_A */ -CNL_GPP (1 ,25 ,50 ),/* GPP_B */ -CNL_GPP (2 ,51 ,58 ),/* GPP_G */ -CNL_GPP (3 ,59 ,67 ),/* SPI */ +CNL_GPP (0 ,0 ,24 ,0 ),/* GPP_A */ +CNL_GPP (1 ,25 ,50 ,32 ),/* GPP_B */ +CNL_GPP (2 ,51 ,58 ,64 ),/* GPP_G */ +CNL_GPP (3 ,59 ,67 ,CNL_NO_GPIO ),/* SPI */ };static const struct intel_padgroup cnllp_community1_gpps[] = { -CNL_GPP (0 ,68 ,92 ),/* GPP_D */ -CNL_GPP (1 ,93 ,116 ),/* GPP_F */ -CNL_GPP (2 ,117 ,140 ),/* GPP_H */ -CNL_GPP (3 ,141 ,172 ),/* vGPIO */ -CNL_GPP (4 ,173 ,180 ),/* vGPIO */ +CNL_GPP (0 ,68 ,92 ,96 ),/* GPP_D */ +CNL_GPP (1 ,93 ,116 ,128 ),/* GPP_F */ +CNL_GPP (2 ,117 ,140 ,160 ),/* GPP_H */ +CNL_GPP (3 ,141 ,172 ,192 ),/* vGPIO */ +CNL_GPP (4 ,173 ,180 ,224 ),/* vGPIO */ };static const struct intel_padgroup cnllp_community4_gpps[] = { -CNL_GPP (0 ,181 ,204 ),/* GPP_C */ -CNL_GPP (1 ,205 ,228 ),/* GPP_E */ -CNL_GPP (2 ,229 ,237 ),/* JTAG */ -CNL_GPP (3 ,238 ,243 ),/* HVCMOS */ +CNL_GPP (0 ,181 ,204 ,256 ),/* GPP_C */ +CNL_GPP (1 ,205 ,228 ,288 ),/* GPP_E */ +CNL_GPP (2 ,229 ,237 ,CNL_NO_GPIO ),/* JTAG */ +CNL_GPP (3 ,238 ,243 ,CNL_NO_GPIO ),/* HVCMOS */ };static const struct intel_community cnllp_communities[] = {
Signature · 1 line
2.15.0
Quoted 37 lines · Mika Westerberg
Hi,
It turns out that the Cannon Lake GPIO driver in Windows uses different
GPIO numbering scheme than what Linux uses. Instead of hardware numbers it
has "banks" of 32 pins even if the hardware group actually does not have
that many pins. This is problematic for Linux because BIOS uses the same
Windows numbering scheme in ACPI GpioIo/GpioInt resources, making Linux to
pick a wrong pin.For example the SD card detection GPIO resource in BIOS ACPI tables looks
like:GpioInt (...) {231} //
vSD3_CD_BWhere the real hardware number would be 180 instead of 231.
Unfortunately changing the BIOS and the Windows driver is not possible for
Cannon Lake anymore so we need to handle it in Linux instead. This should
be done properly in future platforms.The patch series updates the Intel pinctrl driver to allow passing custom
GPIO number space, taking advantage of pin ranges supported by the pinctrl
core. However, before we can add these pin ranges we need to drop the custom Cherryview GPIO/ACPI translation first and make the driver to use
direct mapping instead (which turns out to be much simpler).
Quoted 3 lines
Once that is done we update the Cannon Lake pinctrl driver to align with
the Windows GPIO driver numbering scheme.
For all three:
Quoted 14 lines
Mika Westerberg (3):
gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation
pinctrl: intel: Allow custom GPIO base for pad groups
pinctrl: cannonlake: Align GPIO number space with Windowsdrivers/gpio/gpiolib-acpi.c | 75 +------------- drivers/pinctrl/intel/pinctrl-cannonlake.c | 65 ++++++------ drivers/pinctrl/intel/pinctrl-cherryview.c | 59 ++++------- drivers/pinctrl/intel/pinctrl-intel.c | 156 +++++++++++++++++++++-------- drivers/pinctrl/intel/pinctrl-intel.h | 3 + 5 files changed, 176 insertions(+), 182 deletions(-)
Signature · 2 lines
Andy Shevchenko <[email protected]> Intel Finland Oy
Quoted 24 lines · Mika Westerberg
It turns out that the Cannon Lake GPIO driver in Windows uses different GPIO numbering scheme than what Linux uses. Instead of hardware numbers it has "banks" of 32 pins even if the hardware group actually does not have that many pins. This is problematic for Linux because BIOS uses the same Windows numbering scheme in ACPI GpioIo/GpioInt resources, making Linux to pick a wrong pin.
For example the SD card detection GPIO resource in BIOS ACPI tables looks like:
GpioInt (...) {231} //
vSD3_CD_BWhere the real hardware number would be 180 instead of 231.
Unfortunately changing the BIOS and the Windows driver is not possible for Cannon Lake anymore so we need to handle it in Linux instead. This should be done properly in future platforms.
The patch series updates the Intel pinctrl driver to allow passing custom GPIO number space, taking advantage of pin ranges supported by the pinctrl core. However, before we can add these pin ranges we need to drop the custom Cherryview GPIO/ACPI translation first and make the driver to use direct mapping instead (which turns out to be much simpler).
Quoted 7 lines
Once that is done we update the Cannon Lake pinctrl driver to align with the Windows GPIO driver numbering scheme.
Mika Westerberg (3):
gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation
pinctrl: intel: Allow custom GPIO base for pad groups
pinctrl: cannonlake: Align GPIO number space with Windows
I applied these with Andy's ACKs.
I guess I vageuly understand what happened.
So the ACPI GPIO numberspace was misaligned with the actual hardware GPIO numberspace. That's unfortunate.
I hope these is nothing in here trying to align the *LINUX* global GPIO numberspace with this weirdness and that lsgpio still gives something reasonable per-gpiochip?
Yours,
Linus Walleij
Mika Westerberg
maintainerQuoted 30 lines · Linus Walleij
Quoted 27 lines · Mika Westerberg
It turns out that the Cannon Lake GPIO driver in Windows uses different GPIO numbering scheme than what Linux uses. Instead of hardware numbers it has "banks" of 32 pins even if the hardware group actually does not have that many pins. This is problematic for Linux because BIOS uses the same Windows numbering scheme in ACPI GpioIo/GpioInt resources, making Linux to pick a wrong pin.
For example the SD card detection GPIO resource in BIOS ACPI tables looks like:
GpioInt (...) {231} //
vSD3_CD_BWhere the real hardware number would be 180 instead of 231.
Unfortunately changing the BIOS and the Windows driver is not possible for Cannon Lake anymore so we need to handle it in Linux instead. This should be done properly in future platforms.
The patch series updates the Intel pinctrl driver to allow passing custom GPIO number space, taking advantage of pin ranges supported by the pinctrl core. However, before we can add these pin ranges we need to drop the custom Cherryview GPIO/ACPI translation first and make the driver to use direct mapping instead (which turns out to be much simpler).
Once that is done we update the Cannon Lake pinctrl driver to align with the Windows GPIO driver numbering scheme.
Quoted 6 lines
Quoted 4 lines
Mika Westerberg (3):
gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation
pinctrl: intel: Allow custom GPIO base for pad groups
pinctrl: cannonlake: Align GPIO number space with WindowsI applied these with Andy's ACKs.
Thanks!
Quoted 4 lines
I guess I vageuly understand what happened.
So the ACPI GPIO numberspace was misaligned with the actual hardware GPIO numberspace. That's unfortunate.
That's right.
Quoted 3 lines
I hope these is nothing in here trying to align the *LINUX* global GPIO numberspace with this weirdness and that lsgpio still gives something reasonable per-gpiochip?
The resulting GPIO ranges for the chip look like following on the problematic system:
# cat /sys/kernel/debug/pinctrl/INT34BB\:00/gpio-ranges GPIO ranges handled: 0: INT34BB:00 GPIOS [200 - 224] PINS [0 - 24] 32: INT34BB:00 GPIOS [232 - 257] PINS [25 - 50] 64: INT34BB:00 GPIOS [264 - 271] PINS [51 - 58] 96: INT34BB:00 GPIOS [296 - 320] PINS [68 - 92] 128: INT34BB:00 GPIOS [328 - 351] PINS [93 - 116] 160: INT34BB:00 GPIOS [360 - 383] PINS [117 - 140] 192: INT34BB:00 GPIOS [392 - 423] PINS [141 - 172] 224: INT34BB:00 GPIOS [424 - 431] PINS [173 - 180] 256: INT34BB:00 GPIOS [456 - 479] PINS [181 - 204] 288: INT34BB:00 GPIOS [488 - 511] PINS [205 - 228]
So we will have GPIO ranges for each pad group starting at 32 pin "boundary" to align it with what the BIOS expects. Pinctrl pin numbers still follow the hardware numbering and is continuous.