Commit a0b02859 authored by Hans de Goede's avatar Hans de Goede Committed by Linus Walleij

pinctrl: cherryview: Add support for GMMR GPIO opregion

On some Cherry Trail devices the ASL uses the GMMR GPIO to access
GPIOs so as to serialize MMIO accesses to GPIO registers with the
OS, because:

"Due to a silicon issue, a shared lock must be used to prevent concurrent
accesses across the 4 GPIO controllers.

See Intel Atom Z8000 Processor Series Specification Update (Rev. 005),
errata #CHT34, for further information."

This commit adds support for this opregion, this fixes a number of
ASL errors on my Ezpad mini3 tablet and makes the otg port device/host
muxing which is controlled in firmware on this model work properly.
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent b9c6dcab
...@@ -148,6 +148,7 @@ struct chv_community { ...@@ -148,6 +148,7 @@ struct chv_community {
size_t ngpio_ranges; size_t ngpio_ranges;
size_t ngpios; size_t ngpios;
size_t nirqs; size_t nirqs;
acpi_adr_space_type acpi_space_id;
}; };
struct chv_pin_context { struct chv_pin_context {
...@@ -404,6 +405,7 @@ static const struct chv_community southwest_community = { ...@@ -404,6 +405,7 @@ static const struct chv_community southwest_community = {
* trigger GPEs. * trigger GPEs.
*/ */
.nirqs = 8, .nirqs = 8,
.acpi_space_id = 0x91,
}; };
static const struct pinctrl_pin_desc north_pins[] = { static const struct pinctrl_pin_desc north_pins[] = {
...@@ -493,6 +495,7 @@ static const struct chv_community north_community = { ...@@ -493,6 +495,7 @@ static const struct chv_community north_community = {
* GPEs. * GPEs.
*/ */
.nirqs = 8, .nirqs = 8,
.acpi_space_id = 0x92,
}; };
static const struct pinctrl_pin_desc east_pins[] = { static const struct pinctrl_pin_desc east_pins[] = {
...@@ -536,6 +539,7 @@ static const struct chv_community east_community = { ...@@ -536,6 +539,7 @@ static const struct chv_community east_community = {
.ngpio_ranges = ARRAY_SIZE(east_gpio_ranges), .ngpio_ranges = ARRAY_SIZE(east_gpio_ranges),
.ngpios = ARRAY_SIZE(east_pins), .ngpios = ARRAY_SIZE(east_pins),
.nirqs = 16, .nirqs = 16,
.acpi_space_id = 0x93,
}; };
static const struct pinctrl_pin_desc southeast_pins[] = { static const struct pinctrl_pin_desc southeast_pins[] = {
...@@ -662,6 +666,7 @@ static const struct chv_community southeast_community = { ...@@ -662,6 +666,7 @@ static const struct chv_community southeast_community = {
.ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges), .ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges),
.ngpios = ARRAY_SIZE(southeast_pins), .ngpios = ARRAY_SIZE(southeast_pins),
.nirqs = 16, .nirqs = 16,
.acpi_space_id = 0x94,
}; };
static const struct chv_community *chv_communities[] = { static const struct chv_community *chv_communities[] = {
...@@ -1586,11 +1591,34 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) ...@@ -1586,11 +1591,34 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
return 0; return 0;
} }
static acpi_status chv_pinctrl_mmio_access_handler(u32 function,
acpi_physical_address address, u32 bits, u64 *value,
void *handler_context, void *region_context)
{
struct chv_pinctrl *pctrl = region_context;
unsigned long flags;
acpi_status ret = AE_OK;
raw_spin_lock_irqsave(&chv_lock, flags);
if (function == ACPI_WRITE)
chv_writel((u32)(*value), pctrl->regs + (u32)address);
else if (function == ACPI_READ)
*value = readl(pctrl->regs + (u32)address);
else
ret = AE_BAD_PARAMETER;
raw_spin_unlock_irqrestore(&chv_lock, flags);
return ret;
}
static int chv_pinctrl_probe(struct platform_device *pdev) static int chv_pinctrl_probe(struct platform_device *pdev)
{ {
struct chv_pinctrl *pctrl; struct chv_pinctrl *pctrl;
struct acpi_device *adev; struct acpi_device *adev;
struct resource *res; struct resource *res;
acpi_status status;
int ret, irq, i; int ret, irq, i;
adev = ACPI_COMPANION(&pdev->dev); adev = ACPI_COMPANION(&pdev->dev);
...@@ -1646,11 +1674,29 @@ static int chv_pinctrl_probe(struct platform_device *pdev) ...@@ -1646,11 +1674,29 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
status = acpi_install_address_space_handler(adev->handle,
pctrl->community->acpi_space_id,
chv_pinctrl_mmio_access_handler,
NULL, pctrl);
if (ACPI_FAILURE(status))
dev_err(&pdev->dev, "failed to install ACPI addr space handler\n");
platform_set_drvdata(pdev, pctrl); platform_set_drvdata(pdev, pctrl);
return 0; return 0;
} }
static int chv_pinctrl_remove(struct platform_device *pdev)
{
struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
acpi_remove_address_space_handler(ACPI_COMPANION(&pdev->dev),
pctrl->community->acpi_space_id,
chv_pinctrl_mmio_access_handler);
return 0;
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int chv_pinctrl_suspend_noirq(struct device *dev) static int chv_pinctrl_suspend_noirq(struct device *dev)
{ {
...@@ -1758,6 +1804,7 @@ MODULE_DEVICE_TABLE(acpi, chv_pinctrl_acpi_match); ...@@ -1758,6 +1804,7 @@ MODULE_DEVICE_TABLE(acpi, chv_pinctrl_acpi_match);
static struct platform_driver chv_pinctrl_driver = { static struct platform_driver chv_pinctrl_driver = {
.probe = chv_pinctrl_probe, .probe = chv_pinctrl_probe,
.remove = chv_pinctrl_remove,
.driver = { .driver = {
.name = "cherryview-pinctrl", .name = "cherryview-pinctrl",
.pm = &chv_pinctrl_pm_ops, .pm = &chv_pinctrl_pm_ops,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment