diff --git a/src/device/pnp_device.c b/src/device/pnp_device.c index c58b375277..81aa8890b2 100644 --- a/src/device/pnp_device.c +++ b/src/device/pnp_device.c @@ -31,6 +31,19 @@ void pnp_exit_conf_mode(struct device *dev) dev->ops->ops_pnp_mode->exit_conf_mode(dev); } +#if CONFIG(HAVE_ACPI_TABLES) +void pnp_ssdt_enter_conf_mode(struct device *dev, const char *idx, const char *data) +{ + if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_enter_conf_mode) + dev->ops->ops_pnp_mode->ssdt_enter_conf_mode(dev, idx, data); +} +void pnp_ssdt_exit_conf_mode(struct device *dev, const char *idx, const char *data) +{ + if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_exit_conf_mode) + dev->ops->ops_pnp_mode->ssdt_exit_conf_mode(dev, idx, data); +} +#endif + /* PNP fundamental operations */ void pnp_write_config(struct device *dev, u8 reg, u8 value) diff --git a/src/include/device/pnp.h b/src/include/device/pnp.h index d459fd2fd0..800bcc0557 100644 --- a/src/include/device/pnp.h +++ b/src/include/device/pnp.h @@ -67,13 +67,34 @@ struct resource *pnp_get_resource(struct device *dev, unsigned int index); void pnp_enable_devices(struct device *dev, struct device_operations *ops, unsigned int functions, struct pnp_info *info); + struct pnp_mode_ops { void (*enter_conf_mode)(struct device *dev); void (*exit_conf_mode)(struct device *dev); +#if CONFIG(HAVE_ACPI_TABLES) + /* + * Generates ASL code to enter/exit config mode. + * + * @param idx The ACPI name of the SuperIO index port register. eg. 'INDX'. + * @param data The ACPI name of the SuperIO data port register. eg. 'DATA'. + */ + void (*ssdt_enter_conf_mode)(struct device *dev, const char *idx, const char *data); + void (*ssdt_exit_conf_mode)(struct device *dev, const char *idx, const char *data); +#endif }; void pnp_enter_conf_mode(struct device *dev); void pnp_exit_conf_mode(struct device *dev); - +#if CONFIG(HAVE_ACPI_TABLES) +/* + * Generates ASL code to enter/exit config mode if supported. + * The calling code has to place this within an ASL MethodOP. + * + * @param idx The ACPI name of the SuperIO index port register. eg. 'INDX'. + * @param data The ACPI name of the SuperIO data port register. eg. 'DATA'. + */ +void pnp_ssdt_enter_conf_mode(struct device *dev, const char *idx, const char *data); +void pnp_ssdt_exit_conf_mode(struct device *dev, const char *idx, const char *data); +#endif /* PNP indexed I/O operations */ /* diff --git a/src/superio/common/conf_mode.c b/src/superio/common/conf_mode.c index 8ba1cddba9..1e62285444 100644 --- a/src/superio/common/conf_mode.c +++ b/src/superio/common/conf_mode.c @@ -17,6 +17,7 @@ #include #include #include +#include /* Common enter/exit implementations */ @@ -77,38 +78,173 @@ void pnp_exit_conf_mode_0202(struct device *dev) pnp_write_config(dev, 0x02, (1 << 1)); } +/* Functions for ACPI */ +#if CONFIG(HAVE_ACPI_TABLES) +static void pnp_ssdt_enter_conf_mode_55(struct device *dev, const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0x55); + acpigen_emit_namestring(idx); +} + +static void pnp_ssdt_enter_conf_mode_6767(struct device *dev, const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0x67); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0x67); + acpigen_emit_namestring(idx); +} + +static void pnp_ssdt_enter_conf_mode_7777(struct device *dev, const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0x77); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0x77); + acpigen_emit_namestring(idx); +} + +static void pnp_ssdt_enter_conf_mode_8787(struct device *dev, const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0x87); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0x87); + acpigen_emit_namestring(idx); +} + +static void pnp_ssdt_enter_conf_mode_a0a0(struct device *dev, const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0xa0); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0xa0); + acpigen_emit_namestring(idx); + +} + +static void pnp_ssdt_enter_conf_mode_a5a5(struct device *dev, const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0xa5); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0xa5); + acpigen_emit_namestring(idx); +} + +static void pnp_ssdt_enter_conf_mode_870155aa(struct device *dev, + const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0x87); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0x01); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0x55); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + if (dev->path.pnp.port == 0x4e) + acpigen_write_byte(0xaa); + else + acpigen_write_byte(0x55); + acpigen_emit_namestring(idx); +} + +static void pnp_ssdt_exit_conf_mode_aa(struct device *dev, const char *idx, const char *data) +{ + acpigen_write_store(); + acpigen_write_byte(0xaa); + acpigen_emit_namestring(idx); +} + +static void pnp_ssdt_exit_conf_mode_0202(struct device *dev, const char *idx, const char *data) +{ + + acpigen_write_store(); + acpigen_write_byte(0x02); + acpigen_emit_namestring(idx); + + acpigen_write_store(); + acpigen_write_byte(0x02); + acpigen_emit_namestring(data); +} +#endif const struct pnp_mode_ops pnp_conf_mode_55_aa = { .enter_conf_mode = pnp_enter_conf_mode_55, .exit_conf_mode = pnp_exit_conf_mode_aa, +#if CONFIG(HAVE_ACPI_TABLES) + .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_55, + .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa, +#endif }; const struct pnp_mode_ops pnp_conf_mode_6767_aa = { .enter_conf_mode = pnp_enter_conf_mode_6767, .exit_conf_mode = pnp_exit_conf_mode_aa, +#if CONFIG(HAVE_ACPI_TABLES) + .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_6767, + .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa, +#endif }; const struct pnp_mode_ops pnp_conf_mode_7777_aa = { .enter_conf_mode = pnp_enter_conf_mode_7777, .exit_conf_mode = pnp_exit_conf_mode_aa, +#if CONFIG(HAVE_ACPI_TABLES) + .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_7777, + .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa, +#endif }; const struct pnp_mode_ops pnp_conf_mode_8787_aa = { .enter_conf_mode = pnp_enter_conf_mode_8787, .exit_conf_mode = pnp_exit_conf_mode_aa, +#if CONFIG(HAVE_ACPI_TABLES) + .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_8787, + .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa, +#endif }; const struct pnp_mode_ops pnp_conf_mode_a0a0_aa = { .enter_conf_mode = pnp_enter_conf_mode_a0a0, .exit_conf_mode = pnp_exit_conf_mode_aa, +#if CONFIG(HAVE_ACPI_TABLES) + .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_a0a0, + .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa, +#endif }; const struct pnp_mode_ops pnp_conf_mode_a5a5_aa = { .enter_conf_mode = pnp_enter_conf_mode_a5a5, .exit_conf_mode = pnp_exit_conf_mode_aa, +#if CONFIG(HAVE_ACPI_TABLES) + .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_a5a5, + .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa, +#endif }; const struct pnp_mode_ops pnp_conf_mode_870155_aa = { .enter_conf_mode = pnp_enter_conf_mode_870155aa, .exit_conf_mode = pnp_exit_conf_mode_0202, +#if CONFIG(HAVE_ACPI_TABLES) + .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_870155aa, + .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_0202, +#endif };